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 | |
13 | int |
14 | parse_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 | |
47 | lng |
48 | qualifier2multiplier( 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 | |
76 | static int |
77 | parse_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 | |
180 | int |
181 | parse_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 | |
269 | int 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 | |
277 | char * |
278 | datetime_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 | |
309 | int 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 | |
348 | int 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 | |
365 | int 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 | |