Changeset: 2ddcea96061c for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/2ddcea96061c Modified Files: sql/backends/monet5/UDF/pyapi3/type_conversion3.c Branch: Jun2023 Log Message:
Ported to Python 3.12, new code also used on 3.10 and 3.11. On 3.12 the representation of the Python Long was changed, so now we avoid looking into the object completely and use slightly higher level interfaces to get at needed information. diffs (234 lines): diff --git a/sql/backends/monet5/UDF/pyapi3/type_conversion3.c b/sql/backends/monet5/UDF/pyapi3/type_conversion3.c --- a/sql/backends/monet5/UDF/pyapi3/type_conversion3.c +++ b/sql/backends/monet5/UDF/pyapi3/type_conversion3.c @@ -9,6 +9,7 @@ */ #include "monetdb_config.h" +#define PY_SSIZE_T_CLEAN #include "type_conversion.h" #include "unicode.h" @@ -42,6 +43,7 @@ int hge_to_string(char *str, hge x) PyObject *PyLong_FromHge(hge h) { +#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 10 PyLongObject *z; size_t size = 0; hge shift = h >= 0 ? h : -h; @@ -65,6 +67,15 @@ PyObject *PyLong_FromHge(hge h) #endif } return (PyObject *)z; +#else + return PyObject_CallMethod((PyObject *) &PyLong_Type, "from_bytes", "(y#s)", &h, (Py_ssize_t) sizeof(h), +#ifdef WORDS_BIGENDIAN + "big" +#else + "little" +#endif + ); +#endif } #endif @@ -255,23 +266,23 @@ wrapup: return msg; } -#define STRING_TO_NUMBER_FACTORY(tpe) \ - str str_to_##tpe(const char *ptr, size_t maxsize, tpe *value) \ - { \ - size_t len = sizeof(tpe); \ - char buf[256]; \ - if (maxsize > 0) { \ - if (maxsize >= sizeof(buf)) \ - maxsize = sizeof(buf) - 1; \ - strncpy(buf, ptr, maxsize); \ - buf[maxsize] = 0; \ - if (strlen(buf) >= sizeof(buf) - 1) \ - return GDKstrdup("string too long to convert."); \ - ptr = buf; \ - } \ +#define STRING_TO_NUMBER_FACTORY(tpe) \ + str str_to_##tpe(const char *ptr, size_t maxsize, tpe *value) \ + { \ + size_t len = sizeof(tpe); \ + char buf[256]; \ + if (maxsize > 0) { \ + if (maxsize >= sizeof(buf)) \ + maxsize = sizeof(buf) - 1; \ + strncpy(buf, ptr, maxsize); \ + buf[maxsize] = 0; \ + if (strlen(buf) >= sizeof(buf) - 1) \ + return GDKstrdup("string too long to convert."); \ + ptr = buf; \ + } \ if (BATatoms[TYPE_##tpe].atomFromStr(ptr, &len, (void **)&value, false) < 0) \ - return GDKstrdup("Error converting string."); \ - return MAL_SUCCEED; \ + return GDKstrdup("Error converting string."); \ + return MAL_SUCCEED; \ } str str_to_date(const char *ptr, size_t maxsize, date *value) @@ -329,53 +340,118 @@ str unicode_to_timestamp(Py_UNICODE *ptr } -#define PY_TO_(type, inttpe) \ +#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 10 +#define PY_TO_(type, inttpe) \ str pyobject_to_##type(PyObject **pyobj, size_t maxsize, type *value) \ -{ \ - PyObject *ptr = *pyobj; \ - str retval = MAL_SUCCEED; \ - (void) maxsize; \ - if (PyLong_CheckExact(ptr)) { \ - PyLongObject *p = (PyLongObject*) ptr; \ - inttpe h = 0; \ - inttpe prev = 0; \ - Py_ssize_t i = Py_SIZE(p); \ - int sign = i < 0 ? -1 : 1; \ - i *= sign; \ - while (--i >= 0) { \ - prev = h; (void)prev; \ - h = (h << PyLong_SHIFT) + p->ob_digit[i]; \ - if ((h >> PyLong_SHIFT) != prev) { \ +{ \ + PyObject *ptr = *pyobj; \ + str retval = MAL_SUCCEED; \ + (void) maxsize; \ + if (PyLong_CheckExact(ptr)) { \ + PyLongObject *p = (PyLongObject*) ptr; \ + inttpe h = 0; \ + inttpe prev = 0; \ + Py_ssize_t i = Py_SIZE(p); \ + int sign = i < 0 ? -1 : 1; \ + i *= sign; \ + while (--i >= 0) { \ + prev = h; (void)prev; \ + h = (h << PyLong_SHIFT) + p->ob_digit[i]; \ + if ((h >> PyLong_SHIFT) != prev) { \ return GDKstrdup("Overflow when converting value."); \ - } \ - } \ - *value = (type)(h * sign); \ - } else if (PyBool_Check(ptr)) { \ - *value = ptr == Py_True ? (type) 1 : (type) 0; \ - } else if (PyFloat_CheckExact(ptr)) { \ + } \ + } \ + *value = (type)(h * sign); \ + } else if (PyBool_Check(ptr)) { \ + *value = ptr == Py_True ? (type) 1 : (type) 0; \ + } else if (PyFloat_CheckExact(ptr)) { \ *value = isnan(((PyFloatObject*)ptr)->ob_fval) ? type##_nil : (type) ((PyFloatObject*)ptr)->ob_fval; \ - } else if (PyUnicode_CheckExact(ptr)) { \ - return str_to_##type(PyUnicode_AsUTF8(ptr), 0, value); \ - } else if (PyByteArray_CheckExact(ptr)) { \ + } else if (PyUnicode_CheckExact(ptr)) { \ + return str_to_##type(PyUnicode_AsUTF8(ptr), 0, value); \ + } else if (PyByteArray_CheckExact(ptr)) { \ return str_to_##type(((PyByteArrayObject*)ptr)->ob_bytes, 0, value); \ - } else if (ptr == Py_None) { \ - *value = type##_nil; \ - } \ - return retval; \ + } else if (ptr == Py_None) { \ + *value = type##_nil; \ + } \ + return retval; \ } +#else +#ifdef WORDS_BIGENDIAN +#define ENDIAN "big" +#else +#define ENDIAN "little" +#endif +#define PY_TO_(type, inttpe) \ +str pyobject_to_##type(PyObject **pyobj, size_t maxsize, type *value) \ +{ \ + PyObject *ptr = *pyobj; \ + str retval = MAL_SUCCEED; \ + (void) maxsize; \ + if (PyLong_CheckExact(ptr)) { \ + inttpe h; \ + PyObject *m = PyObject_GetAttrString(ptr, "to_bytes"); \ + PyObject *d = PyDict_New(); \ + PyObject *v, *z; \ + v = PyLong_FromLong((long) sizeof(inttpe)); \ + if (m == NULL || d == NULL || v == NULL) { \ + Py_XDECREF(m); \ + Py_XDECREF(d); \ + Py_XDECREF(v); \ + throw(MAL, "pyapi3.eval", SQLSTATE(HY013) MAL_MALLOC_FAIL); \ + } \ + PyDict_SetItemString(d, "length", v); \ + Py_DECREF(v); \ + v = PyUnicode_FromString(ENDIAN); \ + if (v == NULL) { \ + Py_DECREF(m); \ + Py_DECREF(d); \ + throw(MAL, "pyapi3.eval", SQLSTATE(HY013) MAL_MALLOC_FAIL); \ + } \ + PyDict_SetItemString(d, "byteorder", v); \ + Py_DECREF(v); \ + PyDict_SetItemString(d, "signed", Py_True); \ + v = PyTuple_New(0); \ + if (v == NULL) { \ + Py_DECREF(m); \ + Py_DECREF(d); \ + throw(MAL, "pyapi3.eval", SQLSTATE(HY013) MAL_MALLOC_FAIL); \ + } \ + z = PyObject_Call(m, v, d); \ + Py_DECREF(v); \ + Py_DECREF(d); \ + if (z == NULL) { \ + throw(MAL, "pyapi3.eval", SQLSTATE(HY013) MAL_MALLOC_FAIL); \ + } \ + memcpy(&h, PyBytes_AS_STRING(z), sizeof(inttpe)); \ + Py_DECREF(z); \ + *value = (type) h; \ + } else if (PyBool_Check(ptr)) { \ + *value = ptr == Py_True ? (type) 1 : (type) 0; \ + } else if (PyFloat_CheckExact(ptr)) { \ + *value = isnan(((PyFloatObject*)ptr)->ob_fval) ? type##_nil : (type) ((PyFloatObject*)ptr)->ob_fval; \ + } else if (PyUnicode_CheckExact(ptr)) { \ + return str_to_##type(PyUnicode_AsUTF8(ptr), 0, value); \ + } else if (PyByteArray_CheckExact(ptr)) { \ + return str_to_##type(((PyByteArrayObject*)ptr)->ob_bytes, 0, value); \ + } else if (ptr == Py_None) { \ + *value = type##_nil; \ + } \ + return retval; \ +} +#endif -#define CONVERSION_FUNCTION_FACTORY(tpe, inttpe) \ - STRING_TO_NUMBER_FACTORY(tpe) \ +#define CONVERSION_FUNCTION_FACTORY(tpe, inttpe) \ + STRING_TO_NUMBER_FACTORY(tpe) \ str unicode_to_##tpe(Py_UNICODE *ptr, size_t maxsize, tpe *value) \ - { \ - char utf8[1024]; \ - if (maxsize == 0) \ - maxsize = utf32_strlen(ptr); \ - if (maxsize > 255) \ - maxsize = 255; \ - unicode_to_utf8(0, maxsize, utf8, ptr); \ - return str_to_##tpe(utf8, 0, value); \ - } \ + { \ + char utf8[1024]; \ + if (maxsize == 0) \ + maxsize = utf32_strlen(ptr); \ + if (maxsize > 255) \ + maxsize = 255; \ + unicode_to_utf8(0, maxsize, utf8, ptr); \ + return str_to_##tpe(utf8, 0, value); \ + } \ PY_TO_(tpe, inttpe); CONVERSION_FUNCTION_FACTORY(bte, bte) _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org