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 1208 : parse_interval(mvc *sql, lng sign, const char *str, int sk, int ek, int sp, int ep, lng *i)
187 : {
188 1208 : char *n = NULL, sep = ':';
189 1208 : lng val = 0, mul, msec = 0;
190 1208 : int type;
191 :
192 1208 : if (*str == '-') {
193 210 : sign *= -1;
194 210 : str++;
195 : }
196 1208 : mul = sign;
197 :
198 1208 : 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 1208 : val = strtoll(str, &n, 10);
226 1208 : if (!n)
227 : return -1;
228 1208 : 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 1208 : switch (sk) {
243 417 : case iyear:
244 : case imonth:
245 417 : if (val > (lng) GDK_int_max / MABS(mul)) {
246 2 : if (sql)
247 0 : snprintf(sql->errstr, ERRSIZE, _("Overflow\n"));
248 2 : 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 160 : int interval_from_str(const char *str, int d, int p, lng *val)
292 : {
293 160 : int sk = digits2sk(d);
294 160 : int ek = digits2ek(d);
295 160 : *val = 0;
296 160 : 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 48701 : int inttype2digits( int sk, int ek )
334 : {
335 48701 : 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 37890 : case ihour:
357 37890 : switch(ek) {
358 : case ihour:
359 : return 8;
360 47 : case imin:
361 47 : return 9;
362 37763 : default:
363 37763 : 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 160 : int digits2sk( int digits)
376 : {
377 160 : int sk = iyear;
378 :
379 160 : if (digits > 2)
380 154 : sk = imonth;
381 154 : 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 160 : return sk;
390 : }
391 :
392 168 : int digits2ek( int digits)
393 : {
394 168 : int ek = iyear;
395 :
396 168 : if (digits == 2 || digits == 3)
397 : ek = imonth;
398 146 : if (digits == 4)
399 6 : ek = iday;
400 168 : if (digits == 5 || digits == 8)
401 30 : ek = ihour;
402 168 : if (digits == 6 || digits == 9 || digits == 11)
403 6 : ek = imin;
404 168 : if (digits == 7 || digits == 10 || digits == 12 || digits == 13)
405 101 : ek = isec;
406 168 : 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 : }
|