LCOV - code coverage report
Current view: top level - sql/backends/monet5/UDF/pyapi3 - type_conversion3.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 43 105 41.0 %
Date: 2020-06-29 20:00:14 Functions: 7 34 20.6 %

          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 "type_conversion.h"
      11             : #include "unicode.h"
      12             : 
      13             : #include <longintrepr.h>
      14             : 
      15             : #if PY_MAJOR_VERSION >= 3
      16             : #define IS_PY3K
      17             : #define PyInt_Check PyLong_Check
      18             : #define PyString_CheckExact PyUnicode_CheckExact
      19             : #endif
      20             : 
      21          15 : bool string_copy(const char *source, char *dest, size_t max_size, bool allow_unicode)
      22             : {
      23          15 :         size_t i;
      24         152 :         for (i = 0; i < max_size; i++) {
      25         152 :                 dest[i] = source[i];
      26         152 :                 if (dest[i] == 0)
      27             :                         return TRUE;
      28         137 :                 if (!allow_unicode && source[i] & 0x80)
      29             :                         return FALSE;
      30             :         }
      31           0 :         dest[max_size] = '\0';
      32           0 :         return TRUE;
      33             : }
      34             : 
      35             : #ifdef HAVE_HGE
      36           2 : int hge_to_string(char *str, hge x)
      37             : {
      38           2 :         size_t len = 256; /* assume str is large enough */
      39           2 :         hgeToStr(&str, &len, &x, false);
      40           2 :         return TRUE;
      41             : }
      42             : 
      43           0 : PyObject *PyLong_FromHge(hge h)
      44             : {
      45           0 :         PyLongObject *z;
      46           0 :         size_t size = 0;
      47           0 :         hge shift = h >= 0 ? h : -h;
      48           0 :         hge prev = shift;
      49           0 :         int i;
      50           0 :         while (shift > 0) {
      51           0 :                 size++;
      52           0 :                 shift = shift >> PyLong_SHIFT;
      53             :         }
      54           0 :         z = _PyLong_New(size);
      55           0 :         for (i = size - 1; i >= 0; i--) {
      56           0 :                 digit result = (digit)(prev >> (PyLong_SHIFT * i));
      57           0 :                 prev = prev - ((prev >> (PyLong_SHIFT * i)) << (PyLong_SHIFT * i));
      58           0 :                 z->ob_digit[i] = result;
      59             :         }
      60           0 :         if (h < 0)
      61           0 :                 Py_SIZE(z) = -(Py_SIZE(z));
      62           0 :         return (PyObject *)z;
      63             : }
      64             : #endif
      65             : 
      66          17 : size_t pyobject_get_size(PyObject *obj)
      67             : {
      68          17 :         size_t size = 256;
      69             : 
      70          17 :         if (
      71             : #ifndef IS_PY3K
      72             :             PyString_CheckExact(obj) ||
      73             : #endif
      74          17 :             PyByteArray_CheckExact(obj)) {
      75           0 :                 size = Py_SIZE(obj); // Normal strings are 1 byte per character
      76          17 :         } else if (PyUnicode_CheckExact(obj)) {
      77          15 :                 size = Py_SIZE(obj) * 4; // UTF32 is 4 bytes per character
      78             :         }
      79          17 :         return size;
      80             : }
      81             : 
      82             : 
      83           0 : str pyobject_to_blob(PyObject **ptr, size_t maxsize, blob **value) {
      84           0 :         size_t size;
      85           0 :         char* bytes_data;
      86           0 :         PyObject *obj;
      87           0 :         str msg = MAL_SUCCEED;
      88           0 :         if (ptr == NULL || *ptr == NULL) {
      89           0 :                 msg = createException(MAL, "pyapi3.eval", "Invalid PyObject.");
      90           0 :                 goto wrapup;
      91             :         }
      92           0 :         obj = *ptr;
      93             : 
      94           0 :         (void)maxsize;
      95             : #ifndef IS_PY3K
      96             :         if (PyString_CheckExact(obj)) {
      97             :                 size = PyString_Size(obj);
      98             :                 bytes_data = ((PyStringObject *)obj)->ob_sval;
      99             :         } else
     100             : #endif
     101           0 :         if (PyByteArray_CheckExact(obj)) {
     102           0 :                 size = PyByteArray_Size(obj);
     103           0 :                 bytes_data = ((PyByteArrayObject *)obj)->ob_bytes;
     104             :         } else {
     105           0 :                 msg = createException(
     106             :                         MAL, "pyapi3.eval",
     107             :                         "Unrecognized Python object. Could not convert to blob.\n");
     108           0 :                 goto wrapup;
     109             :         }
     110             : 
     111           0 :         *value = GDKmalloc(sizeof(blob) + size + 1);
     112           0 :         if (!*value) {
     113           0 :                 msg = createException(MAL, "pyapi3.eval", SQLSTATE(HY013) MAL_MALLOC_FAIL);
     114           0 :                 goto wrapup;
     115             :         }
     116           0 :         (*value)->nitems = size;
     117           0 :         memcpy((*value)->data, bytes_data, size);
     118           0 : wrapup:
     119           0 :         return msg;
     120             : }
     121             : 
     122          17 : str pyobject_to_str(PyObject **ptr, size_t maxsize, str *value)
     123             : {
     124          17 :         PyObject *obj;
     125          17 :         str msg = MAL_SUCCEED;
     126          17 :         str utf8_string = NULL;
     127          17 :         size_t len = 0;
     128             : 
     129          17 :         if (ptr == NULL || *ptr == NULL) {
     130           0 :                 msg = createException(MAL, "pyapi3.eval", SQLSTATE(PY000) "Invalid PyObject.");
     131           0 :                 goto wrapup;
     132             :         }
     133          17 :         obj = *ptr;
     134             : 
     135          17 :         utf8_string = *value;
     136          17 :         if (!utf8_string) {
     137           7 :                 utf8_string = (str)malloc(len = (pyobject_get_size(obj) + 1));
     138           7 :                 if (!utf8_string) {
     139           0 :                         msg = createException(MAL, "pyapi3.eval",
     140             :                                                                   SQLSTATE(HY013) MAL_MALLOC_FAIL "python string");
     141           0 :                         goto wrapup;
     142             :                 }
     143           7 :                 *value = utf8_string;
     144             :         } else {
     145             :                 len = maxsize;
     146             :         }
     147             : 
     148             : #ifndef IS_PY3K
     149             :         if (PyString_CheckExact(obj)) {
     150             :                 char *str = ((PyStringObject *)obj)->ob_sval;
     151             :                 if (!string_copy(str, utf8_string, len-1, false)) {
     152             :                         msg = createException(MAL, "pyapi3.eval",
     153             :                                                                   SQLSTATE(PY000) "Invalid string encoding used. Please return "
     154             :                                                                   "a regular ASCII string, or a Numpy_Unicode "
     155             :                                                                   "object.\n");
     156             :                         goto wrapup;
     157             :                 }
     158             :         } else
     159             : #endif
     160          17 :                 if (PyByteArray_CheckExact(obj)) {
     161           0 :                 char *str = ((PyByteArrayObject *)obj)->ob_bytes;
     162           0 :                 if (!string_copy(str, utf8_string, len-1, false)) {
     163           0 :                         msg = createException(MAL, "pyapi3.eval",
     164             :                                                                   SQLSTATE(PY000) "Invalid string encoding used. Please return "
     165             :                                                                   "a regular ASCII string, or a Numpy_Unicode "
     166             :                                                                   "object.\n");
     167           0 :                         goto wrapup;
     168             :                 }
     169          17 :         } else if (PyUnicode_CheckExact(obj)) {
     170             : #ifndef IS_PY3K
     171             :                 Py_UNICODE *str = (Py_UNICODE *)((PyUnicodeObject *)obj)->str;
     172             : #if Py_UNICODE_SIZE >= 4
     173             :                 utf32_to_utf8(0, ((PyUnicodeObject *)obj)->length, utf8_string, str);
     174             : #else
     175             :                 ucs2_to_utf8(0, ((PyUnicodeObject *)obj)->length, utf8_string, str);
     176             : #endif
     177             : #else
     178          15 :                 const char *str = PyUnicode_AsUTF8(obj);
     179          15 :                 if (!string_copy(str, utf8_string, len-1, true)) {
     180           0 :                         msg = createException(MAL, "pyapi3.eval",
     181             :                                                                   SQLSTATE(PY000) "Invalid string encoding used. Please return "
     182             :                                                                   "a regular ASCII string, or a Numpy_Unicode "
     183             :                                                                   "object.\n");
     184           0 :                         goto wrapup;
     185             :                 }
     186             : #endif
     187           2 :         } else if (PyBool_Check(obj) || PyLong_Check(obj) || PyInt_Check(obj) ||
     188           2 :                            PyFloat_Check(obj)) {
     189             : #ifdef HAVE_HGE
     190           2 :                 hge h;
     191           2 :                 pyobject_to_hge(&obj, 0, &h);
     192           2 :                 hge_to_string(utf8_string, h);
     193             : #else
     194             :                 lng h;
     195             :                 pyobject_to_lng(&obj, 0, &h);
     196             :                 snprintf(utf8_string, utf8string_minlength, LLFMT, h);
     197             : #endif
     198             :         } else {
     199           0 :                 msg = createException(
     200             :                         MAL, "pyapi3.eval",
     201             :                         SQLSTATE(PY000) "Unrecognized Python object. Could not convert to NPY_UNICODE.\n");
     202           0 :                 goto wrapup;
     203             :         }
     204          17 : wrapup:
     205          17 :         return msg;
     206             : }
     207             : 
     208             : #define STRING_TO_NUMBER_FACTORY(tpe)                                          \
     209             :         str str_to_##tpe(const char *ptr, size_t maxsize, tpe *value)              \
     210             :         {                                                                          \
     211             :                 size_t len = sizeof(tpe);                                              \
     212             :                 char buf[256];                                                         \
     213             :                 if (maxsize > 0) {                                                     \
     214             :                         if (maxsize >= sizeof(buf))                                        \
     215             :                                 maxsize = sizeof(buf) - 1;                                     \
     216             :                         strncpy(buf, ptr, maxsize);                                        \
     217             :                         buf[maxsize] = 0;                                                  \
     218             :                         if (strlen(buf) >= sizeof(buf) - 1)                                \
     219             :                                 return GDKstrdup("string too long to convert.");               \
     220             :                         ptr = buf;                                                         \
     221             :                 }                                                                      \
     222             :                 if (BATatoms[TYPE_##tpe].atomFromStr(ptr, &len, (void **)&value, false) < 0) \
     223             :                         return GDKstrdup("Error converting string.");                      \
     224             :                 return MAL_SUCCEED;                                                    \
     225             :         }
     226             : 
     227             : #ifndef IS_PY3K
     228             : #define PY_TO_(type, inttpe)                                            \
     229             : str pyobject_to_##type(PyObject **pyobj, size_t maxsize, type *value)   \
     230             : {                                                                       \
     231             :         PyObject *ptr = *pyobj;                                         \
     232             :         str retval = MAL_SUCCEED;                                               \
     233             :         (void) maxsize;                                                 \
     234             :         if (PyLong_CheckExact(ptr)) {                                   \
     235             :                 PyLongObject *p = (PyLongObject*) ptr;                          \
     236             :                 inttpe h = 0;                                                   \
     237             :                 inttpe prev = 0;                                                \
     238             :                 ssize_t i = Py_SIZE(p);                                         \
     239             :                 int sign = i < 0 ? -1 : 1;                                   \
     240             :                 i *= sign;                                                      \
     241             :                 while (--i >= 0) {                                           \
     242             :                         prev = h; (void)prev;                                   \
     243             :                         h = (h << PyLong_SHIFT) + p->ob_digit[i];                      \
     244             :                         if ((h >> PyLong_SHIFT) != prev) {                                \
     245             :                                 return GDKstrdup("Overflow when converting value.");  \
     246             :                         }                                                               \
     247             :                 }                                                               \
     248             :                 *value = (type)(h * sign);                                      \
     249             :         } else if (PyInt_CheckExact(ptr) || PyBool_Check(ptr)) {                \
     250             :                 *value = (type)((PyIntObject*)ptr)->ob_ival;                 \
     251             :         } else if (PyFloat_CheckExact(ptr)) {                           \
     252             :                 *value = isnan(((PyFloatObject*)ptr)->ob_fval) ? type##_nil : (type) ((PyFloatObject*)ptr)->ob_fval; \
     253             :         } else if (PyString_CheckExact(ptr)) {                          \
     254             :                 return str_to_##type(((PyStringObject*)ptr)->ob_sval, 0, value); \
     255             :         }  else if (PyByteArray_CheckExact(ptr)) {                              \
     256             :                 return str_to_##type(((PyByteArrayObject*)ptr)->ob_bytes, 0, value); \
     257             :         } else if (PyUnicode_CheckExact(ptr)) {                         \
     258             :                 return unicode_to_##type(((PyUnicodeObject*)ptr)->str, 0, value); \
     259             :         } else if (ptr == Py_None) {                                    \
     260             :                 *value = type##_nil;                                            \
     261             :         }                                                                       \
     262             :         return retval;                                                  \
     263             : }
     264             : #else
     265             : #define PY_TO_(type, inttpe)                                            \
     266             : str pyobject_to_##type(PyObject **pyobj, size_t maxsize, type *value)   \
     267             : {                                                                       \
     268             :         PyObject *ptr = *pyobj;                                         \
     269             :         str retval = MAL_SUCCEED;                                               \
     270             :         (void) maxsize;                                                 \
     271             :         if (PyLong_CheckExact(ptr)) {                                   \
     272             :                 PyLongObject *p = (PyLongObject*) ptr;                          \
     273             :                 inttpe h = 0;                                                   \
     274             :                 inttpe prev = 0;                                                \
     275             :                 Py_ssize_t i = Py_SIZE(p);                                              \
     276             :                 int sign = i < 0 ? -1 : 1;                                   \
     277             :                 i *= sign;                                                      \
     278             :                 while (--i >= 0) {                                           \
     279             :                         prev = h; (void)prev;                                   \
     280             :                         h = (h << PyLong_SHIFT) + p->ob_digit[i];                      \
     281             :                         if ((h >> PyLong_SHIFT) != prev) {                                \
     282             :                                 return GDKstrdup("Overflow when converting value.");  \
     283             :                         }                                                               \
     284             :                 }                                                               \
     285             :                 *value = (type)(h * sign);                                      \
     286             :         } else if (PyBool_Check(ptr)) {                                 \
     287             :                 *value = ptr == Py_True ? (type) 1 : (type) 0;                  \
     288             :         } else if (PyFloat_CheckExact(ptr)) {                           \
     289             :                 *value = isnan(((PyFloatObject*)ptr)->ob_fval) ? type##_nil : (type) ((PyFloatObject*)ptr)->ob_fval; \
     290             :         } else if (PyUnicode_CheckExact(ptr)) {                         \
     291             :                 return str_to_##type(PyUnicode_AsUTF8(ptr), 0, value);          \
     292             :         }  else if (PyByteArray_CheckExact(ptr)) {                              \
     293             :                 return str_to_##type(((PyByteArrayObject*)ptr)->ob_bytes, 0, value); \
     294             :         }  else if (ptr == Py_None) {                                   \
     295             :                 *value = type##_nil;                                            \
     296             :         }                                                                       \
     297             :         return retval;                                                  \
     298             : }
     299             : #endif
     300             : 
     301             : #define CONVERSION_FUNCTION_FACTORY(tpe, inttpe)            \
     302             :         STRING_TO_NUMBER_FACTORY(tpe)                   \
     303             :         str unicode_to_##tpe(Py_UNICODE *ptr, size_t maxsize, tpe *value)   \
     304             :         {                                   \
     305             :                 char utf8[1024];                        \
     306             :         if (maxsize == 0)                       \
     307             :                         maxsize = utf32_strlen(ptr);                \
     308             :         if (maxsize > 255)                      \
     309             :                         maxsize = 255;                      \
     310             :                 unicode_to_utf8(0, maxsize, utf8, ptr);             \
     311             :                 return str_to_##tpe(utf8, 0, value);                \
     312             :         }                                   \
     313             :         PY_TO_(tpe, inttpe);
     314             : 
     315           0 : CONVERSION_FUNCTION_FACTORY(bte, bte)
     316           0 : CONVERSION_FUNCTION_FACTORY(oid, oid)
     317           0 : CONVERSION_FUNCTION_FACTORY(bit, bit)
     318           0 : CONVERSION_FUNCTION_FACTORY(sht, sht)
     319         368 : CONVERSION_FUNCTION_FACTORY(int, int)
     320           0 : CONVERSION_FUNCTION_FACTORY(lng, lng)
     321           0 : CONVERSION_FUNCTION_FACTORY(flt, lng)
     322             : 
     323             : #ifdef HAVE_HGE
     324           4 : CONVERSION_FUNCTION_FACTORY(hge, hge)
     325          12 : CONVERSION_FUNCTION_FACTORY(dbl, hge)
     326             : #else
     327             : CONVERSION_FUNCTION_FACTORY(dbl, lng)
     328             : #endif
     329             : 
     330           0 : void _typeconversion_init(void) { _import_array(); }

Generated by: LCOV version 1.14