Changeset: 985acf30fee6 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/985acf30fee6
Modified Files:
        sql/backends/monet5/UDF/pyapi3/Tests/pyapi3_18.test
        sql/backends/monet5/UDF/pyapi3/conversion3.c
        sql/backends/monet5/UDF/pyapi3/convert_loops.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 test and fix for issue #7289 (time type)


diffs (288 lines):

diff --git a/sql/backends/monet5/UDF/pyapi3/Tests/pyapi3_18.test 
b/sql/backends/monet5/UDF/pyapi3/Tests/pyapi3_18.test
--- a/sql/backends/monet5/UDF/pyapi3/Tests/pyapi3_18.test
+++ b/sql/backends/monet5/UDF/pyapi3/Tests/pyapi3_18.test
@@ -24,15 +24,20 @@ statement ok
 CREATE TABLE time_table(d TIME)
 
 statement ok rowcount 1
-INSERT INTO time_table VALUES (cast('12:00:00' AS TIME))
+INSERT INTO time_table VALUES (cast('12:00:00.000001' AS TIME))
 
 statement ok
-CREATE FUNCTION pyapi_time(d TIME) RETURNS STRING LANGUAGE PYTHON { return d; }
+CREATE FUNCTION pyapi_time(d TIME) RETURNS TIME LANGUAGE PYTHON { return d; }
+
+query T rowsort
+SELECT pyapi_time(cast('12:00:00.000001' AS TIME))
+----
+12:00:00.000001
 
 query T rowsort
 SELECT pyapi_time(d) FROM time_table
 ----
-12:00:00.000000
+12:00:00.000001
 
 statement ok
 CREATE TABLE timestamp_table(d TIMESTAMP)
@@ -81,8 +86,9 @@ statement ok
 CREATE FUNCTION pyapi_ret_time() RETURNS TABLE(d TIME)
 LANGUAGE PYTHON
 {
+    import datetime
     result = dict()
-    result['d'] = '12:00:00'
+    result['d'] = datetime.time(12, 0, 0, 0)
     return result
 }
 
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
@@ -78,6 +78,15 @@ PyObject *PyArrayObject_FromScalar(PyInp
                                /* error checking */
                                break;
                        }
+               case TYPE_daytime:
+                       {
+                               USE_DATETIME_API;
+                               daytime dt = *(daytime *)inp->dataptr;
+                               vararray = PyTime_FromTime(daytime_hour(dt), 
daytime_min(dt), daytime_sec(dt), daytime_usec(dt));
+                               /* error checking */
+                               break;
+                       }
+
                case TYPE_str:
                        vararray = PyUnicode_FromString(*((char 
**)inp->dataptr));
                        break;
@@ -269,6 +278,27 @@ PyObject *PyArrayObject_FromBAT(PyInput 
                                bat_iterator_end(&li);
                                break;
                        }
