Changeset: c570affc88c2 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=c570affc88c2 Added Files: clients/examples/C/bincopydata.h clients/examples/C/bincopytemporaldata.c sql/test/bincopy/Tests/bincopy_timestamps_on_client.SQL.py sql/test/bincopy/Tests/bincopy_timestamps_on_server.SQL.py Modified Files: clients/examples/C/CMakeLists.txt clients/examples/C/bincopydata.c sql/test/bincopy/Tests/All sql/test/bincopy/Tests/bincopy_support.py Branch: copybinary Log Message:
Add test for binary copy timestamp diffs (truncated from 308 to 300 lines): diff --git a/clients/examples/C/CMakeLists.txt b/clients/examples/C/CMakeLists.txt --- a/clients/examples/C/CMakeLists.txt +++ b/clients/examples/C/CMakeLists.txt @@ -47,6 +47,8 @@ if(TESTING) add_executable(bincopydata bincopydata.c + bincopydata.h + bincopytemporaldata.c ) target_link_libraries(bincopydata diff --git a/clients/examples/C/bincopydata.c b/clients/examples/C/bincopydata.c --- a/clients/examples/C/bincopydata.c +++ b/clients/examples/C/bincopydata.c @@ -1,4 +1,4 @@ -#include "monetdb_config.h" +#include "bincopydata.h" static char *exe_name = "<to_be_filled_in>"; @@ -141,6 +141,18 @@ static struct gen generators[] = { { "broken_strings", gen_broken_strings }, { "newline_strings", gen_newline_strings }, { "null_strings", gen_null_strings }, + // + { "timestamps", gen_timestamps }, + { "timestamp_times", gen_timestamp_times }, + { "timestamp_dates", gen_timestamp_dates }, + { "timestamp_ms", gen_timestamp_ms }, + { "timestamp_seconds", gen_timestamp_seconds }, + { "timestamp_minutes", gen_timestamp_minutes }, + { "timestamp_hours", gen_timestamp_hours }, + { "timestamp_days", gen_timestamp_days }, + { "timestamp_months", gen_timestamp_months }, + { "timestamp_years", gen_timestamp_years }, + { NULL, NULL }, }; diff --git a/clients/examples/C/bincopydata.h b/clients/examples/C/bincopydata.h new file mode 100644 --- /dev/null +++ b/clients/examples/C/bincopydata.h @@ -0,0 +1,15 @@ +#include "monetdb_config.h" + +void gen_timestamps(FILE *f, long nrecs); + +void gen_timestamp_times(FILE *f, long nrecs); +void gen_timestamp_dates(FILE *f, long nrecs); + + +void gen_timestamp_ms(FILE *f, long nrecs); +void gen_timestamp_seconds(FILE *f, long nrecs); +void gen_timestamp_minutes(FILE *f, long nrecs); +void gen_timestamp_hours(FILE *f, long nrecs); +void gen_timestamp_days(FILE *f, long nrecs); +void gen_timestamp_months(FILE *f, long nrecs); +void gen_timestamp_years(FILE *f, long nrecs); diff --git a/clients/examples/C/bincopytemporaldata.c b/clients/examples/C/bincopytemporaldata.c new file mode 100644 --- /dev/null +++ b/clients/examples/C/bincopytemporaldata.c @@ -0,0 +1,169 @@ +#include "bincopydata.h" + +struct lfsr +{ + uint32_t bits; +}; + +static struct lfsr +my_favorite_lfsr(void) +{ + return (struct lfsr){42}; +} + +static uint32_t +lfsr_bit(struct lfsr *lfsr) +{ + const uint32_t mask = 0xB400; + uint32_t bit = lfsr->bits & 1; + lfsr->bits >>= 1; + lfsr->bits ^= mask & (-bit); + return bit; +} + +static uint32_t +lfsr_bits(struct lfsr *lfsr, int n) +{ + uint32_t value = 0; + for (int i = 0; i < n; i++) + value = (value << 1) | lfsr_bit(lfsr); + return value; +} + + +typedef struct { + uint8_t day; + uint8_t month; + int16_t year; +} binary_date; // natural size: 32, natural alignment: 16 + +typedef struct { + uint32_t ms; + uint8_t seconds; + uint8_t minutes; + uint8_t hours; + uint8_t padding; // implied in C, explicit elsewhere +} binary_time; // natural size: 64, natural alignment: 32 + +typedef struct { + binary_time time; + binary_date date; +} binary_timestamp; // natural size: 96, natural alignment: 32 + +static binary_timestamp +random_timestamp(struct lfsr *lfsr) +{ + // the % trick gives a little skew but we don't care + binary_timestamp ts = { + .time = { + .ms = lfsr_bits(lfsr, 32) % 1000000, + .seconds = lfsr_bits(lfsr, 16) % 60, // 61 ?? + .minutes = lfsr_bits(lfsr, 16) % 60, + .hours = lfsr_bits(lfsr, 8) % 24, + .padding = 0, + }, + .date = { + .day = 0, // determine later + .month = 1 + lfsr_bits(lfsr, 8) % 12, + .year = 2030 - (int16_t)lfsr_bits(lfsr, 6), + }, + }; + + const uint32_t durations[] = { 0, + 31, 28, 31, 30, + 31, 30, 31, 31, + 30, 31, 30, 31, + }; + uint32_t year = ts.date.year; + uint32_t days = durations[ts.date.month]; + bool leap_year = ( + days == 28 && + year % 4 == 0 && + (year % 100 != 0 || year % 400 == 0) + ); + if (leap_year) + days = 29; + ts.date.day = 1 + lfsr_bits(lfsr, 8) % days; + + return ts; +} + +void fix_endian(binary_timestamp *p); +void fix_endian2(int16_t *p); +void fix_endian4(uint32_t *p); + +#ifdef WORDS_BIGENDIAN +void fix_endian2(int16_t *p) { + char *bytes = (char*) p; + + char b0 = bytes[0]; + char b1 = bytes[1]; + + bytes[0] = b1; + bytes[1] = b0; +} + +void fix_endian4(uint32_t *p) { + char *bytes = (char*) p; + + char b0 = bytes[0]; + char b1 = bytes[1]; + char b2 = bytes[2]; + char b3 = bytes[3]; + + bytes[0] = b3; + bytes[1] = b2; + bytes[2] = b1; + bytes[3] = b0; +} +#else +void fix_endian2(int16_t *p) { + (void)p; +} + +void fix_endian4(uint32_t *p) { + (void)p; +} +#endif + +void fix_endian(binary_timestamp *ts) +{ + fix_endian2(&ts->date.year); + fix_endian4(&ts->time.ms); +} + +void +gen_timestamps(FILE *f, long nrecs) +{ + struct lfsr lfsr = my_favorite_lfsr(); + + for (long i = 0; i < nrecs; i++) { + binary_timestamp ts = random_timestamp(&lfsr); + fix_endian(&ts); + fwrite(&ts, sizeof(ts), 1, f); + } +} + +#define GEN_TIMESTAMP_FIELD(name, fld) \ + void name \ + (FILE *f, long nrecs) \ + { \ + struct lfsr lfsr = my_favorite_lfsr(); \ + \ + for (long i = 0; i < nrecs; i++) { \ + binary_timestamp ts = random_timestamp(&lfsr); \ + fix_endian(&ts); \ + fwrite(&ts.fld, sizeof(ts.fld), 1, f); \ + } \ + } + +GEN_TIMESTAMP_FIELD(gen_timestamp_times, time) +GEN_TIMESTAMP_FIELD(gen_timestamp_dates, date) + +GEN_TIMESTAMP_FIELD(gen_timestamp_ms, time.ms) +GEN_TIMESTAMP_FIELD(gen_timestamp_seconds, time.seconds) +GEN_TIMESTAMP_FIELD(gen_timestamp_minutes, time.minutes) +GEN_TIMESTAMP_FIELD(gen_timestamp_hours, time.hours) +GEN_TIMESTAMP_FIELD(gen_timestamp_days, date.day) +GEN_TIMESTAMP_FIELD(gen_timestamp_months, date.month) +GEN_TIMESTAMP_FIELD(gen_timestamp_years, date.year) diff --git a/sql/test/bincopy/Tests/All b/sql/test/bincopy/Tests/All --- a/sql/test/bincopy/Tests/All +++ b/sql/test/bincopy/Tests/All @@ -15,3 +15,5 @@ bincopy_newlines_on_client bincopy_newlines_on_server bincopy_null_strings_on_client bincopy_null_strings_on_server +bincopy_timestamps_on_client +bincopy_timestamps_on_server 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 @@ -108,3 +108,39 @@ SELECT COUNT(id) FROM foo WHERE (id % 2 = 0 AND s IS NULL) OR (id % 2 = 1 AND s = 'banana'); """ + +TIMESTAMPS = """ +CREATE TABLE foo( + id INT NOT NULL, + ts TIMESTAMP, + "year" SMALLINT, + "month" TINYINT, + "day" TINYINT, + "hour" TINYINT, + "minute" TINYINT, + "second" TINYINT, + ms INTEGER +); +COPY BINARY INTO foo(id, ts, "year", "month", "day", "hour", "minute", "second", ms) +FROM @ints@, + @timestamps@, + @timestamp_years@, + @timestamp_months@, + @timestamp_days@, + @timestamp_hours@, + @timestamp_minutes@, + @timestamp_seconds@, + @timestamp_ms@ + @ON@; +""" + +# 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) diff --git a/sql/test/bincopy/Tests/bincopy_timestamps_on_client.SQL.py b/sql/test/bincopy/Tests/bincopy_timestamps_on_client.SQL.py new file mode 100644 --- /dev/null +++ b/sql/test/bincopy/Tests/bincopy_timestamps_on_client.SQL.py @@ -0,0 +1,6 @@ +#!/usr/bin/env python3 + +from bincopy_support import run_test +from bincopy_support import TIMESTAMPS as testcode + +run_test('client', testcode) diff --git a/sql/test/bincopy/Tests/bincopy_timestamps_on_server.SQL.py b/sql/test/bincopy/Tests/bincopy_timestamps_on_server.SQL.py new file mode 100644 --- /dev/null _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list