Changeset: 4c533be99225 for MonetDB
URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=4c533be99225
Modified Files:
        clients/mapilib/mapi.c
        common/utils/conversion.c
        common/utils/conversion.h
        monetdb5/modules/atoms/mtime.c
        monetdb5/modules/atoms/mtime.h
        sql/backends/monet5/sql_result.c
Branch: protocol
Log Message:

Added support for TIME and TIMESTAMP, and default to STRING conversion for 
unknown types.

TIME is send over as the standard binary representation (4-byte int containing 
miliseconds since 00:00:00), however, TIMESTAMP is send over as 8-byte int 
containing miliseconds since EPOCH.


diffs (246 lines):

diff --git a/clients/mapilib/mapi.c b/clients/mapilib/mapi.c
--- a/clients/mapilib/mapi.c
+++ b/clients/mapilib/mapi.c
@@ -4167,6 +4167,20 @@ static char* mapi_convert_decimal(struct
        return (char*) col->write_buf;
 }
 
+static char* mapi_convert_time(struct MapiColumn *col) {
+       if (conversion_time_to_string(col->write_buf, COLBUFSIZ, (int*) 
col->buffer_ptr, *((int*)col->null_value), 0) < 0) {
+               return NULL;
+       }
+       return (char*) col->write_buf;
+}
+
+static char* mapi_convert_timestamp(struct MapiColumn *col) {
+       if (conversion_epoch_to_string(col->write_buf, COLBUFSIZ, (lng*) 
col->buffer_ptr, *((lng*)col->null_value), 0) < 0) {
+               return NULL;
+       }
+       return (char*) col->write_buf;
+}
+
 static char* mapi_convert_unknown(struct MapiColumn *col) {
        (void) col;
        return "<unknown>";
@@ -4317,6 +4331,10 @@ read_into_cache(MapiHdl hdl, int lookahe
                                        result->fields[i].converter = 
(mapi_converter) mapi_convert_real;
                                } else if (strcasecmp(type_sql_name, "hugeint") 
== 0) {
                                        result->fields[i].converter = 
(mapi_converter) mapi_convert_hugeint;
+                               } else if (strcasecmp(type_sql_name, "time") == 
0) {
+                                       result->fields[i].converter = 
(mapi_converter) mapi_convert_time;
+                               } else if (strcasecmp(type_sql_name, 
"timestamp") == 0) {
+                                       result->fields[i].converter = 
(mapi_converter) mapi_convert_timestamp;
                                } else if (typelen < 0) { /* any type besides 
the ones shown above should be converted to strings by the server */
                                        result->fields[i].converter = 
(mapi_converter) mapi_convert_clob;
                                } else {
diff --git a/common/utils/conversion.c b/common/utils/conversion.c
--- a/common/utils/conversion.c
+++ b/common/utils/conversion.c
@@ -217,6 +217,10 @@ int
 conversion_date_to_string(char *dst, int len, const int *src, int null_value) {
        int day, month, year;
        if (len < dateStrlen) return -1;
+       if (*src == null_value) {
+               strcpy(dst, "nil");
+               return 3;
+       }
 
        year = *src / 365;
        day = (*src - year * 365) - leapyears(year >= 0 ? year - 1 : year);
@@ -248,11 +252,62 @@ conversion_date_to_string(char *dst, int
                        }
                day -= CUMDAYS[month - 1];
        }
+       // YYYY-MM-DD
+       sprintf(dst, "%d-%02d-%02d", year, month, day);
+       return (int) strlen(dst);
+}
+
+int 
+conversion_time_to_string(char *dst, int len, const int *src, int null_value, 
int timezone_diff) {
+       int ms, sec, min, hour;
+       int time = *src;
+       if (len < daytimeStrlen) return -1;
        if (*src == null_value) {
                strcpy(dst, "nil");
                return 3;
        }
-       // YYYY-MM-DD
-       sprintf(dst, "%d-%02d-%02d", year, month, day);
-       return (int) strlen(dst);
+       // account for the timezone of the client
+       time += timezone_diff * 1000 * 60 * 60;
+
+       // for some reason, mclient does not render the ms part of the time, so 
we don't either
+       hour = time / 3600000;
+       time -= hour * 3600000;
+       min = time / 60000;
+       time -= min * 60000;
+       sec = time / 1000;
+       //time -= sec * 1000;
+       //ms = time;
+       return sprintf(dst, "%02d:%02d:%02d", hour, min, sec);
 }
+
+static int days_between_zero_and_epoch = 719528;
+
+int
+conversion_epoch_to_string(char *dst, int len, const lng *src, lng null_value, 
int timezone_diff) {
+       int ms, sec, min, hour, day, month, year;
+       int days = 0;
+       lng time = *src;
+
+       if (*src == null_value) {
+               strcpy(dst, "nil");
+               return 3;
+       }
+       // account for the timezone of the client
+       time += timezone_diff * 1000 * 60 * 60;
+
+       ms = time % 1000 * 1000;
+       time /= 1000;
+       sec = time % 60;
+       time /= 60;
+       min = time % 60;
+       time /= 60;
+       hour = time % 24;
+       time /= 24;
+       // we know the amount of days since epoch, just add the days between 
0000-01-01 and epoch 
+       // then we can use our conversion_date_to_string function
+       days = (int)(time + days_between_zero_and_epoch);
+
+       int offset = conversion_date_to_string(dst, len, &days, -2147483647);
+       if (offset < 0) return -1;
+       return snprintf(dst + offset, len - offset, " %02d:%02d:%02d.%06d", 
hour, min, sec, ms);
+}
diff --git a/common/utils/conversion.h b/common/utils/conversion.h
--- a/common/utils/conversion.h
+++ b/common/utils/conversion.h
@@ -61,4 +61,10 @@ numeric_conversion(hge, hge);
 // date conversion
 numeric_conversion(int, date);
 
+// *src is ms since 00:00:00
+int conversion_time_to_string(char *dst, int len, const int *src, int 
null_value, int timezone_diff);
+
+// *src is time since epoch in ms
+int conversion_epoch_to_string(char *dst, int len, const lng *src, lng 
null_value, int timezone_diff);
+
 #endif
diff --git a/monetdb5/modules/atoms/mtime.c b/monetdb5/modules/atoms/mtime.c
--- a/monetdb5/modules/atoms/mtime.c
+++ b/monetdb5/modules/atoms/mtime.c
@@ -2608,6 +2608,50 @@ MTIMEepoch2int(int *ret, const timestamp
 }
 
 str
+MTIMEepoch_bulk(bat *ret, bat *bid)
+{
+       timestamp epoch;
+       const timestamp *t;
+       lng *tn;
+       str msg = MAL_SUCCEED;
+       BAT *b, *bn;
+       BUN i, n;
+
+       if ((msg = MTIMEunix_epoch(&epoch)) != MAL_SUCCEED)
+               return msg;
+       if ((b = BATdescriptor(*bid)) == NULL) {
+               throw(MAL, "batcalc.epoch", RUNTIME_OBJECT_MISSING);
+       }
+       n = BATcount(b);
+       if ((bn = COLnew(b->hseqbase, TYPE_lng, n, TRANSIENT)) == NULL) {
+               BBPunfix(b->batCacheid);
+               throw(MAL, "batcalc.epoch", MAL_MALLOC_FAIL);
+       }
+       t = (const timestamp *) Tloc(b, 0);
+       tn = (lng *) Tloc(bn, 0);
+       bn->tnonil = 1;
+       b->tnil = 0;
+       for (i = 0; i < n; i++) {
+               if (ts_isnil(*t)) {
+                       *tn = lng_nil;
+                       bn->tnonil = 0;
+                       bn->tnil = 1;
+               } else {
+                       *tn = ((lng) (t->days - epoch.days)) * ((lng) 24 * 60 * 
60 * 1000) + ((lng) (t->msecs - epoch.msecs));
+               }
+               t++;
+               tn++;
+       }
+       BBPunfix(b->batCacheid);
+       BATsetcount(bn, (BUN) (tn - (lng *) Tloc(bn, 0)));
+       bn->tsorted = BATcount(bn) <= 1;
+       bn->trevsorted = BATcount(bn) <= 1;
+       BBPkeepref(bn->batCacheid);
+       *ret = bn->batCacheid;
+       return msg;
+}
+
+str
 MTIMEtimestamp(timestamp *ret, const int *sec)
 {
        timestamp t;
diff --git a/monetdb5/modules/atoms/mtime.h b/monetdb5/modules/atoms/mtime.h
--- a/monetdb5/modules/atoms/mtime.h
+++ b/monetdb5/modules/atoms/mtime.h
@@ -168,6 +168,7 @@ mal_export str MTIMEdaytime_diff(lng *re
 mal_export str MTIMEtimestamp_diff(lng *ret, const timestamp *v1, const 
timestamp *v2);
 mal_export str MTIMEtimestamp_diff_bulk(bat *ret, const bat *bid1, const bat 
*bid2);
 mal_export str MTIMEtimestamp_inside_dst(bit *ret, const timestamp *p, const 
tzone *z);
+mal_export str MTIMEepoch_bulk(bat *ret, bat *bid);
 
 mal_export str MTIMEtimestamp_year(int *ret, const timestamp *t);
 mal_export str MTIMEtimestamp_month(int *ret, const timestamp *t);
diff --git a/sql/backends/monet5/sql_result.c b/sql/backends/monet5/sql_result.c
--- a/sql/backends/monet5/sql_result.c
+++ b/sql/backends/monet5/sql_result.c
@@ -1830,7 +1830,16 @@ static int write_str_term(stream* s, str
 #endif
 
 static int type_supports_binary_transfer(sql_type *type) {
-       return type->eclass == EC_CHAR || type->eclass == EC_STRING || 
type->eclass == EC_BLOB || type->eclass == EC_DEC || type->eclass == EC_FLT || 
type->eclass == EC_NUM || type->eclass == EC_DATE;
+       return 
+               type->eclass == EC_CHAR || 
+               type->eclass == EC_STRING || 
+               type->eclass == EC_BLOB || 
+               type->eclass == EC_DEC || 
+               type->eclass == EC_FLT || 
+               type->eclass == EC_NUM || 
+               type->eclass == EC_DATE || 
+               type->eclass == EC_TIME || 
+               type->eclass == EC_TIMESTAMP;
 }
 
 static size_t max(size_t a, size_t b) {
@@ -1894,6 +1903,11 @@ static int mvc_export_resultset_prot10(r
                int convert_to_string = 
!type_supports_binary_transfer(c->type.type);
                sql_type *type = c->type.type;
 
+               if (type->eclass == EC_TIMESTAMP) {
+                       // timestamps are converted to Unix Timestamps
+                       mtype = TYPE_lng;
+                       typelen = sizeof(lng);  
+               }
                if (ATOMvarsized(mtype) || convert_to_string) {
                        typelen = -1;
                        if (!convert_to_string && mtype == TYPE_str && 
c->type.digits > 0) {
@@ -1949,10 +1963,17 @@ static int mvc_export_resultset_prot10(r
                if (convert_to_string) {
                        BAT *res = BATconvert(iterators[i].b, NULL, TYPE_str, 
1);
                        // if converting to string, we use str_nil
-                       BBPunfix(iterators[i].b);
+                       BBPunfix(iterators[i].b->batCacheid);
                        iterators[i] = bat_iterator(res);
                        mtype = TYPE_str;
+               } else if (type->eclass == EC_TIMESTAMP) {
+                       bat ret;
+                       // convert to UNIX timestamp
+                       MTIMEepoch_bulk(&ret, &iterators[i].b->batCacheid);
+                       BBPunfix(iterators[i].b->batCacheid);
+                       iterators[i] = bat_iterator(BATdescriptor(ret));
                }
+
                switch(ATOMstorage(mtype)) {
                        case TYPE_str:
                                retval = write_str_term(s, str_nil);
_______________________________________________
checkin-list mailing list
[email protected]
https://www.monetdb.org/mailman/listinfo/checkin-list

Reply via email to