Changeset: d148562e8a06 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/d148562e8a06
Modified Files:
        sql/server/sql_datetime.c
        sql/server/sql_datetime.h
        sql/server/sql_parser.y
        sql/server/sql_scan.c
        sql/test/odbc-escape-sequences/Tests/time-date-interval-functions.test
Branch: escape-sequences
Log Message:

partial case for timestampadd add


diffs (233 lines):

diff --git a/sql/server/sql_datetime.c b/sql/server/sql_datetime.c
--- a/sql/server/sql_datetime.c
+++ b/sql/server/sql_datetime.c
@@ -329,10 +329,13 @@ int inttype2digits( int sk, int ek )
                if(ek == iyear)
                        return 1;
                return 2;
+       case iquarter:
        case imonth:
                return 3;
+       case iweek:
        case iday:
                switch(ek) {
+               case iweek:
                case iday:
                        return 4;
                case ihour:
@@ -473,3 +476,59 @@ get_timestamp_precision(const char* val)
        parse_timestamp(val, &yr, &mt, &dy, &hr, &mn, &sc, &fr, &pr);
        return pr;
 }
+
+
+int
+process_odbc_interval(mvc *sql, itype interval, int val, sql_subtype *t, lng 
*i)
+{
+       assert(sql);
+       int mul = 1;
+       int d = inttype2digits(interval, interval);
+       switch (interval) {
+               case iyear:
+                       mul *= 12;
+                       /* fall through */
+               case iquarter:
+                       mul *= 3;
+                       /* fall through */
+               case imonth:
+                       break;
+               case iweek:
+                       mul *= 7;
+                       /* fall through */
+               case iday:
+                       mul *= 24;
+                       /* fall through */
+               case ihour:
+                       mul *= 60;
+                       /* fall through */
+               case imin:
+                       mul *= 60000;
+                       /* fall through */
+               case isec:
+                       break;
+               default:
+                       snprintf(sql->errstr, ERRSIZE, _("Internal error: bad 
interval qualifier (%d)\n"), interval);
+                       return -1;
+       }
+
+       // check for overflow
+       if (((lng) abs(val) * mul) > GDK_lng_max) {
+               snprintf(sql->errstr, ERRSIZE, _("Overflow\n"));
+               return -1;
+       }
+       // compute value month or sec interval
+       *i += val * mul;
+
+       int r = 0;
+       if (d < 4){
+               r = sql_find_subtype(t, "month_interval", d, 0);
+       } else if (d == 4) {
+               r = sql_find_subtype(t, "day_interval", d, 0);
+       } else {
+               r = sql_find_subtype(t, "sec_interval", d, 0);
+       }
+       if (!r)
+               return -1;
+       return 0;
+}
diff --git a/sql/server/sql_datetime.h b/sql/server/sql_datetime.h
--- a/sql/server/sql_datetime.h
+++ b/sql/server/sql_datetime.h
@@ -25,7 +25,8 @@ typedef enum inttype {
        idoy,
        icentury,
        idecade,
-       iepoch
+       iepoch,
+       insec
 } itype;
 
 int parse_interval_qualifier(mvc *sql, struct dlist *pers, int *sk, int *ek, 
int *sp, int *ep);
@@ -74,5 +75,7 @@ parse_timestamp(const char* val,
                unsigned int* pr);
 unsigned int
 get_timestamp_precision(const char* val);
+int
+process_odbc_interval(mvc *sql, itype interval, int val, sql_subtype *t, lng 
*i);
 
 #endif /*_SQL_DATETIME_H_*/
diff --git a/sql/server/sql_parser.y b/sql/server/sql_parser.y
--- a/sql/server/sql_parser.y
+++ b/sql/server/sql_parser.y
@@ -724,7 +724,7 @@ SQLCODE SQLERROR UNDER WHENEVER
 %token X_BODY 
 %token MAX_MEMORY MAX_WORKERS OPTIMIZER
 /* odbc tokens */
-%token DAYNAME MONTHNAME
+%token DAYNAME MONTHNAME TIMESTAMPADD TIMESTAMPDIFF
 /* odbc data type tokens */
 %token <sval>
                SQL_BIGINT
@@ -775,7 +775,10 @@ SQLCODE SQLERROR UNDER WHENEVER
         SQL_TSI_YEAR
 
 %type <type>
-       odbc_data_type
+       odbc_data_type 
+
+%type <i_val>
+    odbc_tsi_qualifier
     
 /* odbc escape prefix tokens */
 %token <sval>
@@ -796,6 +799,7 @@ SQLCODE SQLERROR UNDER WHENEVER
     odbc_scalar_func_escape
     odbc_scalar_func
     odbc_datetime_func
+
 %%
 
 sqlstmt:
@@ -5677,6 +5681,8 @@ non_reserved_word:
 | ODBC_OJ_ESCAPE_PREFIX { $$ = sa_strdup(SA, "oj"); }
 | DAYNAME { $$ = sa_strdup(SA, "dayname"); }
 | MONTHNAME { $$ = sa_strdup(SA, "monthname"); }
+| TIMESTAMPADD { $$ = sa_strdup(SA, "timestampadd"); }
+| TIMESTAMPDIFF { $$ = sa_strdup(SA, "timestampdiff"); }
 ;
 
 lngval:
@@ -6463,6 +6469,22 @@ odbc_datetime_func:
           append_symbol(l, $3);
           $$ = _symbol_create_list( SQL_UNOP, l ); 
                }
+    | TIMESTAMPADD '(' odbc_tsi_qualifier ',' intval ',' search_condition ')'
+               { dlist *l = L(); 
+          // TODO sql_add or custom func ?
+                 append_list( l, append_string(L(), sa_strdup(SA, "sql_add")));
+             append_int(l, FALSE); /* ignore distinct */
+          sql_subtype t; 
+                 lng i = 0;
+          if (process_odbc_interval(m, $3, $5, &t, &i) < 0) {
+                   yyerror(m, "incorrect interval");
+                       $$ = NULL;
+                       YYABORT;
+          }
+          append_symbol(l, _newAtomNode(atom_int(SA, &t, i)));
+          append_symbol(l, $7);
+          $$ = _symbol_create_list( SQL_BINOP, l ); 
+               }
 ;
 
 
@@ -6579,6 +6601,30 @@ odbc_data_type:
         { sql_find_subtype(&$$, "clob", 0, 0); }
 ;
 
+odbc_tsi_qualifier:
+    SQL_TSI_FRAC_SECOND
+        { $$ = insec; }
+    | SQL_TSI_SECOND
+        { $$ = isec; }
+    | SQL_TSI_MINUTE
+        { $$ = imin; }
+    | SQL_TSI_HOUR
+        { $$ = ihour; }
+    | SQL_TSI_DAY
+        { $$ = iday; }
+    | SQL_TSI_WEEK
+        { $$ = iweek; }
+    | SQL_TSI_MONTH
+        { $$ = imonth; }
+    | SQL_TSI_QUARTER
+        { $$ = iquarter; }
+    | SQL_TSI_YEAR
+        { $$ = iyear; }
+
+;
+
+
+
 %%
 
 
diff --git a/sql/server/sql_scan.c b/sql/server/sql_scan.c
--- a/sql/server/sql_scan.c
+++ b/sql/server/sql_scan.c
@@ -529,6 +529,8 @@ scanner_init_keywords(void)
        failed += keywords_insert("oj", ODBC_OJ_ESCAPE_PREFIX);
        failed += keywords_insert("DAYNAME", DAYNAME);
        failed += keywords_insert("MONTHNAME", MONTHNAME);
+       failed += keywords_insert("TIMESTAMPADD", TIMESTAMPADD);
+       failed += keywords_insert("TIMESTAMPDIFF", TIMESTAMPDIFF);
        failed += keywords_insert("SQL_BIGINT", SQL_BIGINT);
        failed += keywords_insert("SQL_BINARY", SQL_BINARY);
        failed += keywords_insert("SQL_BIT", SQL_BIT);
@@ -566,6 +568,15 @@ scanner_init_keywords(void)
        failed += keywords_insert("SQL_WCHAR", SQL_WCHAR);
        failed += keywords_insert("SQL_WLONGVARCHAR", SQL_WLONGVARCHAR);
        failed += keywords_insert("SQL_WVARCHAR", SQL_WVARCHAR);
+       failed += keywords_insert("SQL_TSI_FRAC_SECOND", SQL_TSI_FRAC_SECOND);
+       failed += keywords_insert("SQL_TSI_SECOND", SQL_TSI_SECOND);
+       failed += keywords_insert("SQL_TSI_MINUTE", SQL_TSI_MINUTE);
+       failed += keywords_insert("SQL_TSI_HOUR", SQL_TSI_HOUR);
+       failed += keywords_insert("SQL_TSI_DAY", SQL_TSI_DAY);
+       failed += keywords_insert("SQL_TSI_WEEK", SQL_TSI_WEEK);
+       failed += keywords_insert("SQL_TSI_MONTH", SQL_TSI_MONTH);
+       failed += keywords_insert("SQL_TSI_QUARTER", SQL_TSI_QUARTER);
+       failed += keywords_insert("SQL_TSI_YEAR", SQL_TSI_YEAR);
 
        return failed;
 }
diff --git 
a/sql/test/odbc-escape-sequences/Tests/time-date-interval-functions.test 
b/sql/test/odbc-escape-sequences/Tests/time-date-interval-functions.test
--- a/sql/test/odbc-escape-sequences/Tests/time-date-interval-functions.test
+++ b/sql/test/odbc-escape-sequences/Tests/time-date-interval-functions.test
@@ -101,3 +101,8 @@ query I rowsort
 select { fn year(date'2022-11-14') }
 ----
 2022
+
+query T rowsort
+select { fn timestampadd(SQL_TSI_HOUR, 1, timestamp'2022-11-14 12:12:12') }
+----
+2022-11-14 13:12:12
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to