1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9#include "monetdb_config.h"
10#include "sql_datetime.h"
11#include "sql_string.h"
12
13int
14parse_interval_qualifier(mvc *sql, struct dlist *pers, int *sk, int *ek, int *sp, int *ep)
15{
16 *sk = iyear;
17 *ek = isec;
18
19 if (pers) {
20 dlist *s = pers->h->data.lval;
21
22 assert(s->h->type == type_int);
23 *ek = *sk = s->h->data.i_val;
24 *ep = *sp = s->h->next->data.i_val;
25
26 if (dlist_length(pers) == 2) {
27 dlist *e = pers->h->next->data.lval;
28
29 assert(e->h->type == type_int);
30 *ek = e->h->data.i_val;
31 *ep = e->h->next->data.i_val;
32 }
33 }
34 if (*sk > *ek) {
35 snprintf(sql->errstr, ERRSIZE, _("End interval field is larger than the start field\n"));
36 return -1;
37 }
38 if ((*sk == iyear || *sk == imonth) && *ek > imonth) {
39 snprintf(sql->errstr, ERRSIZE, _("Correct interval ranges are year-month or day-seconds\n"));
40 return -1;
41 }
42 if (*sk == iyear || *sk == imonth)
43 return 0;
44 return 1;
45}
46
47lng
48qualifier2multiplier( int sk )
49{
50 lng mul = 1;
51
52 switch (sk) {
53 case iyear:
54 mul *= 12;
55 /* fall through */
56 case imonth:
57 break;
58
59 case iday:
60 mul *= 24;
61 /* fall through */
62 case ihour:
63 mul *= 60;
64 /* fall through */
65 case imin:
66 mul *= 60000;
67 /* fall through */
68 case isec:
69 break;
70 default:
71 return -1;
72 }
73 return mul;
74}
75
76static int
77parse_interval_(mvc *sql, lng sign, char *str, int sk, int ek, int sp, int ep, lng *i)
78{
79 char *n = NULL;
80 lng val = 0;
81 char sep = ':';
82 int type;
83 lng mul;
84
85 if (*str == '-') {
86 sign *= -1;
87 str++;
88 }
89 mul = sign;
90
91 switch (sk) {
92 case iyear:
93 mul *= 12;
94 /* fall through */
95 case imonth:
96 sep = '-';
97 type = 0;
98 break;
99
100 case iday:
101 mul *= 24;
102 sep = ' ';
103 /* fall through */
104 case ihour:
105 mul *= 60;
106 /* fall through */
107 case imin:
108 mul *= 60000;
109 /* fall through */
110 case isec:
111 type = 1;
112 break;
113
114 default:
115 if (sql)
116 snprintf(sql->errstr, ERRSIZE, _("Internal error: parse_interval: bad value for sk (%d)\n"), sk);
117 return -1;
118 }
119
120 val = strtoll(str, &n, 10);
121 if (!n)
122 return -1;
123 if (sk == isec) {
124 lng msec = 0;
125 val *= 1000;
126 if (n && n[0] == '.') {
127 char *nn;
128 msec = strtol(n+1, &nn, 10);
129 if (msec && nn) {
130 ptrdiff_t d = nn-(n+1);
131 for( ;d<3; d++)
132 msec *= 10;
133 for( ;d>3; d--)
134 msec /= 10;
135 n = nn;
136 }
137 }
138 val += msec;
139 }
140 switch (sk) {
141 case imonth:
142 if (val >= 12) {
143 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in months (" LLFMT ")\n"), val);
144 return -1;
145 }
146 break;
147 case ihour:
148 if (val >= 24) {
149 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in hours (" LLFMT ")\n"), val);
150 return -1;
151 }
152 break;
153 case imin:
154 if (val >= 60) {
155 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in minutes (" LLFMT ")\n"), val);
156 return -1;
157 }
158 break;
159 case isec:
160 if (val >= 60000) {
161 snprintf(sql->errstr, ERRSIZE, _("Overflow detected in seconds (" LLFMT ")\n"), val);
162 return -1;
163 }
164 break;
165 }
166 val *= mul;
167 *i += val;
168 if (ek != sk) {
169 if (*n != sep) {
170 if (sql)
171 snprintf(sql->errstr, ERRSIZE, _("Interval field seperator \'%c\' missing\n"), sep);
172 return -1;
173 }
174 return parse_interval_(sql, sign, n + 1, sk + 1, ek, sp, ep, i);
175 } else {
176 return type;
177 }
178}
179
180int
181parse_interval(mvc *sql, lng sign, char *str, int sk, int ek, int sp, int ep, lng *i)
182{
183 char *n = NULL;
184 lng val = 0;
185 char sep = ':';
186 int type;
187 lng mul;
188
189 if (*str == '-') {
190 sign *= -1;
191 str++;
192 }
193 mul = sign;
194
195 switch (sk) {
196 case iyear:
197 mul *= 12;
198 /* fall through */
199 case imonth:
200 sep = '-';
201 type = 0;
202 break;
203
204 case iday:
205 mul *= 24;
206 sep = ' ';
207 /* fall through */
208 case ihour:
209 mul *= 60;
210 /* fall through */
211 case imin:
212 mul *= 60000;
213 /* fall through */
214 case isec:
215 type = 1;
216 break;
217
218 default:
219 if (sql)
220 snprintf(sql->errstr, ERRSIZE, _("Internal error: parse_interval: bad value for sk (%d)\n"), sk);
221 return -1;
222 }
223
224 val = strtoll(str, &n, 10);
225 if (!n)
226 return -1;
227 if (sk == isec) {
228 lng msec = 0;
229 if (n && n[0] == '.') {
230 char *nn;
231 msec = strtol(n+1, &nn, 10);
232 if (msec && nn) {
233 ptrdiff_t d = nn-(n+1);
234 for( ;d<3; d++)
235 msec *= 10;
236 for( ;d>3; d--)
237 msec /= 10;
238 n = nn;
239 }
240 }
241 if (val > GDK_lng_max / 1000 ||
242 (val == GDK_lng_max / 1000 && msec > GDK_lng_max % 1000)) {
243 if (sql)
244 snprintf(sql->errstr, ERRSIZE, _("Overflow\n"));
245 return -1;
246 }
247 val *= 1000;
248 val += msec;
249 }
250 val *= mul;
251 *i += val;
252 if (ek != sk) {
253 if (*n != sep) {
254 if (sql)
255 snprintf(sql->errstr, ERRSIZE, _("Interval field seperator \'%c\' missing\n"), sep);
256 return -1;
257 }
258 return parse_interval_(sql, sign, n + 1, sk + 1, ek, sp, ep, i);
259 } else {
260 if (!n || *n) {
261 if (sql)
262 snprintf(sql->errstr, ERRSIZE, _("Interval type miss match '%s'\n"), (!n)?"":n);
263 return -1;
264 }
265 return type;
266 }
267}
268
269int interval_from_str(char *str, int d, int p, lng *val)
270{
271 int sk = digits2sk(d);
272 int ek = digits2ek(d);
273 *val = 0;
274 return parse_interval(NULL, 1, str, sk, ek, p, p, val);
275}
276
277char *
278datetime_field(itype f)
279{
280 switch (f) {
281 default:
282 case icentury:
283 return "century";
284 case idecade:
285 return "decade";
286 case iyear:
287 return "year";
288 case imonth:
289 return "month";
290 case iday:
291 return "day";
292 case ihour:
293 return "hour";
294 case imin:
295 return "minute";
296 case isec:
297 return "second";
298 case iquarter:
299 return "quarter";
300 case iweek:
301 return "week";
302 case idow:
303 return "dayofweek";
304 case idoy:
305 return "dayofyear";
306 }
307}
308
309int inttype2digits( int sk, int ek )
310{
311 switch(sk) {
312 case iyear:
313 if(ek == iyear)
314 return 1;
315 return 2;
316 case imonth:
317 return 3;
318 case iday:
319 switch(ek) {
320 case iday:
321 return 4;
322 case ihour:
323 return 5;
324 case imin:
325 return 6;
326 default:
327 return 7;
328 }
329 case ihour:
330 switch(ek) {
331 case ihour:
332 return 8;
333 case imin:
334 return 9;
335 default:
336 return 10;
337 }
338 case imin:
339 if(ek == imin)
340 return 11;
341 return 12;
342 case isec:
343 return 13;
344 }
345 return 1;
346}
347
348int digits2sk( int digits)
349{
350 int sk = iyear;
351
352 if (digits > 2)
353 sk = imonth;
354 if (digits > 3)
355 sk = iday;
356 if (digits > 7)
357 sk = ihour;
358 if (digits > 10)
359 sk = imin;
360 if (digits > 12)
361 sk = isec;
362 return sk;
363}
364
365int digits2ek( int digits)
366{
367 int ek = iyear;
368
369 if (digits == 2 || digits == 3)
370 ek = imonth;
371 if (digits == 4)
372 ek = iday;
373 if (digits == 5 || digits == 8)
374 ek = ihour;
375 if (digits == 6 || digits == 9 || digits == 11)
376 ek = imin;
377 if (digits == 7 || digits == 10 || digits == 12 || digits == 13)
378 ek = isec;
379 return ek;
380}
381
382