LCOV - code coverage report
Current view: top level - sql/server - sql_datetime.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 263 316 83.2 %
Date: 2024-10-03 20:03:20 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "monetdb_config.h"
      14             : #include "sql_datetime.h"
      15             : #include "sql_string.h"
      16             : 
      17             : int
      18       10948 : parse_interval_qualifier(mvc *sql, struct dlist *pers, int *sk, int *ek, int *sp, int *ep)
      19             : {
      20       10948 :         *sk = iyear;
      21       10948 :         *ek = isec;
      22             : 
      23       10948 :         if (pers) {
      24       10948 :                 dlist *s = pers->h->data.lval;
      25             : 
      26       10948 :                 assert(s->h->type == type_int);
      27       10948 :                 *ek = *sk = s->h->data.i_val;
      28       10948 :                 *ep = *sp = s->h->next->data.i_val;
      29             : 
      30       10948 :                 if (dlist_length(pers) == 2) {
      31         186 :                         dlist *e = pers->h->next->data.lval;
      32             : 
      33         186 :                         assert(e->h->type == type_int);
      34         186 :                         *ek = e->h->data.i_val;
      35         186 :                         *ep = e->h->next->data.i_val;
      36             :                 }
      37             :         }
      38       10948 :         if (*sk > *ek) {
      39           0 :                 snprintf(sql->errstr, ERRSIZE, _("End interval field is larger than the start field\n"));
      40           0 :                 return -1;
      41             :         }
      42       10948 :         if ((*sk == iyear || *sk == imonth) && *ek > imonth) {
      43           0 :                 snprintf(sql->errstr, ERRSIZE, _("Correct interval ranges are year-month or day-seconds\n"));
      44           0 :                 return -1;
      45             :         }
      46       10948 :         if (*sk == iyear || *sk == imonth)
      47        3467 :                 return 0;
      48             :         return 1;
      49             : }
      50             : 
      51             : lng
      52           0 : qualifier2multiplier( int sk )
      53             : {
      54           0 :         lng mul = 1;
      55             : 
      56           0 :         switch (sk) {
      57           0 :         case iyear:
      58           0 :                 mul *= 12;
      59             :                 /* fall through */
      60             :         case imonth:
      61             :                 break;
      62           0 :         case iday:
      63           0 :                 mul *= 24;
      64             :                 /* fall through */
      65           0 :         case ihour:
      66           0 :                 mul *= 60;
      67             :                 /* fall through */
      68           0 :         case imin:
      69           0 :                 mul *= 60000;
      70             :                 /* fall through */
      71             :         case isec:
      72             :                 break;
      73             :         default:
      74             :                 return -1;
      75             :         }
      76             :         return mul;
      77             : }
      78             : 
      79             : static int
      80         139 : parse_interval_(mvc *sql, lng sign, const char *str, int sk, int ek, int sp, int ep, lng *i)
      81             : {
      82         139 :         char *n = NULL, sep = ':';
      83         139 :         lng val = 0, mul;
      84         139 :         int type;
      85             : 
      86         139 :         if (*str == '-') {
      87           0 :                 sign *= -1;
      88           0 :                 str++;
      89             :         }
      90         139 :         mul = sign;
      91             : 
      92         139 :         switch (sk) {
      93           0 :         case iyear:
      94           0 :                 mul *= 12;
      95             :                 /* fall through */
      96             :         case imonth:
      97             :                 sep = '-';
      98             :                 type = 0;
      99             :                 break;
     100           0 :         case iday:
     101           0 :                 mul *= 24;
     102           0 :                 sep = ' ';
     103             :                 /* fall through */
     104          21 :         case ihour:
     105          21 :                 mul *= 60;
     106             :                 /* fall through */
     107          82 :         case imin:
     108          82 :                 mul *= 60000;
     109             :                 /* fall through */
     110             :         case isec:
     111             :                 type = 1;
     112             :                 break;
     113           0 :         default:
     114           0 :                 if (sql)
     115           0 :                         snprintf(sql->errstr, ERRSIZE, _("Internal error: parse_interval: bad value for sk (%d)\n"), sk);
     116             :                 return -1;
     117             :         }
     118             : 
     119         139 :         val = strtoll(str, &n, 10);
     120         139 :         if (!n)
     121             :                 return -1;
     122         139 :         if (sk == isec) {
     123          26 :                 lng msec = 0;
     124          26 :                 val *= 1000;
     125          26 :                 if (n && n[0] == '.') {
     126           8 :                         char *nn;
     127           8 :                         msec = strtol(n+1, &nn, 10);
     128           8 :                         if (msec && nn) {
     129           8 :                                 ptrdiff_t d = nn-(n+1);
     130           8 :                                 for( ;d<3; d++)
     131           0 :                                         msec *= 10;
     132           8 :                                 for( ;d>3; d--)
     133           0 :                                         msec /= 10;
     134           8 :                                 n = nn;
     135             :                         }
     136             :                 }
     137          26 :                 val += msec;
     138             :         }
     139         139 :         switch (sk) {
     140          31 :         case imonth:
     141          31 :                 if (val >= 12) {
     142           0 :                         if (sql)
     143           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in months (" LLFMT ")\n"), val);
     144           0 :                         return -1;
     145             :                 }
     146             :                 break;
     147          21 :         case ihour:
     148          21 :                 if (val >= 24) {
     149           0 :                         if (sql)
     150           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in hours (" LLFMT ")\n"), val);
     151           0 :                         return -1;
     152             :                 }
     153             :                 break;
     154          61 :         case imin:
     155          61 :                 if (val >= 60) {
     156           1 :                         if (sql)
     157           1 :                                 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in minutes (" LLFMT ")\n"), val);
     158           1 :                         return -1;
     159             :                 }
     160             :                 break;
     161          26 :         case isec:
     162          26 :                 if (val >= 60000) {
     163           4 :                         if (sql)
     164           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in seconds (" LLFMT ")\n"), val);
     165           4 :                         return -1;
     166             :                 }
     167             :                 break;
     168             :         }
     169         134 :         val *= mul;
     170         134 :         *i += val;
     171         134 :         if (ek != sk) {
     172          33 :                 if (*n != sep) {
     173           0 :                         if (sql)
     174           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Interval field separator \'%c\' missing\n"), sep);
     175           0 :                         return -1;
     176             :                 }
     177          33 :                 return parse_interval_(sql, sign, n + 1, sk + 1, ek, sp, ep, i);
     178             :         } else {
     179             :                 return type;
     180             :         }
     181             : }
     182             : 
     183             : #define MABS(a) (((a) < 0) ? -(a) : (a))
     184             : 
     185             : int
     186        1209 : parse_interval(mvc *sql, lng sign, const char *str, int sk, int ek, int sp, int ep, lng *i)
     187             : {
     188        1209 :         char *n = NULL, sep = ':';
     189        1209 :         lng val = 0, mul, msec = 0;
     190        1209 :         int type;
     191             : 
     192        1209 :         if (*str == '-') {
     193         210 :                 sign *= -1;
     194         210 :                 str++;
     195             :         }
     196        1209 :         mul = sign;
     197             : 
     198        1209 :         switch (sk) {
     199          59 :         case iyear:
     200          59 :                 mul *= 12;
     201             :                 /* fall through */
     202             :         case imonth:
     203             :                 sep = '-';
     204             :                 type = 0;
     205             :                 break;
     206         184 :         case iday:
     207         184 :                 mul *= 24;
     208         184 :                 sep = ' ';
     209             :                 /* fall through */
     210         304 :         case ihour:
     211         304 :                 mul *= 60;
     212             :                 /* fall through */
     213         335 :         case imin:
     214         335 :                 mul *= 60000;
     215             :                 /* fall through */
     216             :         case isec:
     217             :                 type = 1;
     218             :                 break;
     219           0 :         default:
     220           0 :                 if (sql)
     221           0 :                         snprintf(sql->errstr, ERRSIZE, _("Internal error: parse_interval: bad value for sk (%d)\n"), sk);
     222             :                 return -1;
     223             :         }
     224             : 
     225        1209 :         val = strtoll(str, &n, 10);
     226        1209 :         if (!n)
     227             :                 return -1;
     228        1209 :         if (sk == isec) {
     229         456 :                 if (n && n[0] == '.') {
     230           8 :                         char *nn;
     231           8 :                         msec = strtol(n+1, &nn, 10);
     232           8 :                         if (msec && nn) {
     233           8 :                                 ptrdiff_t d = nn-(n+1);
     234          11 :                                 for( ;d<3; d++)
     235           3 :                                         msec *= 10;
     236           9 :                                 for( ;d>3; d--)
     237           1 :                                         msec /= 10;
     238           8 :                                 n = nn;
     239             :                         }
     240             :                 }
     241             :         }
     242        1209 :         switch (sk) {
     243         418 :         case iyear:
     244             :         case imonth:
     245         418 :                 if (val > (lng) GDK_int_max / MABS(mul)) {
     246           3 :                         if (sql)
     247           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Overflow\n"));
     248           3 :                         return -1;
     249             :                 }
     250             :                 break;
     251         335 :         case iday:
     252             :         case ihour:
     253             :         case imin:
     254         335 :                 if (val > GDK_lng_max / MABS(mul)) {
     255           0 :                         if (sql)
     256           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Overflow\n"));
     257           0 :                         return -1;
     258             :                 }
     259             :                 break;
     260         456 :         case isec:
     261         456 :                 if (val > GDK_lng_max / 1000 / MABS(mul) || (val == GDK_lng_max / 1000 / MABS(mul) && msec > GDK_lng_max % 1000)) {
     262           6 :                         if (sql)
     263           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Overflow\n"));
     264           6 :                         return -1;
     265             :                 }
     266         450 :                 val *= 1000;
     267         450 :                 val += msec;
     268         450 :                 break;
     269             :         default:
     270           0 :                 assert(0);
     271             :         }
     272        1200 :         val *= mul;
     273        1200 :         *i += val;
     274        1200 :         if (ek != sk) {
     275         110 :                 if (*n != sep) {
     276           4 :                         if (sql)
     277           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Interval field separator \'%c\' missing\n"), sep);
     278           4 :                         return -1;
     279             :                 }
     280         106 :                 return parse_interval_(sql, sign, n + 1, sk + 1, ek, sp, ep, i);
     281             :         } else {
     282        1090 :                 if (!n || *n) {
     283          77 :                         if (sql)
     284           0 :                                 snprintf(sql->errstr, ERRSIZE, _("Interval type miss match '%s'\n"), (!n)?"":n);
     285          77 :                         return -1;
     286             :                 }
     287             :                 return type;
     288             :         }
     289             : }
     290             : 
     291         161 : int interval_from_str(const char *str, int d, int p, lng *val)
     292             : {
     293         161 :         int sk = digits2sk(d);
     294         161 :         int ek = digits2ek(d);
     295         161 :         *val = 0;
     296         161 :         return parse_interval(NULL, 1, str, sk, ek, p, p, val);
     297             : }
     298             : 
     299             : char *
     300         287 : datetime_field(itype f)
     301             : {
     302         287 :         switch (f) {
     303             :         default:
     304             :         case icentury:
     305             :                 return "century";
     306           7 :         case idecade:
     307           7 :                 return "decade";
     308          95 :         case iyear:
     309          95 :                 return "year";
     310          66 :         case imonth:
     311          66 :                 return "month";
     312          25 :         case iday:
     313          25 :                 return "day";
     314          20 :         case ihour:
     315          20 :                 return "hour";
     316          16 :         case imin:
     317          16 :                 return "minute";
     318          17 :         case isec:
     319          17 :                 return "second";
     320           8 :         case iquarter:
     321           8 :                 return "quarter";
     322          10 :         case iweek:
     323          10 :                 return "week";
     324           0 :         case idow:
     325           0 :                 return "dayofweek";
     326           1 :         case idoy:
     327           1 :                 return "dayofyear";
     328           7 :         case iepoch:
     329           7 :                 return "epoch_ms";
     330             :         }
     331             : }
     332             : 
     333       49781 : int inttype2digits( int sk, int ek )
     334             : {
     335       49781 :         switch(sk) {
     336          87 :         case iyear:
     337          87 :                 if(ek == iyear)
     338             :                         return 1;
     339             :                 return 2;
     340             :         case iquarter:
     341             :         case imonth:
     342             :                 return 3;
     343        3876 :         case iweek:
     344             :         case iday:
     345        3876 :                 switch(ek) {
     346             :                 case iweek:
     347             :                 case iday:
     348             :                         return 4;
     349             :                 case ihour:
     350             :                         return 5;
     351             :                 case imin:
     352             :                         return 6;
     353             :                 default:
     354             :                         return 7;
     355             :                 }
     356       38970 :         case ihour:
     357       38970 :                 switch(ek) {
     358             :                 case ihour:
     359             :                         return 8;
     360          47 :                 case imin:
     361          47 :                         return 9;
     362       38843 :                 default:
     363       38843 :                         return 10;
     364             :                 }
     365          54 :         case imin:
     366          54 :                 if(ek == imin)
     367          40 :                         return 11;
     368             :                 return 12;
     369        3410 :         case isec:
     370        3410 :                 return 13;
     371             :         }
     372             :         return 1;
     373             : }
     374             : 
     375         161 : int digits2sk( int digits)
     376             : {
     377         161 :         int sk = iyear;
     378             : 
     379         161 :         if (digits > 2)
     380         155 :                 sk = imonth;
     381         155 :         if (digits > 3)
     382             :                 sk = iday;
     383         149 :         if (digits > 7)
     384         130 :                 sk = ihour;
     385         130 :         if (digits > 10)
     386          92 :                 sk = imin;
     387          92 :         if (digits > 12)
     388          90 :                 sk = isec;
     389         161 :         return sk;
     390             : }
     391             : 
     392         169 : int digits2ek( int digits)
     393             : {
     394         169 :         int ek = iyear;
     395             : 
     396         169 :         if (digits == 2 || digits == 3)
     397             :                 ek = imonth;
     398         146 :         if (digits == 4)
     399           6 :                 ek = iday;
     400         169 :         if (digits == 5 || digits == 8)
     401          30 :                 ek = ihour;
     402         169 :         if (digits == 6 || digits == 9 || digits == 11)
     403           6 :                 ek = imin;
     404         169 :         if (digits == 7 || digits == 10 || digits == 12 || digits == 13)
     405         101 :                 ek = isec;
     406         169 :         return ek;
     407             : }
     408             : 
     409             : 
     410             : static int
     411           4 : parse_time(const char* val,
     412             :                 unsigned int* hr,
     413             :                 unsigned int* mn,
     414             :                 unsigned int* sc,
     415             :                 unsigned long* fr,
     416             :                 unsigned int* pr)
     417             : {
     418           4 :         int n;
     419           4 :         const char* p = val;
     420           4 :         if (sscanf(p, "%u:%u:%u%n", hr, mn, sc, &n) >= 3) {
     421           4 :                 p += n;
     422           4 :                 if (*p == '.') {
     423           1 :                         char* e;
     424           1 :                         p++;
     425           1 :                         *fr = strtoul(p, &e, 10);
     426           1 :                         if (e > p)
     427           1 :                                 *pr = (unsigned int) (e - p);
     428             :                 }
     429             :         }
     430           4 :         return -1;
     431             : }
     432             : 
     433             : 
     434             : static int
     435          15 : parse_timestamp(const char* val,
     436             :                 unsigned int* yr,
     437             :                 unsigned int* mt,
     438             :                 unsigned int* dy,
     439             :                 unsigned int* hr,
     440             :                 unsigned int* mn,
     441             :                 unsigned int* sc,
     442             :                 unsigned long* fr,
     443             :                 unsigned int* pr)
     444             : {
     445          15 :         int n;
     446          15 :         const char* p = val;
     447          15 :         if (sscanf(p, "%u-%u-%u %u:%u:%u%n",
     448             :                                 yr, mt, dy, hr, mn, sc, &n) >= 6) {
     449          15 :                 p += n;
     450          15 :                 if (*p == '.') {
     451           4 :                         char* e;
     452           4 :                         p++;
     453           4 :                         *fr = strtoul(p, &e, 10);
     454           4 :                         if (e > p)
     455           4 :                                 *pr = (unsigned int) (e - p);
     456             :                 }
     457             :         }
     458          15 :         return -1;
     459             : }
     460             : 
     461             : unsigned int
     462           4 : get_time_precision(const char* val)
     463             : {
     464           4 :         unsigned int hr;
     465           4 :         unsigned int mn;
     466           4 :         unsigned int sc;
     467           4 :         unsigned long fr;
     468           4 :         unsigned int pr = 0;
     469           4 :         parse_time(val, &hr, &mn, &sc, &fr, &pr);
     470           4 :         return pr;
     471             : }
     472             : 
     473             : unsigned int
     474          15 : get_timestamp_precision(const char* val)
     475             : {
     476          15 :         unsigned int yr;
     477          15 :         unsigned int mt;
     478          15 :         unsigned int dy;
     479          15 :         unsigned int hr;
     480          15 :         unsigned int mn;
     481          15 :         unsigned int sc;
     482          15 :         unsigned long fr;
     483          15 :         unsigned int pr = 0;
     484          15 :         parse_timestamp(val, &yr, &mt, &dy, &hr, &mn, &sc, &fr, &pr);
     485          15 :         return pr;
     486             : }
     487             : 
     488             : 
     489             : int
     490          17 : process_odbc_interval(mvc *sql, itype interval, int val, sql_subtype *t, lng *i)
     491             : {
     492          17 :         assert(sql);
     493          17 :         lng mul = 1;
     494          17 :         int d = inttype2digits(interval, interval);
     495          17 :         switch (interval) {
     496           1 :                 case iyear:
     497           1 :                         mul *= 12;
     498           1 :                         break;
     499           1 :                 case iquarter:
     500           1 :                         mul *= 3;
     501           1 :                         break;
     502             :                 case imonth:
     503             :                         break;
     504           1 :                 case iweek:
     505           1 :                         mul *= 7;
     506             :                         /* fall through */
     507           5 :                 case iday:
     508           5 :                         mul *= 24;
     509             :                         /* fall through */
     510           9 :                 case ihour:
     511           9 :                         mul *= 60;
     512             :                         /* fall through */
     513          10 :                 case imin:
     514          10 :                         mul *= 60;
     515             :                         /* fall through */
     516          13 :                 case isec:
     517          13 :                         mul *= 1000;
     518          13 :                         break;
     519           1 :                 case insec:
     520           1 :                         d = 5;
     521           1 :                         break;
     522           0 :                 default:
     523           0 :                         snprintf(sql->errstr, ERRSIZE, _("Internal error: bad interval qualifier (%d)\n"), interval);
     524           0 :                         return -1;
     525             :         }
     526             : 
     527             :         // check for overflow
     528          17 :         if (((lng) abs(val) * mul) > GDK_lng_max) {
     529             :                 snprintf(sql->errstr, ERRSIZE, _("Overflow\n"));
     530             :                 return -1;
     531             :         }
     532             :         // compute value month or sec interval
     533          17 :         *i += val * mul;
     534             : 
     535          17 :         int r = 0;
     536          17 :         if (d < 4){
     537           3 :                 r = sql_find_subtype(t, "month_interval", d, 0);
     538          14 :         } else if (d == 4) {
     539           5 :                 r = sql_find_subtype(t, "day_interval", d, 0);
     540             :         } else {
     541           9 :                 r = sql_find_subtype(t, "sec_interval", d, 0);
     542             :         }
     543          17 :         if (!r)
     544             :                 return -1;
     545             :         return 0;
     546             : }

Generated by: LCOV version 1.14