Changeset: fa0188a309fd for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=fa0188a309fd Modified Files: sql/backends/monet5/CMakeLists.txt sql/backends/monet5/sql.c sql/test/bincopy/Tests/bincopy_support.py Branch: copybinary Log Message:
Add support for timestamp, date and time diffs (260 lines): diff --git a/sql/backends/monet5/CMakeLists.txt b/sql/backends/monet5/CMakeLists.txt --- a/sql/backends/monet5/CMakeLists.txt +++ b/sql/backends/monet5/CMakeLists.txt @@ -109,7 +109,8 @@ target_link_libraries(sql sqlcommon batstore sqlserver - sqlinclude) + sqlinclude + copybinary) set_target_properties(sql PROPERTIES diff --git a/sql/backends/monet5/sql.c b/sql/backends/monet5/sql.c --- a/sql/backends/monet5/sql.c +++ b/sql/backends/monet5/sql.c @@ -41,6 +41,7 @@ #include "mal_resource.h" #include "mal_authorize.h" #include "gdk_cand.h" +#include "copybinary.h" static int rel_is_table(sql_rel *rel) @@ -3227,6 +3228,61 @@ bad_utf8: return createException(SQL, "BATattach_stream", SQLSTATE(42000) "malformed utf-8 byte sequence"); } + +static str +BATattach_fixed_width(bstream *in, BAT *bn, str (*converter)(void*, size_t, char*, char*), void *cookie, size_t size_external) +{ + int internal_type = BATttype(bn); + int storage_type = ATOMstorage(internal_type); + size_t internal_size = ATOMsize(storage_type); + while (1) { + ssize_t nread = bstream_next(in); + if (nread < 0) { + return createException(SQL, "BATattach_fixed_width", SQLSTATE(42000) "%s", mnstr_peek_error(in->s)); + } + if (nread == 0) + break; + + size_t n = (in->len - in->pos) / size_external; + BUN count = bn->batCount; + BUN newCount = count + n; + if (BATextend(bn, newCount) != GDK_SUCCEED) + return createException(SQL, "BATattach_fixed_width", GDK_EXCEPTION); + + // future work: parallellize this.. + for (size_t i = 0; i < n; i++) { + char *external = in->buf + in->pos + i * size_external; + char *internal = Tloc(bn, count + i); + str msg = converter(cookie, internal_size, external, internal); + if (msg != MAL_SUCCEED) + return msg; + } + + // All conversions succeeded. Update the bookkeeping. + bn->batCount += n; + in->pos += n * size_external; + } + + // It's an error to have data left after falling out of the loop. + if (in->pos < in->len) + return createException(SQL, "BATattach_str", SQLSTATE(42000) "incomplete value at end"); + + BATsetcount(bn, bn->batCount); + bn->tseqbase = oid_nil; + bn->tnonil = bn->batCount == 0; + bn->tnil = false; + if (bn->batCount <= 1) { + bn->tsorted = true; + bn->trevsorted = true; + bn->tkey = true; + } else { + bn->tsorted = false; + bn->trevsorted = false; + bn->tkey = false; + } + return MAL_SUCCEED; +} + static str BATattach_as_bytes(int tt, stream *s, BAT *bn, bool *eof_seen) { @@ -3285,6 +3341,53 @@ BATattach_as_bytes(int tt, stream *s, BA } static str +convert_timestamp(void *cookie, size_t internal_size, char *external, char *internal) +{ + copy_binary_timestamp *src = (copy_binary_timestamp*) external; + timestamp *dst = (timestamp*) internal; + assert(internal_size == sizeof(*dst)); + + date dt = date_create(src->date.year, src->date.month, src->date.day); + daytime tm = daytime_create(src->time.hours, src->time.minutes, src->time.seconds, src->time.ms); + timestamp value = timestamp_create(dt, tm); + + (void)cookie; + *dst = value; + + return MAL_SUCCEED; +} + +static str +convert_date(void *cookie, size_t internal_size, char *external, char *internal) +{ + copy_binary_date *src = (copy_binary_date*) external; + date *dst = (date*) internal; + assert(internal_size == sizeof(*dst)); + + date value = date_create(src->year, src->month, src->day); + + (void)cookie; + *dst = value; + + return MAL_SUCCEED; +} + +static str +convert_time(void *cookie, size_t internal_size, char *external, char *internal) +{ + copy_binary_time *src = (copy_binary_time*) external; + timestamp *dst = (timestamp*) internal; + assert(internal_size == sizeof(*dst)); + + daytime value = daytime_create(src->hours, src->minutes, src->seconds, src->ms); + + (void)cookie; + *dst = value; + + return MAL_SUCCEED; +} + +static str BATattach_stream(BAT **result, const char *colname, int tt, stream *s, BUN size, bool *eof_seen) { str msg = MAL_SUCCEED; @@ -3325,8 +3428,38 @@ BATattach_stream(BAT **result, const cha break; case TYPE_date: + in = bstream_create(s, 1 << 20); + if (in == NULL) { + msg = createException(SQL, "sql", SQLSTATE(HY013) MAL_MALLOC_FAIL); + goto end; + } + msg = BATattach_fixed_width(in, bn, convert_date, NULL, sizeof(copy_binary_date)); + if (eof_seen != NULL) + *eof_seen = in->eof; + break; + case TYPE_daytime: + in = bstream_create(s, 1 << 20); + if (in == NULL) { + msg = createException(SQL, "sql", SQLSTATE(HY013) MAL_MALLOC_FAIL); + goto end; + } + msg = BATattach_fixed_width(in, bn, convert_time, NULL, sizeof(copy_binary_time)); + if (eof_seen != NULL) + *eof_seen = in->eof; + break; + case TYPE_timestamp: + in = bstream_create(s, 1 << 20); + if (in == NULL) { + msg = createException(SQL, "sql", SQLSTATE(HY013) MAL_MALLOC_FAIL); + goto end; + } + msg = BATattach_fixed_width(in, bn, convert_timestamp, NULL, sizeof(copy_binary_timestamp)); + if (eof_seen != NULL) + *eof_seen = in->eof; + break; + default: msg = createException(SQL, "sql", SQLSTATE(42000) "Type of column %s not supported for BINARY COPY", diff --git a/sql/test/bincopy/Tests/bincopy_support.py b/sql/test/bincopy/Tests/bincopy_support.py --- a/sql/test/bincopy/Tests/bincopy_support.py +++ b/sql/test/bincopy/Tests/bincopy_support.py @@ -113,6 +113,8 @@ TIMESTAMPS = """ CREATE TABLE foo( id INT NOT NULL, ts TIMESTAMP, + dt DATE, + tm TIME, "year" SMALLINT, "month" TINYINT, "day" TINYINT, @@ -121,9 +123,11 @@ CREATE TABLE foo( "second" TINYINT, ms INTEGER ); -COPY BINARY INTO foo(id, ts, "year", "month", "day", "hour", "minute", "second", ms) +COPY BINARY INTO foo(id, ts, dt, tm, "year", "month", "day", "hour", "minute", "second", ms) FROM @ints@, @timestamps@, + @timestamp_dates@, + @timestamp_times@, @timestamp_years@, @timestamp_months@, @timestamp_days@, @@ -132,15 +136,45 @@ FROM @ints@, @timestamp_seconds@, @timestamp_ms@ @ON@; + +SELECT * FROM foo + WHERE EXTRACT(YEAR FROM ts) <> "year" + LIMIT 4; +SELECT * FROM foo + WHERE EXTRACT(MONTH FROM ts) <> "month" + LIMIT 4; +SELECT * FROM foo + WHERE EXTRACT(DAY FROM ts) <> "day" + LIMIT 4; +SELECT * FROM foo + WHERE EXTRACT(HOUR FROM ts) <> "hour" + LIMIT 4; +SELECT * FROM foo + WHERE EXTRACT(MINUTE FROM ts) <> "minute" + LIMIT 4; +SELECT * FROM foo + WHERE 1000000 * EXTRACT(SECOND FROM ts) <> 1000000 * "second" + ms + LIMIT 4; + +SELECT * FROM foo + WHERE EXTRACT(YEAR FROM dt) <> "year" + LIMIT 4; +SELECT * FROM foo + WHERE EXTRACT(MONTH FROM dt) <> "month" + LIMIT 4; +SELECT * FROM foo + WHERE EXTRACT(DAY FROM dt) <> "day" + LIMIT 4; + +SELECT * FROM foo + WHERE EXTRACT(HOUR FROM tm) <> "hour" + LIMIT 4; +SELECT * FROM foo + WHERE EXTRACT(MINUTE FROM tm) <> "minute" + LIMIT 4; +SELECT * FROM foo + WHERE 1000000 * EXTRACT(SECOND FROM tm) <> 1000000 * "second" + ms + LIMIT 4; + """ -# GEN_TIMESTAMP_FIELD(gen_timestamp_times, time) -# GEN_TIMESTAMP_FIELD(gen_timestamp_dates, date) - -# GEN_TIMESTAMP_FIELD(gen_timestamp_years, date.year) -# GEN_TIMESTAMP_FIELD(gen_timestamp_months, date.month) -# GEN_TIMESTAMP_FIELD(gen_timestamp_days, date.day) -# GEN_TIMESTAMP_FIELD(gen_timestamp_hours, time.hours) -# GEN_TIMESTAMP_FIELD(gen_timestamp_minutes, time.minutes) -# GEN_TIMESTAMP_FIELD(gen_timestamp_seconds, time.seconds) -# GEN_TIMESTAMP_FIELD(gen_timestamp_ms, time.ms) _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list