Changeset: f7406735f6d8 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/f7406735f6d8 Added Files: sql/backends/monet5/generator/Tests/generator05.test Modified Files: sql/backends/monet5/generator/90_generator.sql sql/backends/monet5/generator/Tests/All sql/backends/monet5/generator/generator.c Branch: default Log Message:
add generate_series for dates, ie steps of 1 or more days or months. diffs (truncated from 670 to 300 lines): diff --git a/sql/backends/monet5/generator/90_generator.sql b/sql/backends/monet5/generator/90_generator.sql --- a/sql/backends/monet5/generator/90_generator.sql +++ b/sql/backends/monet5/generator/90_generator.sql @@ -54,6 +54,14 @@ create function sys.generate_series(firs returns table (value decimal(10,2)) external name generator.series; +create function sys.generate_series(first date, "limit" date, stepsize interval month) +returns table (value date) +external name generator.series; + +create function sys.generate_series(first date, "limit" date, stepsize interval day) +returns table (value date) +external name generator.series; + create function sys.generate_series(first timestamp, "limit" timestamp, stepsize interval second) returns table (value timestamp) external name generator.series; diff --git a/sql/backends/monet5/generator/Tests/All b/sql/backends/monet5/generator/Tests/All --- a/sql/backends/monet5/generator/Tests/All +++ b/sql/backends/monet5/generator/Tests/All @@ -3,6 +3,7 @@ generator01 generator02 generator03 generator04 +generator05 rangejoin diff --git a/sql/backends/monet5/generator/Tests/generator05.test b/sql/backends/monet5/generator/Tests/generator05.test new file mode 100644 --- /dev/null +++ b/sql/backends/monet5/generator/Tests/generator05.test @@ -0,0 +1,24 @@ +query T nosort +select * from generate_series(date '2023-01-01',date '2024-01-01', interval '1' month) where value < date '2023-06-06' +---- +2023-01-01 +2023-02-01 +2023-03-01 +2023-04-01 +2023-05-01 + +query T nosort +select * from generate_series(date '2023-01-01',date '2024-01-01', interval '15' day) where value < date '2023-06-06' +---- +2023-01-01 +2023-01-16 +2023-01-31 +2023-02-15 +2023-03-02 +2023-03-17 +2023-04-01 +2023-04-16 +2023-05-01 +2023-05-16 +2023-05-31 + diff --git a/sql/backends/monet5/generator/generator.c b/sql/backends/monet5/generator/generator.c --- a/sql/backends/monet5/generator/generator.c +++ b/sql/backends/monet5/generator/generator.c @@ -12,7 +12,7 @@ /* * (c) Martin Kersten, Sjoerd Mullender - * Series generating module for integer, decimal, real, double and timestamps. + * Series generating module for integer, decimal, real, double, date and timestamps. */ #include "monetdb_config.h" @@ -51,11 +51,21 @@ VLTgenerator_noop(Client cntxt, MalBlkPt case TYPE_flt: VLTnoop(flt); break; case TYPE_dbl: VLTnoop(dbl); break; default: - if (tpe == TYPE_timestamp){ + if (tpe == TYPE_date) { + /* with date, step is of SQL type "interval month or day", + * i.e., MAL / C type "int" or "lng" */ + int steptpe = pci->argc==4 ? getArgType(mb,pci,3) : 0; + if (steptpe == TYPE_int) + VLTnoop(int); + else /* default interval days */ + VLTnoop(lng); + } else if (tpe == TYPE_timestamp) { /* with timestamp, step is of SQL type "interval seconds", * i.e., MAL / C type "lng" */ VLTnoop(lng); - } else throw(MAL,"generator.noop", SQLSTATE(42000) "unknown data type %d", getArgType(mb,pci,1)); + } else { + throw(MAL,"generator.noop", SQLSTATE(42000) "unknown data type %d", getArgType(mb,pci,1)); + } } if( zeroerror) throw(MAL,"generator.noop", SQLSTATE(42000) "Zero step size not allowed"); @@ -204,7 +214,77 @@ VLTgenerator_table_(BAT **result, Client VLTmaterialize_flt(dbl); break; default: - if (tpe == TYPE_timestamp) { + if (tpe == TYPE_date && pci->argc == 3) + throw(MAL,"generator.table", SQLSTATE(42000) "Date step missing"); + if (tpe == TYPE_date && getArgType(mb, pci, 3) == TYPE_int) { /* months */ + date *v,f,l; + int s; + ValRecord ret; + if (VARcalccmp(&ret, &stk->stk[pci->argv[1]], + &stk->stk[pci->argv[2]]) != GDK_SUCCEED) + throw(MAL, "generator.table", + SQLSTATE(42000) "Illegal generator expression range"); + f = *getArgReference_TYPE(stk, pci, 1, date); + l = *getArgReference_TYPE(stk, pci, 2, date); + s = *getArgReference_int(stk, pci, 3); + if (s == 0 || + (s > 0 && ret.val.btval > 0) || + (s < 0 && ret.val.btval < 0) || + is_date_nil(f) || is_date_nil(l)) + throw(MAL, "generator.table", + SQLSTATE(42000) "Illegal generator range"); + n = (BUN) (date_diff(l, f) / (s *28)); /* n maybe too large now */ + bn = COLnew(0, TYPE_date, n + 1, TRANSIENT); + if (bn == NULL) + throw(MAL, "generator.table", SQLSTATE(HY013) MAL_MALLOC_FAIL); + v = (date *) Tloc(bn, 0); + for (c = 0; c < n && f < l; c++) { + *v++ = f; + f = date_add_month(f, s); + if (is_date_nil(f)) { + BBPreclaim(bn); + throw(MAL, "generator.table", SQLSTATE(22003) "overflow in calculation"); + } + } + n = c; + bn->tsorted = s > 0 || n <= 1; + bn->trevsorted = s < 0 || n <= 1; + } else if (tpe == TYPE_date) { /* days */ + date *v,f,l; + lng s; + ValRecord ret; + if (VARcalccmp(&ret, &stk->stk[pci->argv[1]], + &stk->stk[pci->argv[2]]) != GDK_SUCCEED) + throw(MAL, "generator.table", + SQLSTATE(42000) "Illegal generator expression range"); + f = *getArgReference_TYPE(stk, pci, 1, date); + l = *getArgReference_TYPE(stk, pci, 2, date); + s = *getArgReference_lng(stk, pci, 3); + if (s == 0 || + (s > 0 && ret.val.btval > 0) || + (s < 0 && ret.val.btval < 0) || + is_date_nil(f) || is_date_nil(l)) + throw(MAL, "generator.table", + SQLSTATE(42000) "Illegal generator range"); + s /= 24*60*60*1000; + /* check if s is really in nr of days or usecs */ + n = (BUN) (date_diff(l, f) / s) + 1; /* n maybe too large now */ + bn = COLnew(0, TYPE_date, n + 1, TRANSIENT); + if (bn == NULL) + throw(MAL, "generator.table", SQLSTATE(HY013) MAL_MALLOC_FAIL); + v = (date *) Tloc(bn, 0); + for (c = 0; c < n && f < l; c++) { + *v++ = f; + f = date_add_day(f, s); + if (is_date_nil(f)) { + BBPreclaim(bn); + throw(MAL, "generator.table", SQLSTATE(22003) "overflow in calculation"); + } + } + n = c; + bn->tsorted = s > 0 || n <= 1; + bn->trevsorted = s < 0 || n <= 1; + } else if (tpe == TYPE_timestamp) { timestamp *v,f,l; lng s; ValRecord ret; @@ -421,7 +501,158 @@ VLTgenerator_subselect(Client cntxt, Mal case TYPE_flt: calculate_range(flt, dbl); break; case TYPE_dbl: calculate_range(dbl, dbl); break; default: - if( tpe == TYPE_timestamp){ + if (p->argc == 3) { + BBPreclaim(cand); + throw(MAL,"generator.table", SQLSTATE(42000) "Date step missing"); + } + if (tpe == TYPE_date && getArgType(mb, p, 3) == TYPE_int) { /* months */ + date tsf,tsl; + date tlow,thgh; + int tss; + oid *ol; + + tsf = *getArgReference_TYPE(stk, p, 1, date); + tsl = *getArgReference_TYPE(stk, p, 2, date); + tss = *getArgReference_int(stk, p, 3); + if ( tss == 0 || + is_date_nil(tsf) || is_date_nil(tsl) || + (tss > 0 && tsf > tsl ) || + (tss < 0 && tsf < tsl ) + ) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(42000) "Illegal generator range"); + } + + tlow = *getArgReference_TYPE(stk,pci,i, date); + thgh = *getArgReference_TYPE(stk,pci,i+1, date); + + if (!is_date_nil(tlow) && tlow == thgh) + hi = li; + if( hi && !is_date_nil(thgh)) { + thgh = date_add_month(thgh, 1); + if (is_date_nil(thgh)) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation"); + } + } + if( !li && !is_date_nil(tlow)) { + tlow = date_add_month(tlow, 1); + if (is_date_nil(tlow)) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation"); + } + } + + o2 = (BUN) (date_diff(tsl, tsf) / (tss*28)); + bn = COLnew(0, TYPE_oid, o2 + 1, TRANSIENT); + if (bn == NULL) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(HY013) MAL_MALLOC_FAIL); + } + + // simply enumerate the sequence and filter it by predicate and candidate list + ol = (oid *) Tloc(bn, 0); + for (o1=0; o1 <= o2; o1++) { + if(((is_date_nil(tlow) || tsf >= tlow) && + (is_date_nil(thgh) || tsf < thgh)) != anti ){ + /* could be improved when no candidate list is available into a void/void BAT */ + if( cand == NULL || canditer_contains(&ci, o1)) { + *ol++ = o1; + n++; + } + } + tsf = date_add_month(tsf, tss); + if (is_date_nil(tsf)) { + BBPreclaim(cand); + BBPreclaim(bn); + throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation"); + } + } + BBPreclaim(cand); + BATsetcount(bn, n); + bn->tsorted = true; + bn->trevsorted = BATcount(bn) <= 1; + bn->tkey = true; + bn->tnil = false; + bn->tnonil = true; + * getArgReference_bat(stk, pci, 0) = bn->batCacheid; + BBPkeepref(bn); + return MAL_SUCCEED; + } else if (tpe == TYPE_date) { /* days */ + date tsf,tsl; + date tlow,thgh; + lng tss; + oid *ol; + + tsf = *getArgReference_TYPE(stk, p, 1, date); + tsl = *getArgReference_TYPE(stk, p, 2, date); + tss = *getArgReference_lng(stk, p, 3); + if ( tss == 0 || + is_date_nil(tsf) || is_date_nil(tsl) || + (tss > 0 && tsf > tsl ) || + (tss < 0 && tsf < tsl ) + ) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(42000) "Illegal generator range"); + } + tss /= 24*60*60*1000; + + tlow = *getArgReference_TYPE(stk,pci,i, date); + thgh = *getArgReference_TYPE(stk,pci,i+1, date); + + if (!is_date_nil(tlow) && tlow == thgh) + hi = li; + if( hi && !is_date_nil(thgh)) { + thgh = date_add_month(thgh, 1); + if (is_date_nil(thgh)) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation"); + } + } + if( !li && !is_date_nil(tlow)) { + tlow = date_add_month(tlow, 1); + if (is_date_nil(tlow)) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(22003) "overflow in calculation"); + } + } + + o2 = (BUN) (date_diff(tsl, tsf) / tss) + 1; + bn = COLnew(0, TYPE_oid, o2 + 1, TRANSIENT); + if (bn == NULL) { + BBPreclaim(cand); + throw(MAL, "generator.select", SQLSTATE(HY013) MAL_MALLOC_FAIL); + } _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org