Changeset: bb647b65e1c9 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=bb647b65e1c9
Modified Files:
        sql/backends/monet5/Tests/pyapi09.sql
        sql/backends/monet5/Tests/pyapi21.sql
        sql/backends/monet5/UDF/pyapi/conversion.c
Branch: default
Log Message:

Add support for blob/sqlblob conversions to Python UDFs.


diffs (truncated from 1793 to 300 lines):

diff --git a/sql/backends/monet5/Tests/pyapi09.sql 
b/sql/backends/monet5/Tests/pyapi09.sql
--- a/sql/backends/monet5/Tests/pyapi09.sql
+++ b/sql/backends/monet5/Tests/pyapi09.sql
@@ -40,7 +40,7 @@ DROP TABLE pyapi09multiplication;
 
 #Third test: Store python object in table and load it in later function
 
-CREATE FUNCTION pyapi09create() returns TABLE(s STRING)
+CREATE FUNCTION pyapi09create() returns TABLE(s BLOB)
 language P
 {
     import pickle
@@ -58,7 +58,7 @@ language P
     import pickle
     res = _conn.execute('SELECT s FROM pyapi09objects;')
     array = pickle.loads(res['s'][0])
-    print array
+    print(array)
     return array[:10]
 };
 
diff --git a/sql/backends/monet5/Tests/pyapi21.sql 
b/sql/backends/monet5/Tests/pyapi21.sql
--- a/sql/backends/monet5/Tests/pyapi21.sql
+++ b/sql/backends/monet5/Tests/pyapi21.sql
@@ -2,7 +2,7 @@
 START TRANSACTION;
 
 
-CREATE FUNCTION pyapi21_create() returns TABLE(s STRING)
+CREATE FUNCTION pyapi21_create() returns TABLE(s BLOB)
 language P
 {
        import pickle
@@ -18,12 +18,12 @@ language P
     return result
 };
 
-CREATE FUNCTION pyapi21_load(objects STRING) returns BOOLEAN
+CREATE FUNCTION pyapi21_load(objects BLOB) returns BOOLEAN
 LANGUAGE P
 {
        import pickle
        for x in [pickle.loads(y) for y in objects]:
-               print str(type(x)) + ": " + str(x)
+               print(str(type(x)) + ": " + str(x))
        return True
 };
 
diff --git a/sql/backends/monet5/UDF/pyapi/conversion.c 
b/sql/backends/monet5/UDF/pyapi/conversion.c
--- a/sql/backends/monet5/UDF/pyapi/conversion.c
+++ b/sql/backends/monet5/UDF/pyapi/conversion.c
@@ -4,6 +4,7 @@
 #include "pytypes.h"
 #include "type_conversion.h"
 #include "unicode.h"
+#include "blob.h"
 #ifndef HAVE_EMBEDDED
 #include "gdk_interprocess.h"
 #endif