+                       case TYPE_daytime: {
+                               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 daytime* dt = (const 
daytime*)BUNtail(li, p);
+                                               data[j++] = 
PyTime_FromTime(daytime_hour(*dt),
+                                                                               
                        daytime_min(*dt),
+                                                                               
                        daytime_sec(*dt),
+                                                                               
                        daytime_usec(*dt));
+                                       }
+                               }
+                               bat_iterator_end(&li);
+                               break;
+                       }
                        case TYPE_str: {
                                bool unicode = false;
                                li = bat_iterator(b);
@@ -863,8 +893,10 @@ BAT *PyObject_ConvertToBAT(PyReturn *ret
 
        switch (GetSQLType(type)) {
                case EC_TIMESTAMP:
+                       bat_type = TYPE_str;
+                       break;
                case EC_TIME:
-                       bat_type = TYPE_str;
+                       bat_type = TYPE_daytime;
                        break;
                case EC_DATE:
                        bat_type = TYPE_date;
@@ -1023,6 +1055,9 @@ BAT *PyObject_ConvertToBAT(PyReturn *ret
                        case TYPE_date:
                                NP_CREATE_BAT(b, date);
                                break;
+                       case TYPE_daytime:
+                               NP_CREATE_BAT(b, daytime);
+                               break;
                        case TYPE_str: {
                                bool *mask = NULL;
                                char *data = NULL;
@@ -1084,7 +1119,7 @@ bit ConvertableSQLType(sql_subtype *sql_
 {
        switch (GetSQLType(sql_subtype)) {
                /* case EC_DATE: */
-               case EC_TIME:
+               /* case EC_TIME: */
                case EC_TIMESTAMP:
                case EC_DEC:
                        return 1;
@@ -1111,8 +1146,8 @@ str ConvertFromSQLType(BAT *b, sql_subty
        assert(sql_subtype->type);
 
        switch (sql_subtype->type->eclass) {
-               case EC_DATE:
-               case EC_TIME:
+               /* case EC_DATE: */
+               /* case EC_TIME: */
                case EC_TIMESTAMP:
                        conv_type = TYPE_str;
                        break;
@@ -1267,6 +1302,7 @@ bit IsStandardBATType(int type)
                case TYPE_hge:
 #endif
                case TYPE_date:
+               case TYPE_daytime:
                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
@@ -66,6 +66,7 @@
 #define nancheck_hge(bat) ((void)0) /* not used if no HAVE_HGE */
 #define nancheck_oid(bat) ((void)0)
 #define nancheck_date(bat) ((void)0)
+#define nancheck_daytime(bat) ((void)0)
 #if defined(HAVE_FORK)
 #define CREATE_BAT_ZEROCOPY(bat, mtpe, batstore)                               
\
        {                                                                       
   \
@@ -550,8 +551,8 @@ convert_and_append(BAT* b, const char* t
                                                ((PyObject 
**)&data[(index_offset * ret->count + iu) * \
                                                                                
        ret->memory_size]),                \
                                                utf8_size, &utf8_string);       
                       \
-                                       if (msg != MAL_SUCCEED)                 
                                        \
-                                               goto wrapup;                    
                                                \
+                                       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/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
@@ -279,7 +279,8 @@ bool PyType_IsPyScalar(PyObject *object)
        return (PyArray_CheckScalar(object) || PyLong_Check(object) ||
                        PyFloat_Check(object) || PyUnicode_Check(object) ||
                        PyBool_Check(object) || PyByteArray_Check(object) ||
-                       PyBytes_Check(object) || PyDate_Check(object));
+                       PyBytes_Check(object) || PyDate_Check(object) ||
+                       PyTime_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
@@ -50,6 +50,10 @@ str pyobject_to_date(PyObject **ptr, siz
 str str_to_date(const char *ptr, size_t maxsize, date *value);
 str unicode_to_date(Py_UNICODE *ptr, size_t maxsize, date *value);
 
+str pyobject_to_daytime(PyObject **ptr, size_t maxsize, daytime *value);
+str str_to_daytime(const char *ptr, size_t maxsize, daytime *value);
+str unicode_to_daytime(Py_UNICODE *ptr, size_t maxsize, daytime *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
@@ -93,6 +93,32 @@ str pyobject_to_date(PyObject **ptr, siz
        return msg;
 }
 
+str pyobject_to_daytime(PyObject **ptr, size_t maxsize, daytime *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(PyTime_Check(*ptr)) {
+               *value = daytime_create(PyDateTime_TIME_GET_HOUR(*ptr),
+                                                               
PyDateTime_TIME_GET_MINUTE(*ptr),
+                                                               
PyDateTime_TIME_GET_SECOND(*ptr),
+                                                               
PyDateTime_TIME_GET_MICROSECOND(*ptr));
+       }
+       else {
+               msg = createException(MAL, "pyapi3.eval", "Invalid PyTime 
object.");
+       }
+
+ wrapup:
+       return msg;
+}
+
+
 str pyobject_to_blob(PyObject **ptr, size_t maxsize, blob **value) {
        size_t size;
        char* bytes_data;
@@ -211,41 +237,41 @@ wrapup:
 
 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");
+       (void)ptr;
+       (void)maxsize;
+       (void)value;
 
-       return MAL_SUCCEED;
+       return GDKstrdup("Implicit conversion of date to string is not 
allowed.");
 }
 
 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
-               return createException(MAL, "pyapi3.eval",
-                                                          SQLSTATE(PY000) 
"Invalid PyObject");
+       (void)ptr;
+       (void)maxsize;
+       (void)value;
+
+       return GDKstrdup("Implicit conversion of date to string is not 
allowed.");
+}
+
+str str_to_daytime(const char *ptr, size_t maxsize, daytime *value)
+{
+       (void)ptr;
+       (void)maxsize;
+       (void)value;
 
+       return GDKstrdup("Implicit conversion of time to string is not 
allowed.");
+}
 
-       return MAL_SUCCEED;
+str unicode_to_daytime(Py_UNICODE *ptr, size_t maxsize, daytime *value)
+{
+       (void)ptr;
+       (void)maxsize;
+       (void)value;
+
+       return GDKstrdup("Implicit conversion of time to string is not 
allowed.");
 }
 
+
 #define PY_TO_(type, inttpe)                                           \
 str pyobject_to_##type(PyObject **pyobj, size_t maxsize, type *value)  \
 {                                                                      \
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to