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]

Reply via email to