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