@@ -23,899 +24,960 @@ CREATE_SQL_FUNCTION_PTR(str,batdbl_num2d
 //! Wrapper to get eclass of SQL type
 int GetSQLType(sql_subtype *sql_subtype);
 
+static bool IsBlobType(int type) {
+       return type == TYPE_blob || type == TYPE_sqlblob;
+}
+
 PyObject *PyArrayObject_FromScalar(PyInput* inp, char **return_message)
 {
-    PyObject *vararray = NULL;
-    char *msg = NULL;
-    assert(inp->scalar); //input has to be a scalar
+       PyObject *vararray = NULL;
+       char *msg = NULL;
+       assert(inp->scalar); //input has to be a scalar
 
-    switch(inp->bat_type)
-    {
-        case TYPE_bit:
-            vararray = PyInt_FromLong((long)(*(bit*)inp->dataptr));
-            break;
-        case TYPE_bte:
-            vararray = PyInt_FromLong((long)(*(bte*)inp->dataptr));
-            break;
-        case TYPE_sht:
-            vararray = PyInt_FromLong((long)(*(sht*)inp->dataptr));
-            break;
-        case TYPE_int:
-            vararray = PyInt_FromLong((long)(*(int*)inp->dataptr));
-            break;
-        case TYPE_lng:
-            vararray = PyLong_FromLongLong((*(lng*)inp->dataptr));
-            break;
-        case TYPE_flt:
-            vararray = PyFloat_FromDouble((double)(*(flt*)inp->dataptr));
-            break;
-        case TYPE_dbl:
-            vararray = PyFloat_FromDouble((double)(*(dbl*)inp->dataptr));
-            break;
+       switch(inp->bat_type)
+       {
+               case TYPE_bit:
+                       vararray = PyInt_FromLong((long)(*(bit*)inp->dataptr));
+                       break;
+               case TYPE_bte:
+                       vararray = PyInt_FromLong((long)(*(bte*)inp->dataptr));
+                       break;
+               case TYPE_sht:
+                       vararray = PyInt_FromLong((long)(*(sht*)inp->dataptr));
+                       break;
+               case TYPE_int:
+                       vararray = PyInt_FromLong((long)(*(int*)inp->dataptr));
+                       break;
+               case TYPE_lng:
+                       vararray = PyLong_FromLongLong((*(lng*)inp->dataptr));
+                       break;
+               case TYPE_flt:
+                       vararray = 
PyFloat_FromDouble((double)(*(flt*)inp->dataptr));
+                       break;
+               case TYPE_dbl:
+                       vararray = 
PyFloat_FromDouble((double)(*(dbl*)inp->dataptr));
+                       break;
 #ifdef HAVE_HGE
-        case TYPE_hge:
-            vararray = PyLong_FromHge(*((hge *) inp->dataptr));
-            break;
+               case TYPE_hge:
+                       vararray = PyLong_FromHge(*((hge *) inp->dataptr));
+                       break;
 #endif
-        case TYPE_str:
-            vararray = PyUnicode_FromString(*((char**) inp->dataptr));
-            break;
-        default:
-            msg = createException(MAL, "pyapi.eval", "Unsupported scalar type 
%i.", inp->bat_type);
-            goto wrapup;
-    }
-    if (vararray == NULL)
-    {
-        msg = createException(MAL, "pyapi.eval", "Something went wrong 
converting the MonetDB scalar to a Python scalar.");
-        goto wrapup;
-    }
+               case TYPE_str:
+                       vararray = PyUnicode_FromString(*((char**) 
inp->dataptr));
+                       break;
+               default:
+                       msg = createException(MAL, "pyapi.eval", "Unsupported 
scalar type %i.", inp->bat_type);
+                       goto wrapup;
+       }
+       if (vararray == NULL)
+       {
+               msg = createException(MAL, "pyapi.eval", "Something went wrong 
converting the MonetDB scalar to a Python scalar.");
+               goto wrapup;
+       }
 wrapup:
-    *return_message = msg;
-    return vararray;
+       *return_message = msg;
+       return vararray;
 }
 
 PyObject *PyMaskedArray_FromBAT(PyInput *inp, size_t t_start, size_t t_end, 
char **return_message, bool copy)
 {
-    BAT *b = inp->bat;
-    char *msg;
-    PyObject *vararray;
+       BAT *b = inp->bat;
+       char *msg;
+       PyObject *vararray;
 
-    vararray = PyArrayObject_FromBAT(inp, t_start, t_end, return_message, 
copy);
-    if (vararray == NULL) {
-        return NULL;
-    }
-    // To deal with null values, we use the numpy masked array structure
-    // The masked array structure is an object with two arrays of equal size, 
a data array and a mask array
-    // The mask array is a boolean array that has the value 'True' when the 
element is NULL, and 'False' otherwise
-    // If the BAT has Null values, we construct this masked array
-    if (!(b->tnil == 0 && b->tnonil == 1))
-    {
-        PyObject *mask;
-        PyObject *mafunc = 
PyObject_GetAttrString(PyImport_Import(PyString_FromString("numpy.ma")), 
"masked_array");
-        PyObject *maargs;
-        PyObject *nullmask = PyNullMask_FromBAT(b, t_start, t_end);
+       vararray = PyArrayObject_FromBAT(inp, t_start, t_end, return_message, 
copy);
+       if (vararray == NULL) {
+               return NULL;
+       }
+       // To deal with null values, we use the numpy masked array structure
+       // The masked array structure is an object with two arrays of equal 
size, a data array and a mask array
+       // The mask array is a boolean array that has the value 'True' when the 
element is NULL, and 'False' otherwise
+       // If the BAT has Null values, we construct this masked array
+       if (!(b->tnil == 0 && b->tnonil == 1))
+       {
+               PyObject *mask;
+               PyObject *mafunc = 
PyObject_GetAttrString(PyImport_Import(PyString_FromString("numpy.ma")), 
"masked_array");
+               PyObject *maargs;
+               PyObject *nullmask = PyNullMask_FromBAT(b, t_start, t_end);
 
-        if (nullmask == Py_None) {
-            maargs = PyTuple_New(1);
-            PyTuple_SetItem(maargs, 0, vararray);
-        } else {
-            maargs = PyTuple_New(2);
-            PyTuple_SetItem(maargs, 0, vararray);
-            PyTuple_SetItem(maargs, 1, (PyObject*) nullmask);
-        }
+               if (nullmask == Py_None) {
+                       maargs = PyTuple_New(1);
+                       PyTuple_SetItem(maargs, 0, vararray);
+               } else {
+                       maargs = PyTuple_New(2);
+                       PyTuple_SetItem(maargs, 0, vararray);
+                       PyTuple_SetItem(maargs, 1, (PyObject*) nullmask);
+               }
 
-        // Now we will actually construct the mask by calling the masked array 
constructor
-        mask = PyObject_CallObject(mafunc, maargs);
-        if (!mask) {
-            msg = createException(MAL, "pyapi.eval", "Failed to create mask");
-            goto wrapup;
-        }
-        Py_DECREF(maargs);
-        Py_DECREF(mafunc);
+               // Now we will actually construct the mask by calling the 
masked array constructor
+               mask = PyObject_CallObject(mafunc, maargs);
+               if (!mask) {
+                       msg = createException(MAL, "pyapi.eval", "Failed to 
create mask");
+                       goto wrapup;
+               }
+               Py_DECREF(maargs);
+               Py_DECREF(mafunc);
 
-        vararray = mask;
-    }
-    return vararray;
+               vararray = mask;
+       }
+       return vararray;
 wrapup:
-    *return_message = msg;
-    return NULL;
+       *return_message = msg;
+       return NULL;
 }
 
 PyObject *PyArrayObject_FromBAT(PyInput *inp, size_t t_start, size_t t_end, 
char **return_message, bool copy)
 {
-    // This variable will hold the converted Python object
-    PyObject *vararray = NULL;
-    char *msg;
-    size_t j = 0;
-    BUN p = 0, q = 0;
-    BATiter li;
-    BAT *b = inp->bat;
-    npy_intp elements[1] = { t_end-t_start };
+       // This variable will hold the converted Python object
+       PyObject *vararray = NULL;
+       char *msg;
+       size_t j = 0;
+       BUN p = 0, q = 0;
+       BATiter li;
+       BAT *b = inp->bat;
+       npy_intp elements[1] = { t_end-t_start };
 
-    assert(!inp->scalar); //input has to be a BAT
+       assert(!inp->scalar); //input has to be a BAT
 
-    if (!b) {
-        // No BAT was found, we can't do anything in this case
-        msg = createException(MAL, "pyapi.eval", MAL_MALLOC_FAIL" bat.");
-        goto wrapup;
-    }
+       if (!b) {
+               // No BAT was found, we can't do anything in this case
+               msg = createException(MAL, "pyapi.eval", MAL_MALLOC_FAIL" 
bat.");
+               goto wrapup;
+       }
 
-    if (!IsStandardBATType(inp->bat_type) || 
ConvertableSQLType(inp->sql_subtype)) { // if the sql type is set, we have to 
do some conversion
-        if (inp->scalar) {
-            // todo: scalar SQL types
-            msg = createException(MAL, "pyapi.eval", "Scalar SQL types haven't 
been implemented yet... sorry");
-            goto wrapup;
-        } else {
-            BAT *ret_bat = NULL;
-            msg = ConvertFromSQLType(inp->bat, inp->sql_subtype, &ret_bat, 
&inp->bat_type);
-            if (msg != MAL_SUCCEED) {
-                msg = createException(MAL, "pyapi.eval", "Failed to convert 
BAT.");
-                goto wrapup;
-            }
-            BBPunfix(inp->bat->batCacheid);
-            inp->bat = ret_bat;
-        }
-    }
+       if (!IsBlobType(inp->bat_type) && (!IsStandardBATType(inp->bat_type) || 
ConvertableSQLType(inp->sql_subtype))) { // if the sql type is set, we have to 
do some conversion
+               if (inp->scalar) {
+                       // FIXME: scalar SQL types
+                       msg = createException(MAL, "pyapi.eval", "Scalar SQL 
types haven't been implemented yet... sorry");
+                       goto wrapup;
_______________________________________________
checkin-list mailing list
checkin-list@monetdb.org
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to