LCOV - code coverage report
Current view: top level - sql/backends/monet5/UDF/pyapi3 - connection3.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 64 78 82.1 %
Date: 2024-12-19 20:05:57 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.14