CUBRID Engine  latest
db_date.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 /*
20  * db_date.c - Julian date conversion routines and added functions for
21  * handling relative time values.
22  */
23 
24 #ident "$Id$"
25 
26 #include <stdio.h>
27 #include <math.h>
28 #include <time.h>
29 
30 #include "system.h"
31 #include "tz_support.h"
32 #include "db_date.h"
33 
34 #include <assert.h>
35 
36 #include "error_manager.h"
37 #include "chartype.h"
38 #include "tz_support.h"
39 #include "numeric_opfunc.h"
40 #include "object_representation.h"
41 #include "dbtype.h"
42 
43 #if defined (SUPPRESS_STRLEN_WARNING)
44 #define strlen(s1) ((int) strlen(s1))
45 #endif /* defined (SUPPRESS_STRLEN_WARNING) */
46 
47 /* used in conversion to julian */
48 #define IGREG1 (15 + 31L * (10 + 12L * 1582))
49 /* used in conversion from julian */
50 #define IGREG2 2299161 /* 10/15/1582 */
51 /* used in special zero date */
52 #define IGREG_SPECIAL 0 /* 01/01/-4713 DATE || 01/01/1970 00:00:00 TIMESTAMP */
53 
54 #define FLOOR(d1) (int) (d1 + 4000000.0) - 4000000
55 
56 #define YBIAS 1900
57 
58 #define MMDDYYYY 0
59 #define YYYYMMDD 1
60 
61 /* affects DATE/TIME parsing (from string) for mysql compatibility */
62 #define DATETIME_FIELD_LIMIT 1000000
63 
64 typedef struct ampm_buf
65 {
66  char str[10];
67  int len;
68 } AMPM_BUF;
69 
70 /* should be regarded as const */
71 static char local_am_str[10] = "am", local_pm_str[10] = "pm";
72 static int local_am_strlen = 2, local_pm_strlen = 2;
73 
74 static void fill_local_ampm_str (char str[10], bool am);
75 static void decode_time (int timeval, int *hourp, int *minutep, int *secondp);
76 static int encode_time (int hour, int minute, int second);
77 static void decode_mtime (int mtimeval, int *hourp, int *minutep, int *secondp, int *millisecondp);
78 static unsigned int encode_mtime (int hour, int minute, int second, int millisecond);
79 static int init_tm (struct tm *);
80 static int get_current_year (void);
81 static const char *parse_date (const char *buf, int buf_len, DB_DATE * date);
82 static const char *parse_time (const char *buf, int buf_len, DB_TIME * mtime);
83 static const char *parse_mtime (const char *buf, int buf_len, unsigned int *mtime, bool * is_msec, bool * is_explicit);
84 static const char *parse_for_timestamp (const char *buf, int buf_len, DB_DATE * date, DB_TIME * time, bool allow_msec);
85 static const char *parse_datetime (const char *buf, int buf_len, DB_DATETIME * datetime);
86 static char const *parse_date_separated (char const *str, char const *strend, DB_DATE * date, char const **syntax_check,
87  int *year_digits, char *sep_ch);
88 static char const *parse_mtime_separated (char const *str, char const *strend, unsigned int *mtime,
89  char const **syntax_check, int *time_parts, char *sep_ch,
90  bool * has_explicit_msec, bool is_datetime);
91 static char const *parse_explicit_mtime_separated (char const *str, char const *strend, unsigned int *mtime,
92  char const **syntax_check, bool * has_explicit_msec);
93 static char const *parse_explicit_mtime_compact (char const *str, char const *strend, unsigned int *mtime);
94 static char const *parse_timestamp_compact (char const *str, char const *strend, DB_DATE * date, unsigned int *mtime,
95  bool * has_explicit_time, bool * has_explicit_msec);
96 static char const *parse_timedate_separated (char const *str, char const *strend, DB_DATE * date, unsigned int *mtime,
97  char const **syntax_check, bool * has_explicit_msec);
98 static int get_end_of_week_one_of_year (int year, int mode);
99 static bool is_local_am_str (const char *p, const char *p_end);
100 static bool is_local_pm_str (const char *p, const char *p_end);
101 static int db_timestamp_encode_w_reg (const DB_DATE * date, const DB_TIME * timeval, const TZ_REGION * tz_region,
102  DB_TIMESTAMP * utime, TZ_ID * dest_tz_id);
103 
104 /*
105  * julian_encode() - Generic routine for calculating a julian date given
106  * separate month/day/year values.
107  * return : encoded julian date
108  * m(in): month (1 - 12)
109  * d(in): day(1 - 31)
110  * y(in): year
111  */
112 int
113 julian_encode (int m, int d, int y)
114 {
115  int jul;
116  int ja, jy, jm;
117 
118  if (y == 0)
119  {
120  return (0L);
121  }
122 
123  if (m == 1 && d == 1 && y == -4713)
124  {
125  /* used for special meaning (IGREG_SPECIAL) */
126  return (0L);
127  }
128 
129  if (y < 0)
130  {
131  ++y;
132  }
133 
134  if (m > 2)
135  {
136  jy = y;
137  jm = m + 1;
138  }
139  else
140  {
141  jy = y - 1;
142  jm = m + 13;
143  }
144 
145  jul = (int) (FLOOR (365.25 * jy) + FLOOR (30.6001 * jm) + d + 1720995);
146 
147  /*
148  * Test whether to convert to gregorian calander, started Oct 15, 1582
149  */
150  if ((d + 31L * (m + 12L * y)) >= IGREG1)
151  {
152  ja = (int) (0.01 * jy);
153  jul += 2 - ja + (int) (0.25 * ja);
154  }
155 
156  return (jul);
157 }
158 
159 /*
160  * day_of_week() - Returns the day of the week, relative to Sunday, which
161  * this day occurred on.
162  * return :
163  * return value day of the week
164  * ------------ ---------------
165  * 0 Sunday
166  * 1 Monday
167  * 2 Tuesday
168  * 3 Wednesday
169  * 4 Thursday
170  * 5 Friday
171  * 6 Saturday
172  *
173  * jul_day(in): the julian day to reason over
174  */
175 int
176 day_of_week (int jul_day)
177 {
178  if (jul_day == IGREG_SPECIAL)
179  {
180  return IGREG_SPECIAL;
181  }
182  return ((int) ((jul_day + 1) % 7));
183 }
184 
185 /*
186  * julian_decode() - Generic function for decoding a julian date into
187  * interesting pieces.
188  * return : void
189  * jul(in): encoded julian value
190  * monthp(out): pointer to month value
191  * dayp(out): pointer to day value
192  * yearp(out): pointer to year value
193  * weekp(out): pointer to weekday value
194  */
195 void
196 julian_decode (int jul, int *monthp, int *dayp, int *yearp, int *weekp)
197 {
198  int ja, jalpha, jb, jc, jd, je;
199  int day, month, year;
200 
201  if (jul >= IGREG2)
202  {
203  /* correction if Gregorian conversion occurred */
204  jalpha = (int) (((float) (jul - 1867216) - 0.25) / 36524.25);
205  ja = jul + 1 + jalpha - (int) (0.25 * jalpha);
206  }
207  else
208  {
209  ja = jul; /* else no conversion necessary */
210  }
211 
212  if (ja == IGREG_SPECIAL)
213  {
214  month = day = year = 0;
215  }
216  else
217  {
218  jb = ja + 1524;
219  jc = (int) (6680.0 + ((float) (jb - 2439870) - 122.1) / 365.25);
220  jd = (int) (365 * jc + (0.25 * jc));
221  je = (int) ((jb - jd) / 30.6001);
222 
223  day = jb - jd - (int) (30.6001 * je);
224  month = je - 1;
225  if (month > 12)
226  {
227  month -= 12;
228  }
229  year = jc - 4715;
230  if (month > 2)
231  {
232  --year;
233  }
234  if (year <= 0)
235  {
236  --year;
237  }
238  }
239 
240  if (monthp != NULL)
241  {
242  *monthp = month;
243  }
244  if (dayp != NULL)
245  {
246  *dayp = day;
247  }
248  if (yearp != NULL)
249  {
250  *yearp = year;
251  }
252  if (weekp != NULL)
253  {
254  if (jul == IGREG_SPECIAL)
255  {
256  *weekp = 0;
257  }
258  *weekp = (int) ((jul + 1) % 7);
259  }
260 }
261 
262 /*
263  * DB_DATE FUNCTIONS
264  */
265 
266 /*
267  * db_date_encode() -
268  * return : error code
269  * date(out):
270  * month(in): month (1 - 12)
271  * day(in): day (1 - 31)
272  * year(in):
273  */
274 int
275 db_date_encode (DB_DATE * date, int month, int day, int year)
276 {
277  DB_DATE tmp;
278  int tmp_month, tmp_day, tmp_year;
279 
280  if (date == NULL)
281  {
283  return ER_DATE_CONVERSION;
284  }
285 
286  *date = 0;
287  if (year < 0 || year > 9999 || month < 0 || month > 12 || day < 0 || day > 31)
288  {
290  return ER_DATE_CONVERSION;
291  }
292  else
293  {
294  tmp = julian_encode (month, day, year);
295  /*
296  * Now turn around and decode the produced date; if it doesn't
297  * jive with the parameters that came in, someone tried to give
298  * us some bogus data.
299  */
300  julian_decode (tmp, &tmp_month, &tmp_day, &tmp_year, NULL);
301  if (month == tmp_month && day == tmp_day && year == tmp_year)
302  {
303  *date = tmp;
304  }
305  else
306  {
308  return ER_DATE_CONVERSION;
309  }
310  }
311 
312  return NO_ERROR;
313 }
314 
315 /*
316  * db_date_weekday() - Please refer to the day_of_week() function
317  * return : weekday
318  * date(in): pointer to DB_DATE
319  */
320 int
322 {
323  int retval;
324 
325  retval = (day_of_week (*date));
326  return (retval);
327 }
328 
329 /*
330  * db_date_decode() - Decodes a DB_DATE value into interesting sub fields.
331  * return : void
332  * date(in): pointer to DB_DATE
333  * monthp(out): pointer to month
334  * dayp(out): pointer to day
335  * yearp(out): pointer to year
336  */
337 void
338 db_date_decode (const DB_DATE * date, int *monthp, int *dayp, int *yearp)
339 {
340  julian_decode (*date, monthp, dayp, yearp, NULL);
341 }
342 
343 /*
344  * DB_TIME FUNCTIONS
345  */
346 
347 /*
348  * encode_time() -
349  * return : time value
350  * hour(in): hour
351  * minute(in): minute
352  * second(in): second
353  */
354 static int
355 encode_time (int hour, int minute, int second)
356 {
357  return ((((hour * 60) + minute) * 60) + second);
358 }
359 
360 /*
361  * db_time_encode() - Converts hour/minute/second into an encoded relative
362  * time value.
363  * return : error code
364  * timeval(out) : time value
365  * hour(in): hour
366  * minute(in): minute
367  * second(in): second
368  */
369 int
370 db_time_encode (DB_TIME * timeval, int hour, int minute, int second)
371 {
372  if (timeval == NULL)
373  {
375  return ER_TIME_CONVERSION;
376  }
377 
378  if (hour >= 0 && minute >= 0 && second >= 0 && hour < 24 && minute < 60 && second < 60)
379  {
380  *timeval = (((hour * 60) + minute) * 60) + second;
381  }
382  else
383  {
384  *timeval = -1;
386  return ER_TIME_CONVERSION;
387  }
388 
389  return NO_ERROR;
390 }
391 
392 /*
393  * db_time_decode() - Converts encoded time into hour/minute/second values.
394  * return : void
395  * time(in): encoded relative time value
396  * hourp(out): hour pointer
397  * minutep(out) : minute pointer
398  * secondp(out) : second pointer
399  */
400 static void
401 decode_time (int timeval, int *hourp, int *minutep, int *secondp)
402 {
403  int minutes, hours, seconds;
404 
405  seconds = timeval % 60;
406  minutes = (timeval / 60) % 60;
407  hours = (timeval / 3600) % 24;
408 
409  if (hourp != NULL)
410  {
411  *hourp = hours;
412  }
413  if (minutep != NULL)
414  {
415  *minutep = minutes;
416  }
417  if (secondp != NULL)
418  {
419  *secondp = seconds;
420  }
421 }
422 
423 /*
424  * db_time_decode() - Converts encoded time into hour/minute/second values.
425  * return: void
426  * timeval(in) : encoded relative time value
427  * hourp(out) : hour pointer
428  * minutep(out) : minute pointer
429  * secondp(out) : second pointer
430  */
431 void
432 db_time_decode (DB_TIME * timeval, int *hourp, int *minutep, int *secondp)
433 {
434  decode_time (*timeval, hourp, minutep, secondp);
435 }
436 
437 /*
438  * DB_TIMESTAMP FUNCTIONS
439  */
440 
441 /*
442  * tm_encode() - This function is used in conjunction with Unix mktime to
443  * convert julian/time pairs into a universal time constant.
444  * Be careful not to pass pointers to the tm_ structure to the decoding
445  * functions. When these go through the PC int-to-long filter, they
446  * expect long* pointers which isn't what the fields in tm_ are.
447  * return : error code
448  * c_time_struct(out): c time structure from time.h
449  * retval(out): time value (time_t)
450  * date(in) : database date structure
451  * time(in) : database time structure
452  *
453  * Note: This function is kept only for DB Interface (backward compatibility)
454  * Do not use it in CUBRID code since is using libc library. Prefer
455  * db_timestamp_encode... functions.
456  */
457 static int
458 tm_encode (struct tm *c_time_struct, time_t * retval, DB_DATE * date, DB_TIME * timeval)
459 {
460  int mon, day, year, hour, min, sec;
461  struct tm loc;
462 
463  *retval = -1;
464 
465  if (c_time_struct == NULL || ((date == NULL) && (timeval == NULL)) || init_tm (c_time_struct) == -1)
466  {
468  return ER_DATE_CONVERSION;
469  }
470 
471  if (date != NULL)
472  {
473  julian_decode (*date, &mon, &day, &year, NULL);
474  c_time_struct->tm_mon = mon;
475  c_time_struct->tm_mday = day;
476  c_time_struct->tm_year = year;
477 
478  if (c_time_struct->tm_year < 1900)
479  {
481  return ER_DATE_CONVERSION;
482  }
483  c_time_struct->tm_year -= 1900;
484  c_time_struct->tm_mon -= 1;
485  c_time_struct->tm_isdst = -1; /* Don't know if DST applies or not */
486  }
487 
488  if (timeval != NULL)
489  {
490  decode_time (*timeval, &hour, &min, &sec);
491  c_time_struct->tm_hour = hour;
492  c_time_struct->tm_min = min;
493  c_time_struct->tm_sec = sec;
494  }
495 
496  loc = *c_time_struct;
497 
498  /* mktime() on Sun anomalously returns negative values other than -1. */
499  *retval = mktime (&loc);
500  if (*retval < (time_t) 0) /* get correct tm_isdst */
501  {
503  return ER_DATE_CONVERSION;
504  }
505 
506  /* If tm_isdst equals to zero, we do not need to convert the broken-down time (loc) again. */
507  if (loc.tm_isdst == 0)
508  {
509  return NO_ERROR;
510  }
511 
512  c_time_struct->tm_isdst = loc.tm_isdst;
513 
514  *retval = mktime (c_time_struct);
515  if (*retval < (time_t) 0)
516  {
518  return ER_DATE_CONVERSION;
519  }
520 
521  return NO_ERROR;
522 }
523 
524 /*
525  * db_tm_encode() - This function is used in conjunction with Unix mktime to
526  * convert julian/time pairs into a universal time constant.
527  * Be careful not to pass pointers to the tm_ structure to the decoding
528  * functions. When these go through the PC int-to-long filter, they
529  * expect long* pointers which isn't what the fields in tm_ are.
530  * return : error code
531  * c_time_struct(out): c time structure from time.h
532  * date(in) : database date structure
533  * time(in) : database time structure
534  */
535 int
536 db_tm_encode (struct tm *c_time_struct, DB_DATE * date, DB_TIME * timeval)
537 {
538  time_t retval;
539  return tm_encode (c_time_struct, &retval, date, timeval);
540 }
541 
542 /*
543  * db_mktime() - Converts the date and time arguments into the representation
544  * used by time() and returns it.
545  * return : time_t
546  * date(in): database date structure
547  * time(in): database time structure
548  *
549  * note : This obeys the same convention as mktime(), returning a
550  * value of (time_t)-1 if an error occurred. Consult errid()
551  * for the db error code.
552  * Note2: This function is kept only for DB Interface (backward compatibility)
553  * Do not use it in CUBRID code since is using libc library. Prefer
554  * db_timestamp_encode... functions.
555  */
556 time_t
557 db_mktime (DB_DATE * date, DB_TIME * timeval)
558 {
559  time_t retval;
560  struct tm temp;
561 
562  if (tm_encode (&temp, &retval, date, timeval) != NO_ERROR)
563  {
564  return -1;
565  }
566 
567  return (retval);
568 }
569 
570 /*
571  * db_timestamp_encode() - This function is used to construct DB_TIMESTAMP
572  * from DB_DATE and DB_TIME.
573  * return : error code
574  * utime(out): pointer to universal time value
575  * date(in): encoded julian date
576  * time(in): relative time
577  */
578 int
579 db_timestamp_encode (DB_TIMESTAMP * utime, DB_DATE * date, DB_TIME * timeval)
580 {
581  return db_timestamp_encode_ses (date, timeval, utime, NULL);
582 }
583 
584 
585 /*
586  * db_timestamp_encode_ses() - This function is used to construct DB_TIMESTAMP
587  * from DB_DATE and DB_TIME, considering the time and date in session
588  * local timezone
589  * return : error code
590  * date(in): encoded julian date
591  * timeval(in): relative time
592  * utime(out): pointer to universal time value
593  * dest_tz_id(out): pointer to packed timezone identifier of the result
594  * (can be NULL, in which case no identifier is provided)
595  */
596 int
597 db_timestamp_encode_ses (const DB_DATE * date, const DB_TIME * timeval, DB_TIMESTAMP * utime, TZ_ID * dest_tz_id)
598 {
599  TZ_REGION ses_tz_region;
600  tz_get_session_tz_region (&ses_tz_region);
601 
602  return db_timestamp_encode_w_reg (date, timeval, &ses_tz_region, utime, dest_tz_id);
603 }
604 
605 /*
606  * db_timestamp_encode_sys() - This function is used to construct DB_TIMESTAMP
607  * from DB_DATE and DB_TIME, considering the time and date in system timezone
608  *
609  * return : error code
610  * date(in): encoded julian date
611  * timeval(in): relative time
612  * utime(out): pointer to universal time value
613  * dest_tz_id(out): pointer to packed timezone identifier of the result
614  * (can be NULL, in which case no identifier is provided)
615  */
616 int
617 db_timestamp_encode_sys (const DB_DATE * date, const DB_TIME * timeval, DB_TIMESTAMP * utime, TZ_ID * dest_tz_id)
618 {
619  TZ_REGION sys_tz_region;
620  tz_get_system_tz_region (&sys_tz_region);
621 
622  return db_timestamp_encode_w_reg (date, timeval, &sys_tz_region, utime, dest_tz_id);
623 }
624 
625 /*
626  * db_timestamp_encode_utc() - This function is used to construct DB_TIMESTAMP
627  * from DB_DATE and DB_TIME considering the date and
628  * time in UTC
629  * return : error code
630  * date(in): encoded julian date
631  * time(in): relative time
632  * utime(out): pointer to universal time value
633  */
634 int
635 db_timestamp_encode_utc (const DB_DATE * date, const DB_TIME * timeval, DB_TIMESTAMP * utime)
636 {
637  DB_BIGINT t = 0;
638  int mon, day, year, hour, min, sec;
639  const int year_century = 1900;
640  const int year_max_epoch = 2040;
641  const int secs_per_day = 24 * 3600;
642  const int secs_in_a_year = secs_per_day * 365;
643  const int days_up_to_month[] = { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
644 
645  assert (date != NULL && timeval != NULL);
646 
647  if (*date == IGREG_SPECIAL && *timeval == 0)
648  {
649  *utime = IGREG_SPECIAL;
650  return NO_ERROR;
651  }
652 
653  julian_decode (*date, &mon, &day, &year, NULL);
654 
655  year -= year_century;
656  if (year < 70 || year > year_max_epoch - year_century)
657  {
659  return ER_DATE_CONVERSION;
660  }
661 
662  mon -= 1;
663  decode_time (*timeval, &hour, &min, &sec);
664 
665  /* The first item adds the days off all the years between 1970 and the given year considering that each year has 365
666  * days. The second item adds a day every 4 years starting from 1973. The third item subtracts a day back out every
667  * 100 years starting with 2001. The fourth item adds a day back every 400 years starting with 2001 */
668  t = ((year - 70) * secs_in_a_year + ((year - 69) / 4) * secs_per_day - ((year - 1) / 100) * secs_per_day
669  + ((year + 299) / 400) * secs_per_day);
670 
671  if (mon > TZ_MON_JAN)
672  {
673  t += days_up_to_month[mon - 1] * secs_per_day;
674  if (IS_LEAP_YEAR (year_century + year) && mon > TZ_MON_FEB)
675  {
676  t += secs_per_day;
677  }
678  }
679 
680  t += (day - 1) * secs_per_day;
681  t += hour * 3600;
682  t += min * 60;
683  t += sec;
684 
685  t += tz_timestamp_encode_leap_sec_adj (year_century, year, mon, day);
686 
687  if (t < 0 || OR_CHECK_INT_OVERFLOW (t))
688  {
690  return ER_DATE_CONVERSION;
691  }
692  else
693  {
694  *utime = (DB_TIMESTAMP) t;
695  }
696  return NO_ERROR;
697 }
698 
699 /*
700  * db_timestamp_encode_w_reg() - This function is used to construct
701  * DB_TIMESTAMP from DB_DATE and DB_TIME considering the date and time in
702  * timezone tz_region
703  * return : error code
704  * date(in): encoded julian date
705  * time(in): relative time
706  * tz_region(in): timezone region of date and time
707  * utime(out): pointer to universal time value
708  * dest_tz_id(out): pointer to packed timezone identifier of the result
709 * (can be NULL, in which case no identifier is provided)
710  */
711 static int
712 db_timestamp_encode_w_reg (const DB_DATE * date, const DB_TIME * timeval, const TZ_REGION * tz_region,
713  DB_TIMESTAMP * utime, TZ_ID * dest_tz_id)
714 {
715  int err = NO_ERROR;
716  DB_DATETIME datetime, utc_datetime;
717  DB_DATE utc_date;
718  DB_TIME utc_time;
719 
720  if (*date == IGREG_SPECIAL && *timeval == 0)
721  {
722  *utime = IGREG_SPECIAL;
723  return NO_ERROR;
724  }
725 
726  datetime.date = *date;
727  datetime.time = *timeval * 1000;
728 
729  if (!TZ_IS_UTC_TZ_REGION (tz_region))
730  {
731  /* convert datetime from source timezone to UTC */
732  err =
733  tz_conv_tz_datetime_w_region (&datetime, tz_region, tz_get_utc_tz_region (), &utc_datetime, dest_tz_id, NULL);
734  if (err != NO_ERROR)
735  {
736  return err;
737  }
738  }
739  else
740  {
741  utc_datetime = datetime;
742  if (dest_tz_id != NULL)
743  {
744  *dest_tz_id = *tz_get_utc_tz_id ();
745  }
746  }
747 
748  utc_date = utc_datetime.date;
749  utc_time = utc_datetime.time / 1000;
750 
751  return db_timestamp_encode_utc (&utc_date, &utc_time, utime);
752 }
753 
754 /*
755  * db_timestamp_decode_ses() - This function converts a DB_TIMESTAMP into
756  * a DB_DATE and DB_TIME pair, considering the
757  * session local timezone
758  * return : void
759  * time(in): universal time
760  * date(out): return julian date or zero date
761  * time(out): return relative time
762  */
763 int
764 db_timestamp_decode_ses (const DB_TIMESTAMP * utime, DB_DATE * date, DB_TIME * timeval)
765 {
766  TZ_REGION ses_tz_region;
767 
768  tz_get_session_tz_region (&ses_tz_region);
769  return db_timestamp_decode_w_reg (utime, &ses_tz_region, date, timeval);
770 }
771 
772 /*
773  * db_timestamp_decode_utc() - This function converts a DB_TIMESTAMP into
774  * a DB_DATE and DB_TIME pair using UTC time reference
775  * return : void
776  * time(in): universal time
777  * date(out): return julian date or zero date
778  * time(out): return relative time
779  */
780 void
781 db_timestamp_decode_utc (const DB_TIMESTAMP * utime, DB_DATE * date, DB_TIME * timeval)
782 {
783  int timestamp;
784  int year, months, day;
785  int hours, minutes, seconds;
786 
787  assert (utime != NULL);
788 
789  if (*utime == IGREG_SPECIAL)
790  {
791  if (date != NULL)
792  {
793  *date = IGREG_SPECIAL;
794  }
795  if (timeval != NULL)
796  {
797  *timeval = 0;
798  }
799  return;
800  }
801 
802  timestamp = *utime;
803 
804  tz_timestamp_decode_sec (timestamp, &year, &months, &day, &hours, &minutes, &seconds);
805 
806  if (date != NULL)
807  {
808  *date = julian_encode (months + 1, day, year);
809  }
810 
811  if (timeval != NULL)
812  {
813  *timeval = encode_time (hours, minutes, seconds);
814  }
815 }
816 
817 /*
818  * db_timestamp_decode_w_reg() - This function converts a DB_TIMESTAMP into
819  * a DB_DATE and DB_TIME pair, directly into a time zone specified by
820  * tz_region
821  * return : error code
822  * utime(in): universal time
823  * tz_region(in): timezone region of destination date and time
824  * date(out): return julian date or zero date
825  * time(out): return relative time
826  */
827 int
828 db_timestamp_decode_w_reg (const DB_TIMESTAMP * utime, const TZ_REGION * tz_region, DB_DATE * date, DB_TIME * timeval)
829 {
830  int err = NO_ERROR;
831  DB_DATETIME datetime, utc_datetime;
832  DB_DATE tmp_date;
833  DB_TIME tmp_time;
834 
835  db_timestamp_decode_utc (utime, &tmp_date, &tmp_time);
836 
837  if (tmp_date == IGREG_SPECIAL)
838  {
839  if (date != NULL)
840  {
841  *date = IGREG_SPECIAL;
842  }
843  if (timeval != NULL)
844  {
845  *timeval = 0;
846  }
847  return err;
848  }
849 
850  utc_datetime.date = tmp_date;
851  utc_datetime.time = tmp_time * 1000;
852 
853  if (!TZ_IS_UTC_TZ_REGION (tz_region))
854  {
855  /* convert datetime from UTC to destination timezone */
856  err = tz_conv_tz_datetime_w_region (&utc_datetime, tz_get_utc_tz_region (), tz_region, &datetime, NULL, NULL);
857  }
858  else
859  {
860  datetime = utc_datetime;
861  }
862 
863  if (err != NO_ERROR)
864  {
865  /* error condition */
866  if (date != NULL)
867  {
868  *date = 0;
869  }
870  if (timeval != NULL)
871  {
872  *timeval = 0;
873  }
874  }
875  else
876  {
877  if (date != NULL)
878  {
879  *date = datetime.date;
880  }
881 
882  if (timeval != NULL)
883  {
884  *timeval = datetime.time / 1000;
885  }
886  }
887 
888  return err;
889 }
890 
891 /*
892  * db_timestamp_decode_w_tz_id() - This function converts a DB_TIMESTAMP into
893  * a DB_DATE and DB_TIME pair, directly into a time zone specified by
894  * tz_id
895  * return : error code
896  * utime(in): universal time
897  * tz_id(in): timezone id of destination date and time
898  * date(out): return julian date or zero date
899  * time(out): return relative time
900  */
901 int
902 db_timestamp_decode_w_tz_id (const DB_TIMESTAMP * utime, const TZ_ID * tz_id, DB_DATE * date, DB_TIME * timeval)
903 {
904  int err = NO_ERROR;
905  DB_DATETIME datetime, utc_datetime;
906  DB_DATE v_date;
907  DB_TIME v_time;
908 
909  db_timestamp_decode_utc (utime, &v_date, &v_time);
910 
911  if (v_date == IGREG_SPECIAL)
912  {
913  if (date != NULL)
914  {
915  *date = IGREG_SPECIAL;
916  }
917  if (timeval != NULL)
918  {
919  *timeval = 0;
920  }
921  return err;
922  }
923 
924  utc_datetime.date = v_date;
925  utc_datetime.time = v_time * 1000;
926 
927  err = tz_utc_datetimetz_to_local (&utc_datetime, tz_id, &datetime);
928 
929  if (err != NO_ERROR)
930  {
931  /* error condition */
932  if (date != NULL)
933  {
934  *date = 0;
935  }
936  if (timeval != NULL)
937  {
938  *timeval = 0;
939  }
940  }
941  else
942  {
943  if (date != NULL)
944  {
945  *date = datetime.date;
946  }
947 
948  if (timeval != NULL)
949  {
950  *timeval = datetime.time / 1000;
951  }
952  }
953 
954  return err;
955 }
956 
957 /*
958  * UNIX COMPATIBILITY FUNCTIONS
959  */
960 
961 /*
962  * db_strftime() - This is a database interface for the standard C library
963  * routine strftime(). Either date or time can be NULL, depending on the
964  * desired conversion. The format string is the same as used by strftime()
965  * return : error code
966  * s(out): string to print to
967  * smax(in): maximum size of this the string s
968  * fmt(in): format string
969  * date(in): date
970  * time(in): time
971  */
972 int
973 db_strftime (char *s, int smax, const char *fmt, DB_DATE * date, DB_TIME * timeval)
974 {
975  int retval;
976  struct tm date_and_time;
977  int conversion_error;
978 
979  conversion_error = db_tm_encode (&date_and_time, date, timeval);
980  if (conversion_error != NO_ERROR)
981  {
982  return ((int) conversion_error);
983  }
984 
985  retval = ((int) strftime (s, (size_t) smax, fmt, &date_and_time));
986 
987  return (retval);
988 }
989 
990 /*
991  * db_localtime() - Converts the time since epoch (jan 1 1970) into database
992  * date and time structure. date or time can be NULL if conversion to that
993  * structure is not desired.
994  * return : void
995  * epoch_time(in): number of seconds since epoch
996  * date(out): database date structure
997  * timeval(out): database time structure
998  */
999 void
1000 db_localtime (time_t * epoch_time, DB_DATE * date, DB_TIME * timeval)
1001 {
1002  struct tm *temp;
1003  struct tm t;
1004 
1005  temp = localtime_r (epoch_time, &t);
1006  if (temp == NULL)
1007  {
1008  return;
1009  }
1010 
1011  if (date != NULL)
1012  {
1013  *date = julian_encode (temp->tm_mon + 1, temp->tm_mday, temp->tm_year + 1900);
1014  }
1015  if (timeval != NULL)
1016  {
1017  *timeval = encode_time (temp->tm_hour, temp->tm_min, temp->tm_sec);
1018  }
1019 }
1020 
1021 
1022 /*
1023  * db_localdatetime() - Converts the time since epoch (jan 1 1970) into database
1024  * datetime structure.
1025  * return : void
1026  * epoch_time(in): number of seconds since epoch
1027  * datetime(out): database datetime structure
1028  */
1029 void
1030 db_localdatetime (time_t * epoch_time, DB_DATETIME * datetime)
1031 {
1032  db_localdatetime_msec (epoch_time, 0, datetime);
1033 }
1034 
1035 /*
1036  * db_localdatetime_msec() - Converts the time include milliseconds since
1037  * epoch (jan 1 1970) into database datetime structure.
1038  * return : void
1039  * epoch_time(in): number of seconds since epoch
1040  * millisecond(in): part of extra milliseconds
1041  * datetime(out): database datetime structure
1042  */
1043 void
1044 db_localdatetime_msec (time_t * epoch_time, int millisecond, DB_DATETIME * datetime)
1045 {
1046  struct tm *temp;
1047  struct tm t;
1048 
1049  temp = localtime_r (epoch_time, &t);
1050  if (temp == NULL)
1051  {
1052  return;
1053  }
1054 
1055  if (datetime != NULL)
1056  {
1057  db_datetime_encode (datetime, temp->tm_mon + 1, temp->tm_mday, temp->tm_year + 1900, temp->tm_hour, temp->tm_min,
1058  temp->tm_sec, millisecond);
1059  }
1060 }
1061 
1062 /*
1063  * DATE/TIME/TIMESTAMP PARSING FUNCTIONS
1064  */
1065 
1066 /*
1067  * init_tm() - This function uses time() and localtime() to initialize a struct
1068  * tm with the current time.
1069  * return : zero or -1(on error)
1070  * tm(in) : a pointer to a struct tm to be modified.
1071  */
1072 static int
1073 init_tm (struct tm *tm)
1074 {
1075  time_t tloc;
1076  struct tm *tmp;
1077  struct tm t;
1078 
1079  if (time (&tloc) == -1)
1080  {
1081  return -1;
1082  }
1083 
1084  tmp = localtime_r (&tloc, &t);
1085  if (tmp == NULL)
1086  {
1087  return -1;
1088  }
1089 
1090  *tm = *tmp;
1091 
1092  return 0;
1093 }
1094 
1095 /*
1096  * get_current_year() - This function returns current year.
1097  * return : current year or -1(on error)
1098  */
1099 static int
1101 {
1102  struct tm tm;
1103  return (init_tm (&tm) == -1) ? -1 : tm.tm_year + YBIAS;
1104 }
1105 
1106 /*
1107  * parse_date() - Parse an ordinary date string (e.g., '10/15/86').
1108  * Whitespace is permitted between components. If the year is omitted, the
1109  * current year will be discovered and used.
1110  * return : NULL on error
1111  * buf(in): a buffer containing a date to be parsed
1112  * buf_len(in): the length of the string to be parsed
1113  * date(out): a pointer to a DB_DATE to be modified
1114  */
1115 static const char *
1116 parse_date (const char *buf, int buf_len, DB_DATE * date)
1117 {
1118  int part[3] = { 0, 0, 0 };
1119  int part_char_len[3] = { 0, 0, 0 };
1120  int month, day, year;
1121  int julian_date;
1122  unsigned int i;
1123  const char *p;
1124  int date_style = -1;
1125  int year_part, month_part, day_part;
1126  int separator = '\0';
1127  const char *strend = buf + buf_len;
1128 
1129  if (buf == NULL)
1130  {
1131  return NULL;
1132  }
1133 
1134  /* for each date part (year, month, day) */
1135  for (i = 0, p = buf; i < DIM (part); i++)
1136  {
1137  /* skip leading space */
1138  for (; p < strend && char_isspace (*p); ++p)
1139  {
1140  ;
1141  }
1142 
1143  /* read found decimal field value */
1144  for (; p < strend && char_isdigit (*p); ++p)
1145  {
1146  part[i] = part[i] * 10 + (*p - '0');
1147  part_char_len[i]++;
1148  }
1149 
1150  if (i < DIM (part) - 1)
1151  {
1152  /* skip inter-field space */
1153  for (; p < strend && char_isspace (*p); ++p)
1154  {
1155  ;
1156  }
1157 
1158  if (p == strend)
1159  {
1160  break;
1161  }
1162 
1163  /* check date separator ('/' or '-'), if any */
1164  if (separator != '\0' && *p != '\0' && *p != separator)
1165  {
1166  return NULL;
1167  }
1168 
1169  /* find and skip the separator */
1170  if (*p == '/')
1171  {
1172  separator = *p;
1173  ++p;
1174  date_style = MMDDYYYY;
1175  }
1176  else if (*p == '-')
1177  {
1178  separator = *p;
1179  ++p;
1180  date_style = YYYYMMDD;
1181  }
1182  else
1183  {
1184  break;
1185  }
1186  }
1187  }
1188 
1189  /* skip trailing space */
1190  for (; p < strend && char_isspace (*p); ++p)
1191  {
1192  ;
1193  }
1194 
1195  if (date_style == MMDDYYYY)
1196  {
1197  if (i == 1)
1198  {
1199  year_part = -1;
1200  }
1201  else
1202  {
1203  year_part = 2;
1204  }
1205  month_part = 0;
1206  day_part = 1;
1207  }
1208  else if (date_style == YYYYMMDD)
1209  {
1210  if (i == 1)
1211  {
1212  year_part = -1;
1213  month_part = 0;
1214  day_part = 1;
1215  }
1216  else
1217  {
1218  year_part = 0;
1219  month_part = 1;
1220  day_part = 2;
1221  }
1222  }
1223  else
1224  {
1225  return NULL;
1226  }
1227 
1228  /* stop parsing if year is present and over 10000 */
1229  if (0 <= year_part && 10000 <= part[year_part])
1230  {
1231  return NULL;
1232  }
1233 
1234  /* fill the year if not present */
1235  if (year_part == -1)
1236  {
1237  year = get_current_year ();
1238  }
1239  else
1240  {
1241  year = part[year_part];
1242  if (part_char_len[year_part] == 2)
1243  {
1244  if (year < 70)
1245  {
1246  year += 2000;
1247  }
1248  else
1249  {
1250  year += 1900;
1251  }
1252  }
1253  }
1254 
1255  month = part[month_part];
1256  day = part[day_part];
1257 
1258  /*
1259  * 0000-00-00 00:00:00 means timestamp 1970-01-01 00:00:00
1260  * but 0000-00-00 XX:XX:XX (one of X is not zero) means error
1261  * so in this parse_date return OK but set date as 0
1262  * (It should be treated differ with '1970-01-01')
1263  */
1264  if (year == 0 && month == 0 && day == 0)
1265  {
1266  *date = IGREG_SPECIAL;
1267  return p;
1268  }
1269 
1270  /*
1271  * Now encode it and then decode it again and see if we get the same
1272  * day; if not, it was a bogus specification, like 2/29 on a non-leap
1273  * year.
1274  */
1275  julian_date = julian_encode (month, day, year);
1276  julian_decode (julian_date, &part[0], &part[1], &part[2], NULL);
1277 
1278  if (month == part[0] && day == part[1] && year == part[2])
1279  {
1280  *date = julian_date;
1281  return p;
1282  }
1283  else
1284  {
1285  return NULL;
1286  }
1287 
1288 }
1289 
1290 /*
1291  * parse_time() - If parse_time() succeeds, it returns a pointer to the
1292  * rest of the buffer following the parsed time expr. This accepts both
1293  * 12 and 24 hour times, with optional am/pm designators.
1294  * An am designator on a 24 hour time after 12pm is considered an
1295  * error, e.g., "13:45am" will fail.
1296  * Minutes and seconds can be omitted; they will default to 0.
1297  * return : const char or NULL on error
1298  * buf(in): pointer to time expression
1299  * buf_len(in): the length of the string to be parsed
1300  * time(out): pointer to DB_TIME to be updated with the parsed time
1301  */
1302 static const char *
1303 parse_time (const char *buf, int buf_len, DB_TIME * time)
1304 {
1305  unsigned int mtime;
1306  const char *p;
1307  bool is_msec;
1308 
1309  p = parse_mtime (buf, buf_len, &mtime, &is_msec, NULL);
1310 
1311  if (p != NULL)
1312  {
1313  if (is_msec == true)
1314  {
1315  return NULL;
1316  }
1317 
1318  *time = mtime / 1000;
1319  }
1320 
1321  return p;
1322 }
1323 
1324 /*
1325  * db_string_check_explicit_time() -
1326  * return : true if explicit time expression
1327  * str(in): pointer to time expression
1328  * str_len(in): the length of the string to be checked
1329  */
1330 bool
1331 db_string_check_explicit_time (const char *str, int str_len)
1332 {
1333  unsigned int mtime;
1334  bool is_explicit;
1335 
1336  const char *result = parse_mtime (str, str_len, &mtime, NULL, &is_explicit);
1337  if (result == NULL || *result != '\0')
1338  {
1339  return false;
1340  }
1341  return is_explicit;
1342 }
1343 
1344 /*
1345  * parse_mtime() -
1346  * return : const char or NULL on error
1347  * buf(in): pointer to time expression
1348  * buf_len(in): the length of the string to be parsed
1349  * mtime(out): pointer to unsigned int to be updated with the parsed time
1350  */
1351 static const char *
1352 parse_mtime (const char *buf, int buf_len, unsigned int *mtime, bool * is_msec, bool * is_explicit)
1353 {
1354  int part[4] = { 0, 0, 0, 0 };
1355  unsigned int i;
1356  const char *p;
1357  double fraction = 100;
1358  const char *strend = buf + buf_len;
1359 
1360  if (buf == NULL)
1361  {
1362  return NULL;
1363  }
1364 
1365  if (is_msec != NULL)
1366  {
1367  *is_msec = false;
1368  }
1369 
1370  if (is_explicit != NULL)
1371  {
1372  *is_explicit = true;
1373  }
1374 
1375  for (i = 0, p = buf; i < DIM (part); i++)
1376  {
1377  for (; p < strend && char_isspace (*p); ++p)
1378  ;
1379  for (; p < strend && char_isdigit (*p); ++p)
1380  {
1381  if (i != 3)
1382  {
1383  part[i] = part[i] * 10 + (*p - '0');
1384  }
1385  else
1386  {
1387  part[i] += (int) (fraction * (*p - '0') + 0.5);
1388  fraction /= 10;
1389  }
1390  }
1391  if (i < DIM (part) - 1)
1392  {
1393  for (; p < strend && char_isspace (*p); ++p)
1394  ;
1395 
1396  if (p < strend && *p == ':')
1397  {
1398  if (i == 2)
1399  {
1400  return NULL;
1401  }
1402  ++p;
1403  }
1404  else if (p < strend && *p == '.' && i == 2)
1405  {
1406  ++p;
1407  if (is_msec != NULL)
1408  {
1409  *is_msec = true;
1410  }
1411  }
1412  else
1413  {
1414  /* This allows time' ' to be interpreted as 0 which means 12:00:00 AM. */
1415  ++i;
1416 
1417  /* This means time string format is not completed (like 0, 01:00) * This flag will be used by operate
1418  * like [select 1 + '1'] which should not be converted to time */
1419  if (is_explicit != NULL && i < 3)
1420  {
1421  *is_explicit = false;
1422  }
1423 
1424  break;
1425  }
1426  }
1427  }
1428 
1429  for (; p < strend && char_isspace (*p); ++p)
1430  ;
1431  if (is_local_am_str (p, strend) && ((*(p + local_am_strlen) == ' ') || p + local_am_strlen == strend))
1432  {
1433  p += local_am_strlen;
1434  if (part[0] == 12)
1435  {
1436  part[0] = 0;
1437  }
1438  else if (part[0] > 12)
1439  {
1440  part[0] = -1;
1441  }
1442  }
1443  else if (is_local_pm_str (p, strend) && ((*(p + local_pm_strlen) == ' ') || p + local_pm_strlen == strend))
1444  {
1445  p += local_pm_strlen;
1446  if (part[0] < 12)
1447  {
1448  part[0] += 12;
1449  }
1450  else if (part[0] == 0)
1451  {
1452  part[0] = -1;
1453  }
1454  }
1455  else if (i == 0 && *buf)
1456  {
1457  /* buf is "[0-9]*" */
1458  return NULL;
1459  }
1460 
1461  if (part[0] < 0 || part[0] > 23)
1462  {
1463  return NULL;
1464  }
1465  if (part[1] < 0 || part[1] > 59)
1466  {
1467  return NULL;
1468  }
1469  if (part[2] < 0 || part[2] > 59)
1470  {
1471  return NULL;
1472  }
1473  if (part[3] < 0 || part[3] > 999)
1474  {
1475  return NULL;
1476  }
1477 
1478  *mtime = encode_mtime (part[0], part[1], part[2], part[3]);
1479 
1480  return p;
1481 }
1482 
1483 /*
1484  * fill_local_ampm_str() - writes the "am" or "pm" string as by the current
1485  * locale into the given string
1486  * str(out): string buffer to receive the "am" or the "pm" string from the
1487  * current locale
1488  * am(in): true to return the current "am" string, "false" to return the
1489  * current "pm" string from the current locale
1490  */
1491 static void
1492 fill_local_ampm_str (char str[10], bool am)
1493 {
1494  struct tm tm;
1495  if (init_tm (&tm) == -1)
1496  {
1497  if (am)
1498  {
1499  strcpy (str, "am");
1500  }
1501  else
1502  {
1503  strcpy (str, "pm");
1504  }
1505  }
1506  else
1507  {
1508  /*
1509  * Use strftime() to try to find out this locale's idea of
1510  * the am/pm designators.
1511  */
1512  if (am)
1513  {
1514  tm.tm_hour = 0;
1515  strftime (str, 10, "%p", &tm);
1516  }
1517  else
1518  {
1519  tm.tm_hour = 12;
1520  strftime (str, 10, "%p", &tm);
1521  }
1522  }
1523 }
1524 
1525 /*
1526  * db_date_locale_init() - Initializes the am/pm strings from the current
1527  * locale, to be used when parsing TIME values.
1528  * Should be invoked when CUBRID starts up
1529  */
1530 void
1532 {
1535 
1538 }
1539 
1540 /*
1541  * is_local_am_str() - checks if a string is the local "am" string
1542  *
1543  * returns : 0 if matches the local string, non-zero otherwise
1544  * p(in): null terminated string
1545  */
1546 static bool
1547 is_local_am_str (const char *p, const char *p_end)
1548 {
1549  return ((p + local_am_strlen - 1 < p_end) && (intl_mbs_ncasecmp (p, local_am_str, local_am_strlen) == 0));
1550 }
1551 
1552 /*
1553  * is_local_pm_str() - checks if a string is the local "pm" string
1554  *
1555  * returns : 0 if matches the local string, non-zero otherwise
1556  * p(in): null terminated string
1557  */
1558 static bool
1559 is_local_pm_str (const char *p, const char *p_end)
1560 {
1561  return ((p + local_pm_strlen - 1 < p_end) && (intl_mbs_ncasecmp (p, local_pm_str, local_pm_strlen) == 0));
1562 }
1563 
1564 /*
1565  * parse_date_separated() - Reads DATE in '09-10-12' format
1566  *
1567  * returns: position in str where parsing stopped, if successfull,
1568  * NULL otherwise
1569  * str(in): string with the date to be parsed
1570  * strend(in): the end of the string to be parsed
1571  * date(out): resulting date, after parsing, if successfull
1572  * syntax_check(out):
1573  * if not null and conversion fails, will be set to
1574  * the last read character from the input string, when the
1575  * syntax (parsing) was successfull, but resulting
1576  * value is incorrect (for example for 2009-120-21). Should be
1577  * set to NULL before making the function call.
1578  * year_digits(out):
1579  * if not null will receive the number of digits that the year in
1580  * the date string was specified with. The number can be received
1581  * even if conversion fails. If not null it will also turn any
1582  * date part found larger than DATETIME_FIELD_LIMIT into a syntax
1583  * error (as opposed to an invalid, but correctly delimited, date
1584  * value).
1585  * sep_ch(out): separator character that the parsed date is using, or '\0' if
1586  * parsed date uses more than one separator. Can be modified even
1587  * if parsing fails.
1588  */
1589 static char const *
1590 parse_date_separated (char const *str, char const *strend, DB_DATE * date, char const **syntax_check, int *year_digits,
1591  char *sep_ch)
1592 {
1593  DB_DATE cdate;
1594  unsigned char separator = 0; /* 0 - yet to be read 1 - only single slashes read 2 - non-slashes (or multiple
1595  * slashes) read */
1596 
1597  int date_parts[3] = { 0, 0, 0 };
1598  unsigned char date_parts_len[3] = { 0, 0, 0 };
1599  unsigned char parts_found = 0, year_part, month_part, day_part;
1600 
1601  char const *p = str, *q;
1602 
1603  assert (!syntax_check || *syntax_check == NULL);
1604 
1605  /* skip leading spaces in string */
1606  while (p < strend && char_isspace (*p))
1607  {
1608  p++;
1609  }
1610 
1611  if (p == strend || !char_isdigit (*p))
1612  {
1613  return NULL; /* date should begin with a digit */
1614  }
1615 
1616  /* read up to three date parts (year, month, day) from string, separated by non-blank, non-alphanumeric characters */
1617  if (sep_ch)
1618  {
1619  *sep_ch = '0'; /* a digit can not be a separator */
1620  }
1621 
1622  q = p;
1623 
1624  while (p < strend && q == p && !char_isspace (*p) && !char_isalpha (*p) && parts_found < DIM (date_parts))
1625  {
1626  unsigned char new_separator = separator;
1627 
1628  /* read any separator */
1629  while (p < strend && !char_isspace (*p) && !char_isdigit (*p) && !char_isalpha (*p))
1630  {
1631  if (*p == '/')
1632  {
1633  /* '/' separator found */
1634  if (separator == 0)
1635  {
1636  new_separator = 1;
1637  }
1638  }
1639  else
1640  {
1641  /* non-slash separator found */
1642  new_separator = 2;
1643  }
1644 
1645  if (sep_ch)
1646  {
1647  if (*sep_ch)
1648  {
1649  if (*sep_ch == '0')
1650  {
1651  *sep_ch = *p;
1652  }
1653  else
1654  {
1655  if (*sep_ch != *p)
1656  {
1657  /* more than one separator found */
1658  *sep_ch = '\0';
1659  }
1660  }
1661  }
1662  }
1663 
1664  p++;
1665  }
1666 
1667  /* read the number (date part value) */
1668  if (p < strend && char_isdigit (*p))
1669  {
1670  separator = new_separator;
1671 
1672  while (p < strend && char_isdigit (*p))
1673  {
1674  if (date_parts[parts_found] < DATETIME_FIELD_LIMIT)
1675  {
1676  date_parts[parts_found] *= 10;
1677  date_parts[parts_found] += *p - '0';
1678  }
1679 
1680  if (date_parts_len[parts_found] < 4)
1681  {
1682  date_parts_len[parts_found]++;
1683  }
1684 
1685  p++;
1686  }
1687 
1688  if (year_digits && date_parts[parts_found] >= DATETIME_FIELD_LIMIT)
1689  {
1690  /* In a context where the number of digits specified for the year is requested (when reading a time from
1691  * a datetime string), having any date part larger than the field limit is not only an invalid value, but
1692  * also a parsing error. */
1693  return NULL;
1694  }
1695 
1696  parts_found++;
1697  q = p;
1698  }
1699  }
1700 
1701  p = q;
1702 
1703  if (parts_found < 2)
1704  {
1705  /* Insufficient number of year/month/day fields could be read */
1706  return NULL;
1707  }
1708 
1709  /* Infer the order of date fields: MM/DD[/YY] or [YY-]MM-DD */
1710  if (separator == 1)
1711  {
1712  /* mm/dd[/yy] date format */
1713  year_part = 2;
1714  month_part = 0;
1715  day_part = 1;
1716 
1717  }
1718  else
1719  {
1720  /* [yy-]mm-dd format */
1721  year_part = 0;
1722  month_part = 1;
1723  day_part = 2;
1724 
1725  if (parts_found == 2)
1726  {
1727  date_parts[2] = date_parts[1];
1728  date_parts[1] = date_parts[0];
1729  date_parts_len[2] = date_parts_len[1];
1730  date_parts_len[1] = date_parts_len[0];
1731  }
1732  }
1733 
1734  /* Fill in the year or the century, if omitted */
1735  if (parts_found == 2)
1736  {
1737  if (year_digits)
1738  {
1739  *year_digits = 0;
1740  }
1741  date_parts[year_part] = get_current_year ();
1742  }
1743  else
1744  {
1745  if (year_digits)
1746  {
1747  *year_digits = date_parts_len[year_part];
1748  }
1749 
1750  if (date_parts_len[year_part] == 2)
1751  {
1752  if (date_parts[year_part] < 70)
1753  {
1754  date_parts[year_part] += 2000;
1755  }
1756  else
1757  {
1758  date_parts[year_part] += 1900;
1759  }
1760  }
1761  }
1762 
1763  if (date_parts[month_part] == 0 && date_parts[day_part] == 0 && date_parts[year_part] == 0)
1764  {
1765  *date = IGREG_SPECIAL;
1766  return p;
1767  }
1768 
1769  /* Check and return the resulting date */
1770  if (date_parts[year_part] >= 10000 || date_parts[month_part] > 12 || date_parts[month_part] < 1
1771  || date_parts[day_part] > 31 || date_parts[day_part] < 1)
1772  {
1773  /* malformed or invalid date string */
1774  if (syntax_check)
1775  {
1776  /* parsing successfull, but unexpected value */
1777  *syntax_check = p;
1778  }
1779  return NULL;
1780  }
1781  else
1782  {
1783  int year, month, day;
1784 
1785  cdate = julian_encode (date_parts[month_part], date_parts[day_part], date_parts[year_part]);
1786  julian_decode (cdate, &month, &day, &year, NULL);
1787 
1788  if (day == date_parts[day_part] && month == date_parts[month_part] && year == date_parts[year_part])
1789  {
1790  *date = cdate;
1791  return p;
1792  }
1793  else
1794  {
1795  /* parsing successfull, but unexpected value */
1796  if (syntax_check)
1797  {
1798  *syntax_check = p;
1799  }
1800 
1801  return NULL;
1802  }
1803  }
1804 }
1805 
1806 /*
1807  * parse_mtime_separated() - Reads a TIME from a string, reading hours first
1808  * and accepting any separators
1809  * returns: pointer to the next character in the input string that fallows the
1810  * parsed time value if successfull, NULL otherwise
1811  * str(in): string with the time value to be parsed
1812  * strend(in): the end of the string to be parsed
1813  * mtime(out): the converted time
1814  * syntax_check(out): if not null, upon conversion failure it will be filled
1815  * with the pointer to the last character read if the
1816  * time could be parsed but the time value
1817  * found is invalid (like 10:65:24). Should be set to
1818  * NULL before the function invocation
1819  * time_parts(out): if not NULL will receive the number of time components
1820  * (hour, minute, second) found in the string. The number can
1821  * be received even if parsing later fails. If not NULL this
1822  * parameter will also turn any TIME part larger than
1823  * DATETIME_FIELD_LIMIT into a syntax error (as opposed to an
1824  * invalid, but correctly delimited, time value).
1825  * sep_ch(out): if not NULL will receive the separator character used for
1826  * the time, or '\0' if more separators are used.
1827  * has_explicit_msec(out):
1828  * If not NULL and parsing successfull, will receive true if
1829  * the input string explicitly sepcifies a number of
1830  * milliseconds or the decimal point for time
1831  */
1832 static char const *
1833 parse_mtime_separated (char const *str, char const *strend, unsigned int *mtime, char const **syntax_check,
1834  int *time_parts, char *sep_ch, bool * has_explicit_msec, bool is_datetime)
1835 {
1836  int h = 0, m = 0, s = 0, msec = 0;
1837  char const *p = str, *q;
1838 
1839  assert (!syntax_check || !*syntax_check);
1840 
1841  if (sep_ch)
1842  {
1843  *sep_ch = '0'; /* a digit can not be a separator */
1844  }
1845 
1846  if (p == strend || !char_isdigit (*p))
1847  {
1848  /* no time value written in this string */
1849  return NULL;
1850  }
1851 
1852  /* read hours value */
1853  while (p < strend && char_isdigit (*p))
1854  {
1855  if (h < DATETIME_FIELD_LIMIT)
1856  {
1857  h *= 10;
1858  h += *p - '0';
1859  }
1860 
1861  p++;
1862  }
1863 
1864  /* numeric datetime field overflowed and failed parsing */
1865  if (time_parts && h >= DATETIME_FIELD_LIMIT)
1866  {
1867  return NULL;
1868  }
1869 
1870 
1871  /* skip separators */
1872  q = p;
1873  while (p < strend && !char_isspace (*p) && !char_isalpha (*p) && !char_isdigit (*p))
1874  {
1875  if (sep_ch)
1876  {
1877  if (*sep_ch)
1878  {
1879  if (*sep_ch == '0')
1880  {
1881  *sep_ch = *p;
1882  }
1883  else
1884  {
1885  if (*sep_ch != *p)
1886  {
1887  *sep_ch = '\0';
1888  }
1889  }
1890  }
1891  }
1892 
1893  p++;
1894  }
1895 
1896  if (is_datetime && p < strend && char_isspace (*p))
1897  {
1898  *syntax_check = p;
1899  return NULL;
1900  }
1901 
1902  /* read minutes value */
1903  if (p < strend && char_isdigit (*p))
1904  {
1905  while (p < strend && char_isdigit (*p) && DATETIME_FIELD_LIMIT - (*p - '0') / 10 > m)
1906  {
1907  if (m < DATETIME_FIELD_LIMIT)
1908  {
1909  m *= 10;
1910  m += *p - '0';
1911  }
1912 
1913  p++;
1914  }
1915 
1916  if (time_parts && m >= DATETIME_FIELD_LIMIT)
1917  {
1918  return NULL;
1919  }
1920 
1921  /* skip any separators */
1922  q = p;
1923 
1924  while (p < strend && !char_isspace (*p) && !char_isalpha (*p) && !char_isdigit (*p))
1925  {
1926  if (sep_ch)
1927  {
1928  if (*sep_ch)
1929  {
1930  if (*sep_ch == '0')
1931  {
1932  *sep_ch = *p;
1933  }
1934  else
1935  {
1936  if (*sep_ch != *p)
1937  {
1938  *sep_ch = '\0';
1939  }
1940  }
1941  }
1942  }
1943  p++;
1944  }
1945 
1946  if (is_datetime && p < strend && char_isspace (*p))
1947  {
1948  *syntax_check = p;
1949  return NULL;
1950  }
1951 
1952  /* read seconds value */
1953  if (p < strend && char_isdigit (*p))
1954  {
1955  while (p < strend && char_isdigit (*p) && (DATETIME_FIELD_LIMIT - (*p - '0') / 10 > s))
1956  {
1957  if (s < DATETIME_FIELD_LIMIT)
1958  {
1959  s *= 10;
1960  s += *p - '0';
1961  }
1962  p++;
1963  }
1964 
1965  /* numeric datetime field overflowed and failed parsing */
1966  if (time_parts && s >= DATETIME_FIELD_LIMIT)
1967  {
1968  return NULL;
1969  }
1970 
1971 
1972  if (time_parts)
1973  {
1974  *time_parts = 3; /* hh:mm:ss */
1975  }
1976 
1977  /* read milliseconds value */
1978  if (p < strend && *p == '.')
1979  {
1980  p++;
1981  if (p < strend && char_isdigit (*p))
1982  {
1983  msec += (*p - '0') * 100;
1984  p++;
1985 
1986  if (p < strend && char_isdigit (*p))
1987  {
1988  msec += (*p - '0') * 10;
1989  p++;
1990 
1991  if (p < strend && char_isdigit (*p))
1992  {
1993  msec += *p - '0';
1994  p++;
1995 
1996  /* attempting to round, instead of truncate, the number of milliseconds will result in
1997  * userspace problems when '11-02-24 23:59:59.9999' is converted to DATETIME, and then
1998  * '11-02-24' is converted to DATE and '23:59:59:9999' is converted to TIME User might expect
1999  * to get the same results in both cases, when in fact the wrap-around for the time value
2000  * will give different results if the number of milliseconds is rounded. */
2001  while (p < strend && char_isdigit (*p))
2002  {
2003  p++;
2004  }
2005  }
2006  }
2007  }
2008  if (has_explicit_msec)
2009  {
2010  *has_explicit_msec = true;
2011  }
2012  }
2013  }
2014  else
2015  {
2016  /* No seconds present after the minutes and the separator. */
2017 
2018  if (time_parts)
2019  {
2020  *time_parts = 2;
2021  }
2022  }
2023  }
2024  else
2025  {
2026  /* No minutes value present after the hour and separator */
2027 
2028  if (time_parts)
2029  {
2030  if (char_isdigit (*(p - 1)))
2031  {
2032  *time_parts = 1; /* hh */
2033  }
2034  else
2035  {
2036  *time_parts = 2; /* { hh sep } is just like { hh sep mm } */
2037  }
2038  }
2039  }
2040 
2041  /* look for the am/pm string following the time */
2042  q = p; /* save p just in case there is no am/pm string */
2043 
2044  while (p < strend && char_isspace (*p))
2045  {
2046  p++;
2047  }
2048 
2049  /* look for either the local or the English am/pm strings */
2050  if (is_local_am_str (p, strend) && (p + local_am_strlen == strend || !char_isalpha (p[local_am_strlen])))
2051  {
2052  p += local_am_strlen;
2053  if (h == 12)
2054  {
2055  /* 12:01am means 00:01 */
2056  h = 0;
2057  }
2058  }
2059  else if (is_local_pm_str (p, strend) && (p + local_pm_strlen == strend || !char_isalpha (p[local_pm_strlen])))
2060  {
2061  p += local_pm_strlen;
2062  if (h < 12)
2063  {
2064  /* only a 12-hour clock uses the am/pm string */
2065  h += 12;
2066  }
2067  }
2068  else
2069  {
2070  /* no "am"/"pm" string found */
2071  p = q;
2072 
2073  /* check if an incomplete time is followed by a space */
2074  if (time_parts && *time_parts < 3)
2075  {
2076  if (p < strend && char_isspace (*p))
2077  {
2078  /* turn off parsing just the time off the timestamp */
2079  *time_parts = 1;
2080  }
2081  }
2082  }
2083 
2084  /* check the numeric values allowing an hours value of 24, to be treated as 00, would no longer be mysql-compatible,
2085  * since mysql actually stores the value '24', not 00 */
2086  if (h > 23 || m > 59 || s > 59)
2087  {
2088  /* time parsed successfully, but the found value was unexpected */
2089  if (syntax_check)
2090  {
2091  *syntax_check = p;
2092  }
2093  return NULL;
2094  }
2095 
2096  /* encode (from the components) and return the parsed time */
2097  *mtime = encode_mtime (h, m, s, msec);
2098  return p;
2099 }
2100 
2101 /*
2102  * parse_explicit_mtime_separated() - Reads a TIME in '10:22:10.45 am' format.
2103  * Hours (and minutes) field may be omitted,
2104  * but only together with the separator.
2105  * returns: pointer to the next character in the input string that follows
2106  * the parsed time
2107  * str(in): string with the time to be parsed
2108  * strend(in): the end of the string to be parsed
2109  * mtime(out): the converted time
2110  * syntax_check(out):
2111  * if not NULL, upon conversion failure it will be set to
2112  * the pointer in the input string to the last character parsed
2113  * if the time could be parsed but the time value
2114  * found is invalid (like 10:65:24). Should be set to
2115  * false before the function invocation
2116  * has_explicit_msec(out):
2117  * if not NULL and converstion successfull, will receive true if
2118  * the input string explicitly specifies the number of
2119  * milliseconds or the decimal point for time
2120  */
2121 static char const *
2122 parse_explicit_mtime_separated (char const *str, char const *strend, unsigned int *mtime, char const **syntax_check,
2123  bool * has_explicit_msec)
2124 {
2125  int h = 0, m = 0, s = 0, msec = 0, time_parts[3] = { 0, 0, 0 };
2126  unsigned time_parts_found = 0;
2127  char const *p = str, *q;
2128  int msec_digit_order = 100;
2129 
2130  /* skip leading spaces */
2131  while (p < strend && char_isspace (*p))
2132  {
2133  p++;
2134  }
2135 
2136  if (p >= strend)
2137  {
2138  return NULL;
2139  }
2140 
2141  /* read up to 3 time parts (hours, minutes, seconds) from the string */
2142  if (p[0] == ':')
2143  {
2144  /* allow for ':MM:SS.ssss' format */
2145  time_parts_found++;
2146  }
2147 
2148  while (((time_parts_found && p[0] == ':' && (++p < strend && char_isdigit (*p)))
2149  || (!time_parts_found && char_isdigit (p[0]))) && time_parts_found < DIM (time_parts))
2150  {
2151  do
2152  {
2153  time_parts[time_parts_found] *= 10;
2154  time_parts[time_parts_found] += *p - '0';
2155  p++;
2156  }
2157  while (time_parts[time_parts_found] < DATETIME_FIELD_LIMIT && p < strend && char_isdigit (*p));
2158 
2159  if (p < strend && char_isdigit (*p))
2160  {
2161  /* invalid number of seconds/minutes/hours */
2162  return NULL;
2163  }
2164  else
2165  {
2166  time_parts_found++;
2167  }
2168 
2169  if (p >= strend)
2170  {
2171  break;
2172  }
2173  }
2174 
2175  /* Allow trailing ':' separator if time is incomplete */
2176  if (time_parts_found == DIM (time_parts) && *(p - 1) == ':')
2177  {
2178  p--;
2179  }
2180 
2181  if (p < strend && *p == '.')
2182  {
2183  p++;
2184 
2185  while (msec_digit_order && p < strend && char_isdigit (*p))
2186  {
2187  msec += (*p++ - '0') * msec_digit_order;
2188  msec_digit_order /= 10;
2189  }
2190 
2191  /* skip remaining digits in the fractional seconds part, if any trying to round, instead of truncate, the
2192  * milliseconds part can lead to user space problems if wrap-around is needed. */
2193  while (p < strend && char_isdigit (*p))
2194  {
2195  p++;
2196  }
2197 
2198  if (has_explicit_msec)
2199  {
2200  *has_explicit_msec = true;
2201  }
2202  }
2203 
2204  /* infer the hours, minutes and seconds from the number of time parts read */
2205  switch (time_parts_found)
2206  {
2207  case 3:
2208  h = time_parts[0];
2209  m = time_parts[1];
2210  s = time_parts[2];
2211  break;
2212  case 2:
2213  h = time_parts[0];
2214  m = time_parts[1];
2215  break;
2216  case 1:
2217  case 0:
2218  return NULL;
2219  }
2220 
2221  /* skip optional whitespace before the am/pm string following the numeric time value */
2222  q = p; /* save p in case there is no am/pm string */
2223 
2224  while (p < strend && char_isspace (*p))
2225  {
2226  p++;
2227  }
2228 
2229  /* look for either the local or the English am/pm strings */
2230  if (is_local_am_str (p, strend) && (p + local_am_strlen == strend || !char_isalpha (p[local_am_strlen])))
2231  {
2232  p += local_am_strlen;
2233  if (h == 12)
2234  {
2235  h = 0; /* 12:01am means 00:01 */
2236  }
2237  else if (h > 12)
2238  {
2239  if (syntax_check)
2240  {
2241  *syntax_check = p;
2242  }
2243  return NULL;
2244  }
2245  }
2246  else if (is_local_pm_str (p, strend) && (p + local_pm_strlen == strend || !char_isalpha (p[local_pm_strlen])))
2247  {
2248  p += local_pm_strlen;
2249  if (h < 12)
2250  {
2251  /* only a 12-hour clock uses the am/pm string */
2252  h += 12;
2253  }
2254  }
2255  else
2256  {
2257  p = q;
2258  }
2259 
2260  /* check the time parts read */
2261  if (h > 23 || m > 59 || s > 59)
2262  {
2263  if (syntax_check)
2264  {
2265  *syntax_check = p;
2266  }
2267  return NULL;
2268  }
2269 
2270  *mtime = encode_mtime (h, m, s, msec);
2271 
2272  return p;
2273 }
2274 
2275 /*
2276  * parse_explicit_mtime_compact() - Reads a time in
2277  * [[[[YY MM DD] HH] MM] SS[[.][sss]
2278  * format
2279  * '.0' is a valid time that can also be
2280  * written as '.'
2281  * returns: pointer in the input string to the character after
2282  * the converted time, if successfull, or NULL on error
2283  * str(in): the [DATE]TIME string, in compact form, to be converted
2284  * strend(in): the end of the string to be parsed
2285  * mtime(out): pointer to the converted time
2286  *
2287  */
2288 static char const *
2289 parse_explicit_mtime_compact (char const *str, char const *strend, unsigned int *mtime)
2290 {
2291  char const *p = str, *q = str, *r = str;
2292  int y = 0, mo = 0, d = 0, h = 0, m = 0, s = 0, msec = 0;
2293  int ndigits = 0;
2294 
2295  /* skip leading whitespace */
2296  while (p < strend && char_isspace (*p))
2297  {
2298  p++;
2299  }
2300 
2301  /* count number of decimal digits in the string */
2302  q = p;
2303  r = p;
2304 
2305  while (q < strend && char_isdigit (*q))
2306  {
2307  q++;
2308  }
2309 
2310  if (p != q || q[0] == '.')
2311  {
2312  if (q - p > 14)
2313  {
2314  /* YYYY MM DD HH MM SS [.] [ssss..] */
2315  /* if (q[0] != '.') */
2316  {
2317  y = DECODE (p[0]) * 1000 + DECODE (p[1]) * 100 + DECODE (p[2]) * 10 + DECODE (p[3]);
2318  mo = DECODE (p[4]) * 10 + DECODE (p[5]);
2319  d = DECODE (p[6]) * 10 + DECODE (p[7]);
2320  h = DECODE (p[8]) * 10 + DECODE (p[9]);
2321  m = DECODE (p[10]) * 10 + DECODE (p[11]);
2322  s = DECODE (p[12]) * 10 + DECODE (p[13]);
2323 
2324  p += 14;
2325  msec += DECODE (*p++) * 100;
2326  if (p < strend && char_isdigit (*p))
2327  {
2328  msec += DECODE (*p++) * 10;
2329  if (p < strend && char_isdigit (*p))
2330  {
2331  /* reading 3 digits after decimal point is not mysql compatible (which only reads 2 digits) but is
2332  * the expected CUBRID behaviour */
2333  msec += DECODE (*p++);
2334 
2335  /* skil all other digits in the milliseconds field. */
2336  p = q;
2337  }
2338  }
2339  }
2340  }
2341  else
2342  {
2343  switch (q - p)
2344  {
2345  case 14:
2346  /* YYYY-MM-DD HH:MM:SS */
2347  y += DECODE (*p++);
2348  /* FALLTHRU */
2349  case 13:
2350  y *= 10;
2351  y += DECODE (*p++);
2352  /* FALLTHRU */
2353  case 12:
2354  /* YY-MM-DD HH:MM:SS */
2355  y *= 10;
2356  y += DECODE (*p++);
2357  /* FALLTHRU */
2358  case 11:
2359  y *= 10;
2360  y += DECODE (*p++);
2361  /* FALLTHRU */
2362  case 10:
2363  /* MM-DD HH:MM:SS */
2364  mo += DECODE (*p++);
2365  /* FALLTHRU */
2366  case 9:
2367  /* M-DD HH:MM:SS */
2368  mo *= 10;
2369  mo += DECODE (*p++);
2370  d += DECODE (*p++) * 10;
2371  d += DECODE (*p++);
2372  /* FALLTHRU */
2373  case 6:
2374  /* HH:MM:SS */
2375  h += DECODE (*p++);
2376  /* FALLTHRU */
2377  case 5:
2378  /* H:MM:SS */
2379  h *= 10;
2380  h += DECODE (*p++);
2381  /* FALLTHRU */
2382  case 4:
2383  /* MM:SS */
2384  m += DECODE (*p++);
2385  /* FALLTHRU */
2386  case 3:
2387  /* M:SS */
2388  m *= 10;
2389  m += DECODE (*p++);
2390  /* FALLTHRU */
2391  case 2:
2392  /* SS */
2393  s += DECODE (*p++);
2394  /* FALLTHRU */
2395  case 1:
2396  /* S */
2397  s *= 10;
2398  s += DECODE (*p++);
2399  /* FALLTHRU */
2400  case 0:
2401  if (*p == '.')
2402  {
2403  /* read number of milliseconds */
2404 
2405  p++;
2406  if (p < strend && char_isdigit (*p))
2407  {
2408  msec += DECODE (*p++) * 100;
2409  if (p < strend && char_isdigit (*p))
2410  {
2411  msec += DECODE (*p++) * 10;
2412  if (p < strend && char_isdigit (*p))
2413  {
2414  msec += DECODE (*p++);
2415 
2416  while (p < strend && char_isdigit (*p))
2417  {
2418  p++;
2419  }
2420  }
2421  }
2422  }
2423  }
2424  break;
2425  case 7:
2426  /* YY-MM-DD H */
2427  y = DECODE (p[0]) * 10 + DECODE (p[1]);
2428  mo = DECODE (p[2]) * 10 + DECODE (p[3]);
2429  d = DECODE (p[4]) * 10 + DECODE (p[5]);
2430  h = DECODE (p[6]);
2431  p += 7;
2432  break;
2433  default:
2434  /* should not be reached */
2435  case 8:
2436  /* DD HH:MM:SS */
2437  return NULL;
2438  }
2439  }
2440 
2441  /* year, month, day, hour, minute, seconds have been read */
2442  ndigits = CAST_BUFLEN (q - r);
2443  if (ndigits > 6)
2444  {
2445  /* a date precedes the time in the input string */
2446 
2447  DB_DATE cdate;
2448  int year, month, day;
2449 
2450  /* year is also specified in the date */
2451  if ((ndigits == 12) || (ndigits == 7))
2452  {
2453  /* 2-digits year specified, fill in the century */
2454  if (y < 70)
2455  {
2456  y += 2000;
2457  }
2458  else
2459  {
2460  y += 1900;
2461  }
2462  }
2463  else if (ndigits <= 10)
2464  {
2465  /* No year specified with the date, fill in the current year */
2466  y = get_current_year ();
2467  }
2468 
2469  /* check for a valid date preceding the time in the input string */
2470  cdate = julian_encode (mo, d, y);
2471  julian_decode (cdate, &month, &day, &year, NULL);
2472 
2473  if (y != year || mo != month || d != day)
2474  {
2475  /* invalid date specified in front of the time in the input string */
2476  return NULL;
2477  }
2478  }
2479 
2480  /* look for either the local or the English am/pm strings */
2481  /* skip optional whitespace before the am/pm string following the numeric time value */
2482  q = p; /* save p just in case there is no am/pm string */
2483 
2484  while (p < strend && char_isspace (*p))
2485  {
2486  p++;
2487  }
2488 
2489  if (is_local_am_str (p, strend) && (p + local_am_strlen == strend || !char_isalpha (p[local_am_strlen])))
2490  {
2491  p += local_am_strlen;
2492  if (h == 12)
2493  {
2494  h = 0; /* 12:01am means 00:01 */
2495  }
2496  }
2497  else if (is_local_pm_str (p, strend) && (p + local_pm_strlen == strend || !char_isalpha (p[local_pm_strlen])))
2498  {
2499  p += local_pm_strlen;
2500  if (h < 12)
2501  {
2502  /* only a 12-hour clock uses the am/pm string */
2503  h += 12;
2504  }
2505  }
2506  else
2507  {
2508  p = q;
2509  }
2510 
2511  /* check and return the parsed time value */
2512  if (h > 23 || m > 59 || s > 59)
2513  {
2514  return NULL;
2515  }
2516  else
2517  {
2518  *mtime = encode_mtime (h, m, s, msec);
2519  return p;
2520  }
2521  }
2522  else
2523  {
2524  /* No time field nor a decimal point are present */
2525  return NULL;
2526  }
2527 }
2528 
2529 /* parse_timestamp_compact() - Reads a DATETIME in
2530  * [YYYY] MM DD [HH [MM [SS ["."] [msec]]]]
2531  * format
2532  * returns: pointer into the input string pointer to the char after
2533  * the read timestamp, if successfull, or NULL otherwise
2534  * str(in): the input string with the compact timestamp to be
2535  * converted
2536  * strend(in): the end of the string to be parsed
2537  * date(out): the parsed julian date, if successfull
2538  * mtime(out): the parsed time of day (with milliseconds) if successfull
2539  * has_explicit_time(out):
2540  * If not NULL and parsing sucessfull, will receive true if
2541  * the input string explicitly specifies the time part
2542  * has_explicit_msec(out):
2543  * If not NULL and parsing successfull, will receive true if
2544  * the input string explicitly specifies the number of
2545  * milliseconds or the decimal point for time
2546  *
2547  */
2548 static char const *
2549 parse_timestamp_compact (char const *str, char const *strend, DB_DATE * date, unsigned int *mtime,
2550  bool * has_explicit_time, bool * has_explicit_msec)
2551 {
2552  int y = 0, mo = 0, d = 0, h = 0, m = 0, s = 0, msec = 0, ndigits = 0;
2553  char const *p = str, *q = str;
2554 
2555  /* skip leading whitespace */
2556  while (p < strend && char_isspace (*p))
2557  {
2558  p++;
2559  }
2560 
2561  /* cound number of continous digits in the string */
2562  q = p;
2563 
2564  while (q < strend && char_isdigit (*q))
2565  {
2566  q++;
2567  }
2568 
2569  ndigits = CAST_BUFLEN (q - p);
2570 
2571  if (ndigits < 3)
2572  {
2573  /* no, or too few, datetime fields present */
2574  return NULL;
2575  }
2576 
2577  switch (ndigits)
2578  {
2579  case 7:
2580  /* YY MM DD H */
2581  y = DECODE (p[0]) * 10 + DECODE (p[1]);
2582  mo = DECODE (p[2]) * 10 + DECODE (p[3]);
2583  d = DECODE (p[4]) * 10 + DECODE (p[5]);
2584  h = DECODE (p[6]);
2585  p += 7;
2586  break;
2587  case 8:
2588  /* YYYY MM DD */
2589  y += DECODE (*p++);
2590  /* YYY MM DD */
2591  y *= 10;
2592  y += DECODE (*p++);
2593  /* FALLTHRU */
2594  case 6:
2595  /* YY MM DD */
2596  y *= 10;
2597  y += DECODE (*p++);
2598  /* FALLTHRU */
2599  case 5:
2600  /* Y MM DD */
2601  y *= 10;
2602  y += DECODE (*p++);
2603  /* FALLTHRU */
2604  case 4:
2605  /* MM DD */
2606  mo += DECODE (*p++);
2607  /* FALLTHRU */
2608  case 3:
2609  /* M DD */
2610  mo *= 10;
2611  mo += DECODE (*p++);
2612 
2613  d += DECODE (*p++);
2614  d *= 10;
2615  d += DECODE (*p++);
2616 
2617  /* HH:MM:SS remain 00:00:00 */
2618  break;
2619  default:
2620  /* YYYY MM DD HH [MM [SS ["."] [sssss]]] */
2621 
2622  /* read year */
2623  if (ndigits < 14)
2624  {
2625  y = DECODE (p[0]) * 10 + DECODE (p[1]);
2626  if (y < 70)
2627  {
2628  y += 2000;
2629  }
2630  else
2631  {
2632  y += 1900;
2633  }
2634 
2635  p += 2;
2636  }
2637  else
2638  {
2639  y = DECODE (p[0]) * 1000 + DECODE (p[1]) * 100 + DECODE (p[2]) * 10 + DECODE (p[3]);
2640 
2641  p += 4;
2642  }
2643 
2644  /* read month, day, hour, minute */
2645  mo = DECODE (p[0]) * 10 + DECODE (p[1]);
2646  d = DECODE (p[2]) * 10 + DECODE (p[3]);
2647  h = DECODE (p[4]) * 10 + DECODE (p[5]);
2648  p += 6;
2649 
2650  m = DECODE (*p++);
2651  if (p < strend && char_isdigit (*p))
2652  {
2653  m *= 10;
2654  m += DECODE (*p++);
2655 
2656  if (p < strend && char_isdigit (*p))
2657  {
2658  s += DECODE (*p++);
2659 
2660  if (p < strend && char_isdigit (*p))
2661  {
2662  s *= 10;
2663  s += DECODE (*p++);
2664  }
2665 
2666  /* read milliseconds */
2667  if (*p == '.')
2668  {
2669  if (has_explicit_msec)
2670  {
2671  *has_explicit_msec = true;
2672  }
2673  p++;
2674  }
2675 
2676  if (p < strend && char_isdigit (*p))
2677  {
2678  if (has_explicit_msec)
2679  {
2680  *has_explicit_msec = true;
2681  }
2682 
2683  msec += DECODE (*p++) * 100;
2684 
2685  if (p < strend && char_isdigit (*p))
2686  {
2687  msec += DECODE (*p++) * 10;
2688 
2689  if (p < strend && char_isdigit (*p))
2690  {
2691  msec += DECODE (*p);
2692 
2693  /* skip remaining digits */
2694  while (p < strend && char_isdigit (*p))
2695  {
2696  p++;
2697  }
2698  }
2699  }
2700  }
2701  }
2702  }
2703  }
2704 
2705  if (has_explicit_time)
2706  {
2707  *has_explicit_time = (ndigits == 7 || ndigits > 8);
2708  }
2709 
2710  if (ndigits < 5)
2711  {
2712  /* [M]M DD format */
2713  y = get_current_year ();
2714  }
2715  else
2716  {
2717  if (ndigits == 6 || ndigits == 7)
2718  {
2719  /* YY MM DD */
2720  if (y < 70)
2721  {
2722  y += 2000;
2723  }
2724  else
2725  {
2726  y += 1900;
2727  }
2728  }
2729  }
2730 
2731 
2732  /* y, mo, d, h, m, s and msec are now read from string, p is pointing past last digit read */
2733 
2734  if (ndigits > 8 || ndigits == 7)
2735  {
2736  /* the hour or the time-of-day are included in the compact string look for either the local or the English am/pm
2737  * strings */
2738 
2739  /* skip optional whitespace before the am/pm string following the numeric time value */
2740  q = p; /* save p just in case there is no am/pm string */
2741 
2742  while (p < strend && char_isspace (*p))
2743  {
2744  p++;
2745  }
2746 
2747  if (is_local_am_str (p, strend) && (p + local_am_strlen == strend || !char_isalpha (p[local_am_strlen])))
2748  {
2749  p += local_am_strlen;
2750  if (h == 12)
2751  {
2752  h = 0; /* 12:01am means 00:01 */
2753  }
2754  }
2755  else if (is_local_pm_str (p, strend) && (p + local_pm_strlen == strend || !char_isalpha (p[local_pm_strlen])))
2756  {
2757  p += local_pm_strlen;
2758  if (h < 12)
2759  {
2760  /* only a 12-hour clock uses the am/pm string */
2761  h += 12;
2762  }
2763  }
2764  else
2765  {
2766  p = q;
2767  }
2768  }
2769 
2770  /* check and return the date and time read */
2771  if (mo <= 12 && d <= 31 && h <= 23 && m <= 59 && s <= 59)
2772  {
2773  DB_DATE cdate = julian_encode (mo, d, y);
2774  int year, month, day;
2775 
2776  julian_decode (cdate, &month, &day, &year, NULL);
2777 
2778  if (y != year || mo != month || d != day)
2779  {
2780  /* invalid date in the input string */
2781  return NULL;
2782  }
2783 
2784  *date = cdate;
2785  *mtime = encode_mtime (h, m, s, msec);
2786 
2787  return (p == strend ? "" : p);
2788  }
2789  else
2790  {
2791  /* Invalid date or time specified */
2792  return NULL;
2793  }
2794 }
2795 
2796 
2797 /*
2798  * parse_timedate_separated() - Reads a time and a date from a time-date
2799  * string. Note that there is no compact timedate
2800  * possible, only separated timedate strings.
2801  * returns: pointer to the character in str immediately following the
2802  * parsed time and date
2803  * str(in): the time-date string with the time and the date to be
2804  * parsed (read)
2805  * strend(in): the end of the string to be parsed
2806  * date(out): the parsed date from the input string str
2807  * mtime(out): the parsed time from the input string str
2808  * syntax_check(out):
2809  * If not NULL and if parsing was successfull but the found
2810  * value invalid (like '10:80:12 2011-12-18') it will receive
2811  * the pointer to the character in str immediately following
2812  * the parsed time and date.
2813  * has_explicit_msec(out):
2814  * If not NULL and parsing successfull will receive the value
2815  * true if the input string explicitly specifies the number
2816  * of milliseconds for time or specifies the decimal point
2817  * for milliseconds
2818  */
2819 static char const *
2820 parse_timedate_separated (char const *str, char const *strend, DB_DATE * date, unsigned int *mtime, char const **syntax,
2821  bool * has_explicit_msec)
2822 {
2823  char sep_ch = '0';
2824  char const *p = str, *syntax_check = NULL;
2825 
2826  /* attempts to read time in explicit format */
2827  p = parse_explicit_mtime_separated (p, strend, mtime, &syntax_check, has_explicit_msec);
2828 
2829  if (!p && !syntax_check)
2830  {
2831  /* attempt to read time in the relaxed format if explicit format failed */
2832  if (has_explicit_msec)
2833  {
2834  *has_explicit_msec = false;
2835  }
2836 
2837  p = parse_mtime_separated (str, strend, mtime, &syntax_check, NULL, &sep_ch, has_explicit_msec, false);
2838 
2839  if (p || syntax_check)
2840  {
2841  if (sep_ch != '0' && sep_ch != ':')
2842  {
2843  /* the parsed time uses no ':' separator, so fallback to reading a date-time string instead of a
2844  * time-date string */
2845  p = NULL;
2846  syntax_check = NULL;
2847  }
2848  }
2849  }
2850 
2851  if (p || syntax_check)
2852  {
2853  bool space_separator = false;
2854 
2855  if (!syntax_check)
2856  {
2857  syntax_check = p;
2858  }
2859 
2860  while (syntax_check < strend && !char_isalpha (*syntax_check) && !char_isdigit (*syntax_check))
2861  {
2862  if (char_isspace (*syntax_check++))
2863  {
2864  space_separator = true;
2865  }
2866  }
2867 
2868  if (space_separator)
2869  {
2870  char const *q = syntax_check;
2871 
2872  syntax_check = NULL;
2873  sep_ch = '0';
2874 
2875  if (p)
2876  {
2877  p = parse_date_separated (q, strend, date, &syntax_check, NULL, &sep_ch);
2878 
2879  if (p || syntax_check)
2880  {
2881  if (sep_ch == '-' || sep_ch == '/')
2882  {
2883  if (p)
2884  {
2885  /* parsed a time-date string with valid values */
2886  return p;
2887  }
2888  else
2889  {
2890  /* parsed a time-date string, with an invalid date value */
2891  *syntax = syntax_check;
2892  return NULL;
2893  }
2894  }
2895  }
2896  }
2897  else
2898  {
2899  p = parse_date_separated (q, strend, date, &syntax_check, NULL, &sep_ch);
2900 
2901  if ((p || syntax_check) && (sep_ch == '-' || sep_ch == '/'))
2902  {
2903  if (p)
2904  {
2905  *syntax = p;
2906  }
2907  else
2908  {
2909  *syntax = syntax_check;
2910  }
2911 
2912  /* parsed a time-date string, with an invalid time value */
2913  return NULL;
2914  }
2915  }
2916  }
2917  }
2918 
2919  return NULL;
2920 }
2921 
2922 /*
2923  * db_date_parse_time() - Reads a TIME from a time or date-time (or
2924  * time-date) string, in any of the separated
2925  * or compact formats the string is in.
2926  * returns: 0 on success, ER_DATE_CONVERSION on error.
2927  * str(in): the time or date-time string to be converted
2928  * str_len(in): the length of the string to be converted
2929  * time(out): the converted time.
2930  * millisecond(out): the milliseconds part of the converted time
2931  */
2932 int
2933 db_date_parse_time (char const *str, int str_len, DB_TIME * time, int *millisecond)
2934 {
2935  char const *syntax_check = NULL;
2936  int year_digits = 0;
2937  DB_DATE date = 0;
2938  unsigned int mtime = 0;
2939  char sep_ch = '0';
2940  char const *strend = str + str_len;
2941  /* attempt to read a time-date string first */
2942  char const *p = parse_timedate_separated (str, strend, &date, &mtime, &syntax_check,
2943  NULL);
2944 
2945  if (p)
2946  {
2947  *time = mtime / 1000;
2948  *millisecond = mtime % 1000;
2949  return NO_ERROR;
2950  }
2951  else
2952  {
2953  if (syntax_check)
2954  {
2956  return ER_TIME_CONVERSION;
2957  }
2958  else
2959  {
2960  date = 0;
2961  mtime = 0;
2962  }
2963  }
2964 
2965  /* attempt to read a separated DATETIME string after parsing a time-date string failed */
2966 
2967  p = parse_date_separated (str, strend, &date, &syntax_check, &year_digits, &sep_ch);
2968 
2969  if (p || syntax_check)
2970  {
2971  bool space_separator = false;
2972  bool has_explicit_date_part = false;
2973 
2974  /* check whether string has explicit date part */
2975  if (sep_ch == '-' || sep_ch == '/')
2976  {
2977  has_explicit_date_part = true;
2978  }
2979 
2980  if (!syntax_check)
2981  {
2982  syntax_check = p;
2983  }
2984 
2985  while (syntax_check < strend && !char_isalpha (*syntax_check) && !char_isdigit (*syntax_check))
2986  {
2987  if (char_isspace (*syntax_check++))
2988  {
2989  space_separator = true;
2990  }
2991  }
2992 
2993  if (space_separator)
2994  {
2995  if (p)
2996  {
2997  /* Valid date followed by separator */
2998  int time_parts = 0;
2999 
3000  p = syntax_check;
3001  syntax_check = NULL;
3002  p = parse_mtime_separated (p, strend, &mtime, &syntax_check, &time_parts, NULL, NULL, false);
3003 
3004  if (p)
3005  {
3006  while (p < strend && char_isspace (*p))
3007  {
3008  p++;
3009  }
3010 
3011  /* if there is one non-space character in remaining characters */
3012  if (p != strend)
3013  {
3015  return ER_TIME_CONVERSION;
3016  }
3017 
3018  if (year_digits >= 3 || (time_parts >= 2 && year_digits))
3019  {
3020  *time = mtime / 1000;
3021  *millisecond = mtime % 1000;
3022  return NO_ERROR;
3023  }
3024  }
3025  else
3026  {
3027  if (syntax_check)
3028  {
3029  /* date-time string with an invalid time */
3031  return ER_TIME_CONVERSION;
3032  }
3033  else
3034  {
3035  /* no time value found following the date and separator check whether is a Date string with space
3036  * suffix for example,"2012-8-15 " */
3037  if (has_explicit_date_part)
3038  {
3040  return ER_TIME_CONVERSION;
3041  }
3042  }
3043  }
3044  }
3045  else
3046  {
3047  /* Invalid date followed by separator, */
3048  int time_parts = 0;
3049 
3050  p = syntax_check;
3051  syntax_check = NULL;
3052  p = parse_mtime_separated (p, strend, &mtime, &syntax_check, &time_parts, NULL, NULL, false);
3053  if (p || syntax_check)
3054  {
3055  /* date-time string with an invalid date and/or time */
3057  return ER_TIME_CONVERSION;
3058  }
3059  else
3060  {
3061  if (has_explicit_date_part)
3062  {
3064  return ER_TIME_CONVERSION;
3065  }
3066  }
3067  }
3068  }
3069  else
3070  {
3071  if (p && has_explicit_date_part)
3072  {
3073  /* only explicit Date type, should return an error. */
3075  return ER_TIME_CONVERSION;
3076  }
3077  }
3078  }
3079 
3080  /* attempt to read an explicit separated TIME string (a time-only string) */
3081  mtime = 0;
3082  syntax_check = NULL;
3083 
3084  p = parse_explicit_mtime_separated (str, strend, &mtime, &syntax_check, NULL);
3085 
3086  if (p)
3087  {
3088  if (p < strend && p[0] == ' ')
3089  {
3090  while (p < strend && char_isspace (*p))
3091  {
3092  p++;
3093  }
3094 
3095  /* if there is one non-space character in remaining characters */
3096  if (p != strend)
3097  {
3099  return ER_TIME_CONVERSION;
3100  }
3101  }
3102 
3103  *time = mtime / 1000;
3104  *millisecond = mtime % 1000;
3105  return NO_ERROR;
3106  }
3107  else
3108  {
3109  if (syntax_check)
3110  {
3111  /* Time could be parsed as [[HH : ]MM] : SS[.sss], but is an invalid time value */
3113  return ER_TIME_CONVERSION;
3114  }
3115  else
3116  {
3117  /* read a compact TIME string */
3118  p = parse_explicit_mtime_compact (str, strend, &mtime);
3119 
3120  if (p)
3121  {
3122  while (p < strend && char_isspace (*p))
3123  {
3124  p++;
3125  }
3126 
3127  /* if remaining characters includes one non-space character */
3128  if (p != strend)
3129  {
3131  return ER_TIME_CONVERSION;
3132  }
3133 
3134  *time = mtime / 1000;
3135  *millisecond = mtime % 1000;
3136  return NO_ERROR;
3137  }
3138  else
3139  {
3141  return ER_TIME_CONVERSION;
3142  }
3143  }
3144  }
3145 }
3146 
3147 /*
3148  * db_date_parse_datetime_parts() - Reads a DATETIME from a DATE, DATETIME or
3149  * time-date string, in any of the separated or
3150  * compact formats the string might be in.
3151  * returns: 0 on success, ER_DATE_CONVERSION on error.
3152  * str(in): the date or date-time string to be read and converted
3153  * str_len(in): the length of the string to be converted
3154  * datetime(out):
3155  * the read and converted datetime
3156  * is_explicit_time(out):
3157  * If not NULL and parsing successfull will receive true if the
3158  * input string explicitly specifies the time part
3159  * has_explicit_msec(out):
3160  * If not NULL and parsing successfull will receive true if the
3161  * input string explicitly specifies the number of milliseconds
3162  * or the decimal point for the time part
3163  * fits_as_timestamp(out):
3164  * If not NULL and has_explicit_msec is not NULL and parsing
3165  * is successfull will receive true if the value parsed from
3166  * the given input string can be represented exactly as a
3167  * TIMESTAMP value
3168  * endp(out): if the datetime is found to have compact format (110918, as
3169  * opposed to 11-09-18), endp receives the pointer to the end of
3170  * the source string or to the trailing character in the source
3171  * string that was no longer part of the datetime value to be
3172  * read. if given, the pointed value should be NULL before entry
3173  * to the function
3174  */
3175 int
3176 db_date_parse_datetime_parts (char const *str, int str_len, DB_DATETIME * datetime, bool * has_explicit_time,
3177  bool * has_explicit_msec, bool * fits_as_timestamp, char const **endp)
3178 {
3179  DB_DATE date = 0;
3180  unsigned int mtime = 0;
3181  char const *strend = str + str_len;
3182  char const *syntax_check = NULL, *p;
3183 
3184  /* read a separated time-date string first */
3185  p = parse_timedate_separated (str, strend, &date, &mtime, &syntax_check, has_explicit_msec);
3186 
3187  if (p)
3188  {
3189  if (has_explicit_time)
3190  {
3191  *has_explicit_time = true;
3192  }
3193 
3194  if (has_explicit_msec && !*has_explicit_msec && fits_as_timestamp)
3195  {
3196  DB_TIMESTAMP timestamp;
3197  DB_TIME time = mtime / 1000;
3198 
3199  *fits_as_timestamp = db_timestamp_encode_utc (&date, &time, &timestamp);
3200  if (*fits_as_timestamp != NO_ERROR)
3201  {
3202  er_clear ();
3203  }
3204  }
3205 
3206  datetime->date = date;
3207  datetime->time = mtime;
3208 
3209  goto finalcheck;
3210  }
3211  else
3212  {
3213  if (syntax_check)
3214  {
3216  return ER_TIMESTAMP_CONVERSION;
3217  }
3218  }
3219 
3220  /* read a separated DATETIME string */
3221  if (has_explicit_msec)
3222  {
3223  *has_explicit_msec = true;
3224  }
3225 
3226  p = parse_date_separated (str, strend, &datetime->date, &syntax_check, NULL, NULL);
3227  if (p)
3228  {
3229  char const *q, *r;
3230  char sep_ch = '0';
3231 
3232  syntax_check = NULL;
3233 
3234  /* skip the date and time separator from the string */
3235  while (p < strend && !char_isalpha (*p) && !char_isdigit (*p))
3236  {
3237  p++;
3238  }
3239 
3240  /* parse the time portion in the string */
3241  q = parse_mtime_separated (p, strend, &datetime->time, &syntax_check, NULL, &sep_ch, has_explicit_msec, true);
3242  if (q)
3243  {
3244  if (has_explicit_time)
3245  {
3246  r = q;
3247  while (r < strend && ((*r == sep_ch) || (char_isdigit (*r))))
3248  {
3249  r++;
3250  }
3251  if ((r < strend) && (!char_isspace (*r)))
3252  {
3254  return ER_TIMESTAMP_CONVERSION;
3255  }
3256  *has_explicit_time = true;
3257  }
3258 
3259  if (has_explicit_msec && !*has_explicit_msec && fits_as_timestamp)
3260  {
3261  DB_TIMESTAMP timestamp;
3262  DB_TIME time = datetime->time / 1000;
3263 
3264  *fits_as_timestamp = db_timestamp_encode_utc (&datetime->date, &time, &timestamp);
3265  if (*fits_as_timestamp != NO_ERROR)
3266  {
3267  er_clear ();
3268  }
3269  }
3270 
3271  goto finalcheck;
3272  }
3273  else
3274  {
3275  if (syntax_check)
3276  {
3277  /* Invalid time value present in the string */
3279  return ER_TIMESTAMP_CONVERSION;
3280  }
3281  else
3282  {
3283  /* no time value present */
3284  if (has_explicit_time)
3285  {
3286  *has_explicit_time = false;
3287  }
3288 
3289  if (has_explicit_msec)
3290  {
3291  *has_explicit_msec = false;
3292  }
3293 
3294  if (fits_as_timestamp)
3295  {
3296  DB_TIMESTAMP timestamp;
3297  DB_TIME time = 0;
3298 
3299  *fits_as_timestamp = db_timestamp_encode_utc (&datetime->date, &time, &timestamp);
3300  if (*fits_as_timestamp != NO_ERROR)
3301  {
3302  er_clear ();
3303  }
3304  }
3305 
3306  datetime->time = 0;
3307 
3308  goto finalcheck;
3309  }
3310  }
3311  }
3312  else
3313  {
3314  char const *r;
3315 
3316  if (syntax_check)
3317  {
3318  /* try to parse the first date portion as YY MM DD (or more) */
3319  DB_DATETIME cdatetime;
3320 
3321  while (str < strend && char_isspace (*str))
3322  {
3323  str++;
3324  }
3325 
3326  r =
3327  parse_timestamp_compact (str, strend, &cdatetime.date, &cdatetime.time, has_explicit_time,
3328  has_explicit_msec);
3329 
3330  /* mysql prefers a large value here like 14, and returns NULL otherwise */
3331  if (r && (*r == 0 || (*r && (r - str >= 6))))
3332  {
3333  if (has_explicit_msec && !*has_explicit_msec && fits_as_timestamp)
3334  {
3335  DB_TIMESTAMP timestamp;
3336  DB_TIME time = cdatetime.time / 1000;
3337 
3338  *fits_as_timestamp = db_timestamp_encode_utc (&cdatetime.date, &time, &timestamp);
3339  if (*fits_as_timestamp != NO_ERROR)
3340  {
3341  er_clear ();
3342  }
3343  }
3344 
3345  if (endp)
3346  {
3347  *endp = r;
3348  }
3349  *datetime = cdatetime;
3350 
3351  goto finalcheck;
3352  }
3353  else
3354  {
3355  /* invalid date value present in the string */
3357  return ER_TIMESTAMP_CONVERSION;
3358  }
3359  }
3360  else
3361  {
3362  /* read a compact DATETIME string */
3363  r =
3364  parse_timestamp_compact (str, strend, &datetime->date, &datetime->time, has_explicit_time,
3365  has_explicit_msec);
3366 
3367  if (r)
3368  {
3369  if (has_explicit_msec && !*has_explicit_msec && fits_as_timestamp)
3370  {
3371  DB_TIMESTAMP timestamp;
3372  DB_TIME time = datetime->time / 1000;
3373 
3374  *fits_as_timestamp = db_timestamp_encode_utc (&datetime->date, &time, &timestamp);
3375  if (*fits_as_timestamp != NO_ERROR)
3376  {
3377  er_clear ();
3378  }
3379  }
3380 
3381  if (endp)
3382  {
3383  *endp = r;
3384  }
3385 
3386  goto finalcheck;
3387  }
3388  else
3389  {
3391  return ER_TIMESTAMP_CONVERSION;
3392  }
3393  }
3394  }
3395 
3397  return ER_TIMESTAMP_CONVERSION;
3398 
3399 finalcheck:
3400  if (datetime->date == IGREG_SPECIAL)
3401  {
3402  if (datetime->time != 0)
3403  {
3405  return ER_TIMESTAMP_CONVERSION;
3406  }
3407  }
3408 
3409  return NO_ERROR;
3410 }
3411 
3412 /*
3413  * db_date_parse_datetime() - Reads a DATETIME from a DATE or DATETIME string, in any
3414  * of the separated or compact formats the string
3415  * might be in.
3416  * returns: 0 on success, ER_DATE_CONVERSION on error.
3417  * str(in): the date or date-time string to be read and converted
3418  * str_len(in): the length of the string to be converted
3419  * datetime(out):
3420  * the read and converted datetime
3421  */
3422 int
3423 db_date_parse_datetime (char const *str, int str_len, DB_DATETIME * datetime)
3424 {
3425  return db_date_parse_datetime_parts (str, str_len, datetime, NULL, NULL, NULL, NULL);
3426 }
3427 
3428 /*
3429  * db_date_parse_timestamp() - Reads a TIMESTAMP from a DATE or DATETIME
3430  * string, in any of the separated or compact formats
3431  * the string might be in.
3432  * returns: 0 on success, ER_DATE_CONVERSION on error.
3433  * str(in): the date string or datetime string to be read and converted
3434  * str_len(in): the length of the string to be converted
3435  * utime(out): the converted timestamp read from string
3436  */
3437 int
3438 db_date_parse_timestamp (char const *str, int str_len, DB_TIMESTAMP * utime)
3439 {
3440  DB_DATETIME datetime;
3441  DB_TIME time;
3442  int err;
3443 
3444  err = db_date_parse_datetime (str, str_len, &datetime);
3445  if (err == NO_ERROR)
3446  {
3447  if (datetime.date == IGREG_SPECIAL && datetime.time == 0)
3448  {
3449  *utime = IGREG_SPECIAL;
3450  return NO_ERROR;
3451  }
3452 
3453  time = datetime.time / 1000;
3454  if (db_timestamp_encode_ses (&datetime.date, &time, utime, NULL) == NO_ERROR)
3455  {
3456  return NO_ERROR;
3457  }
3458  else
3459  {
3460  er_clear ();
3462  return ER_TIMESTAMP_CONVERSION;
3463  }
3464  }
3465 
3466  er_clear ();
3468  return ER_TIMESTAMP_CONVERSION;
3469 }
3470 
3471 /*
3472  * db_date_parse_date() - Reads a DATE from a DATE string or a DATETIME
3473  * string, in any of the separated or compact formats
3474  * the string might be in.
3475  * returns: 0 on success, ER_DATE_CONVERSION on error.
3476  * str(in): the date or datetime string to be read and converted
3477  * str_len(in): the length of the string to be converted
3478  * date(out): the read and converted date
3479  */
3480 int
3481 db_date_parse_date (char const *str, int str_len, DB_DATE * date)
3482 {
3483  DB_DATETIME datetime = { 0, 0 };
3484  int err;
3485 
3486  err = db_date_parse_datetime (str, str_len, &datetime);
3487  if (err == NO_ERROR)
3488  {
3489  *date = datetime.date;
3490  }
3491  else
3492  {
3493  er_clear ();
3495  err = ER_DATE_CONVERSION;
3496  }
3497 
3498  return err;
3499 }
3500 
3501 /*
3502  * parse_for_timestamp() - Tries to parse a timestamp by finding a date and a
3503  * time, in order.
3504  * Returns: const char or NULL on error
3505  * buf(in): pointer to a date-time expression
3506  * buf_len(in): the length of the string to be parsed
3507  * date(out): pointer to a DB_DATE
3508  * time(out): pointer to a DB_TIME
3509  * allow_msec(in): tells if milliseconds format is allowed
3510  */
3511 static const char *
3512 parse_for_timestamp (const char *buf, int buf_len, DB_DATE * date, DB_TIME * time, bool allow_msec)
3513 {
3514  const char *p;
3515 
3516  /* First try to parse a date followed by a time. */
3517  p = parse_date (buf, buf_len, date);
3518  if (p)
3519  {
3520  if (allow_msec)
3521  {
3522  p = parse_mtime (p, buf_len - CAST_BUFLEN (p - buf), time, NULL, NULL);
3523  *time /= 1000;
3524  }
3525  else
3526  {
3527  p = parse_time (p, buf_len - CAST_BUFLEN (p - buf), time);
3528  }
3529  if (p)
3530  {
3531  goto finalcheck;
3532  }
3533  }
3534 
3535  /* If that fails, try to parse a time followed by a date. */
3536  if (allow_msec)
3537  {
3538  p = parse_mtime (buf, buf_len, time, NULL, NULL);
3539  *time /= 1000;
3540  }
3541  else
3542  {
3543  p = parse_time (buf, buf_len, time);
3544  }
3545 
3546  if (p)
3547  {
3548  p = parse_date (p, buf_len - CAST_BUFLEN (p - buf), date);
3549  if (p)
3550  {
3551  goto finalcheck;
3552  }
3553  }
3554 
3555  return NULL;
3556 
3557 finalcheck:
3558  if (*date == IGREG_SPECIAL)
3559  {
3560  if (*time != 0)
3561  {
3562  return NULL;
3563  }
3564  }
3565 
3566  return p;
3567 }
3568 
3569 /*
3570  * parse_datetime() -
3571  * Returns: const char or NULL on error
3572  * buf(in): pointer to a date-time expression
3573  * buf_len(in): the length of the string to be parsed
3574  * datetime(out): pointer to a DB_DATETIME to be modified
3575  */
3576 static const char *
3577 parse_datetime (const char *buf, int buf_len, DB_DATETIME * datetime)
3578 {
3579  DB_DATE date = 0;
3580  unsigned int mtime;
3581  const char *p;
3582 
3583  /* First try to parse a date followed by a time. */
3584  p = parse_date (buf, buf_len, &date);
3585  if (p)
3586  {
3587  p = parse_mtime (p, buf_len - CAST_BUFLEN (p - buf), &mtime, NULL, NULL);
3588  if (p)
3589  {
3590  goto finalcheck;
3591  }
3592  }
3593 
3594  p = parse_mtime (buf, buf_len, &mtime, NULL, NULL);
3595  if (p)
3596  {
3597  p = parse_date (p, buf_len - CAST_BUFLEN (p - buf), &date);
3598  if (p)
3599  {
3600  goto finalcheck;
3601  }
3602  }
3603 
3604  return NULL;
3605 
3606 finalcheck:
3607  if (date == IGREG_SPECIAL)
3608  {
3609  if (mtime != 0)
3610  {
3611  return NULL;
3612  }
3613  }
3614 
3615  datetime->date = date;
3616  datetime->time = mtime;
3617 
3618  return p;
3619 }
3620 
3621 /*
3622  * db_string_check_explicit_date() - check if a string is formated as a date
3623  * return : true if str is formated exactly as a date
3624  * (not a datetime or a timestamp)
3625  * str(in): the string to be checked
3626  * str_len(in): the length of the string to be parsed
3627  */
3628 bool
3629 db_string_check_explicit_date (const char *str, int str_len)
3630 {
3631  DB_DATE date;
3632  const char *result = NULL;
3633 
3634  result = parse_date (str, str_len, &date);
3635  if (result)
3636  {
3637  while (char_isspace (result[0]))
3638  {
3639  result++;
3640  }
3641  }
3642  if (result == NULL || result[0] != '\0')
3643  {
3644  return false;
3645  }
3646 
3647  return true;
3648 }
3649 
3650 /*
3651  * db_string_to_date_ex() - Parse an ordinary date string (e.g., '10/15/86').
3652  * Whitespace is not permitted between slashed components. If the year is
3653  * omitted, the current year is assumed. Dates are currently accepted
3654  * only in the slashified US style.
3655  * returns: 0 on success, ER_DATE_CONVERSION on error
3656  * str(in): a buffer containing a date to be parsed
3657  * str_len(in): the length of the string to be parsed
3658  * date(out): a pointer to a DB_DATE to be modified
3659  */
3660 int
3661 db_string_to_date_ex (const char *str, int str_len, DB_DATE * date)
3662 {
3663  const char *p;
3664  const char *p_end = str + str_len;
3665 
3666  p = parse_date (str, str_len, date);
3667  if (p != NULL)
3668  {
3669  while (p < p_end && char_isspace (p[0]))
3670  {
3671  p++;
3672  }
3673  }
3674  if (p == NULL || (p < p_end && p[0] != '\0'))
3675  {
3677  return ER_DATE_CONVERSION;
3678  }
3679 
3680  return NO_ERROR;
3681 }
3682 
3683 /*
3684  * db_string_to_date() - Parse an ordinary date string (e.g., '10/15/86').
3685  * Whitespace is not permitted between slashed components. If the year is
3686  * omitted, the current year is assumed. Dates are currently accepted
3687  * only in the slashified US style.
3688  * returns: 0 on success, ER_DATE_CONVERSION on error
3689  * str(in): a buffer containing a date to be parsed
3690  * date(out): a pointer to a DB_DATE to be modified
3691  */
3692 int
3693 db_string_to_date (const char *str, DB_DATE * date)
3694 {
3695  return db_string_to_date_ex (str, strlen (str), date);
3696 }
3697 
3698 /*
3699  * db_string_to_time_ex() - Parse an ordinary time string (e.g., '3:30am').
3700  * Whitespace is not permitted between numeric components, it is permitted
3701  * between the last number and the optional am/pm designator.
3702  * return : 0 on success, ER_DATE_CONVERSION on error.
3703  * str(in): a buffer containing a date to be parsed
3704  * str_len(in): the length of the string to be parsed
3705  * time(out): a pointer to a DB_TIME to be modified
3706  */
3707 int
3708 db_string_to_time_ex (const char *str, int str_len, DB_TIME * time)
3709 {
3710  const char *p;
3711  const char *p_end = str + str_len;
3712 
3713  p = parse_time (str, str_len, time);
3714  if (p != NULL)
3715  {
3716  while (p < p_end && char_isspace (p[0]))
3717  {
3718  p++;
3719  }
3720  }
3721  if (p == NULL || (p < p_end && p[0] != '\0'))
3722  {
3724  return ER_DATE_CONVERSION;
3725  }
3726 
3727  return NO_ERROR;
3728 }
3729 
3730 /*
3731  * db_string_to_time() - Parse an ordinary time string (e.g., '3:30am').
3732  * Whitespace is not permitted between numeric components, it is permitted
3733  * between the last number and the optional am/pm designator.
3734  * return : 0 on success, ER_DATE_CONVERSION on error.
3735  * str(in): a buffer containing a date to be parsed
3736  * time(out): a pointer to a DB_TIME to be modified
3737  */
3738 int
3739 db_string_to_time (const char *str, DB_TIME * time)
3740 {
3741  return db_string_to_time_ex (str, strlen (str), time);
3742 }
3743 
3744 /*
3745  * db_string_to_timestamp_ex() - Parse a date and time string into a utime.
3746  * The time and date are parsed according to the same rules as
3747  * db_string_to_time() and db_string_to_date().
3748  * they may appear in either order.
3749  * return : 0 on success, -1 on error.
3750  * str(in): a buffer containing a date to be parsed
3751  * str_len(in): the length of the string to be parsed
3752  * utime(out): a pointer to a DB_TIMESTAMP to be modified
3753  */
3754 int
3755 db_string_to_timestamp_ex (const char *str, int str_len, DB_TIMESTAMP * utime)
3756 {
3757  DB_DATE date;
3758  DB_TIME time;
3759  int err = NO_ERROR;
3760  const char *p, *p_end;
3761  TZ_ID dummy_tz_id;
3762 
3763  p_end = str + str_len;
3764  p = parse_for_timestamp (str, str_len, &date, &time, false);
3765  if (p != NULL)
3766  {
3767  while (p < p_end && char_isspace (p[0]))
3768  {
3769  p++;
3770  }
3771  }
3772  if (p == NULL || (p < p_end && p[0] != '\0'))
3773  {
3774  goto error_exit;
3775  }
3776 
3777  /* 0000-00-00 00:00:00 treated as time_t 0 */
3778  if (date == IGREG_SPECIAL)
3779  {
3780  *utime = IGREG_SPECIAL;
3781  return err;
3782  }
3783 
3784  err = db_timestamp_encode_ses (&date, &time, utime, &dummy_tz_id);
3785  return err;
3786 
3787 error_exit:
3789  return ER_DATE_CONVERSION;
3790 }
3791 
3792 /*
3793  * db_string_to_timestamp() - Parse a date and time string into a utime.
3794  * The time and date are parsed according to the same rules as
3795  * db_string_to_time() and db_string_to_date().
3796  * they may appear in either order.
3797  * return : 0 on success, -1 on error.
3798  * str(in): a buffer containing a date to be parsed
3799  * utime(out): a pointer to a DB_TIMESTAMP to be modified
3800  */
3801 int
3803 {
3804  return db_string_to_timestamp_ex (str, strlen (str), utime);
3805 }
3806 
3807 /*
3808  * db_string_to_timestamptz_ex() - Parse a date and time with time zone info
3809  * into a timestamp with TZ
3810 
3811  * return : 0 on success, -1 on error.
3812  * str(in): a buffer containing a date to be parsed
3813  * str_len(in): the length of the string to be parsed
3814  * ts_tz(out): a pointer to a DB_TIMESTAMPTZ to be modified
3815  * has_zone(out): true if string had valid zone information to decode, false
3816  * otherwise
3817  * is_cast(in): true if the function is called in a casting context
3818  */
3819 int
3820 db_string_to_timestamptz_ex (const char *str, int str_len, DB_TIMESTAMPTZ * ts_tz, bool * has_zone, bool is_cast)
3821 {
3822  DB_DATE date;
3823  DB_TIME time;
3824  int err = NO_ERROR;
3825  int str_zone_size = 0;
3826  const char *p, *p_end, *str_zone;
3827  TZ_REGION session_tz_region;
3828 
3829  str_zone = NULL;
3830  p_end = str + str_len;
3831  *has_zone = false;
3832 
3833  tz_get_session_tz_region (&session_tz_region);
3834  ts_tz->tz_id = 0;
3835 
3836  p = parse_for_timestamp (str, str_len, &date, &time, is_cast);
3837 
3838  if (p == NULL)
3839  {
3840  goto error_exit;
3841  }
3842 
3843  assert (p != NULL);
3844  while (p < p_end && char_isspace (p[0]))
3845  {
3846  p++;
3847  }
3848 
3849  if (p < p_end)
3850  {
3851  *has_zone = true;
3852  str_zone = p;
3853  str_zone_size = CAST_BUFLEN (p_end - str_zone);
3854  }
3855 
3856  err = tz_create_timestamptz (&date, &time, str_zone, str_zone_size, &session_tz_region, ts_tz, &p);
3857  if (err != NO_ERROR || str_zone == NULL)
3858  {
3859  /* error or no timezone in user string (no trailing chars to check) */
3860  return err;
3861  }
3862 
3863  if (p != NULL)
3864  {
3865  while (p < p_end && char_isspace (p[0]))
3866  {
3867  p++;
3868  }
3869  }
3870 
3871  if (p == NULL || (p < p_end && p[0] != '\0'))
3872  {
3873  goto error_exit;
3874  }
3875 
3876  return err;
3877 
3878 error_exit:
3880  return ER_DATE_CONVERSION;
3881 }
3882 
3883 /*
3884  * db_string_to_timestamptz() - Parse a date and time with time zone info into
3885  * a timestamp with TZ
3886 
3887  * return : 0 on success, -1 on error.
3888  * str(in): a buffer containing a date to be parsed
3889  * ts_tz(out): a pointer to a DB_TIMESTAMPTZ to be modified
3890  * has_zone(out): true if string had valid zone information to decode, false
3891  * otherwise
3892  */
3893 int
3894 db_string_to_timestamptz (const char *str, DB_TIMESTAMPTZ * ts_tz, bool * has_zone)
3895 {
3896  return db_string_to_timestamptz_ex (str, strlen (str), ts_tz, has_zone, false);
3897 }
3898 
3899 /*
3900  * db_string_to_timestampltz_ex() - Parse a date and time into a timestamp
3901  * with local timezone
3902  * return : 0 on success, -1 on error.
3903  * str(in): a buffer containing a date to be parsed
3904  * str_len(in): the length of the string to be parsed
3905  * ts(out): a pointer to a DB_TIMESTAMP to be modified
3906  */
3907 int
3908 db_string_to_timestampltz_ex (const char *str, int str_len, DB_TIMESTAMP * ts)
3909 {
3910  int error = NO_ERROR;
3911  DB_TIMESTAMPTZ ts_tz;
3912  bool dummy_has_zone;
3913 
3914  error = db_string_to_timestamptz_ex (str, str_len, &ts_tz, &dummy_has_zone, false);
3915  if (error != NO_ERROR)
3916  {
3918  return ER_DATE_CONVERSION;
3919  }
3920 
3921  *ts = ts_tz.timestamp;
3922 
3923  return error;
3924 }
3925 
3926 /*
3927  * db_string_to_timestampltz() - Parse a date and time into a timestamp with
3928  * local timezone
3929 
3930  * return : 0 on success, -1 on error.
3931  * str(in): a buffer containing a date to be parsed
3932  * str_len(in): the length of the string to be parsed
3933  * ts(out): a pointer to a DB_TIMESTAMP to be modified
3934  */
3935 int
3937 {
3938  return db_string_to_timestampltz_ex (str, strlen (str), ts);
3939 }
3940 
3941 /*
3942  * db_date_to_string() - Print a DB_DATE into a char buffer using strftime().
3943  * return : the number of characters actually printed.
3944  * buf(out): a buffer to receive the printed representation
3945  * bufsize(in): the size of that buffer
3946  * date(in): a pointer to a DB_DATE to be printed
3947  *
3948  * note: The format string MUST contain a %d in WINDOWS. Keep this file
3949  * from passing through the %ld filter.
3950  * Do note pass pointers to the tm structure to db_date_decode.
3951  */
3952 int
3953 db_date_to_string (char *buf, int bufsize, DB_DATE * date)
3954 {
3955  int mon, day, year;
3956  const int len_out = 10;
3957  int cnt = 0;
3958 
3959  if (buf == NULL || bufsize == 0)
3960  {
3961  return 0;
3962  }
3963  if (bufsize <= len_out)
3964  {
3965  return 0;
3966  }
3967 
3968  db_date_decode (date, &mon, &day, &year);
3969  buf[cnt++] = mon / 10 + '0';
3970  buf[cnt++] = mon % 10 + '0';
3971  buf[cnt++] = '/';
3972  buf[cnt++] = day / 10 + '0';
3973  buf[cnt++] = day % 10 + '0';
3974  buf[cnt++] = '/';
3975  buf[cnt++] = year / 1000 + '0';
3976  buf[cnt++] = (year / 100) % 10 + '0';
3977  buf[cnt++] = (year / 10) % 10 + '0';
3978  buf[cnt++] = year % 10 + '0';
3979  buf[cnt] = '\0';
3980 
3981  return cnt;
3982 }
3983 
3984 /*
3985  * db_time_to_string() - Print a DB_TIME into a char buffer using strftime().
3986  * return : the number of characters actually printed.
3987  * buf(out): a buffer to receive the printed representation
3988  * bufsize(in): the size of that buffer
3989  * time(in): a pointer to a DB_TIME to be printed
3990  *
3991  * note : DO NOT pass pointers to the tm structure to db_time_decode.
3992  */
3993 int
3994 db_time_to_string (char *buf, int bufsize, DB_TIME * time)
3995 {
3996  int hour, min, sec;
3997  bool pm;
3998  int cnt = 0;
3999  const int len_out = 11;
4000 
4001  if (buf == NULL || bufsize == 0)
4002  {
4003  return 0;
4004  }
4005  if (bufsize <= len_out)
4006  {
4007  return 0;
4008  }
4009 
4010  db_time_decode (time, &hour, &min, &sec);
4011  pm = (hour >= 12) ? true : false;
4012  if (hour == 0)
4013  {
4014  hour = 12;
4015  }
4016  else if (hour > 12)
4017  {
4018  hour -= 12;
4019  }
4020 
4021  buf[cnt++] = hour / 10 + '0';
4022  buf[cnt++] = hour % 10 + '0';
4023  buf[cnt++] = ':';
4024  buf[cnt++] = min / 10 + '0';
4025  buf[cnt++] = min % 10 + '0';
4026  buf[cnt++] = ':';
4027  buf[cnt++] = sec / 10 + '0';
4028  buf[cnt++] = sec % 10 + '0';
4029  buf[cnt++] = ' ';
4030  if (pm)
4031  {
4032  buf[cnt++] = 'P';
4033  buf[cnt++] = 'M';
4034  }
4035  else
4036  {
4037  buf[cnt++] = 'A';
4038  buf[cnt++] = 'M';
4039  }
4040  buf[cnt] = '\0';
4041 
4042  return cnt;
4043 }
4044 
4045 /*
4046  * db_timestamp_to_string() - Print a DB_TIMESTAMP into a char buffer using
4047  * strftime().
4048  * return : the number of characters actually printed.
4049  * buf(out): a buffer to receive the printed representation
4050  * bufsize(in): the size of that buffer
4051  * utime(in): a pointer to a DB_TIMESTAMP to be printed
4052  */
4053 int
4054 db_timestamp_to_string (char *buf, int bufsize, DB_TIMESTAMP * utime)
4055 {
4056  DB_DATE date;
4057  DB_TIME time;
4058  int m, n;
4059 
4060  (void) db_timestamp_decode_ses (utime, &date, &time);
4061  m = db_time_to_string (buf, bufsize, &time);
4062  if (m == 0)
4063  {
4064  return 0;
4065  }
4066  if (bufsize - m < 2)
4067  {
4068  return 0;
4069  }
4070  buf[m] = ' ';
4071  m += 1;
4072  n = db_date_to_string (buf + m, bufsize - m, &date);
4073  if (n == 0)
4074  {
4075  return 0;
4076  }
4077  return m + n;
4078 }
4079 
4080 /*
4081  * db_timestamptz_to_string() - Print a DB_TIMESTAMP and a time zone into a
4082  * char buffer
4083  * return : the number of characters actually printed.
4084  * buf(out): a buffer to receive the printed representation
4085  * bufsize(in): the size of that buffer
4086  * utime(in): a pointer to a DB_TIMESTAMP to be printed
4087  * tz_id(in): reference timezone
4088  */
4089 int
4090 db_timestamptz_to_string (char *buf, int bufsize, DB_TIMESTAMP * utime, const TZ_ID * tz_id)
4091 {
4092  int n, res;
4093  DB_DATE date;
4094  DB_TIME time;
4095  int err = NO_ERROR;
4096 
4097  err = db_timestamp_decode_w_tz_id (utime, tz_id, &date, &time);
4098  if (err != NO_ERROR)
4099  {
4100  return 0;
4101  }
4102 
4103  res = db_time_to_string (buf, bufsize, &time);
4104  if (res == 0)
4105  {
4106  return 0;
4107  }
4108 
4109  if (bufsize - res < 2)
4110  {
4111  return 0;
4112  }
4113  n = res;
4114  buf[n] = ' ';
4115  n += 1;
4116  res = db_date_to_string (buf + n, bufsize - n, &date);
4117  if (res == 0)
4118  {
4119  return 0;
4120  }
4121 
4122  n += res;
4123 
4124  buf[n] = ' ';
4125  n += 1;
4126 
4127  res = tz_id_to_str (tz_id, buf + n, bufsize - n);
4128  if (res < 0)
4129  {
4130  return 0;
4131  }
4132 
4133  n += res;
4134  return n;
4135 }
4136 
4137 /*
4138  * db_timestampltz_to_string() - Print a DB_TIMESTAMP with session time zone
4139  * into a char buffer using
4140  * return : the number of characters actually printed.
4141  * buf(out): a buffer to receive the printed representation
4142  * bufsize(in): the size of that buffer
4143  * utime(in): a pointer to a DB_TIMESTAMP to be printed
4144  */
4145 int
4146 db_timestampltz_to_string (char *buf, int bufsize, DB_TIMESTAMP * utime)
4147 {
4148  int err = NO_ERROR;
4149  TZ_ID ses_tz_id;
4150 
4151  err = tz_create_session_tzid_for_timestamp (utime, &ses_tz_id);
4152  if (err != NO_ERROR)
4153  {
4154  return 0;
4155  }
4156 
4157  return db_timestamptz_to_string (buf, bufsize, utime, &ses_tz_id);
4158 }
4159 
4160 /*
4161  * DB_DATETIME FUNCTIONS
4162  */
4163 
4164 /*
4165  * encode_mtime() -
4166  * return : millisecond time value
4167  * hour(in): hour
4168  * minute(in): minute
4169  * second(in): second
4170  * millisecond(in): millisecond
4171  */
4172 static unsigned int
4173 encode_mtime (int hour, int minute, int second, int millisecond)
4174 {
4175  return ((((((hour * 60) + minute) * 60) + second) * 1000) + millisecond);
4176 }
4177 
4178 /*
4179  * decode_mtime() - Converts encoded millisecond time into
4180  * hour/minute/second/millisecond values.
4181  * return : void
4182  * time(in): encoded relative time value
4183  * hourp(out): hour pointer
4184  * minutep(out) : minute pointer
4185  * secondp(out) : second pointer
4186  * millisecondp(out) : millisecond pointer
4187  */
4188 static void
4189 decode_mtime (int mtimeval, int *hourp, int *minutep, int *secondp, int *millisecondp)
4190 {
4191  int hours, minutes, seconds, milliseconds;
4192 
4193  milliseconds = mtimeval % 1000;
4194  seconds = (mtimeval / 1000) % 60;
4195  minutes = (mtimeval / 60000) % 60;
4196  hours = (mtimeval / 3600000) % 24;
4197 
4198  if (hourp != NULL)
4199  {
4200  *hourp = hours;
4201  }
4202  if (minutep != NULL)
4203  {
4204  *minutep = minutes;
4205  }
4206  if (secondp != NULL)
4207  {
4208  *secondp = seconds;
4209  }
4210  if (millisecondp != NULL)
4211  {
4212  *millisecondp = milliseconds;
4213  }
4214 }
4215 
4216 /*
4217  * db_datetime_to_string() - Print a DB_DATETIME into a char buffer using
4218  * strftime().
4219  * return : the number of characters actually printed.
4220  * buf(out): a buffer to receive the printed representation
4221  * bufsize(in): the size of that buffer
4222  * datetime(in): a pointer to a DB_DATETIME to be printed
4223  */
4224 int
4225 db_datetime_to_string (char *buf, int bufsize, DB_DATETIME * datetime)
4226 {
4227  int mon, day, year;
4228  int hour, minute, second, millisecond;
4229  bool pm;
4230  int cnt = 0;
4231  const int len_out = 26;
4232 
4233  if (buf == NULL || bufsize == 0)
4234  {
4235  return 0;
4236  }
4237  if (bufsize <= len_out)
4238  {
4239  return 0;
4240  }
4241 
4242  db_datetime_decode (datetime, &mon, &day, &year, &hour, &minute, &second, &millisecond);
4243  pm = (hour >= 12) ? true : false;
4244  if (hour == 0)
4245  {
4246  hour = 12;
4247  }
4248  else if (hour > 12)
4249  {
4250  hour -= 12;
4251  }
4252 
4253  buf[cnt++] = hour / 10 + '0';
4254  buf[cnt++] = hour % 10 + '0';
4255  buf[cnt++] = ':';
4256  buf[cnt++] = minute / 10 + '0';
4257  buf[cnt++] = minute % 10 + '0';
4258  buf[cnt++] = ':';
4259  buf[cnt++] = second / 10 + '0';
4260  buf[cnt++] = second % 10 + '0';
4261  buf[cnt++] = '.';
4262  buf[cnt++] = millisecond / 100 + '0';
4263  buf[cnt++] = (millisecond / 10) % 10 + '0';
4264  buf[cnt++] = millisecond % 10 + '0';
4265  buf[cnt++] = ' ';
4266  if (pm)
4267  {
4268  buf[cnt++] = 'P';
4269  buf[cnt++] = 'M';
4270  }
4271  else
4272  {
4273  buf[cnt++] = 'A';
4274  buf[cnt++] = 'M';
4275  }
4276  buf[cnt++] = ' ';
4277  buf[cnt++] = mon / 10 + '0';
4278  buf[cnt++] = mon % 10 + '0';
4279  buf[cnt++] = '/';
4280  buf[cnt++] = day / 10 + '0';
4281  buf[cnt++] = day % 10 + '0';
4282  buf[cnt++] = '/';
4283  buf[cnt++] = year / 1000 + '0';
4284  buf[cnt++] = (year / 100) % 10 + '0';
4285  buf[cnt++] = (year / 10) % 10 + '0';
4286  buf[cnt++] = year % 10 + '0';
4287  buf[cnt] = '\0';
4288 
4289  return cnt;
4290 }
4291 
4292 /*
4293  * db_datetimetz_to_string() - Print a DB_DATETIME with time zone into a char
4294  * buffer using timezone specified
4295  * return : the number of characters actually printed.
4296  * buf(out): a buffer to receive the printed representation
4297  * bufsize(in): the size of that buffer
4298  * dt(in): a pointer to a DB_DATETIME to be printed
4299  * tz_id(in): zone identifier
4300  */
4301 int
4302 db_datetimetz_to_string (char *buf, int bufsize, DB_DATETIME * dt, const TZ_ID * tz_id)
4303 {
4304  int retval, n;
4305  DB_DATETIME dt_local;
4306 
4307  retval = tz_utc_datetimetz_to_local (dt, tz_id, &dt_local);
4308  if (retval == ER_QPROC_TIME_UNDERFLOW)
4309  {
4310  db_datetime_encode (&dt_local, 0, 0, 0, 0, 0, 0, 0);
4311  retval = NO_ERROR;
4312  er_clear ();
4313  }
4314 
4315  if (retval != NO_ERROR)
4316  {
4317  return 0;
4318  }
4319 
4320  retval = db_datetime_to_string (buf, bufsize, &dt_local);
4321 
4322  if (retval <= 0 || retval > bufsize + 1)
4323  {
4324  return retval;
4325  }
4326  n = retval;
4327 
4328  buf[n] = ' ';
4329  n++;
4330 
4331  retval = tz_id_to_str (tz_id, buf + n, bufsize - n);
4332  if (retval < 0)
4333  {
4334  return 0;
4335  }
4336 
4337  n += retval;
4338  return n;
4339 }
4340 
4341 /*
4342  * db_datetimeltz_to_string() - Print a DB_DATETIME with time zone into a char
4343  * buffer using session local timezone
4344  * return : the number of characters actually printed.
4345  * buf(out): a buffer to receive the printed representation
4346  * bufsize(in): the size of that buffer
4347  * dt(in): a pointer to a DB_DATETIME to be printed
4348  */
4349 int
4350 db_datetimeltz_to_string (char *buf, int bufsize, DB_DATETIME * dt)
4351 {
4352  int retval;
4353  TZ_ID tz_id;
4354 
4355  retval = tz_create_session_tzid_for_datetime (dt, true, &tz_id);
4356  if (retval != NO_ERROR)
4357  {
4358  return 0;
4359  }
4360 
4361  return db_datetimetz_to_string (buf, bufsize, dt, &tz_id);
4362 }
4363 
4364 /*
4365  * db_datetime_to_string2() - Print a DB_DATETIME into a char buffer using
4366  * strftime().
4367  * return : the number of characters actually printed.
4368  * buf(out): a buffer to receive the printed representation
4369  * bufsize(in): the size of that buffer
4370  * datetime(in): a pointer to a DB_DATETIME to be printed
4371  *
4372  * Note: version without PM and AM and formatted YYYY-MM-DD HH:MM:SS.MMM
4373  */
4374 int
4375 db_datetime_to_string2 (char *buf, int bufsize, DB_DATETIME * datetime)
4376 {
4377  int mon, day, year;
4378  int hour, minute, second, millisecond;
4379  int retval;
4380 
4381  if (buf == NULL || bufsize == 0)
4382  {
4383  return 0;
4384  }
4385 
4386  db_datetime_decode (datetime, &mon, &day, &year, &hour, &minute, &second, &millisecond);
4387 
4388  if (millisecond > 0)
4389  {
4390  retval =
4391  snprintf (buf, bufsize, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, mon, day, hour, minute, second,
4392  millisecond);
4393  }
4394  else
4395  {
4396  retval = snprintf (buf, bufsize, "%04d-%02d-%02d %02d:%02d:%02d", year, mon, day, hour, minute, second);
4397  }
4398  if (bufsize < retval)
4399  {
4400  retval = 0;
4401  }
4402 
4403  return retval;
4404 }
4405 
4406 /*
4407  * db_string_to_datetime_ex() -
4408  * return : 0 on success, -1 on error.
4409  * str(in): a buffer containing a date to be parsed
4410  * str_len(in): the length of the string to be parsed
4411  * datetime(out): a pointer to a DB_DATETIME to be modified
4412  */
4413 int
4414 db_string_to_datetime_ex (const char *str, int str_len, DB_DATETIME * datetime)
4415 {
4416  const char *p;
4417  const char *p_end = str + str_len;
4418 
4419  p = parse_datetime (str, str_len, datetime);
4420  if (p != NULL)
4421  {
4422  while (p < p_end && char_isspace (p[0]))
4423  p++;
4424  }
4425  if (p == NULL || (p < p_end && p[0] != '\0'))
4426  {
4428  return ER_DATE_CONVERSION;
4429  }
4430 
4431  return NO_ERROR;
4432 }
4433 
4434 /*
4435  * db_string_to_datetime() -
4436  * return : 0 on success, -1 on error.
4437  * str(in): a buffer containing a date to be parsed
4438  * datetime(out): a pointer to a DB_DATETIME to be modified
4439  */
4440 int
4441 db_string_to_datetime (const char *str, DB_DATETIME * datetime)
4442 {
4443  return db_string_to_datetime_ex (str, strlen (str), datetime);
4444 }
4445 
4446 /*
4447  * db_string_to_datetimetz_ex() -
4448  * return : 0 on success, -1 on error.
4449  * str(in): a buffer containing a date to be parsed
4450  * str_len(in): the length of the string to be parsed
4451  * dt_tz(out): a pointer to a DB_DATETIMETZ to be modified
4452  * has_zone(out): true if string has valid zone information, false otherwise
4453  */
4454 int
4455 db_string_to_datetimetz_ex (const char *str, int str_len, DB_DATETIMETZ * dt_tz, bool * has_zone)
4456 {
4457  int er_status = NO_ERROR;
4458  int str_zone_size = 0;
4459  const char *p, *p_end;
4460  const char *str_zone = NULL;
4461  TZ_REGION session_tz_region;
4462 
4463  p_end = str + str_len;
4464  dt_tz->tz_id = 0;
4465  *has_zone = false;
4466 
4467  tz_get_session_tz_region (&session_tz_region);
4468 
4469  p = parse_datetime (str, str_len, &dt_tz->datetime);
4470  if (p == NULL)
4471  {
4473  return ER_DATE_CONVERSION;
4474  }
4475 
4476  while (p < p_end && char_isspace (p[0]))
4477  {
4478  p++;
4479  }
4480 
4481  if (p < p_end)
4482  {
4483  *has_zone = true;
4484  str_zone = p;
4485  str_zone_size = CAST_BUFLEN (p_end - str_zone);
4486  }
4487 
4488  er_status = tz_create_datetimetz (&dt_tz->datetime, str_zone, str_zone_size, &session_tz_region, dt_tz, &p);
4489  if (er_status != NO_ERROR || str_zone == NULL)
4490  {
4491  /* error or no timezone in user string (no trailing chars to check) */
4492  return er_status;
4493  }
4494 
4495  if (p != NULL)
4496  {
4497  while (p < p_end && char_isspace (p[0]))
4498  {
4499  p++;
4500  }
4501  }
4502 
4503  if (p == NULL || (p < p_end && p[0] != '\0'))
4504  {
4506  return ER_DATE_CONVERSION;
4507  }
4508 
4509  return er_status;
4510 }
4511 
4512 /*
4513  * db_string_to_datetimetz() -
4514  * return : 0 on success, -1 on error.
4515  * str(in): a buffer containing a date to be parsed
4516  * dt_tz(out): a pointer to a DB_DATETIMETZ to be modified
4517  * has_zone(out): true if string has valid zone information, false otherwise
4518  */
4519 int
4520 db_string_to_datetimetz (const char *str, DB_DATETIMETZ * dt_tz, bool * has_zone)
4521 {
4522  return db_string_to_datetimetz_ex (str, strlen (str), dt_tz, has_zone);
4523 }
4524 
4525 /*
4526  * db_string_to_datetimeltz_ex() -
4527  * return : 0 on success, -1 on error.
4528  * str(in): a buffer containing a date to be parsed
4529  * str_len(in): the length of the string to be parsed
4530  * datetime(out): a pointer to a DB_DATETIME to be modified
4531  */
4532 int
4533 db_string_to_datetimeltz_ex (const char *str, int str_len, DB_DATETIME * datetime)
4534 {
4535  int error = NO_ERROR;
4536  DB_DATETIMETZ dt_tz;
4537  bool dummy_has_zone;
4538 
4539  error = db_string_to_datetimetz_ex (str, str_len, &dt_tz, &dummy_has_zone);
4540  if (error == NO_ERROR)
4541  {
4542  *datetime = dt_tz.datetime;
4543  }
4544 
4545  return error;
4546 }
4547 
4548 /*
4549  * db_string_to_datetimeltz() -
4550  * return : 0 on success, -1 on error.
4551  * str(in): a buffer containing a date to be parsed
4552  * datetime(out): a pointer to a DB_DATETIME to be modified
4553  */
4554 int
4555 db_string_to_datetimeltz (const char *str, DB_DATETIME * datetime)
4556 {
4557  return db_string_to_datetimeltz_ex (str, strlen (str), datetime);
4558 }
4559 
4560 /*
4561  * db_datetime_decode() - Converts encoded datetime into
4562  * month/day/year/hour/minute/second/millisecond values.
4563  * return : error code
4564  * datetime(in): pointer to DB_DATETIME
4565  * month(out): pointer to month
4566  * day(out): pointer to day
4567  * year(out): pointer to year
4568  * hour(out): pointer to hour
4569  * minute(out): pointer to minute
4570  * second(out): pointer to second
4571  * millisecond(out): pointer to millisecond
4572  */
4573 int
4574 db_datetime_decode (const DB_DATETIME * datetime, int *month, int *day, int *year, int *hour, int *minute, int *second,
4575  int *millisecond)
4576 {
4577  db_date_decode (&datetime->date, month, day, year);
4578  decode_mtime (datetime->time, hour, minute, second, millisecond);
4579 
4580  return NO_ERROR;
4581 }
4582 
4583 /*
4584  * db_datetime_encode() - Converts month/day/year/hour/minute/second/millisecond
4585  * into an encoded relative
4586  * return : error code
4587  * datetime(in): pointer to DB_DATETIME
4588  * month(out): month
4589  * day(out): day
4590  * year(out): year
4591  * hour(out): hour
4592  * minute(out): minute
4593  * second(out): second
4594  * millisecond(out): millisecond
4595  */
4596 int
4597 db_datetime_encode (DB_DATETIME * datetime, int month, int day, int year, int hour, int minute, int second,
4598  int millisecond)
4599 {
4600  datetime->time = encode_mtime (hour, minute, second, millisecond);
4601  return db_date_encode (&datetime->date, month, day, year);
4602 }
4603 
4604 /*
4605  * db_subtract_int_from_datetime() -
4606  * return : error code
4607  * datetime(in):
4608  * i2(in):
4609  * result_datetime(out):
4610  */
4611 int
4613 {
4614  DB_BIGINT bi1, result_bi, tmp_bi;
4615 
4616  if (bi2 < 0)
4617  {
4618  if (bi2 == DB_BIGINT_MIN)
4619  {
4621  return ER_QPROC_TIME_UNDERFLOW;
4622  }
4623 
4624  return db_add_int_to_datetime (dt1, -bi2, result_datetime);
4625  }
4626 
4627  bi1 = ((DB_BIGINT) dt1->date) * MILLISECONDS_OF_ONE_DAY + dt1->time;
4628 
4629  result_bi = bi1 - bi2;
4630  if (OR_CHECK_SUB_UNDERFLOW (bi1, bi2, result_bi))
4631  {
4633  return ER_QPROC_TIME_UNDERFLOW;
4634  }
4635 
4636  tmp_bi = (DB_BIGINT) (result_bi / MILLISECONDS_OF_ONE_DAY);
4637  if (OR_CHECK_INT_OVERFLOW (tmp_bi) || tmp_bi > DB_DATE_MAX || tmp_bi < DB_DATE_MIN)
4638  {
4640  return ER_QPROC_TIME_UNDERFLOW;
4641  }
4642  result_datetime->date = (int) tmp_bi;
4643  result_datetime->time = (int) (result_bi % MILLISECONDS_OF_ONE_DAY);
4644 
4645  return NO_ERROR;
4646 }
4647 
4648 /*
4649  * db_add_int_to_datetime() -
4650  * return : error code
4651  * datetime(in):
4652  * i2(in):
4653  * result_datetime(out):
4654  */
4655 int
4656 db_add_int_to_datetime (DB_DATETIME * datetime, DB_BIGINT bi2, DB_DATETIME * result_datetime)
4657 {
4658  DB_BIGINT bi1, result_bi, tmp_bi;
4659 
4660  if (bi2 < 0)
4661  {
4662  if (bi2 == DB_BIGINT_MIN)
4663  {
4665  return ER_QPROC_TIME_UNDERFLOW;
4666  }
4667 
4668  return db_subtract_int_from_datetime (datetime, -bi2, result_datetime);
4669  }
4670 
4671  bi1 = ((DB_BIGINT) datetime->date) * MILLISECONDS_OF_ONE_DAY + datetime->time;
4672 
4673  result_bi = bi1 + bi2;
4674  if (OR_CHECK_ADD_OVERFLOW (bi1, bi2, result_bi))
4675  {
4677  return ER_QPROC_TIME_UNDERFLOW;
4678  }
4679 
4680  tmp_bi = (DB_BIGINT) (result_bi / MILLISECONDS_OF_ONE_DAY);
4681  if (OR_CHECK_INT_OVERFLOW (tmp_bi) || tmp_bi > DB_DATE_MAX || tmp_bi < DB_DATE_MIN)
4682  {
4684  return ER_QPROC_TIME_UNDERFLOW;
4685  }
4686 
4687  result_datetime->date = (int) tmp_bi;
4688  result_datetime->time = (int) (result_bi % MILLISECONDS_OF_ONE_DAY);
4689 
4690  return NO_ERROR;
4691 }
4692 
4693 /*
4694  * db_get_day_of_year() - returns the day of the year (1 to 365(6))
4695  */
4696 int
4697 db_get_day_of_year (int year, int month, int day)
4698 {
4699  int days[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 };
4700  int day_of_year = 0;
4701  int i;
4702 
4703  for (i = 1; i < month; i++)
4704  {
4705  day_of_year += days[i - 1];
4706  }
4707 
4708  day_of_year += day;
4709 
4710  /* for leap years, add one extra day if we're past February. A leap year i a year that is divisible by 4 and if it is
4711  * divisible 100 it is also divisible by 400 */
4712  if (month > 2 && IS_LEAP_YEAR (year))
4713  {
4714  day_of_year++;
4715  }
4716  return day_of_year;
4717 }
4718 
4719 /*
4720  * db_get_day_of_week() - returns the day of week (0 = Sunday, 6 = Saturday)
4721  */
4722 int
4723 db_get_day_of_week (int year, int month, int day)
4724 {
4725  if (year == 0 && month == 0 && day == 0)
4726  {
4727  return 0;
4728  }
4729 
4730  if (month < 3)
4731  {
4732  month = month + 12;
4733  year = year - 1;
4734  }
4735 
4736  return (day + (2 * month) + (int) (6 * (month + 1) / 10) + year + (int) (year / 4) - (int) (year / 100) +
4737  (int) (year / 400) + 1) % 7;
4738 }
4739 
4740 /*
4741  * get_end_of_week_one_of_year() - returns the day number (1-15) at which
4742  * week 1 in the year ends
4743  * year(in) : year
4744  * mode : specifies the way in which to consider what "week 1" means
4745  *
4746  * mode First day Range Week 1 is the first week
4747  * of week
4748  * 0 Sunday 0-53 with a Sunday in this year
4749  * 1 Monday 0-53 with more than 3 days this year
4750  * 2 Sunday 1-53 with a Sunday in this year
4751  * 3 Monday 1-53 with more than 3 days this year
4752  * 4 Sunday 0-53 with more than 3 days this year
4753  * 5 Monday 0-53 with a Monday in this year
4754  * 6 Sunday 1-53 with more than 3 days this year
4755  * 7 Monday 1-53 with a Monday in this year
4756  */
4757 static int
4759 {
4760  int dow_1Jan = 1 + db_get_day_of_week (year, 1, 1);
4761 
4762  switch (mode)
4763  {
4764  case 0:
4765  case 2:
4766  if (dow_1Jan == 1)
4767  {
4768  return 7;
4769  }
4770  else
4771  {
4772  return 7 + 8 - dow_1Jan;
4773  }
4774  case 1:
4775  case 3:
4776  if (dow_1Jan == 1)
4777  {
4778  return 7 + 1;
4779  }
4780  else if (dow_1Jan > 5)
4781  {
4782  return 16 - dow_1Jan;
4783  }
4784  else
4785  {
4786  return 9 - dow_1Jan;
4787  }
4788  case 4:
4789  if (dow_1Jan > 4)
4790  {
4791  return 7 + 8 - dow_1Jan;
4792  }
4793  else
4794  {
4795  return 8 - dow_1Jan;
4796  }
4797  case 5:
4798  if (dow_1Jan == 1)
4799  {
4800  return 7 + 1;
4801  }
4802  else if (dow_1Jan == 2)
4803  {
4804  return 7;
4805  }
4806  else
4807  {
4808  return 16 - dow_1Jan;
4809  }
4810  case 6:
4811  if (dow_1Jan > 4)
4812  {
4813  return 7 + 8 - dow_1Jan;
4814  }
4815  else
4816  {
4817  return 8 - dow_1Jan;
4818  }
4819  case 7:
4820  if (dow_1Jan == 2)
4821  {
4822  return 7;
4823  }
4824  else
4825  {
4826  return 16 - dow_1Jan;
4827  }
4828  }
4829 
4830  assert (false);
4831 
4832  return 7;
4833 }
4834 
4835 /*
4836  * db_get_week_of_year() - returns the week number
4837  * year(in) : year
4838  * month(in) : month
4839  * day(in) : day of month
4840  * mode : specifies the way in which to compute the week number:
4841  *
4842  * mode First day Range Week 1 is the first week
4843  * of week
4844  * 0 Sunday 0-53 with a Sunday in this year
4845  * 1 Monday 0-53 with more than 3 days this year
4846  * 2 Sunday 1-53 with a Sunday in this year
4847  * 3 Monday 1-53 with more than 3 days this year
4848  * 4 Sunday 0-53 with more than 3 days this year
4849  * 5 Monday 0-53 with a Monday in this year
4850  * 6 Sunday 1-53 with more than 3 days this year
4851  * 7 Monday 1-53 with a Monday in this year
4852  */
4853 int
4854 db_get_week_of_year (int year, int month, int day, int mode)
4855 {
4856  const int day_of_year = db_get_day_of_year (year, month, day);
4857  const int end_of_first_week = get_end_of_week_one_of_year (year, mode);
4858  int week_number = 0;
4859  int last_week_of_year = 0;
4860  int days_last_year = 0;
4861 
4862  assert ((0 <= mode) && (mode <= 7));
4863 
4864  if (day_of_year > end_of_first_week)
4865  {
4866  /* if it isn't in the first week, compute week number */
4867  week_number = 1 + (day_of_year - end_of_first_week) / 7;
4868  if ((day_of_year - end_of_first_week) % 7)
4869  {
4870  week_number++;
4871  }
4872  return week_number;
4873  }
4874 
4875  if (day_of_year > end_of_first_week - 7)
4876  {
4877  /* it is in the first week */
4878  return 1;
4879  }
4880 
4881  /* day_of_year is in the last week of the previous year */
4882  if (mode == 0 || mode == 1 || mode == 4 || mode == 5)
4883  {
4884  /* return 0 for those modes */
4885  return 0;
4886  }
4887 
4888  last_week_of_year = get_end_of_week_one_of_year (year - 1, mode);
4889 
4890  days_last_year = 365;
4891  /* if it is a leap year */
4892  if (IS_LEAP_YEAR (year - 1))
4893  {
4894  days_last_year++;
4895  }
4896 
4897  week_number = 1 + (days_last_year - last_week_of_year) / 7;
4898  if ((days_last_year - last_week_of_year) % 7 != 0)
4899  {
4900  week_number++;
4901  }
4902  return week_number;
4903 }
4904 
4905 /* db_check_time_date_format()
4906  returns:
4907  1 if it has only time specifiers,
4908  2 if it has only date specifiers,
4909  3 if it has them both
4910  4 if it has both time and timezone specifiers
4911  5 if it has time, date and timezone specifiers
4912  */
4913 int
4914 db_check_time_date_format (const char *format_s)
4915 {
4916  int i, res = 0, len;
4917  int format_type[256];
4918  bool has_timezone = false;
4919 
4920  len = strlen (format_s);
4921  memset (format_type, 0, sizeof (format_type));
4922 
4923  /* time */
4924  format_type['f'] = TIME_SPECIFIER;
4925  format_type['H'] = TIME_SPECIFIER;
4926  format_type['h'] = TIME_SPECIFIER;
4927  format_type['I'] = TIME_SPECIFIER;
4928  format_type['i'] = TIME_SPECIFIER;
4929  format_type['k'] = TIME_SPECIFIER;
4930  format_type['l'] = TIME_SPECIFIER;
4931  format_type['p'] = TIME_SPECIFIER;
4932  format_type['r'] = TIME_SPECIFIER;
4933  format_type['S'] = TIME_SPECIFIER;
4934  format_type['s'] = TIME_SPECIFIER;
4935  format_type['T'] = TIME_SPECIFIER;
4936 
4937  /* date */
4938  format_type['a'] = DATE_SPECIFIER;
4939  format_type['b'] = DATE_SPECIFIER;
4940  format_type['c'] = DATE_SPECIFIER;
4941  format_type['D'] = DATE_SPECIFIER;
4942  format_type['d'] = DATE_SPECIFIER;
4943  format_type['e'] = DATE_SPECIFIER;
4944  format_type['j'] = DATE_SPECIFIER;
4945  format_type['M'] = DATE_SPECIFIER;
4946  format_type['m'] = DATE_SPECIFIER;
4947  format_type['U'] = DATE_SPECIFIER;
4948  format_type['u'] = DATE_SPECIFIER;
4949  format_type['V'] = DATE_SPECIFIER;
4950  format_type['v'] = DATE_SPECIFIER;
4951  format_type['W'] = DATE_SPECIFIER;
4952  format_type['w'] = DATE_SPECIFIER;
4953  format_type['X'] = DATE_SPECIFIER;
4954  format_type['x'] = DATE_SPECIFIER;
4955  format_type['Y'] = DATE_SPECIFIER;
4956  format_type['y'] = DATE_SPECIFIER;
4957 
4958  for (i = 1; i < len; i++)
4959  {
4960  if (format_s[i - 1] != '%') /* %x */
4961  continue;
4962  if (i > 1 && format_s[i - 2] == '%') /* but not %%x */
4963  continue;
4964 
4965  if (format_type[(unsigned char) format_s[i]] != 0)
4966  {
4967  res |= format_type[(unsigned char) format_s[i]];
4968  }
4969  if (i + 2 < len && format_s[i] == 'T' && format_s[i + 1] == 'Z')
4970  {
4971  switch (format_s[i + 2])
4972  {
4973  case 'R':
4974  case 'D':
4975  case 'H':
4976  case 'M':
4977  has_timezone = true;
4978  break;
4979  default:
4980  break;
4981  }
4982  }
4983  }
4984 
4985  if (has_timezone)
4986  {
4987  if (res == DATE_SPECIFIER || res == DATETIME_SPECIFIER)
4988  {
4989  res = DATETIMETZ_SPECIFIER;
4990  }
4991  }
4992 
4993  return res;
4994 }
4995 
4996 
4997 /*
4998  * db_add_weeks_and_days_to_date () - add weeks and days to a gived date
4999  * return: ER_FAILED error, NO_ERROR ok
5000  * day(in,out) : day of date
5001  * month(in,out) : month of date
5002  * year(in,out) : year of date
5003  * weeks(in) : how many weeks will be added to date
5004  * day_weeks : how many days will be added to date
5005  * Note :
5006  * day, month and year will be updated just in case of no error
5007  */
5008 int
5009 db_add_weeks_and_days_to_date (int *day, int *month, int *year, int weeks, int day_week)
5010 {
5011  int days_months[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
5012  int d, m, y, i;
5013 
5014  if (day == NULL || month == NULL || year == NULL)
5015  {
5016  return ER_FAILED;
5017  }
5018 
5019  if (*year < 0 || *year > 9999)
5020  {
5021  return ER_FAILED;
5022  }
5023 
5024  if (*month < 1 || *month > 12)
5025  {
5026  return ER_FAILED;
5027  }
5028 
5029  if (IS_LEAP_YEAR (*year))
5030  {
5031  days_months[2] += 1;
5032  }
5033 
5034  if (*day < 0 || *day > days_months[*month])
5035  {
5036  return ER_FAILED;
5037  }
5038 
5039  if (weeks < 0)
5040  {
5041  return ER_FAILED;
5042  }
5043 
5044  if (day_week < 0 || day_week > 6)
5045  {
5046  return ER_FAILED;
5047  }
5048 
5049  d = *day;
5050  m = *month;
5051  y = *year;
5052  for (i = 1; i <= weeks; i++)
5053  {
5054  d = d + 7;
5055  if (d > days_months[m])
5056  {
5057  d = d - days_months[m];
5058  m = m + 1;
5059 
5060  if (m > 12)
5061  {
5062  m = 1;
5063  y = y + 1;
5064  if ((y % 400 == 0) || (y % 100 != 0 && y % 4 == 0))
5065  {
5066  days_months[2] = 29;
5067  }
5068  else
5069  {
5070  days_months[2] = 28;
5071  }
5072  }
5073  }
5074  }
5075 
5076  d = d + day_week;
5077  if (d > days_months[m])
5078  {
5079  d = d - days_months[m];
5080  m = m + 1;
5081  if (m > 12)
5082  {
5083  m = 1;
5084  y = y + 1;
5085  }
5086  }
5087 
5088  if (y < 0 || y > 9999)
5089  {
5090  return ER_FAILED;
5091  }
5092 
5093  *day = d;
5094  *month = m;
5095  *year = y;
5096 
5097  return NO_ERROR;
5098 }
int julian_encode(int m, int d, int y)
Definition: db_date.c:113
unsigned int TZ_ID
Definition: dbtype_def.h:756
int char_isspace(int c)
Definition: chartype.c:109
static unsigned int encode_mtime(int hour, int minute, int second, int millisecond)
Definition: db_date.c:4173
static int db_timestamp_encode_w_reg(const DB_DATE *date, const DB_TIME *timeval, const TZ_REGION *tz_region, DB_TIMESTAMP *utime, TZ_ID *dest_tz_id)
Definition: db_date.c:712
int db_strftime(char *s, int smax, const char *fmt, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:973
#define NO_ERROR
Definition: error_code.h:46
static char local_pm_str[10]
Definition: db_date.c:71
static bool is_local_pm_str(const char *p, const char *p_end)
Definition: db_date.c:1559
int db_timestamptz_to_string(char *buf, int bufsize, DB_TIMESTAMP *utime, const TZ_ID *tz_id)
Definition: db_date.c:4090
int db_get_week_of_year(int year, int month, int day, int mode)
Definition: db_date.c:4854
int db_string_to_timestamp(const char *str, DB_TIMESTAMP *utime)
Definition: db_date.c:3802
int db_datetime_to_string2(char *buf, int bufsize, DB_DATETIME *datetime)
Definition: db_date.c:4375
DB_BIGINT tz_timestamp_encode_leap_sec_adj(const int year_century, const int year, const int mon, const int day)
Definition: tz_support.c:415
#define DATETIME_FIELD_LIMIT
Definition: db_date.c:62
int db_add_int_to_datetime(DB_DATETIME *datetime, DB_BIGINT bi2, DB_DATETIME *result_datetime)
Definition: db_date.c:4656
int db_date_to_string(char *buf, int bufsize, DB_DATE *date)
Definition: db_date.c:3953
int db_date_parse_datetime(char const *str, int str_len, DB_DATETIME *datetime)
Definition: db_date.c:3423
int db_string_to_datetimetz(const char *str, DB_DATETIMETZ *dt_tz, bool *has_zone)
Definition: db_date.c:4520
DB_TIMESTAMP timestamp
Definition: dbtype_def.h:766
static int get_end_of_week_one_of_year(int year, int mode)
Definition: db_date.c:4758
#define ER_FAILED
Definition: error_code.h:47
int db_datetime_decode(const DB_DATETIME *datetime, int *month, int *day, int *year, int *hour, int *minute, int *second, int *millisecond)
Definition: db_date.c:4574
#define IGREG1
Definition: db_date.c:48
int len
Definition: db_date.c:67
int db_timestamp_encode_ses(const DB_DATE *date, const DB_TIME *timeval, DB_TIMESTAMP *utime, TZ_ID *dest_tz_id)
Definition: db_date.c:597
static const char * parse_date(const char *buf, int buf_len, DB_DATE *date)
Definition: db_date.c:1116
const TZ_ID * tz_get_utc_tz_id(void)
Definition: tz_support.c:816
static const char * parse_for_timestamp(const char *buf, int buf_len, DB_DATE *date, DB_TIME *time, bool allow_msec)
Definition: db_date.c:3512
int db_string_to_datetime(const char *str, DB_DATETIME *datetime)
Definition: db_date.c:4441
void tz_get_session_tz_region(TZ_REGION *tz_region)
Definition: tz_support.c:767
int db_subtract_int_from_datetime(DB_DATETIME *dt1, DB_BIGINT bi2, DB_DATETIME *result_datetime)
Definition: db_date.c:4612
#define DB_DATE_MIN
Definition: dbtype_def.h:649
static char const * parse_timestamp_compact(char const *str, char const *strend, DB_DATE *date, unsigned int *mtime, bool *has_explicit_time, bool *has_explicit_msec)
Definition: db_date.c:2549
int db_timestampltz_to_string(char *buf, int bufsize, DB_TIMESTAMP *utime)
Definition: db_date.c:4146
int db_string_to_datetime_ex(const char *str, int str_len, DB_DATETIME *datetime)
Definition: db_date.c:4414
#define OR_CHECK_ADD_OVERFLOW(a, b, c)
int db_string_to_timestamptz_ex(const char *str, int str_len, DB_TIMESTAMPTZ *ts_tz, bool *has_zone, bool is_cast)
Definition: db_date.c:3820
int db_string_to_timestamp_ex(const char *str, int str_len, DB_TIMESTAMP *utime)
Definition: db_date.c:3755
static const char * parse_mtime(const char *buf, int buf_len, unsigned int *mtime, bool *is_msec, bool *is_explicit)
Definition: db_date.c:1352
#define ER_TIMESTAMP_CONVERSION
Definition: error_code.h:982
static int local_pm_strlen
Definition: db_date.c:72
int tz_conv_tz_datetime_w_region(const DB_DATETIME *src_dt, const TZ_REGION *src_tz_region, const TZ_REGION *dest_tz_region, DB_DATETIME *dest_dt, TZ_ID *src_tz_id_out, TZ_ID *dest_tz_id_out)
Definition: tz_support.c:3812
int db_timestamp_encode_sys(const DB_DATE *date, const DB_TIME *timeval, DB_TIMESTAMP *utime, TZ_ID *dest_tz_id)
Definition: db_date.c:617
static int init_tm(struct tm *)
Definition: db_date.c:1073
static int tm_encode(struct tm *c_time_struct, time_t *retval, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:458
int db_date_weekday(DB_DATE *date)
Definition: db_date.c:321
int db_datetimetz_to_string(char *buf, int bufsize, DB_DATETIME *dt, const TZ_ID *tz_id)
Definition: db_date.c:4302
int db_date_encode(DB_DATE *date, int month, int day, int year)
Definition: db_date.c:275
int db_timestamp_to_string(char *buf, int bufsize, DB_TIMESTAMP *utime)
Definition: db_date.c:4054
int db_check_time_date_format(const char *format_s)
Definition: db_date.c:4914
static int encode_time(int hour, int minute, int second)
Definition: db_date.c:355
int db_string_to_time(const char *str, DB_TIME *time)
Definition: db_date.c:3739
int tz_create_datetimetz(const DB_DATETIME *dt, const char *tz_str, const int tz_size, const TZ_REGION *default_tz_region, DB_DATETIMETZ *dt_tz, const char **end_tz_str)
Definition: tz_support.c:1383
unsigned int DB_TIMESTAMP
Definition: dbtype_def.h:759
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
bool db_string_check_explicit_date(const char *str, int str_len)
Definition: db_date.c:3629
char str[10]
Definition: db_date.c:66
static char const * parse_mtime_separated(char const *str, char const *strend, unsigned int *mtime, char const **syntax_check, int *time_parts, char *sep_ch, bool *has_explicit_msec, bool is_datetime)
Definition: db_date.c:1833
#define FLOOR(d1)
Definition: db_date.c:54
#define assert(x)
int tz_create_session_tzid_for_datetime(const DB_DATETIME *src_dt, bool src_is_utc, TZ_ID *tz_id)
Definition: tz_support.c:1037
static char local_am_str[10]
Definition: db_date.c:71
int db_string_to_datetimetz_ex(const char *str, int str_len, DB_DATETIMETZ *dt_tz, bool *has_zone)
Definition: db_date.c:4455
static char const * parse_explicit_mtime_compact(char const *str, char const *strend, unsigned int *mtime)
Definition: db_date.c:2289
#define ER_TIME_CONVERSION
Definition: error_code.h:981
int db_timestamp_encode_utc(const DB_DATE *date, const DB_TIME *timeval, DB_TIMESTAMP *utime)
Definition: db_date.c:635
int db_time_encode(DB_TIME *timeval, int hour, int minute, int second)
Definition: db_date.c:370
#define IGREG2
Definition: db_date.c:50
DB_DATETIME datetime
Definition: dbtype_def.h:783
int tz_id_to_str(const TZ_ID *tz_id, char *tz_str, const int tz_str_size)
Definition: tz_support.c:1789
static char const * parse_date_separated(char const *str, char const *strend, DB_DATE *date, char const **syntax_check, int *year_digits, char *sep_ch)
Definition: db_date.c:1590
struct ampm_buf AMPM_BUF
void db_localdatetime(time_t *epoch_time, DB_DATETIME *datetime)
Definition: db_date.c:1030
int db_date_parse_timestamp(char const *str, int str_len, DB_TIMESTAMP *utime)
Definition: db_date.c:3438
static enum scanner_mode mode
#define OR_CHECK_INT_OVERFLOW(i)
#define min(a, b)
#define DB_DATE_MAX
Definition: dbtype_def.h:650
int char_isdigit(int c)
Definition: chartype.c:73
#define IGREG_SPECIAL
Definition: db_date.c:52
static void fill_local_ampm_str(char str[10], bool am)
Definition: db_date.c:1492
#define NULL
Definition: freelistheap.h:34
bool db_string_check_explicit_time(const char *str, int str_len)
Definition: db_date.c:1331
int db_date_parse_time(char const *str, int str_len, DB_TIME *time, int *millisecond)
Definition: db_date.c:2933
#define YYYYMMDD
Definition: db_date.c:59
int db_get_day_of_week(int year, int month, int day)
Definition: db_date.c:4723
void tz_get_system_tz_region(TZ_REGION *tz_region)
Definition: tz_support.c:758
int db_tm_encode(struct tm *c_time_struct, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:536
static const char * parse_time(const char *buf, int buf_len, DB_TIME *mtime)
Definition: db_date.c:1303
static bool is_local_am_str(const char *p, const char *p_end)
Definition: db_date.c:1547
#define MILLISECONDS_OF_ONE_DAY
void tz_timestamp_decode_sec(int timestamp, int *yearp, int *monthsp, int *dayp, int *hoursp, int *minutesp, int *secondsp)
Definition: tz_support.c:458
#define err(fd,...)
Definition: porting.h:431
int db_timestamp_decode_w_tz_id(const DB_TIMESTAMP *utime, const TZ_ID *tz_id, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:902
int db_date_parse_date(char const *str, int str_len, DB_DATE *date)
Definition: db_date.c:3481
#define OR_CHECK_SUB_UNDERFLOW(a, b, c)
int db_timestamp_decode_ses(const DB_TIMESTAMP *utime, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:764
int db_time_to_string(char *buf, int bufsize, DB_TIME *time)
Definition: db_date.c:3994
int db_datetime_to_string(char *buf, int bufsize, DB_DATETIME *datetime)
Definition: db_date.c:4225
int64_t DB_BIGINT
Definition: dbtype_def.h:751
#define ER_DATE_CONVERSION
Definition: error_code.h:242
#define IS_LEAP_YEAR(y)
Definition: tz_support.h:62
#define CAST_BUFLEN
Definition: porting.h:471
static void error(const char *msg)
Definition: gencat.c:331
time_t db_mktime(DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:557
int db_string_to_timestampltz(const char *str, DB_TIMESTAMP *ts)
Definition: db_date.c:3936
int tz_utc_datetimetz_to_local(const DB_DATETIME *dt_utc, const TZ_ID *tz_id, DB_DATETIME *dt_local)
Definition: tz_support.c:1571
int db_string_to_timestampltz_ex(const char *str, int str_len, DB_TIMESTAMP *ts)
Definition: db_date.c:3908
#define ARG_FILE_LINE
Definition: error_manager.h:44
#define ER_QPROC_TIME_UNDERFLOW
Definition: error_code.h:653
int db_string_to_time_ex(const char *str, int str_len, DB_TIME *time)
Definition: db_date.c:3708
static const char * parse_datetime(const char *buf, int buf_len, DB_DATETIME *datetime)
Definition: db_date.c:3577
unsigned int DB_TIME
Definition: dbtype_def.h:754
void db_date_locale_init(void)
Definition: db_date.c:1531
unsigned int DB_DATE
Definition: dbtype_def.h:771
void julian_decode(int jul, int *monthp, int *dayp, int *yearp, int *weekp)
Definition: db_date.c:196
int db_string_to_datetimeltz(const char *str, DB_DATETIME *datetime)
Definition: db_date.c:4555
#define DB_BIGINT_MIN
Definition: dbtype_def.h:641
#define strlen(s1)
Definition: intl_support.c:43
int db_datetime_encode(DB_DATETIME *datetime, int month, int day, int year, int hour, int minute, int second, int millisecond)
Definition: db_date.c:4597
int intl_mbs_ncasecmp(const char *mbs1, const char *mbs2, size_t n)
Definition: intl_support.c:441
unsigned int date
Definition: dbtype_def.h:776
int tz_create_timestamptz(const DB_DATE *date, const DB_TIME *time, const char *tz_str, const int tz_size, const TZ_REGION *default_tz_region, DB_TIMESTAMPTZ *ts_tz, const char **end_tz_str)
Definition: tz_support.c:1435
void er_clear(void)
static int get_current_year(void)
Definition: db_date.c:1100
void db_timestamp_decode_utc(const DB_TIMESTAMP *utime, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:781
static int local_am_strlen
Definition: db_date.c:72
int i
Definition: dynamic_load.c:954
int db_timestamp_encode(DB_TIMESTAMP *utime, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:579
int db_add_weeks_and_days_to_date(int *day, int *month, int *year, int weeks, int day_week)
Definition: db_date.c:5009
void db_date_decode(const DB_DATE *date, int *monthp, int *dayp, int *yearp)
Definition: db_date.c:338
#define YBIAS
Definition: db_date.c:56
int db_timestamp_decode_w_reg(const DB_TIMESTAMP *utime, const TZ_REGION *tz_region, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:828
const TZ_REGION * tz_get_utc_tz_region(void)
Definition: tz_support.c:828
static char const * parse_timedate_separated(char const *str, char const *strend, DB_DATE *date, unsigned int *mtime, char const **syntax_check, bool *has_explicit_msec)
Definition: db_date.c:2820
static char const * parse_explicit_mtime_separated(char const *str, char const *strend, unsigned int *mtime, char const **syntax_check, bool *has_explicit_msec)
Definition: db_date.c:2122
static void decode_time(int timeval, int *hourp, int *minutep, int *secondp)
Definition: db_date.c:401
int db_string_to_timestamptz(const char *str, DB_TIMESTAMPTZ *ts_tz, bool *has_zone)
Definition: db_date.c:3894
static void decode_mtime(int mtimeval, int *hourp, int *minutep, int *secondp, int *millisecondp)
Definition: db_date.c:4189
void db_time_decode(DB_TIME *timeval, int *hourp, int *minutep, int *secondp)
Definition: db_date.c:432
int db_string_to_date_ex(const char *str, int str_len, DB_DATE *date)
Definition: db_date.c:3661
int tz_create_session_tzid_for_timestamp(const DB_UTIME *src_ts, TZ_ID *tz_id)
Definition: tz_support.c:1068
#define MMDDYYYY
Definition: db_date.c:58
int day_of_week(int jul_day)
Definition: db_date.c:176
int db_string_to_datetimeltz_ex(const char *str, int str_len, DB_DATETIME *datetime)
Definition: db_date.c:4533
void db_localdatetime_msec(time_t *epoch_time, int millisecond, DB_DATETIME *datetime)
Definition: db_date.c:1044
int db_string_to_date(const char *str, DB_DATE *date)
Definition: db_date.c:3693
int db_get_day_of_year(int year, int month, int day)
Definition: db_date.c:4697
void db_localtime(time_t *epoch_time, DB_DATE *date, DB_TIME *timeval)
Definition: db_date.c:1000
const char ** p
Definition: dynamic_load.c:945
unsigned int time
Definition: dbtype_def.h:777
int db_datetimeltz_to_string(char *buf, int bufsize, DB_DATETIME *dt)
Definition: db_date.c:4350
int char_isalpha(int c)
Definition: chartype.c:61
int db_date_parse_datetime_parts(char const *str, int str_len, DB_DATETIME *datetime, bool *has_explicit_time, bool *has_explicit_msec, bool *fits_as_timestamp, char const **endp)
Definition: db_date.c:3176
#define TZ_IS_UTC_TZ_REGION(r)
Definition: tz_support.h:122