LCOV - code coverage report
Current view: top level - sql/backends/monet5/UDF/pyapi3 - connection3.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 69 83 83.1 %
Date: 2020-06-29 20:00:14 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2020 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include "pyapi.h"
      11             : #include "conversion.h"
      12             : #include "connection.h"
      13             : #include "type_conversion.h"
      14             : #include "gdk_interprocess.h"
      15             : 
      16             : CREATE_SQL_FUNCTION_PTR(void, SQLdestroyResult);
      17             : CREATE_SQL_FUNCTION_PTR(str, SQLstatementIntern);
      18             : CREATE_SQL_FUNCTION_PTR(str, create_table_from_emit);
      19             : CREATE_SQL_FUNCTION_PTR(str, append_to_table_from_emit);
      20             : 
      21          13 : static PyObject *_connection_execute(Py_ConnectionObject *self, PyObject *args)
      22             : {
      23          13 :         char *query = NULL;
      24             : #ifndef IS_PY3K
      25             :         if (PyUnicode_CheckExact(args)) {
      26             :                 PyObject* str = PyUnicode_AsUTF8String(args);
      27             :                 if (!str) {
      28             :                         PyErr_Format(PyExc_Exception, "Unicode failure.");
      29             :                         return NULL;
      30             :                 }
      31             :                 query = GDKstrdup(((PyStringObject *)str)->ob_sval);
      32             :                 Py_DECREF(str);
      33             :         } else
      34             : #endif
      35          13 :         if (PyString_CheckExact(args)) {
      36             : #ifndef IS_PY3K
      37             :                 query = GDKstrdup(((PyStringObject *)args)->ob_sval);
      38             : #else
      39          13 :                 query = GDKstrdup(PyUnicode_AsUTF8(args));
      40             : #endif
      41             :         } else {
      42           0 :                 PyErr_Format(PyExc_TypeError,
      43             :                                          "expected a query string, but got an object of type %s",
      44             :                                          Py_TYPE(args)->tp_name);
      45           0 :                 return NULL;
      46             :         }
      47          13 :         if (!query) {
      48           0 :                 PyErr_Format(PyExc_Exception, "%s", SQLSTATE(HY013) MAL_MALLOC_FAIL);
      49           0 :                 return NULL;
      50             :         }
      51          13 :         if (!self->mapped || option_disable_fork) {
      52             :                 // This is not a mapped process, so we can just directly execute the
      53             :                 // query here
      54           6 :                 PyObject *result;
      55           6 :                 res_table *output = NULL;
      56           6 :                 char *res = NULL;
      57             : //Py_BEGIN_ALLOW_THREADS;
      58           6 :                 res = _connection_query(self->cntxt, query, &output);
      59             : //Py_END_ALLOW_THREADS;
      60           6 :                 GDKfree(query);
      61           6 :                 if (res != MAL_SUCCEED) {
      62           4 :                         PyErr_Format(PyExc_Exception, "SQL Query Failed: %s",
      63           2 :                                                  (res ? getExceptionMessage(res) : "<no error>"));
      64           2 :                         return NULL;
      65             :                 }
      66             : 
      67           4 :                 result = PyDict_New();
      68           4 :                 if (output && output->nr_cols > 0) {
      69             :                         PyInput input;
      70             :                         PyObject *numpy_array;
      71             :                         int i;
      72           8 :                         for (i = 0; i < output->nr_cols; i++) {
      73           4 :                                 res_col col = output->cols[i];
      74           4 :                                 BAT *b = BATdescriptor(col.b);
      75             : 
      76           4 :                                 if (b == NULL) {
      77           0 :                                         PyErr_Format(PyExc_Exception, "Internal error: could not retrieve bat");
      78           0 :                                         return NULL;
      79             :                                 }
      80             : 
      81           4 :                                 input.bat = b;
      82           4 :                                 input.count = BATcount(b);
      83           4 :                                 input.bat_type = getBatType(b->ttype);
      84           4 :                                 input.scalar = false;
      85           4 :                                 input.sql_subtype = &col.type;
      86             : 
      87           4 :                                 numpy_array =
      88           4 :                                         PyMaskedArray_FromBAT(&input, 0, input.count, &res, true);
      89           4 :                                 if (!numpy_array) {
      90           0 :                                         _connection_cleanup_result(output);
      91           0 :                                         BBPunfix(b->batCacheid);
      92           0 :                                         PyErr_Format(PyExc_Exception, "SQL Query Failed: %s",
      93           0 :                                                                  (res ? getExceptionMessage(res) : "<no error>"));
      94           0 :                                         return NULL;
      95             :                                 }
      96           4 :                                 PyDict_SetItem(result,
      97           4 :                                                            PyString_FromString(output->cols[i].name),
      98             :                                                            numpy_array);
      99           4 :                                 Py_DECREF(numpy_array);
     100           4 :                                 BBPunfix(input.bat->batCacheid);
     101             :                         }
     102           4 :                         _connection_cleanup_result(output);
     103           4 :                         return result;
     104             :                 } else {
     105           0 :                         Py_RETURN_NONE;
     106             :                 }
     107             :         } else {
     108           7 :                 PyErr_Format(PyExc_Exception, "Loopback queries are not supported in parallel.");
     109           7 :                 GDKfree(query);
     110           7 :                 return NULL;
     111             :         }
     112             : }
     113             : 
     114             : static PyMethodDef _connectionObject_methods[] = {
     115             :         {"execute", (PyCFunction)_connection_execute, METH_O,
     116             :          "execute(query) -> executes a SQL query on the database in the current "
     117             :          "client context"},
     118             :         {NULL, NULL, 0, NULL} /* Sentinel */
     119             : };
     120             : 
     121             : PyTypeObject Py_ConnectionType = {
     122             :         .ob_base.ob_base.ob_refcnt = 1,
     123             :         .tp_name = "monetdb._connection",
     124             :         .tp_basicsize = sizeof(Py_ConnectionObject),
     125             :         .tp_hash = (hashfunc)PyObject_HashNotImplemented,
     126             :         .tp_flags = Py_TPFLAGS_DEFAULT,
     127             :         .tp_doc = "Connection to MonetDB",
     128             :         .tp_methods = _connectionObject_methods,
     129             :         .tp_alloc = PyType_GenericAlloc,
     130             :         .tp_new = PyType_GenericNew,
     131             :         .tp_free = PyObject_Del,
     132             : };
     133             : 
     134           4 : void _connection_cleanup_result(void *output)
     135             : {
     136           4 :         (*SQLdestroyResult_ptr)((res_table *)output);
     137           4 : }
     138             : 
     139           6 : str _connection_query(Client cntxt, char *query, res_table **result)
     140             : {
     141           6 :         str res = MAL_SUCCEED;
     142           6 :         res = (*SQLstatementIntern_ptr)(cntxt, &query, "name", 1, 0, result);
     143           6 :         return res;
     144             : }
     145             : 
     146           1 : str _connection_create_table(Client cntxt, char *sname, char *tname,
     147             :                                                          sql_emit_col *columns, size_t ncols)
     148             : {
     149           1 :         return (*create_table_from_emit_ptr)(cntxt, sname, tname, columns, ncols);
     150             : }
     151             : 
     152          12 : str _connection_append_to_table(Client cntxt, char *sname, char *tname,
     153             :                                                          sql_emit_col *columns, size_t ncols)
     154             : {
     155          12 :         return (*append_to_table_from_emit_ptr)(cntxt, sname, tname, columns, ncols);
     156             : }
     157             : 
     158         164 : PyObject *Py_Connection_Create(Client cntxt, bit mapped, QueryStruct *query_ptr,
     159             :                                                            int query_sem)
     160             : {
     161         164 :         register Py_ConnectionObject *op;
     162             : 
     163         164 :         op = (Py_ConnectionObject *)PyObject_MALLOC(sizeof(Py_ConnectionObject));
     164         164 :         if (op == NULL)
     165           0 :                 return PyErr_NoMemory();
     166         164 :         PyObject_Init((PyObject *)op, &Py_ConnectionType);
     167             : 
     168         164 :         op->cntxt = cntxt;
     169         164 :         op->mapped = mapped;
     170         164 :         op->query_ptr = query_ptr;
     171         164 :         op->query_sem = query_sem;
     172             : 
     173         164 :         return (PyObject *)op;
     174             : }
     175             : 
     176           7 : static void _connection_import_array(void) { _import_array(); }
     177             : 
     178           7 : str _connection_init(void)
     179             : {
     180           7 :         str msg = MAL_SUCCEED;
     181           7 :         _connection_import_array();
     182             : 
     183           7 :         LOAD_SQL_FUNCTION_PTR(SQLdestroyResult);
     184           7 :         LOAD_SQL_FUNCTION_PTR(SQLstatementIntern);
     185           7 :         LOAD_SQL_FUNCTION_PTR(create_table_from_emit);
     186           7 :         LOAD_SQL_FUNCTION_PTR(append_to_table_from_emit);
     187             : 
     188           7 :         if (msg != MAL_SUCCEED) {
     189             :                 return msg;
     190             :         }
     191             : 
     192           7 :         if (PyType_Ready(&Py_ConnectionType) < 0)
     193           0 :                 return createException(MAL, "pyapi3.eval",
     194             :                                        SQLSTATE(PY000) "Failed to initialize connection type.");
     195             :         return msg;
     196             : }

Generated by: LCOV version 1.14