Changeset: 56a377041a1f for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/56a377041a1f
Modified Files:
sql/backends/monet5/UDF/pyapi3/conversion3.c
sql/backends/monet5/UDF/pyapi3/convert_loops.h
sql/backends/monet5/UDF/pyapi3/pyapi3.c
sql/backends/monet5/UDF/pyapi3/pyheader.h
sql/backends/monet5/UDF/pyapi3/pytypes3.c
sql/backends/monet5/UDF/pyapi3/type_conversion.h
sql/backends/monet5/UDF/pyapi3/type_conversion3.c
Branch: default
Log Message:
Add fix for issue #7289 (date type)
diffs (truncated from 310 to 300 lines):
diff --git a/sql/backends/monet5/UDF/pyapi3/conversion3.c
b/sql/backends/monet5/UDF/pyapi3/conversion3.c
--- a/sql/backends/monet5/UDF/pyapi3/conversion3.c
+++ b/sql/backends/monet5/UDF/pyapi3/conversion3.c
@@ -70,6 +70,14 @@ PyObject *PyArrayObject_FromScalar(PyInp
vararray = PyLong_FromHge(*((hge *)inp->dataptr));
break;
#endif
+ case TYPE_date:
+ {
+ USE_DATETIME_API;
+ date dt = *(date *)inp->dataptr;
+ vararray = PyDate_FromDate(date_year(dt),
date_month(dt), date_day(dt));
+ /* error checking */
+ break;
+ }
case TYPE_str:
vararray = PyUnicode_FromString(*((char
**)inp->dataptr));
break;
@@ -243,6 +251,24 @@ PyObject *PyArrayObject_FromBAT(PyInput
case TYPE_dbl:
BAT_TO_NP(b, dbl, NPY_FLOAT64);
break;
+ case TYPE_date: {
+ li = bat_iterator(b);
+
+ USE_DATETIME_API;
+ vararray = PyArray_EMPTY(1, elements,
NPY_OBJECT, 0);
+ {
+ PyObject **data = ((PyObject
**)PyArray_DATA((PyArrayObject *)vararray));
+ // PyObject *obj;
+ j = 0;
+ BATloop(b, p, q)
+ {
+ const date* dt = (const
date*)BUNtail(li, p);
+ data[j++] =
PyDate_FromDate(date_year(*dt), date_month(*dt), date_day(*dt));
+ }
+ }
+ bat_iterator_end(&li);
+ break;
+ }
case TYPE_str: {
bool unicode = false;
li = bat_iterator(b);
@@ -572,8 +598,7 @@ PyObject *PyObject_CheckForConversion(Py
}
}
- if (PyType_IsPyScalar(
- pResult)) { // check if the return object is a
scalar
+ if (PyType_IsPyScalar(pResult)) { // check if the return object
is a scalar
if (expected_columns == 1 || expected_columns <= 0) {
// if we only expect a single return value, we
can accept
// scalars by converting it into an array
holding an array
@@ -839,8 +864,10 @@ BAT *PyObject_ConvertToBAT(PyReturn *ret
switch (GetSQLType(type)) {
case EC_TIMESTAMP:
case EC_TIME:
+ bat_type = TYPE_str;
+ break;
case EC_DATE:
- bat_type = TYPE_str;
+ bat_type = TYPE_date;
break;
case EC_DEC:
bat_type = TYPE_dbl;
@@ -993,6 +1020,9 @@ BAT *PyObject_ConvertToBAT(PyReturn *ret
NP_CREATE_BAT(b, hge);
break;
#endif
+ case TYPE_date:
+ NP_CREATE_BAT(b, date);
+ break;
case TYPE_str: {
bool *mask = NULL;
char *data = NULL;
@@ -1053,7 +1083,7 @@ BAT *PyObject_ConvertToBAT(PyReturn *ret
bit ConvertableSQLType(sql_subtype *sql_subtype)
{
switch (GetSQLType(sql_subtype)) {
- case EC_DATE:
+ /* case EC_DATE: */
case EC_TIME:
case EC_TIMESTAMP:
case EC_DEC:
@@ -1236,6 +1266,7 @@ bit IsStandardBATType(int type)
#ifdef HAVE_HGE
case TYPE_hge:
#endif
+ case TYPE_date:
case TYPE_str:
return 1;
default:
diff --git a/sql/backends/monet5/UDF/pyapi3/convert_loops.h
b/sql/backends/monet5/UDF/pyapi3/convert_loops.h
--- a/sql/backends/monet5/UDF/pyapi3/convert_loops.h
+++ b/sql/backends/monet5/UDF/pyapi3/convert_loops.h
@@ -65,12 +65,13 @@
#define nancheck_lng(bat) ((void)0)
#define nancheck_hge(bat) ((void)0) /* not used if no HAVE_HGE */
#define nancheck_oid(bat) ((void)0)
+#define nancheck_date(bat) ((void)0)
#if defined(HAVE_FORK)
#define CREATE_BAT_ZEROCOPY(bat, mtpe, batstore)
\
{
\
bat = COLnew(seqbase, TYPE_##mtpe, 0, TRANSIENT);
\
if (bat == NULL) {
\
- msg = createException(MAL, "pyapi3.eval", SQLSTATE(PY000)
"Cannot create column"); \
+ msg = createException(MAL, "pyapi3.eval",
SQLSTATE(PY000) "Cannot create column"); \
goto wrapup;
\
}
\
bat->tnil = false;
\
@@ -545,10 +546,12 @@ convert_and_append(BAT* b, const char* t
}
\
} else {
\
/* we try to handle as many types as
possible */ \
- pyobject_to_str(
\
+ msg = pyobject_to_str(
\
((PyObject
**)&data[(index_offset * ret->count + iu) * \
ret->memory_size]), \
utf8_size, &utf8_string);
\
+ if (msg != MAL_SUCCEED)
\
+ goto wrapup;
\
if (convert_and_append(b, utf8_string,
false) != GDK_SUCCEED) { \
msg = createException(MAL,
"pyapi3.eval", \
SQLSTATE(PY000) "BUNappend failed.\n"); \
diff --git a/sql/backends/monet5/UDF/pyapi3/pyapi3.c
b/sql/backends/monet5/UDF/pyapi3/pyapi3.c
--- a/sql/backends/monet5/UDF/pyapi3/pyapi3.c
+++ b/sql/backends/monet5/UDF/pyapi3/pyapi3.c
@@ -70,11 +70,21 @@ static const char *FunctionBasePath(void
static MT_Lock pyapiLock = MT_LOCK_INITIALIZER(pyapiLock);
static bool pyapiInitialized = false;
+static PyDateTime_CAPI *PYAPI3_DateTimeAPI;
bool PYAPI3PyAPIInitialized(void) {
return pyapiInitialized;
}
+PyDateTime_CAPI *get_DateTimeAPI(void) {
+ return PYAPI3_DateTimeAPI;
+}
+
+void init_DateTimeAPI(void) {
+ PyDateTime_IMPORT;
+ PYAPI3_DateTimeAPI = PyDateTimeAPI;
+}
+
#ifdef HAVE_FORK
static bool python_call_active = false;
#endif
@@ -1390,6 +1400,7 @@ PYAPI3PyAPIprelude(void) {
_loader_init();
tmp = PyUnicode_FromString("marshal");
marshal_module = PyImport_Import(tmp);
+ init_DateTimeAPI();
Py_DECREF(tmp);
if (marshal_module == NULL) {
MT_lock_unset(&pyapiLock);
diff --git a/sql/backends/monet5/UDF/pyapi3/pyheader.h
b/sql/backends/monet5/UDF/pyapi3/pyheader.h
--- a/sql/backends/monet5/UDF/pyapi3/pyheader.h
+++ b/sql/backends/monet5/UDF/pyapi3/pyheader.h
@@ -40,6 +40,7 @@
#else
#include <Python.h>
#endif
+#include <datetime.h>
// Numpy Library
#ifdef __COVERITY__
@@ -65,6 +66,16 @@
#define pyapi_export extern
#endif
+PyDateTime_CAPI *get_DateTimeAPI(void);
+void init_DateTimeAPI(void);
+
+#define USE_DATETIME_API \
+ do {
\
+ PyDateTimeAPI = get_DateTimeAPI(); \
+ } while(0)
+
+
+
#define utf8string_minlength 256
#endif /* _PYHEADER_H_ */
diff --git a/sql/backends/monet5/UDF/pyapi3/pytypes3.c
b/sql/backends/monet5/UDF/pyapi3/pytypes3.c
--- a/sql/backends/monet5/UDF/pyapi3/pytypes3.c
+++ b/sql/backends/monet5/UDF/pyapi3/pytypes3.c
@@ -133,6 +133,8 @@ char *BatType_Format(int type)
return "STRING";
case TYPE_oid:
return "OID";
+ case TYPE_date:
+ return "DATE";
#ifdef HAVE_HGE
case TYPE_hge:
return "HUGEINT";
@@ -215,6 +217,8 @@ int BatType_ToPyType(int type)
case TYPE_hge:
return NPY_FLOAT64;
#endif
+ case TYPE_date:
+ return NPY_DATETIME;
default:
return NPY_STRING;
}
@@ -271,10 +275,11 @@ bool PyType_IsPyScalar(PyObject *object)
{
if (object == NULL)
return false;
+ USE_DATETIME_API;
return (PyArray_CheckScalar(object) || PyLong_Check(object) ||
PyFloat_Check(object) || PyUnicode_Check(object) ||
PyBool_Check(object) || PyByteArray_Check(object) ||
- PyBytes_Check(object));
+ PyBytes_Check(object) || PyDate_Check(object));
}
void _pytypes_init(void) { _import_array(); }
diff --git a/sql/backends/monet5/UDF/pyapi3/type_conversion.h
b/sql/backends/monet5/UDF/pyapi3/type_conversion.h
--- a/sql/backends/monet5/UDF/pyapi3/type_conversion.h
+++ b/sql/backends/monet5/UDF/pyapi3/type_conversion.h
@@ -46,6 +46,10 @@ str pyobject_to_str(PyObject **ptr, size
//! Converts a PyObject to a blob
str pyobject_to_blob(PyObject **ptr, size_t maxsize, blob **value);
+str pyobject_to_date(PyObject **ptr, size_t maxsize, date *value);
+str str_to_date(const char *ptr, size_t maxsize, date *value);
+str unicode_to_date(Py_UNICODE *ptr, size_t maxsize, date *value);
+
//using macros, create a number of str_to_<type>, unicode_to_<type> and
pyobject_to_<type> functions (we are Java now)
#define CONVERSION_FUNCTION_HEADER_FACTORY(tpe) \
str str_to_##tpe(const char *ptr, size_t maxsize, tpe *value); \
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
@@ -69,6 +69,29 @@ size_t pyobject_get_size(PyObject *obj)
return size;
}
+str pyobject_to_date(PyObject **ptr, size_t maxsize, date *value) {
+ str msg = MAL_SUCCEED;
+
+ if (ptr == NULL || *ptr == NULL) {
+ msg = createException(MAL, "pyapi3.eval", "Invalid PyObject.");
+ goto wrapup;
+ }
+
+ (void) maxsize;
+
+ USE_DATETIME_API;
+ if(PyDate_Check(*ptr)) {
+ *value = date_create(PyDateTime_GET_YEAR(*ptr),
+
PyDateTime_GET_MONTH(*ptr),
+
PyDateTime_GET_DAY(*ptr));
+ }
+ else {
+ msg = createException(MAL, "pyapi3.eval", "Invalid PyDate
object.");
+ }
+
+ wrapup:
+ return msg;
+}
str pyobject_to_blob(PyObject **ptr, size_t maxsize, blob **value) {
size_t size;
@@ -186,6 +209,43 @@ wrapup:
return MAL_SUCCEED;
\
}
+str str_to_date(const char *ptr, size_t maxsize, date *value)
+{
+ if (ptr) {
+ if (date_fromstr(ptr, &maxsize, &value, true) < 0) {
+ return createException(MAL, "pyapi3.eval",
+
SQLSTATE(PY000) "Could not convert string %s to date.",
+ ptr);
+ }
+ }
+ else
+ return createException(MAL, "pyapi3.eval",
+ SQLSTATE(PY000)
"Invalid PyObject");
+
+ return MAL_SUCCEED;
+}
+
+str unicode_to_date(Py_UNICODE *ptr, size_t maxsize, date *value)
+{
+ if (ptr) {
+ const char *buf = PyUnicode_AsUTF8((PyObject *)ptr);
+ if (buf == NULL || !PyUnicode_CheckExact(ptr)) {
+ return createException(MAL, "pyapi3.pyapi",
+
SQLSTATE(PY000) "Invalid UTF-8 when converting to date.");
+ }
+ if (date_fromstr(buf, &maxsize, &value, true) < 0) {
+ return createException(MAL, "pyapi3.eval",
+
SQLSTATE(PY000) "Could not convert string to date.");
+ }
+ }
+ else
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]