PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
datetime.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * datetime.c
4  * Support functions for date/time types.
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/utils/adt/datetime.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <ctype.h>
18 #include <float.h>
19 #include <limits.h>
20 #include <math.h>
21 
22 #include "access/htup_details.h"
23 #include "access/xact.h"
24 #include "catalog/pg_type.h"
25 #include "funcapi.h"
26 #include "miscadmin.h"
27 #include "nodes/nodeFuncs.h"
28 #include "utils/builtins.h"
29 #include "utils/date.h"
30 #include "utils/datetime.h"
31 #include "utils/memutils.h"
32 #include "utils/tzparser.h"
33 
34 
35 static int DecodeNumber(int flen, char *field, bool haveTextMonth,
36  int fmask, int *tmask,
37  struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
38 static int DecodeNumberField(int len, char *str,
39  int fmask, int *tmask,
40  struct pg_tm * tm, fsec_t *fsec, bool *is2digits);
41 static int DecodeTime(char *str, int fmask, int range,
42  int *tmask, struct pg_tm * tm, fsec_t *fsec);
43 static const datetkn *datebsearch(const char *key, const datetkn *base, int nel);
44 static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
45  struct pg_tm * tm);
46 static char *AppendSeconds(char *cp, int sec, fsec_t fsec,
47  int precision, bool fillzeros);
48 static void AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec,
49  int scale);
50 static void AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec,
51  int scale);
52 static int DetermineTimeZoneOffsetInternal(struct pg_tm * tm, pg_tz *tzp,
53  pg_time_t *tp);
55  const char *abbr, pg_tz *tzp,
56  int *offset, int *isdst);
57 static pg_tz *FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp);
58 
59 
60 const int day_tab[2][13] =
61 {
62  {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0},
63  {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0}
64 };
65 
66 const char *const months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
67 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
68 
69 const char *const days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
70 "Thursday", "Friday", "Saturday", NULL};
71 
72 
73 /*****************************************************************************
74  * PRIVATE ROUTINES *
75  *****************************************************************************/
76 
77 /*
78  * datetktbl holds date/time keywords.
79  *
80  * Note that this table must be strictly alphabetically ordered to allow an
81  * O(ln(N)) search algorithm to be used.
82  *
83  * The token field must be NUL-terminated; we truncate entries to TOKMAXLEN
84  * characters to fit.
85  *
86  * The static table contains no TZ, DTZ, or DYNTZ entries; rather those
87  * are loaded from configuration files and stored in zoneabbrevtbl, whose
88  * abbrevs[] field has the same format as the static datetktbl.
89  */
90 static const datetkn datetktbl[] = {
91  /* token, type, value */
92  {EARLY, RESERV, DTK_EARLY}, /* "-infinity" reserved for "early time" */
93  {DA_D, ADBC, AD}, /* "ad" for years > 0 */
94  {"allballs", RESERV, DTK_ZULU}, /* 00:00:00 */
95  {"am", AMPM, AM},
96  {"apr", MONTH, 4},
97  {"april", MONTH, 4},
98  {"at", IGNORE_DTF, 0}, /* "at" (throwaway) */
99  {"aug", MONTH, 8},
100  {"august", MONTH, 8},
101  {DB_C, ADBC, BC}, /* "bc" for years <= 0 */
102  {DCURRENT, RESERV, DTK_CURRENT}, /* "current" is always now */
103  {"d", UNITS, DTK_DAY}, /* "day of month" for ISO input */
104  {"dec", MONTH, 12},
105  {"december", MONTH, 12},
106  {"dow", UNITS, DTK_DOW}, /* day of week */
107  {"doy", UNITS, DTK_DOY}, /* day of year */
108  {"dst", DTZMOD, SECS_PER_HOUR},
109  {EPOCH, RESERV, DTK_EPOCH}, /* "epoch" reserved for system epoch time */
110  {"feb", MONTH, 2},
111  {"february", MONTH, 2},
112  {"fri", DOW, 5},
113  {"friday", DOW, 5},
114  {"h", UNITS, DTK_HOUR}, /* "hour" */
115  {LATE, RESERV, DTK_LATE}, /* "infinity" reserved for "late time" */
116  {INVALID, RESERV, DTK_INVALID}, /* "invalid" reserved for bad time */
117  {"isodow", UNITS, DTK_ISODOW}, /* ISO day of week, Sunday == 7 */
118  {"isoyear", UNITS, DTK_ISOYEAR}, /* year in terms of the ISO week date */
119  {"j", UNITS, DTK_JULIAN},
120  {"jan", MONTH, 1},
121  {"january", MONTH, 1},
122  {"jd", UNITS, DTK_JULIAN},
123  {"jul", MONTH, 7},
124  {"julian", UNITS, DTK_JULIAN},
125  {"july", MONTH, 7},
126  {"jun", MONTH, 6},
127  {"june", MONTH, 6},
128  {"m", UNITS, DTK_MONTH}, /* "month" for ISO input */
129  {"mar", MONTH, 3},
130  {"march", MONTH, 3},
131  {"may", MONTH, 5},
132  {"mm", UNITS, DTK_MINUTE}, /* "minute" for ISO input */
133  {"mon", DOW, 1},
134  {"monday", DOW, 1},
135  {"nov", MONTH, 11},
136  {"november", MONTH, 11},
137  {NOW, RESERV, DTK_NOW}, /* current transaction time */
138  {"oct", MONTH, 10},
139  {"october", MONTH, 10},
140  {"on", IGNORE_DTF, 0}, /* "on" (throwaway) */
141  {"pm", AMPM, PM},
142  {"s", UNITS, DTK_SECOND}, /* "seconds" for ISO input */
143  {"sat", DOW, 6},
144  {"saturday", DOW, 6},
145  {"sep", MONTH, 9},
146  {"sept", MONTH, 9},
147  {"september", MONTH, 9},
148  {"sun", DOW, 0},
149  {"sunday", DOW, 0},
150  {"t", ISOTIME, DTK_TIME}, /* Filler for ISO time fields */
151  {"thu", DOW, 4},
152  {"thur", DOW, 4},
153  {"thurs", DOW, 4},
154  {"thursday", DOW, 4},
155  {TODAY, RESERV, DTK_TODAY}, /* midnight */
156  {TOMORROW, RESERV, DTK_TOMORROW}, /* tomorrow midnight */
157  {"tue", DOW, 2},
158  {"tues", DOW, 2},
159  {"tuesday", DOW, 2},
160  {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
161  {"wed", DOW, 3},
162  {"wednesday", DOW, 3},
163  {"weds", DOW, 3},
164  {"y", UNITS, DTK_YEAR}, /* "year" for ISO input */
165  {YESTERDAY, RESERV, DTK_YESTERDAY} /* yesterday midnight */
166 };
167 
168 static int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
169 
170 /*
171  * deltatktbl: same format as datetktbl, but holds keywords used to represent
172  * time units (eg, for intervals, and for EXTRACT).
173  */
174 static const datetkn deltatktbl[] = {
175  /* token, type, value */
176  {"@", IGNORE_DTF, 0}, /* postgres relative prefix */
177  {DAGO, AGO, 0}, /* "ago" indicates negative time offset */
178  {"c", UNITS, DTK_CENTURY}, /* "century" relative */
179  {"cent", UNITS, DTK_CENTURY}, /* "century" relative */
180  {"centuries", UNITS, DTK_CENTURY}, /* "centuries" relative */
181  {DCENTURY, UNITS, DTK_CENTURY}, /* "century" relative */
182  {"d", UNITS, DTK_DAY}, /* "day" relative */
183  {DDAY, UNITS, DTK_DAY}, /* "day" relative */
184  {"days", UNITS, DTK_DAY}, /* "days" relative */
185  {"dec", UNITS, DTK_DECADE}, /* "decade" relative */
186  {DDECADE, UNITS, DTK_DECADE}, /* "decade" relative */
187  {"decades", UNITS, DTK_DECADE}, /* "decades" relative */
188  {"decs", UNITS, DTK_DECADE}, /* "decades" relative */
189  {"h", UNITS, DTK_HOUR}, /* "hour" relative */
190  {DHOUR, UNITS, DTK_HOUR}, /* "hour" relative */
191  {"hours", UNITS, DTK_HOUR}, /* "hours" relative */
192  {"hr", UNITS, DTK_HOUR}, /* "hour" relative */
193  {"hrs", UNITS, DTK_HOUR}, /* "hours" relative */
194  {INVALID, RESERV, DTK_INVALID}, /* reserved for invalid time */
195  {"m", UNITS, DTK_MINUTE}, /* "minute" relative */
196  {"microsecon", UNITS, DTK_MICROSEC}, /* "microsecond" relative */
197  {"mil", UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
198  {"millennia", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */
199  {DMILLENNIUM, UNITS, DTK_MILLENNIUM}, /* "millennium" relative */
200  {"millisecon", UNITS, DTK_MILLISEC}, /* relative */
201  {"mils", UNITS, DTK_MILLENNIUM}, /* "millennia" relative */
202  {"min", UNITS, DTK_MINUTE}, /* "minute" relative */
203  {"mins", UNITS, DTK_MINUTE}, /* "minutes" relative */
204  {DMINUTE, UNITS, DTK_MINUTE}, /* "minute" relative */
205  {"minutes", UNITS, DTK_MINUTE}, /* "minutes" relative */
206  {"mon", UNITS, DTK_MONTH}, /* "months" relative */
207  {"mons", UNITS, DTK_MONTH}, /* "months" relative */
208  {DMONTH, UNITS, DTK_MONTH}, /* "month" relative */
209  {"months", UNITS, DTK_MONTH},
210  {"ms", UNITS, DTK_MILLISEC},
211  {"msec", UNITS, DTK_MILLISEC},
213  {"mseconds", UNITS, DTK_MILLISEC},
214  {"msecs", UNITS, DTK_MILLISEC},
215  {"qtr", UNITS, DTK_QUARTER}, /* "quarter" relative */
216  {DQUARTER, UNITS, DTK_QUARTER}, /* "quarter" relative */
217  {"s", UNITS, DTK_SECOND},
218  {"sec", UNITS, DTK_SECOND},
220  {"seconds", UNITS, DTK_SECOND},
221  {"secs", UNITS, DTK_SECOND},
222  {DTIMEZONE, UNITS, DTK_TZ}, /* "timezone" time offset */
223  {"timezone_h", UNITS, DTK_TZ_HOUR}, /* timezone hour units */
224  {"timezone_m", UNITS, DTK_TZ_MINUTE}, /* timezone minutes units */
225  {"undefined", RESERV, DTK_INVALID}, /* pre-v6.1 invalid time */
226  {"us", UNITS, DTK_MICROSEC}, /* "microsecond" relative */
227  {"usec", UNITS, DTK_MICROSEC}, /* "microsecond" relative */
228  {DMICROSEC, UNITS, DTK_MICROSEC}, /* "microsecond" relative */
229  {"useconds", UNITS, DTK_MICROSEC}, /* "microseconds" relative */
230  {"usecs", UNITS, DTK_MICROSEC}, /* "microseconds" relative */
231  {"w", UNITS, DTK_WEEK}, /* "week" relative */
232  {DWEEK, UNITS, DTK_WEEK}, /* "week" relative */
233  {"weeks", UNITS, DTK_WEEK}, /* "weeks" relative */
234  {"y", UNITS, DTK_YEAR}, /* "year" relative */
235  {DYEAR, UNITS, DTK_YEAR}, /* "year" relative */
236  {"years", UNITS, DTK_YEAR}, /* "years" relative */
237  {"yr", UNITS, DTK_YEAR}, /* "year" relative */
238  {"yrs", UNITS, DTK_YEAR} /* "years" relative */
239 };
240 
241 static int szdeltatktbl = sizeof deltatktbl / sizeof deltatktbl[0];
242 
244 
245 /* Caches of recent lookup results in the above tables */
246 
247 static const datetkn *datecache[MAXDATEFIELDS] = {NULL};
248 
250 
252 
253 
254 /*
255  * strtoint --- just like strtol, but returns int not long
256  */
257 static int
258 strtoint(const char *nptr, char **endptr, int base)
259 {
260  long val;
261 
262  val = strtol(nptr, endptr, base);
263 #ifdef HAVE_LONG_INT_64
264  if (val != (long) ((int32) val))
265  errno = ERANGE;
266 #endif
267  return (int) val;
268 }
269 
270 
271 /*
272  * Calendar time to Julian date conversions.
273  * Julian date is commonly used in astronomical applications,
274  * since it is numerically accurate and computationally simple.
275  * The algorithms here will accurately convert between Julian day
276  * and calendar date for all non-negative Julian days
277  * (i.e. from Nov 24, -4713 on).
278  *
279  * Rewritten to eliminate overflow problems. This now allows the
280  * routines to work correctly for all Julian day counts from
281  * 0 to 2147483647 (Nov 24, -4713 to Jun 3, 5874898) assuming
282  * a 32-bit integer. Longer types should also work to the limits
283  * of their precision.
284  *
285  * Actually, date2j() will work sanely, in the sense of producing
286  * valid negative Julian dates, significantly before Nov 24, -4713.
287  * We rely on it to do so back to Nov 1, -4713; see IS_VALID_JULIAN()
288  * and associated commentary in timestamp.h.
289  */
290 
291 int
292 date2j(int y, int m, int d)
293 {
294  int julian;
295  int century;
296 
297  if (m > 2)
298  {
299  m += 1;
300  y += 4800;
301  }
302  else
303  {
304  m += 13;
305  y += 4799;
306  }
307 
308  century = y / 100;
309  julian = y * 365 - 32167;
310  julian += y / 4 - century + century / 4;
311  julian += 7834 * m / 256 + d;
312 
313  return julian;
314 } /* date2j() */
315 
316 void
317 j2date(int jd, int *year, int *month, int *day)
318 {
319  unsigned int julian;
320  unsigned int quad;
321  unsigned int extra;
322  int y;
323 
324  julian = jd;
325  julian += 32044;
326  quad = julian / 146097;
327  extra = (julian - quad * 146097) * 4 + 3;
328  julian += 60 + quad * 3 + extra / 146097;
329  quad = julian / 1461;
330  julian -= quad * 1461;
331  y = julian * 4 / 1461;
332  julian = ((y != 0) ? ((julian + 305) % 365) : ((julian + 306) % 366))
333  + 123;
334  y += quad * 4;
335  *year = y - 4800;
336  quad = julian * 2141 / 65536;
337  *day = julian - 7834 * quad / 256;
338  *month = (quad + 10) % MONTHS_PER_YEAR + 1;
339 
340  return;
341 } /* j2date() */
342 
343 
344 /*
345  * j2day - convert Julian date to day-of-week (0..6 == Sun..Sat)
346  *
347  * Note: various places use the locution j2day(date - 1) to produce a
348  * result according to the convention 0..6 = Mon..Sun. This is a bit of
349  * a crock, but will work as long as the computation here is just a modulo.
350  */
351 int
353 {
354  date += 1;
355  date %= 7;
356  /* Cope if division truncates towards zero, as it probably does */
357  if (date < 0)
358  date += 7;
359 
360  return date;
361 } /* j2day() */
362 
363 
364 /*
365  * GetCurrentDateTime()
366  *
367  * Get the transaction start time ("now()") broken down as a struct pg_tm.
368  */
369 void
371 {
372  int tz;
373  fsec_t fsec;
374 
376  NULL, NULL);
377  /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
378 }
379 
380 /*
381  * GetCurrentTimeUsec()
382  *
383  * Get the transaction start time ("now()") broken down as a struct pg_tm,
384  * including fractional seconds and timezone offset.
385  */
386 void
387 GetCurrentTimeUsec(struct pg_tm * tm, fsec_t *fsec, int *tzp)
388 {
389  int tz;
390 
392  NULL, NULL);
393  /* Note: don't pass NULL tzp to timestamp2tm; affects behavior */
394  if (tzp != NULL)
395  *tzp = tz;
396 }
397 
398 
399 /*
400  * Append seconds and fractional seconds (if any) at *cp.
401  *
402  * precision is the max number of fraction digits, fillzeros says to
403  * pad to two integral-seconds digits.
404  *
405  * Returns a pointer to the new end of string. No NUL terminator is put
406  * there; callers are responsible for NUL terminating str themselves.
407  *
408  * Note that any sign is stripped from the input seconds values.
409  */
410 static char *
411 AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
412 {
413  Assert(precision >= 0);
414 
415  if (fillzeros)
416  cp = pg_ltostr_zeropad(cp, Abs(sec), 2);
417  else
418  cp = pg_ltostr(cp, Abs(sec));
419 
420  /* fsec_t is just an int32 */
421  if (fsec != 0)
422  {
423  int32 value = Abs(fsec);
424  char *end = &cp[precision + 1];
425  bool gotnonzero = false;
426 
427  *cp++ = '.';
428 
429  /*
430  * Append the fractional seconds part. Note that we don't want any
431  * trailing zeros here, so since we're building the number in reverse
432  * we'll skip appending zeros until we've output a non-zero digit.
433  */
434  while (precision--)
435  {
436  int32 oldval = value;
437  int32 remainder;
438 
439  value /= 10;
440  remainder = oldval - value * 10;
441 
442  /* check if we got a non-zero */
443  if (remainder)
444  gotnonzero = true;
445 
446  if (gotnonzero)
447  cp[precision] = '0' + remainder;
448  else
449  end = &cp[precision];
450  }
451 
452  /*
453  * If we still have a non-zero value then precision must have not been
454  * enough to print the number. We punt the problem to pg_ltostr(),
455  * which will generate a correct answer in the minimum valid width.
456  */
457  if (value)
458  return pg_ltostr(cp, Abs(fsec));
459 
460  return end;
461  }
462  else
463  return cp;
464 }
465 
466 
467 /*
468  * Variant of above that's specialized to timestamp case.
469  *
470  * Returns a pointer to the new end of string. No NUL terminator is put
471  * there; callers are responsible for NUL terminating str themselves.
472  */
473 static char *
474 AppendTimestampSeconds(char *cp, struct pg_tm * tm, fsec_t fsec)
475 {
476  return AppendSeconds(cp, tm->tm_sec, fsec, MAX_TIMESTAMP_PRECISION, true);
477 }
478 
479 /*
480  * Multiply frac by scale (to produce seconds) and add to *tm & *fsec.
481  * We assume the input frac is less than 1 so overflow is not an issue.
482  */
483 static void
484 AdjustFractSeconds(double frac, struct pg_tm * tm, fsec_t *fsec, int scale)
485 {
486  int sec;
487 
488  if (frac == 0)
489  return;
490  frac *= scale;
491  sec = (int) frac;
492  tm->tm_sec += sec;
493  frac -= sec;
494  *fsec += rint(frac * 1000000);
495 }
496 
497 /* As above, but initial scale produces days */
498 static void
499 AdjustFractDays(double frac, struct pg_tm * tm, fsec_t *fsec, int scale)
500 {
501  int extra_days;
502 
503  if (frac == 0)
504  return;
505  frac *= scale;
506  extra_days = (int) frac;
507  tm->tm_mday += extra_days;
508  frac -= extra_days;
509  AdjustFractSeconds(frac, tm, fsec, SECS_PER_DAY);
510 }
511 
512 /* Fetch a fractional-second value with suitable error checking */
513 static int
515 {
516  double frac;
517 
518  /* Caller should always pass the start of the fraction part */
519  Assert(*cp == '.');
520  errno = 0;
521  frac = strtod(cp, &cp);
522  /* check for parse failure */
523  if (*cp != '\0' || errno != 0)
524  return DTERR_BAD_FORMAT;
525  *fsec = rint(frac * 1000000);
526  return 0;
527 }
528 
529 
530 /* ParseDateTime()
531  * Break string into tokens based on a date/time context.
532  * Returns 0 if successful, DTERR code if bogus input detected.
533  *
534  * timestr - the input string
535  * workbuf - workspace for field string storage. This must be
536  * larger than the largest legal input for this datetime type --
537  * some additional space will be needed to NUL terminate fields.
538  * buflen - the size of workbuf
539  * field[] - pointers to field strings are returned in this array
540  * ftype[] - field type indicators are returned in this array
541  * maxfields - dimensions of the above two arrays
542  * *numfields - set to the actual number of fields detected
543  *
544  * The fields extracted from the input are stored as separate,
545  * null-terminated strings in the workspace at workbuf. Any text is
546  * converted to lower case.
547  *
548  * Several field types are assigned:
549  * DTK_NUMBER - digits and (possibly) a decimal point
550  * DTK_DATE - digits and two delimiters, or digits and text
551  * DTK_TIME - digits, colon delimiters, and possibly a decimal point
552  * DTK_STRING - text (no digits or punctuation)
553  * DTK_SPECIAL - leading "+" or "-" followed by text
554  * DTK_TZ - leading "+" or "-" followed by digits (also eats ':', '.', '-')
555  *
556  * Note that some field types can hold unexpected items:
557  * DTK_NUMBER can hold date fields (yy.ddd)
558  * DTK_STRING can hold months (January) and time zones (PST)
559  * DTK_DATE can hold time zone names (America/New_York, GMT-8)
560  */
561 int
562 ParseDateTime(const char *timestr, char *workbuf, size_t buflen,
563  char **field, int *ftype, int maxfields, int *numfields)
564 {
565  int nf = 0;
566  const char *cp = timestr;
567  char *bufp = workbuf;
568  const char *bufend = workbuf + buflen;
569 
570  /*
571  * Set the character pointed-to by "bufptr" to "newchar", and increment
572  * "bufptr". "end" gives the end of the buffer -- we return an error if
573  * there is no space left to append a character to the buffer. Note that
574  * "bufptr" is evaluated twice.
575  */
576 #define APPEND_CHAR(bufptr, end, newchar) \
577  do \
578  { \
579  if (((bufptr) + 1) >= (end)) \
580  return DTERR_BAD_FORMAT; \
581  *(bufptr)++ = newchar; \
582  } while (0)
583 
584  /* outer loop through fields */
585  while (*cp != '\0')
586  {
587  /* Ignore spaces between fields */
588  if (isspace((unsigned char) *cp))
589  {
590  cp++;
591  continue;
592  }
593 
594  /* Record start of current field */
595  if (nf >= maxfields)
596  return DTERR_BAD_FORMAT;
597  field[nf] = bufp;
598 
599  /* leading digit? then date or time */
600  if (isdigit((unsigned char) *cp))
601  {
602  APPEND_CHAR(bufp, bufend, *cp++);
603  while (isdigit((unsigned char) *cp))
604  APPEND_CHAR(bufp, bufend, *cp++);
605 
606  /* time field? */
607  if (*cp == ':')
608  {
609  ftype[nf] = DTK_TIME;
610  APPEND_CHAR(bufp, bufend, *cp++);
611  while (isdigit((unsigned char) *cp) ||
612  (*cp == ':') || (*cp == '.'))
613  APPEND_CHAR(bufp, bufend, *cp++);
614  }
615  /* date field? allow embedded text month */
616  else if (*cp == '-' || *cp == '/' || *cp == '.')
617  {
618  /* save delimiting character to use later */
619  char delim = *cp;
620 
621  APPEND_CHAR(bufp, bufend, *cp++);
622  /* second field is all digits? then no embedded text month */
623  if (isdigit((unsigned char) *cp))
624  {
625  ftype[nf] = ((delim == '.') ? DTK_NUMBER : DTK_DATE);
626  while (isdigit((unsigned char) *cp))
627  APPEND_CHAR(bufp, bufend, *cp++);
628 
629  /*
630  * insist that the delimiters match to get a three-field
631  * date.
632  */
633  if (*cp == delim)
634  {
635  ftype[nf] = DTK_DATE;
636  APPEND_CHAR(bufp, bufend, *cp++);
637  while (isdigit((unsigned char) *cp) || *cp == delim)
638  APPEND_CHAR(bufp, bufend, *cp++);
639  }
640  }
641  else
642  {
643  ftype[nf] = DTK_DATE;
644  while (isalnum((unsigned char) *cp) || *cp == delim)
645  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
646  }
647  }
648 
649  /*
650  * otherwise, number only and will determine year, month, day, or
651  * concatenated fields later...
652  */
653  else
654  ftype[nf] = DTK_NUMBER;
655  }
656  /* Leading decimal point? Then fractional seconds... */
657  else if (*cp == '.')
658  {
659  APPEND_CHAR(bufp, bufend, *cp++);
660  while (isdigit((unsigned char) *cp))
661  APPEND_CHAR(bufp, bufend, *cp++);
662 
663  ftype[nf] = DTK_NUMBER;
664  }
665 
666  /*
667  * text? then date string, month, day of week, special, or timezone
668  */
669  else if (isalpha((unsigned char) *cp))
670  {
671  bool is_date;
672 
673  ftype[nf] = DTK_STRING;
674  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
675  while (isalpha((unsigned char) *cp))
676  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
677 
678  /*
679  * Dates can have embedded '-', '/', or '.' separators. It could
680  * also be a timezone name containing embedded '/', '+', '-', '_',
681  * or ':' (but '_' or ':' can't be the first punctuation). If the
682  * next character is a digit or '+', we need to check whether what
683  * we have so far is a recognized non-timezone keyword --- if so,
684  * don't believe that this is the start of a timezone.
685  */
686  is_date = false;
687  if (*cp == '-' || *cp == '/' || *cp == '.')
688  is_date = true;
689  else if (*cp == '+' || isdigit((unsigned char) *cp))
690  {
691  *bufp = '\0'; /* null-terminate current field value */
692  /* we need search only the core token table, not TZ names */
693  if (datebsearch(field[nf], datetktbl, szdatetktbl) == NULL)
694  is_date = true;
695  }
696  if (is_date)
697  {
698  ftype[nf] = DTK_DATE;
699  do
700  {
701  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
702  } while (*cp == '+' || *cp == '-' ||
703  *cp == '/' || *cp == '_' ||
704  *cp == '.' || *cp == ':' ||
705  isalnum((unsigned char) *cp));
706  }
707  }
708  /* sign? then special or numeric timezone */
709  else if (*cp == '+' || *cp == '-')
710  {
711  APPEND_CHAR(bufp, bufend, *cp++);
712  /* soak up leading whitespace */
713  while (isspace((unsigned char) *cp))
714  cp++;
715  /* numeric timezone? */
716  /* note that "DTK_TZ" could also be a signed float or yyyy-mm */
717  if (isdigit((unsigned char) *cp))
718  {
719  ftype[nf] = DTK_TZ;
720  APPEND_CHAR(bufp, bufend, *cp++);
721  while (isdigit((unsigned char) *cp) ||
722  *cp == ':' || *cp == '.' || *cp == '-')
723  APPEND_CHAR(bufp, bufend, *cp++);
724  }
725  /* special? */
726  else if (isalpha((unsigned char) *cp))
727  {
728  ftype[nf] = DTK_SPECIAL;
729  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
730  while (isalpha((unsigned char) *cp))
731  APPEND_CHAR(bufp, bufend, pg_tolower((unsigned char) *cp++));
732  }
733  /* otherwise something wrong... */
734  else
735  return DTERR_BAD_FORMAT;
736  }
737  /* ignore other punctuation but use as delimiter */
738  else if (ispunct((unsigned char) *cp))
739  {
740  cp++;
741  continue;
742  }
743  /* otherwise, something is not right... */
744  else
745  return DTERR_BAD_FORMAT;
746 
747  /* force in a delimiter after each field */
748  *bufp++ = '\0';
749  nf++;
750  }
751 
752  *numfields = nf;
753 
754  return 0;
755 }
756 
757 
758 /* DecodeDateTime()
759  * Interpret previously parsed fields for general date and time.
760  * Return 0 if full date, 1 if only time, and negative DTERR code if problems.
761  * (Currently, all callers treat 1 as an error return too.)
762  *
763  * External format(s):
764  * "<weekday> <month>-<day>-<year> <hour>:<minute>:<second>"
765  * "Fri Feb-7-1997 15:23:27"
766  * "Feb-7-1997 15:23:27"
767  * "2-7-1997 15:23:27"
768  * "1997-2-7 15:23:27"
769  * "1997.038 15:23:27" (day of year 1-366)
770  * Also supports input in compact time:
771  * "970207 152327"
772  * "97038 152327"
773  * "20011225T040506.789-07"
774  *
775  * Use the system-provided functions to get the current time zone
776  * if not specified in the input string.
777  *
778  * If the date is outside the range of pg_time_t (in practice that could only
779  * happen if pg_time_t is just 32 bits), then assume UTC time zone - thomas
780  * 1997-05-27
781  */
782 int
783 DecodeDateTime(char **field, int *ftype, int nf,
784  int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
785 {
786  int fmask = 0,
787  tmask,
788  type;
789  int ptype = 0; /* "prefix type" for ISO y2001m02d04 format */
790  int i;
791  int val;
792  int dterr;
793  int mer = HR24;
794  bool haveTextMonth = FALSE;
795  bool isjulian = FALSE;
796  bool is2digits = FALSE;
797  bool bc = FALSE;
798  pg_tz *namedTz = NULL;
799  pg_tz *abbrevTz = NULL;
800  pg_tz *valtz;
801  char *abbrev = NULL;
802  struct pg_tm cur_tm;
803 
804  /*
805  * We'll insist on at least all of the date fields, but initialize the
806  * remaining fields in case they are not set later...
807  */
808  *dtype = DTK_DATE;
809  tm->tm_hour = 0;
810  tm->tm_min = 0;
811  tm->tm_sec = 0;
812  *fsec = 0;
813  /* don't know daylight savings time status apriori */
814  tm->tm_isdst = -1;
815  if (tzp != NULL)
816  *tzp = 0;
817 
818  for (i = 0; i < nf; i++)
819  {
820  switch (ftype[i])
821  {
822  case DTK_DATE:
823 
824  /*
825  * Integral julian day with attached time zone? All other
826  * forms with JD will be separated into distinct fields, so we
827  * handle just this case here.
828  */
829  if (ptype == DTK_JULIAN)
830  {
831  char *cp;
832  int val;
833 
834  if (tzp == NULL)
835  return DTERR_BAD_FORMAT;
836 
837  errno = 0;
838  val = strtoint(field[i], &cp, 10);
839  if (errno == ERANGE || val < 0)
840  return DTERR_FIELD_OVERFLOW;
841 
842  j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
843  isjulian = TRUE;
844 
845  /* Get the time zone from the end of the string */
846  dterr = DecodeTimezone(cp, tzp);
847  if (dterr)
848  return dterr;
849 
850  tmask = DTK_DATE_M | DTK_TIME_M | DTK_M(TZ);
851  ptype = 0;
852  break;
853  }
854 
855  /*
856  * Already have a date? Then this might be a time zone name
857  * with embedded punctuation (e.g. "America/New_York") or a
858  * run-together time with trailing time zone (e.g. hhmmss-zz).
859  * - thomas 2001-12-25
860  *
861  * We consider it a time zone if we already have month & day.
862  * This is to allow the form "mmm dd hhmmss tz year", which
863  * we've historically accepted.
864  */
865  else if (ptype != 0 ||
866  ((fmask & (DTK_M(MONTH) | DTK_M(DAY))) ==
867  (DTK_M(MONTH) | DTK_M(DAY))))
868  {
869  /* No time zone accepted? Then quit... */
870  if (tzp == NULL)
871  return DTERR_BAD_FORMAT;
872 
873  if (isdigit((unsigned char) *field[i]) || ptype != 0)
874  {
875  char *cp;
876 
877  if (ptype != 0)
878  {
879  /* Sanity check; should not fail this test */
880  if (ptype != DTK_TIME)
881  return DTERR_BAD_FORMAT;
882  ptype = 0;
883  }
884 
885  /*
886  * Starts with a digit but we already have a time
887  * field? Then we are in trouble with a date and time
888  * already...
889  */
890  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
891  return DTERR_BAD_FORMAT;
892 
893  if ((cp = strchr(field[i], '-')) == NULL)
894  return DTERR_BAD_FORMAT;
895 
896  /* Get the time zone from the end of the string */
897  dterr = DecodeTimezone(cp, tzp);
898  if (dterr)
899  return dterr;
900  *cp = '\0';
901 
902  /*
903  * Then read the rest of the field as a concatenated
904  * time
905  */
906  dterr = DecodeNumberField(strlen(field[i]), field[i],
907  fmask,
908  &tmask, tm,
909  fsec, &is2digits);
910  if (dterr < 0)
911  return dterr;
912 
913  /*
914  * modify tmask after returning from
915  * DecodeNumberField()
916  */
917  tmask |= DTK_M(TZ);
918  }
919  else
920  {
921  namedTz = pg_tzset(field[i]);
922  if (!namedTz)
923  {
924  /*
925  * We should return an error code instead of
926  * ereport'ing directly, but then there is no way
927  * to report the bad time zone name.
928  */
929  ereport(ERROR,
930  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
931  errmsg("time zone \"%s\" not recognized",
932  field[i])));
933  }
934  /* we'll apply the zone setting below */
935  tmask = DTK_M(TZ);
936  }
937  }
938  else
939  {
940  dterr = DecodeDate(field[i], fmask,
941  &tmask, &is2digits, tm);
942  if (dterr)
943  return dterr;
944  }
945  break;
946 
947  case DTK_TIME:
948 
949  /*
950  * This might be an ISO time following a "t" field.
951  */
952  if (ptype != 0)
953  {
954  /* Sanity check; should not fail this test */
955  if (ptype != DTK_TIME)
956  return DTERR_BAD_FORMAT;
957  ptype = 0;
958  }
959  dterr = DecodeTime(field[i], fmask, INTERVAL_FULL_RANGE,
960  &tmask, tm, fsec);
961  if (dterr)
962  return dterr;
963 
964  /*
965  * Check upper limit on hours; other limits checked in
966  * DecodeTime()
967  */
968  /* test for > 24:00:00 */
969  if (tm->tm_hour > HOURS_PER_DAY ||
970  (tm->tm_hour == HOURS_PER_DAY &&
971  (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)))
972  return DTERR_FIELD_OVERFLOW;
973  break;
974 
975  case DTK_TZ:
976  {
977  int tz;
978 
979  if (tzp == NULL)
980  return DTERR_BAD_FORMAT;
981 
982  dterr = DecodeTimezone(field[i], &tz);
983  if (dterr)
984  return dterr;
985  *tzp = tz;
986  tmask = DTK_M(TZ);
987  }
988  break;
989 
990  case DTK_NUMBER:
991 
992  /*
993  * Was this an "ISO date" with embedded field labels? An
994  * example is "y2001m02d04" - thomas 2001-02-04
995  */
996  if (ptype != 0)
997  {
998  char *cp;
999  int val;
1000 
1001  errno = 0;
1002  val = strtoint(field[i], &cp, 10);
1003  if (errno == ERANGE)
1004  return DTERR_FIELD_OVERFLOW;
1005 
1006  /*
1007  * only a few kinds are allowed to have an embedded
1008  * decimal
1009  */
1010  if (*cp == '.')
1011  switch (ptype)
1012  {
1013  case DTK_JULIAN:
1014  case DTK_TIME:
1015  case DTK_SECOND:
1016  break;
1017  default:
1018  return DTERR_BAD_FORMAT;
1019  break;
1020  }
1021  else if (*cp != '\0')
1022  return DTERR_BAD_FORMAT;
1023 
1024  switch (ptype)
1025  {
1026  case DTK_YEAR:
1027  tm->tm_year = val;
1028  tmask = DTK_M(YEAR);
1029  break;
1030 
1031  case DTK_MONTH:
1032 
1033  /*
1034  * already have a month and hour? then assume
1035  * minutes
1036  */
1037  if ((fmask & DTK_M(MONTH)) != 0 &&
1038  (fmask & DTK_M(HOUR)) != 0)
1039  {
1040  tm->tm_min = val;
1041  tmask = DTK_M(MINUTE);
1042  }
1043  else
1044  {
1045  tm->tm_mon = val;
1046  tmask = DTK_M(MONTH);
1047  }
1048  break;
1049 
1050  case DTK_DAY:
1051  tm->tm_mday = val;
1052  tmask = DTK_M(DAY);
1053  break;
1054 
1055  case DTK_HOUR:
1056  tm->tm_hour = val;
1057  tmask = DTK_M(HOUR);
1058  break;
1059 
1060  case DTK_MINUTE:
1061  tm->tm_min = val;
1062  tmask = DTK_M(MINUTE);
1063  break;
1064 
1065  case DTK_SECOND:
1066  tm->tm_sec = val;
1067  tmask = DTK_M(SECOND);
1068  if (*cp == '.')
1069  {
1070  dterr = ParseFractionalSecond(cp, fsec);
1071  if (dterr)
1072  return dterr;
1073  tmask = DTK_ALL_SECS_M;
1074  }
1075  break;
1076 
1077  case DTK_TZ:
1078  tmask = DTK_M(TZ);
1079  dterr = DecodeTimezone(field[i], tzp);
1080  if (dterr)
1081  return dterr;
1082  break;
1083 
1084  case DTK_JULIAN:
1085  /* previous field was a label for "julian date" */
1086  if (val < 0)
1087  return DTERR_FIELD_OVERFLOW;
1088  tmask = DTK_DATE_M;
1089  j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1090  isjulian = TRUE;
1091 
1092  /* fractional Julian Day? */
1093  if (*cp == '.')
1094  {
1095  double time;
1096 
1097  errno = 0;
1098  time = strtod(cp, &cp);
1099  if (*cp != '\0' || errno != 0)
1100  return DTERR_BAD_FORMAT;
1101  time *= USECS_PER_DAY;
1102  dt2time(time,
1103  &tm->tm_hour, &tm->tm_min,
1104  &tm->tm_sec, fsec);
1105  tmask |= DTK_TIME_M;
1106  }
1107  break;
1108 
1109  case DTK_TIME:
1110  /* previous field was "t" for ISO time */
1111  dterr = DecodeNumberField(strlen(field[i]), field[i],
1112  (fmask | DTK_DATE_M),
1113  &tmask, tm,
1114  fsec, &is2digits);
1115  if (dterr < 0)
1116  return dterr;
1117  if (tmask != DTK_TIME_M)
1118  return DTERR_BAD_FORMAT;
1119  break;
1120 
1121  default:
1122  return DTERR_BAD_FORMAT;
1123  break;
1124  }
1125 
1126  ptype = 0;
1127  *dtype = DTK_DATE;
1128  }
1129  else
1130  {
1131  char *cp;
1132  int flen;
1133 
1134  flen = strlen(field[i]);
1135  cp = strchr(field[i], '.');
1136 
1137  /* Embedded decimal and no date yet? */
1138  if (cp != NULL && !(fmask & DTK_DATE_M))
1139  {
1140  dterr = DecodeDate(field[i], fmask,
1141  &tmask, &is2digits, tm);
1142  if (dterr)
1143  return dterr;
1144  }
1145  /* embedded decimal and several digits before? */
1146  else if (cp != NULL && flen - strlen(cp) > 2)
1147  {
1148  /*
1149  * Interpret as a concatenated date or time Set the
1150  * type field to allow decoding other fields later.
1151  * Example: 20011223 or 040506
1152  */
1153  dterr = DecodeNumberField(flen, field[i], fmask,
1154  &tmask, tm,
1155  fsec, &is2digits);
1156  if (dterr < 0)
1157  return dterr;
1158  }
1159 
1160  /*
1161  * Is this a YMD or HMS specification, or a year number?
1162  * YMD and HMS are required to be six digits or more, so
1163  * if it is 5 digits, it is a year. If it is six or more
1164  * more digits, we assume it is YMD or HMS unless no date
1165  * and no time values have been specified. This forces 6+
1166  * digit years to be at the end of the string, or to use
1167  * the ISO date specification.
1168  */
1169  else if (flen >= 6 && (!(fmask & DTK_DATE_M) ||
1170  !(fmask & DTK_TIME_M)))
1171  {
1172  dterr = DecodeNumberField(flen, field[i], fmask,
1173  &tmask, tm,
1174  fsec, &is2digits);
1175  if (dterr < 0)
1176  return dterr;
1177  }
1178  /* otherwise it is a single date/time field... */
1179  else
1180  {
1181  dterr = DecodeNumber(flen, field[i],
1182  haveTextMonth, fmask,
1183  &tmask, tm,
1184  fsec, &is2digits);
1185  if (dterr)
1186  return dterr;
1187  }
1188  }
1189  break;
1190 
1191  case DTK_STRING:
1192  case DTK_SPECIAL:
1193  /* timezone abbrevs take precedence over built-in tokens */
1194  type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
1195  if (type == UNKNOWN_FIELD)
1196  type = DecodeSpecial(i, field[i], &val);
1197  if (type == IGNORE_DTF)
1198  continue;
1199 
1200  tmask = DTK_M(type);
1201  switch (type)
1202  {
1203  case RESERV:
1204  switch (val)
1205  {
1206  case DTK_CURRENT:
1207  ereport(ERROR,
1208  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1209  errmsg("date/time value \"current\" is no longer supported")));
1210 
1211  return DTERR_BAD_FORMAT;
1212  break;
1213 
1214  case DTK_NOW:
1215  tmask = (DTK_DATE_M | DTK_TIME_M | DTK_M(TZ));
1216  *dtype = DTK_DATE;
1217  GetCurrentTimeUsec(tm, fsec, tzp);
1218  break;
1219 
1220  case DTK_YESTERDAY:
1221  tmask = DTK_DATE_M;
1222  *dtype = DTK_DATE;
1223  GetCurrentDateTime(&cur_tm);
1224  j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) - 1,
1225  &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1226  break;
1227 
1228  case DTK_TODAY:
1229  tmask = DTK_DATE_M;
1230  *dtype = DTK_DATE;
1231  GetCurrentDateTime(&cur_tm);
1232  tm->tm_year = cur_tm.tm_year;
1233  tm->tm_mon = cur_tm.tm_mon;
1234  tm->tm_mday = cur_tm.tm_mday;
1235  break;
1236 
1237  case DTK_TOMORROW:
1238  tmask = DTK_DATE_M;
1239  *dtype = DTK_DATE;
1240  GetCurrentDateTime(&cur_tm);
1241  j2date(date2j(cur_tm.tm_year, cur_tm.tm_mon, cur_tm.tm_mday) + 1,
1242  &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1243  break;
1244 
1245  case DTK_ZULU:
1246  tmask = (DTK_TIME_M | DTK_M(TZ));
1247  *dtype = DTK_DATE;
1248  tm->tm_hour = 0;
1249  tm->tm_min = 0;
1250  tm->tm_sec = 0;
1251  if (tzp != NULL)
1252  *tzp = 0;
1253  break;
1254 
1255  default:
1256  *dtype = val;
1257  }
1258 
1259  break;
1260 
1261  case MONTH:
1262 
1263  /*
1264  * already have a (numeric) month? then see if we can
1265  * substitute...
1266  */
1267  if ((fmask & DTK_M(MONTH)) && !haveTextMonth &&
1268  !(fmask & DTK_M(DAY)) && tm->tm_mon >= 1 &&
1269  tm->tm_mon <= 31)
1270  {
1271  tm->tm_mday = tm->tm_mon;
1272  tmask = DTK_M(DAY);
1273  }
1274  haveTextMonth = TRUE;
1275  tm->tm_mon = val;
1276  break;
1277 
1278  case DTZMOD:
1279 
1280  /*
1281  * daylight savings time modifier (solves "MET DST"
1282  * syntax)
1283  */
1284  tmask |= DTK_M(DTZ);
1285  tm->tm_isdst = 1;
1286  if (tzp == NULL)
1287  return DTERR_BAD_FORMAT;
1288  *tzp -= val;
1289  break;
1290 
1291  case DTZ:
1292 
1293  /*
1294  * set mask for TZ here _or_ check for DTZ later when
1295  * getting default timezone
1296  */
1297  tmask |= DTK_M(TZ);
1298  tm->tm_isdst = 1;
1299  if (tzp == NULL)
1300  return DTERR_BAD_FORMAT;
1301  *tzp = -val;
1302  break;
1303 
1304  case TZ:
1305  tm->tm_isdst = 0;
1306  if (tzp == NULL)
1307  return DTERR_BAD_FORMAT;
1308  *tzp = -val;
1309  break;
1310 
1311  case DYNTZ:
1312  tmask |= DTK_M(TZ);
1313  if (tzp == NULL)
1314  return DTERR_BAD_FORMAT;
1315  /* we'll determine the actual offset later */
1316  abbrevTz = valtz;
1317  abbrev = field[i];
1318  break;
1319 
1320  case AMPM:
1321  mer = val;
1322  break;
1323 
1324  case ADBC:
1325  bc = (val == BC);
1326  break;
1327 
1328  case DOW:
1329  tm->tm_wday = val;
1330  break;
1331 
1332  case UNITS:
1333  tmask = 0;
1334  ptype = val;
1335  break;
1336 
1337  case ISOTIME:
1338 
1339  /*
1340  * This is a filler field "t" indicating that the next
1341  * field is time. Try to verify that this is sensible.
1342  */
1343  tmask = 0;
1344 
1345  /* No preceding date? Then quit... */
1346  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1347  return DTERR_BAD_FORMAT;
1348 
1349  /***
1350  * We will need one of the following fields:
1351  * DTK_NUMBER should be hhmmss.fff
1352  * DTK_TIME should be hh:mm:ss.fff
1353  * DTK_DATE should be hhmmss-zz
1354  ***/
1355  if (i >= nf - 1 ||
1356  (ftype[i + 1] != DTK_NUMBER &&
1357  ftype[i + 1] != DTK_TIME &&
1358  ftype[i + 1] != DTK_DATE))
1359  return DTERR_BAD_FORMAT;
1360 
1361  ptype = val;
1362  break;
1363 
1364  case UNKNOWN_FIELD:
1365 
1366  /*
1367  * Before giving up and declaring error, check to see
1368  * if it is an all-alpha timezone name.
1369  */
1370  namedTz = pg_tzset(field[i]);
1371  if (!namedTz)
1372  return DTERR_BAD_FORMAT;
1373  /* we'll apply the zone setting below */
1374  tmask = DTK_M(TZ);
1375  break;
1376 
1377  default:
1378  return DTERR_BAD_FORMAT;
1379  }
1380  break;
1381 
1382  default:
1383  return DTERR_BAD_FORMAT;
1384  }
1385 
1386  if (tmask & fmask)
1387  return DTERR_BAD_FORMAT;
1388  fmask |= tmask;
1389  } /* end loop over fields */
1390 
1391  /* do final checking/adjustment of Y/M/D fields */
1392  dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
1393  if (dterr)
1394  return dterr;
1395 
1396  /* handle AM/PM */
1397  if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
1398  return DTERR_FIELD_OVERFLOW;
1399  if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
1400  tm->tm_hour = 0;
1401  else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
1402  tm->tm_hour += HOURS_PER_DAY / 2;
1403 
1404  /* do additional checking for full date specs... */
1405  if (*dtype == DTK_DATE)
1406  {
1407  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
1408  {
1409  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1410  return 1;
1411  return DTERR_BAD_FORMAT;
1412  }
1413 
1414  /*
1415  * If we had a full timezone spec, compute the offset (we could not do
1416  * it before, because we need the date to resolve DST status).
1417  */
1418  if (namedTz != NULL)
1419  {
1420  /* daylight savings time modifier disallowed with full TZ */
1421  if (fmask & DTK_M(DTZMOD))
1422  return DTERR_BAD_FORMAT;
1423 
1424  *tzp = DetermineTimeZoneOffset(tm, namedTz);
1425  }
1426 
1427  /*
1428  * Likewise, if we had a dynamic timezone abbreviation, resolve it
1429  * now.
1430  */
1431  if (abbrevTz != NULL)
1432  {
1433  /* daylight savings time modifier disallowed with dynamic TZ */
1434  if (fmask & DTK_M(DTZMOD))
1435  return DTERR_BAD_FORMAT;
1436 
1437  *tzp = DetermineTimeZoneAbbrevOffset(tm, abbrev, abbrevTz);
1438  }
1439 
1440  /* timezone not specified? then use session timezone */
1441  if (tzp != NULL && !(fmask & DTK_M(TZ)))
1442  {
1443  /*
1444  * daylight savings time modifier but no standard timezone? then
1445  * error
1446  */
1447  if (fmask & DTK_M(DTZMOD))
1448  return DTERR_BAD_FORMAT;
1449 
1451  }
1452  }
1453 
1454  return 0;
1455 }
1456 
1457 
1458 /* DetermineTimeZoneOffset()
1459  *
1460  * Given a struct pg_tm in which tm_year, tm_mon, tm_mday, tm_hour, tm_min,
1461  * and tm_sec fields are set, and a zic-style time zone definition, determine
1462  * the applicable GMT offset and daylight-savings status at that time.
1463  * Set the struct pg_tm's tm_isdst field accordingly, and return the GMT
1464  * offset as the function result.
1465  *
1466  * Note: if the date is out of the range we can deal with, we return zero
1467  * as the GMT offset and set tm_isdst = 0. We don't throw an error here,
1468  * though probably some higher-level code will.
1469  */
1470 int
1472 {
1473  pg_time_t t;
1474 
1475  return DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1476 }
1477 
1478 
1479 /* DetermineTimeZoneOffsetInternal()
1480  *
1481  * As above, but also return the actual UTC time imputed to the date/time
1482  * into *tp.
1483  *
1484  * In event of an out-of-range date, we punt by returning zero into *tp.
1485  * This is okay for the immediate callers but is a good reason for not
1486  * exposing this worker function globally.
1487  *
1488  * Note: it might seem that we should use mktime() for this, but bitter
1489  * experience teaches otherwise. This code is much faster than most versions
1490  * of mktime(), anyway.
1491  */
1492 static int
1494 {
1495  int date,
1496  sec;
1497  pg_time_t day,
1498  mytime,
1499  prevtime,
1500  boundary,
1501  beforetime,
1502  aftertime;
1503  long int before_gmtoff,
1504  after_gmtoff;
1505  int before_isdst,
1506  after_isdst;
1507  int res;
1508 
1509  /*
1510  * First, generate the pg_time_t value corresponding to the given
1511  * y/m/d/h/m/s taken as GMT time. If this overflows, punt and decide the
1512  * timezone is GMT. (For a valid Julian date, integer overflow should be
1513  * impossible with 64-bit pg_time_t, but let's check for safety.)
1514  */
1515  if (!IS_VALID_JULIAN(tm->tm_year, tm->tm_mon, tm->tm_mday))
1516  goto overflow;
1517  date = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday) - UNIX_EPOCH_JDATE;
1518 
1519  day = ((pg_time_t) date) * SECS_PER_DAY;
1520  if (day / SECS_PER_DAY != date)
1521  goto overflow;
1522  sec = tm->tm_sec + (tm->tm_min + tm->tm_hour * MINS_PER_HOUR) * SECS_PER_MINUTE;
1523  mytime = day + sec;
1524  /* since sec >= 0, overflow could only be from +day to -mytime */
1525  if (mytime < 0 && day > 0)
1526  goto overflow;
1527 
1528  /*
1529  * Find the DST time boundary just before or following the target time. We
1530  * assume that all zones have GMT offsets less than 24 hours, and that DST
1531  * boundaries can't be closer together than 48 hours, so backing up 24
1532  * hours and finding the "next" boundary will work.
1533  */
1534  prevtime = mytime - SECS_PER_DAY;
1535  if (mytime < 0 && prevtime > 0)
1536  goto overflow;
1537 
1538  res = pg_next_dst_boundary(&prevtime,
1539  &before_gmtoff, &before_isdst,
1540  &boundary,
1541  &after_gmtoff, &after_isdst,
1542  tzp);
1543  if (res < 0)
1544  goto overflow; /* failure? */
1545 
1546  if (res == 0)
1547  {
1548  /* Non-DST zone, life is simple */
1549  tm->tm_isdst = before_isdst;
1550  *tp = mytime - before_gmtoff;
1551  return -(int) before_gmtoff;
1552  }
1553 
1554  /*
1555  * Form the candidate pg_time_t values with local-time adjustment
1556  */
1557  beforetime = mytime - before_gmtoff;
1558  if ((before_gmtoff > 0 &&
1559  mytime < 0 && beforetime > 0) ||
1560  (before_gmtoff <= 0 &&
1561  mytime > 0 && beforetime < 0))
1562  goto overflow;
1563  aftertime = mytime - after_gmtoff;
1564  if ((after_gmtoff > 0 &&
1565  mytime < 0 && aftertime > 0) ||
1566  (after_gmtoff <= 0 &&
1567  mytime > 0 && aftertime < 0))
1568  goto overflow;
1569 
1570  /*
1571  * If both before or both after the boundary time, we know what to do. The
1572  * boundary time itself is considered to be after the transition, which
1573  * means we can accept aftertime == boundary in the second case.
1574  */
1575  if (beforetime < boundary && aftertime < boundary)
1576  {
1577  tm->tm_isdst = before_isdst;
1578  *tp = beforetime;
1579  return -(int) before_gmtoff;
1580  }
1581  if (beforetime > boundary && aftertime >= boundary)
1582  {
1583  tm->tm_isdst = after_isdst;
1584  *tp = aftertime;
1585  return -(int) after_gmtoff;
1586  }
1587 
1588  /*
1589  * It's an invalid or ambiguous time due to timezone transition. In a
1590  * spring-forward transition, prefer the "before" interpretation; in a
1591  * fall-back transition, prefer "after". (We used to define and implement
1592  * this test as "prefer the standard-time interpretation", but that rule
1593  * does not help to resolve the behavior when both times are reported as
1594  * standard time; which does happen, eg Europe/Moscow in Oct 2014.)
1595  */
1596  if (beforetime > aftertime)
1597  {
1598  tm->tm_isdst = before_isdst;
1599  *tp = beforetime;
1600  return -(int) before_gmtoff;
1601  }
1602  tm->tm_isdst = after_isdst;
1603  *tp = aftertime;
1604  return -(int) after_gmtoff;
1605 
1606 overflow:
1607  /* Given date is out of range, so assume UTC */
1608  tm->tm_isdst = 0;
1609  *tp = 0;
1610  return 0;
1611 }
1612 
1613 
1614 /* DetermineTimeZoneAbbrevOffset()
1615  *
1616  * Determine the GMT offset and DST flag to be attributed to a dynamic
1617  * time zone abbreviation, that is one whose meaning has changed over time.
1618  * *tm contains the local time at which the meaning should be determined,
1619  * and tm->tm_isdst receives the DST flag.
1620  *
1621  * This differs from the behavior of DetermineTimeZoneOffset() in that a
1622  * standard-time or daylight-time abbreviation forces use of the corresponding
1623  * GMT offset even when the zone was then in DS or standard time respectively.
1624  * (However, that happens only if we can match the given abbreviation to some
1625  * abbreviation that appears in the IANA timezone data. Otherwise, we fall
1626  * back to doing DetermineTimeZoneOffset().)
1627  */
1628 int
1629 DetermineTimeZoneAbbrevOffset(struct pg_tm * tm, const char *abbr, pg_tz *tzp)
1630 {
1631  pg_time_t t;
1632  int zone_offset;
1633  int abbr_offset;
1634  int abbr_isdst;
1635 
1636  /*
1637  * Compute the UTC time we want to probe at. (In event of overflow, we'll
1638  * probe at the epoch, which is a bit random but probably doesn't matter.)
1639  */
1640  zone_offset = DetermineTimeZoneOffsetInternal(tm, tzp, &t);
1641 
1642  /*
1643  * Try to match the abbreviation to something in the zone definition.
1644  */
1645  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1646  &abbr_offset, &abbr_isdst))
1647  {
1648  /* Success, so use the abbrev-specific answers. */
1649  tm->tm_isdst = abbr_isdst;
1650  return abbr_offset;
1651  }
1652 
1653  /*
1654  * No match, so use the answers we already got from
1655  * DetermineTimeZoneOffsetInternal.
1656  */
1657  return zone_offset;
1658 }
1659 
1660 
1661 /* DetermineTimeZoneAbbrevOffsetTS()
1662  *
1663  * As above but the probe time is specified as a TimestampTz (hence, UTC time),
1664  * and DST status is returned into *isdst rather than into tm->tm_isdst.
1665  */
1666 int
1668  pg_tz *tzp, int *isdst)
1669 {
1671  int zone_offset;
1672  int abbr_offset;
1673  int tz;
1674  struct pg_tm tm;
1675  fsec_t fsec;
1676 
1677  /*
1678  * If the abbrev matches anything in the zone data, this is pretty easy.
1679  */
1680  if (DetermineTimeZoneAbbrevOffsetInternal(t, abbr, tzp,
1681  &abbr_offset, isdst))
1682  return abbr_offset;
1683 
1684  /*
1685  * Else, break down the timestamp so we can use DetermineTimeZoneOffset.
1686  */
1687  if (timestamp2tm(ts, &tz, &tm, &fsec, NULL, tzp) != 0)
1688  ereport(ERROR,
1689  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
1690  errmsg("timestamp out of range")));
1691 
1692  zone_offset = DetermineTimeZoneOffset(&tm, tzp);
1693  *isdst = tm.tm_isdst;
1694  return zone_offset;
1695 }
1696 
1697 
1698 /* DetermineTimeZoneAbbrevOffsetInternal()
1699  *
1700  * Workhorse for above two functions: work from a pg_time_t probe instant.
1701  * On success, return GMT offset and DST status into *offset and *isdst.
1702  */
1703 static bool
1705  int *offset, int *isdst)
1706 {
1707  char upabbr[TZ_STRLEN_MAX + 1];
1708  unsigned char *p;
1709  long int gmtoff;
1710 
1711  /* We need to force the abbrev to upper case */
1712  strlcpy(upabbr, abbr, sizeof(upabbr));
1713  for (p = (unsigned char *) upabbr; *p; p++)
1714  *p = pg_toupper(*p);
1715 
1716  /* Look up the abbrev's meaning at this time in this zone */
1717  if (pg_interpret_timezone_abbrev(upabbr,
1718  &t,
1719  &gmtoff,
1720  isdst,
1721  tzp))
1722  {
1723  /* Change sign to agree with DetermineTimeZoneOffset() */
1724  *offset = (int) -gmtoff;
1725  return true;
1726  }
1727  return false;
1728 }
1729 
1730 
1731 /* DecodeTimeOnly()
1732  * Interpret parsed string as time fields only.
1733  * Returns 0 if successful, DTERR code if bogus input detected.
1734  *
1735  * Note that support for time zone is here for
1736  * SQL TIME WITH TIME ZONE, but it reveals
1737  * bogosity with SQL date/time standards, since
1738  * we must infer a time zone from current time.
1739  * - thomas 2000-03-10
1740  * Allow specifying date to get a better time zone,
1741  * if time zones are allowed. - thomas 2001-12-26
1742  */
1743 int
1744 DecodeTimeOnly(char **field, int *ftype, int nf,
1745  int *dtype, struct pg_tm * tm, fsec_t *fsec, int *tzp)
1746 {
1747  int fmask = 0,
1748  tmask,
1749  type;
1750  int ptype = 0; /* "prefix type" for ISO h04mm05s06 format */
1751  int i;
1752  int val;
1753  int dterr;
1754  bool isjulian = FALSE;
1755  bool is2digits = FALSE;
1756  bool bc = FALSE;
1757  int mer = HR24;
1758  pg_tz *namedTz = NULL;
1759  pg_tz *abbrevTz = NULL;
1760  char *abbrev = NULL;
1761  pg_tz *valtz;
1762 
1763  *dtype = DTK_TIME;
1764  tm->tm_hour = 0;
1765  tm->tm_min = 0;
1766  tm->tm_sec = 0;
1767  *fsec = 0;
1768  /* don't know daylight savings time status apriori */
1769  tm->tm_isdst = -1;
1770 
1771  if (tzp != NULL)
1772  *tzp = 0;
1773 
1774  for (i = 0; i < nf; i++)
1775  {
1776  switch (ftype[i])
1777  {
1778  case DTK_DATE:
1779 
1780  /*
1781  * Time zone not allowed? Then should not accept dates or time
1782  * zones no matter what else!
1783  */
1784  if (tzp == NULL)
1785  return DTERR_BAD_FORMAT;
1786 
1787  /* Under limited circumstances, we will accept a date... */
1788  if (i == 0 && nf >= 2 &&
1789  (ftype[nf - 1] == DTK_DATE || ftype[1] == DTK_TIME))
1790  {
1791  dterr = DecodeDate(field[i], fmask,
1792  &tmask, &is2digits, tm);
1793  if (dterr)
1794  return dterr;
1795  }
1796  /* otherwise, this is a time and/or time zone */
1797  else
1798  {
1799  if (isdigit((unsigned char) *field[i]))
1800  {
1801  char *cp;
1802 
1803  /*
1804  * Starts with a digit but we already have a time
1805  * field? Then we are in trouble with time already...
1806  */
1807  if ((fmask & DTK_TIME_M) == DTK_TIME_M)
1808  return DTERR_BAD_FORMAT;
1809 
1810  /*
1811  * Should not get here and fail. Sanity check only...
1812  */
1813  if ((cp = strchr(field[i], '-')) == NULL)
1814  return DTERR_BAD_FORMAT;
1815 
1816  /* Get the time zone from the end of the string */
1817  dterr = DecodeTimezone(cp, tzp);
1818  if (dterr)
1819  return dterr;
1820  *cp = '\0';
1821 
1822  /*
1823  * Then read the rest of the field as a concatenated
1824  * time
1825  */
1826  dterr = DecodeNumberField(strlen(field[i]), field[i],
1827  (fmask | DTK_DATE_M),
1828  &tmask, tm,
1829  fsec, &is2digits);
1830  if (dterr < 0)
1831  return dterr;
1832  ftype[i] = dterr;
1833 
1834  tmask |= DTK_M(TZ);
1835  }
1836  else
1837  {
1838  namedTz = pg_tzset(field[i]);
1839  if (!namedTz)
1840  {
1841  /*
1842  * We should return an error code instead of
1843  * ereport'ing directly, but then there is no way
1844  * to report the bad time zone name.
1845  */
1846  ereport(ERROR,
1847  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1848  errmsg("time zone \"%s\" not recognized",
1849  field[i])));
1850  }
1851  /* we'll apply the zone setting below */
1852  ftype[i] = DTK_TZ;
1853  tmask = DTK_M(TZ);
1854  }
1855  }
1856  break;
1857 
1858  case DTK_TIME:
1859  dterr = DecodeTime(field[i], (fmask | DTK_DATE_M),
1861  &tmask, tm, fsec);
1862  if (dterr)
1863  return dterr;
1864  break;
1865 
1866  case DTK_TZ:
1867  {
1868  int tz;
1869 
1870  if (tzp == NULL)
1871  return DTERR_BAD_FORMAT;
1872 
1873  dterr = DecodeTimezone(field[i], &tz);
1874  if (dterr)
1875  return dterr;
1876  *tzp = tz;
1877  tmask = DTK_M(TZ);
1878  }
1879  break;
1880 
1881  case DTK_NUMBER:
1882 
1883  /*
1884  * Was this an "ISO time" with embedded field labels? An
1885  * example is "h04m05s06" - thomas 2001-02-04
1886  */
1887  if (ptype != 0)
1888  {
1889  char *cp;
1890  int val;
1891 
1892  /* Only accept a date under limited circumstances */
1893  switch (ptype)
1894  {
1895  case DTK_JULIAN:
1896  case DTK_YEAR:
1897  case DTK_MONTH:
1898  case DTK_DAY:
1899  if (tzp == NULL)
1900  return DTERR_BAD_FORMAT;
1901  default:
1902  break;
1903  }
1904 
1905  errno = 0;
1906  val = strtoint(field[i], &cp, 10);
1907  if (errno == ERANGE)
1908  return DTERR_FIELD_OVERFLOW;
1909 
1910  /*
1911  * only a few kinds are allowed to have an embedded
1912  * decimal
1913  */
1914  if (*cp == '.')
1915  switch (ptype)
1916  {
1917  case DTK_JULIAN:
1918  case DTK_TIME:
1919  case DTK_SECOND:
1920  break;
1921  default:
1922  return DTERR_BAD_FORMAT;
1923  break;
1924  }
1925  else if (*cp != '\0')
1926  return DTERR_BAD_FORMAT;
1927 
1928  switch (ptype)
1929  {
1930  case DTK_YEAR:
1931  tm->tm_year = val;
1932  tmask = DTK_M(YEAR);
1933  break;
1934 
1935  case DTK_MONTH:
1936 
1937  /*
1938  * already have a month and hour? then assume
1939  * minutes
1940  */
1941  if ((fmask & DTK_M(MONTH)) != 0 &&
1942  (fmask & DTK_M(HOUR)) != 0)
1943  {
1944  tm->tm_min = val;
1945  tmask = DTK_M(MINUTE);
1946  }
1947  else
1948  {
1949  tm->tm_mon = val;
1950  tmask = DTK_M(MONTH);
1951  }
1952  break;
1953 
1954  case DTK_DAY:
1955  tm->tm_mday = val;
1956  tmask = DTK_M(DAY);
1957  break;
1958 
1959  case DTK_HOUR:
1960  tm->tm_hour = val;
1961  tmask = DTK_M(HOUR);
1962  break;
1963 
1964  case DTK_MINUTE:
1965  tm->tm_min = val;
1966  tmask = DTK_M(MINUTE);
1967  break;
1968 
1969  case DTK_SECOND:
1970  tm->tm_sec = val;
1971  tmask = DTK_M(SECOND);
1972  if (*cp == '.')
1973  {
1974  dterr = ParseFractionalSecond(cp, fsec);
1975  if (dterr)
1976  return dterr;
1977  tmask = DTK_ALL_SECS_M;
1978  }
1979  break;
1980 
1981  case DTK_TZ:
1982  tmask = DTK_M(TZ);
1983  dterr = DecodeTimezone(field[i], tzp);
1984  if (dterr)
1985  return dterr;
1986  break;
1987 
1988  case DTK_JULIAN:
1989  /* previous field was a label for "julian date" */
1990  if (val < 0)
1991  return DTERR_FIELD_OVERFLOW;
1992  tmask = DTK_DATE_M;
1993  j2date(val, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
1994  isjulian = TRUE;
1995 
1996  if (*cp == '.')
1997  {
1998  double time;
1999 
2000  errno = 0;
2001  time = strtod(cp, &cp);
2002  if (*cp != '\0' || errno != 0)
2003  return DTERR_BAD_FORMAT;
2004  time *= USECS_PER_DAY;
2005  dt2time(time,
2006  &tm->tm_hour, &tm->tm_min,
2007  &tm->tm_sec, fsec);
2008  tmask |= DTK_TIME_M;
2009  }
2010  break;
2011 
2012  case DTK_TIME:
2013  /* previous field was "t" for ISO time */
2014  dterr = DecodeNumberField(strlen(field[i]), field[i],
2015  (fmask | DTK_DATE_M),
2016  &tmask, tm,
2017  fsec, &is2digits);
2018  if (dterr < 0)
2019  return dterr;
2020  ftype[i] = dterr;
2021 
2022  if (tmask != DTK_TIME_M)
2023  return DTERR_BAD_FORMAT;
2024  break;
2025 
2026  default:
2027  return DTERR_BAD_FORMAT;
2028  break;
2029  }
2030 
2031  ptype = 0;
2032  *dtype = DTK_DATE;
2033  }
2034  else
2035  {
2036  char *cp;
2037  int flen;
2038 
2039  flen = strlen(field[i]);
2040  cp = strchr(field[i], '.');
2041 
2042  /* Embedded decimal? */
2043  if (cp != NULL)
2044  {
2045  /*
2046  * Under limited circumstances, we will accept a
2047  * date...
2048  */
2049  if (i == 0 && nf >= 2 && ftype[nf - 1] == DTK_DATE)
2050  {
2051  dterr = DecodeDate(field[i], fmask,
2052  &tmask, &is2digits, tm);
2053  if (dterr)
2054  return dterr;
2055  }
2056  /* embedded decimal and several digits before? */
2057  else if (flen - strlen(cp) > 2)
2058  {
2059  /*
2060  * Interpret as a concatenated date or time Set
2061  * the type field to allow decoding other fields
2062  * later. Example: 20011223 or 040506
2063  */
2064  dterr = DecodeNumberField(flen, field[i],
2065  (fmask | DTK_DATE_M),
2066  &tmask, tm,
2067  fsec, &is2digits);
2068  if (dterr < 0)
2069  return dterr;
2070  ftype[i] = dterr;
2071  }
2072  else
2073  return DTERR_BAD_FORMAT;
2074  }
2075  else if (flen > 4)
2076  {
2077  dterr = DecodeNumberField(flen, field[i],
2078  (fmask | DTK_DATE_M),
2079  &tmask, tm,
2080  fsec, &is2digits);
2081  if (dterr < 0)
2082  return dterr;
2083  ftype[i] = dterr;
2084  }
2085  /* otherwise it is a single date/time field... */
2086  else
2087  {
2088  dterr = DecodeNumber(flen, field[i],
2089  FALSE,
2090  (fmask | DTK_DATE_M),
2091  &tmask, tm,
2092  fsec, &is2digits);
2093  if (dterr)
2094  return dterr;
2095  }
2096  }
2097  break;
2098 
2099  case DTK_STRING:
2100  case DTK_SPECIAL:
2101  /* timezone abbrevs take precedence over built-in tokens */
2102  type = DecodeTimezoneAbbrev(i, field[i], &val, &valtz);
2103  if (type == UNKNOWN_FIELD)
2104  type = DecodeSpecial(i, field[i], &val);
2105  if (type == IGNORE_DTF)
2106  continue;
2107 
2108  tmask = DTK_M(type);
2109  switch (type)
2110  {
2111  case RESERV:
2112  switch (val)
2113  {
2114  case DTK_CURRENT:
2115  ereport(ERROR,
2116  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2117  errmsg("date/time value \"current\" is no longer supported")));
2118  return DTERR_BAD_FORMAT;
2119  break;
2120 
2121  case DTK_NOW:
2122  tmask = DTK_TIME_M;
2123  *dtype = DTK_TIME;
2124  GetCurrentTimeUsec(tm, fsec, NULL);
2125  break;
2126 
2127  case DTK_ZULU:
2128  tmask = (DTK_TIME_M | DTK_M(TZ));
2129  *dtype = DTK_TIME;
2130  tm->tm_hour = 0;
2131  tm->tm_min = 0;
2132  tm->tm_sec = 0;
2133  tm->tm_isdst = 0;
2134  break;
2135 
2136  default:
2137  return DTERR_BAD_FORMAT;
2138  }
2139 
2140  break;
2141 
2142  case DTZMOD:
2143 
2144  /*
2145  * daylight savings time modifier (solves "MET DST"
2146  * syntax)
2147  */
2148  tmask |= DTK_M(DTZ);
2149  tm->tm_isdst = 1;
2150  if (tzp == NULL)
2151  return DTERR_BAD_FORMAT;
2152  *tzp -= val;
2153  break;
2154 
2155  case DTZ:
2156 
2157  /*
2158  * set mask for TZ here _or_ check for DTZ later when
2159  * getting default timezone
2160  */
2161  tmask |= DTK_M(TZ);
2162  tm->tm_isdst = 1;
2163  if (tzp == NULL)
2164  return DTERR_BAD_FORMAT;
2165  *tzp = -val;
2166  ftype[i] = DTK_TZ;
2167  break;
2168 
2169  case TZ:
2170  tm->tm_isdst = 0;
2171  if (tzp == NULL)
2172  return DTERR_BAD_FORMAT;
2173  *tzp = -val;
2174  ftype[i] = DTK_TZ;
2175  break;
2176 
2177  case DYNTZ:
2178  tmask |= DTK_M(TZ);
2179  if (tzp == NULL)
2180  return DTERR_BAD_FORMAT;
2181  /* we'll determine the actual offset later */
2182  abbrevTz = valtz;
2183  abbrev = field[i];
2184  ftype[i] = DTK_TZ;
2185  break;
2186 
2187  case AMPM:
2188  mer = val;
2189  break;
2190 
2191  case ADBC:
2192  bc = (val == BC);
2193  break;
2194 
2195  case UNITS:
2196  tmask = 0;
2197  ptype = val;
2198  break;
2199 
2200  case ISOTIME:
2201  tmask = 0;
2202 
2203  /***
2204  * We will need one of the following fields:
2205  * DTK_NUMBER should be hhmmss.fff
2206  * DTK_TIME should be hh:mm:ss.fff
2207  * DTK_DATE should be hhmmss-zz
2208  ***/
2209  if (i >= nf - 1 ||
2210  (ftype[i + 1] != DTK_NUMBER &&
2211  ftype[i + 1] != DTK_TIME &&
2212  ftype[i + 1] != DTK_DATE))
2213  return DTERR_BAD_FORMAT;
2214 
2215  ptype = val;
2216  break;
2217 
2218  case UNKNOWN_FIELD:
2219 
2220  /*
2221  * Before giving up and declaring error, check to see
2222  * if it is an all-alpha timezone name.
2223  */
2224  namedTz = pg_tzset(field[i]);
2225  if (!namedTz)
2226  return DTERR_BAD_FORMAT;
2227  /* we'll apply the zone setting below */
2228  tmask = DTK_M(TZ);
2229  break;
2230 
2231  default:
2232  return DTERR_BAD_FORMAT;
2233  }
2234  break;
2235 
2236  default:
2237  return DTERR_BAD_FORMAT;
2238  }
2239 
2240  if (tmask & fmask)
2241  return DTERR_BAD_FORMAT;
2242  fmask |= tmask;
2243  } /* end loop over fields */
2244 
2245  /* do final checking/adjustment of Y/M/D fields */
2246  dterr = ValidateDate(fmask, isjulian, is2digits, bc, tm);
2247  if (dterr)
2248  return dterr;
2249 
2250  /* handle AM/PM */
2251  if (mer != HR24 && tm->tm_hour > HOURS_PER_DAY / 2)
2252  return DTERR_FIELD_OVERFLOW;
2253  if (mer == AM && tm->tm_hour == HOURS_PER_DAY / 2)
2254  tm->tm_hour = 0;
2255  else if (mer == PM && tm->tm_hour != HOURS_PER_DAY / 2)
2256  tm->tm_hour += HOURS_PER_DAY / 2;
2257 
2258  /*
2259  * This should match the checks in make_timestamp_internal
2260  */
2261  if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2262  tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2263  tm->tm_hour > HOURS_PER_DAY ||
2264  /* test for > 24:00:00 */
2265  (tm->tm_hour == HOURS_PER_DAY &&
2266  (tm->tm_min > 0 || tm->tm_sec > 0 || *fsec > 0)) ||
2267  *fsec < INT64CONST(0) || *fsec > USECS_PER_SEC)
2268  return DTERR_FIELD_OVERFLOW;
2269 
2270  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2271  return DTERR_BAD_FORMAT;
2272 
2273  /*
2274  * If we had a full timezone spec, compute the offset (we could not do it
2275  * before, because we may need the date to resolve DST status).
2276  */
2277  if (namedTz != NULL)
2278  {
2279  long int gmtoff;
2280 
2281  /* daylight savings time modifier disallowed with full TZ */
2282  if (fmask & DTK_M(DTZMOD))
2283  return DTERR_BAD_FORMAT;
2284 
2285  /* if non-DST zone, we do not need to know the date */
2286  if (pg_get_timezone_offset(namedTz, &gmtoff))
2287  {
2288  *tzp = -(int) gmtoff;
2289  }
2290  else
2291  {
2292  /* a date has to be specified */
2293  if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2294  return DTERR_BAD_FORMAT;
2295  *tzp = DetermineTimeZoneOffset(tm, namedTz);
2296  }
2297  }
2298 
2299  /*
2300  * Likewise, if we had a dynamic timezone abbreviation, resolve it now.
2301  */
2302  if (abbrevTz != NULL)
2303  {
2304  struct pg_tm tt,
2305  *tmp = &tt;
2306 
2307  /*
2308  * daylight savings time modifier but no standard timezone? then error
2309  */
2310  if (fmask & DTK_M(DTZMOD))
2311  return DTERR_BAD_FORMAT;
2312 
2313  if ((fmask & DTK_DATE_M) == 0)
2314  GetCurrentDateTime(tmp);
2315  else
2316  {
2317  tmp->tm_year = tm->tm_year;
2318  tmp->tm_mon = tm->tm_mon;
2319  tmp->tm_mday = tm->tm_mday;
2320  }
2321  tmp->tm_hour = tm->tm_hour;
2322  tmp->tm_min = tm->tm_min;
2323  tmp->tm_sec = tm->tm_sec;
2324  *tzp = DetermineTimeZoneAbbrevOffset(tmp, abbrev, abbrevTz);
2325  tm->tm_isdst = tmp->tm_isdst;
2326  }
2327 
2328  /* timezone not specified? then use session timezone */
2329  if (tzp != NULL && !(fmask & DTK_M(TZ)))
2330  {
2331  struct pg_tm tt,
2332  *tmp = &tt;
2333 
2334  /*
2335  * daylight savings time modifier but no standard timezone? then error
2336  */
2337  if (fmask & DTK_M(DTZMOD))
2338  return DTERR_BAD_FORMAT;
2339 
2340  if ((fmask & DTK_DATE_M) == 0)
2341  GetCurrentDateTime(tmp);
2342  else
2343  {
2344  tmp->tm_year = tm->tm_year;
2345  tmp->tm_mon = tm->tm_mon;
2346  tmp->tm_mday = tm->tm_mday;
2347  }
2348  tmp->tm_hour = tm->tm_hour;
2349  tmp->tm_min = tm->tm_min;
2350  tmp->tm_sec = tm->tm_sec;
2352  tm->tm_isdst = tmp->tm_isdst;
2353  }
2354 
2355  return 0;
2356 }
2357 
2358 /* DecodeDate()
2359  * Decode date string which includes delimiters.
2360  * Return 0 if okay, a DTERR code if not.
2361  *
2362  * str: field to be parsed
2363  * fmask: bitmask for field types already seen
2364  * *tmask: receives bitmask for fields found here
2365  * *is2digits: set to TRUE if we find 2-digit year
2366  * *tm: field values are stored into appropriate members of this struct
2367  */
2368 static int
2369 DecodeDate(char *str, int fmask, int *tmask, bool *is2digits,
2370  struct pg_tm * tm)
2371 {
2372  fsec_t fsec;
2373  int nf = 0;
2374  int i,
2375  len;
2376  int dterr;
2377  bool haveTextMonth = FALSE;
2378  int type,
2379  val,
2380  dmask = 0;
2381  char *field[MAXDATEFIELDS];
2382 
2383  *tmask = 0;
2384 
2385  /* parse this string... */
2386  while (*str != '\0' && nf < MAXDATEFIELDS)
2387  {
2388  /* skip field separators */
2389  while (*str != '\0' && !isalnum((unsigned char) *str))
2390  str++;
2391 
2392  if (*str == '\0')
2393  return DTERR_BAD_FORMAT; /* end of string after separator */
2394 
2395  field[nf] = str;
2396  if (isdigit((unsigned char) *str))
2397  {
2398  while (isdigit((unsigned char) *str))
2399  str++;
2400  }
2401  else if (isalpha((unsigned char) *str))
2402  {
2403  while (isalpha((unsigned char) *str))
2404  str++;
2405  }
2406 
2407  /* Just get rid of any non-digit, non-alpha characters... */
2408  if (*str != '\0')
2409  *str++ = '\0';
2410  nf++;
2411  }
2412 
2413  /* look first for text fields, since that will be unambiguous month */
2414  for (i = 0; i < nf; i++)
2415  {
2416  if (isalpha((unsigned char) *field[i]))
2417  {
2418  type = DecodeSpecial(i, field[i], &val);
2419  if (type == IGNORE_DTF)
2420  continue;
2421 
2422  dmask = DTK_M(type);
2423  switch (type)
2424  {
2425  case MONTH:
2426  tm->tm_mon = val;
2427  haveTextMonth = TRUE;
2428  break;
2429 
2430  default:
2431  return DTERR_BAD_FORMAT;
2432  }
2433  if (fmask & dmask)
2434  return DTERR_BAD_FORMAT;
2435 
2436  fmask |= dmask;
2437  *tmask |= dmask;
2438 
2439  /* mark this field as being completed */
2440  field[i] = NULL;
2441  }
2442  }
2443 
2444  /* now pick up remaining numeric fields */
2445  for (i = 0; i < nf; i++)
2446  {
2447  if (field[i] == NULL)
2448  continue;
2449 
2450  if ((len = strlen(field[i])) <= 0)
2451  return DTERR_BAD_FORMAT;
2452 
2453  dterr = DecodeNumber(len, field[i], haveTextMonth, fmask,
2454  &dmask, tm,
2455  &fsec, is2digits);
2456  if (dterr)
2457  return dterr;
2458 
2459  if (fmask & dmask)
2460  return DTERR_BAD_FORMAT;
2461 
2462  fmask |= dmask;
2463  *tmask |= dmask;
2464  }
2465 
2466  if ((fmask & ~(DTK_M(DOY) | DTK_M(TZ))) != DTK_DATE_M)
2467  return DTERR_BAD_FORMAT;
2468 
2469  /* validation of the field values must wait until ValidateDate() */
2470 
2471  return 0;
2472 }
2473 
2474 /* ValidateDate()
2475  * Check valid year/month/day values, handle BC and DOY cases
2476  * Return 0 if okay, a DTERR code if not.
2477  */
2478 int
2479 ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc,
2480  struct pg_tm * tm)
2481 {
2482  if (fmask & DTK_M(YEAR))
2483  {
2484  if (isjulian)
2485  {
2486  /* tm_year is correct and should not be touched */
2487  }
2488  else if (bc)
2489  {
2490  /* there is no year zero in AD/BC notation */
2491  if (tm->tm_year <= 0)
2492  return DTERR_FIELD_OVERFLOW;
2493  /* internally, we represent 1 BC as year zero, 2 BC as -1, etc */
2494  tm->tm_year = -(tm->tm_year - 1);
2495  }
2496  else if (is2digits)
2497  {
2498  /* process 1 or 2-digit input as 1970-2069 AD, allow '0' and '00' */
2499  if (tm->tm_year < 0) /* just paranoia */
2500  return DTERR_FIELD_OVERFLOW;
2501  if (tm->tm_year < 70)
2502  tm->tm_year += 2000;
2503  else if (tm->tm_year < 100)
2504  tm->tm_year += 1900;
2505  }
2506  else
2507  {
2508  /* there is no year zero in AD/BC notation */
2509  if (tm->tm_year <= 0)
2510  return DTERR_FIELD_OVERFLOW;
2511  }
2512  }
2513 
2514  /* now that we have correct year, decode DOY */
2515  if (fmask & DTK_M(DOY))
2516  {
2517  j2date(date2j(tm->tm_year, 1, 1) + tm->tm_yday - 1,
2518  &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
2519  }
2520 
2521  /* check for valid month */
2522  if (fmask & DTK_M(MONTH))
2523  {
2524  if (tm->tm_mon < 1 || tm->tm_mon > MONTHS_PER_YEAR)
2525  return DTERR_MD_FIELD_OVERFLOW;
2526  }
2527 
2528  /* minimal check for valid day */
2529  if (fmask & DTK_M(DAY))
2530  {
2531  if (tm->tm_mday < 1 || tm->tm_mday > 31)
2532  return DTERR_MD_FIELD_OVERFLOW;
2533  }
2534 
2535  if ((fmask & DTK_DATE_M) == DTK_DATE_M)
2536  {
2537  /*
2538  * Check for valid day of month, now that we know for sure the month
2539  * and year. Note we don't use MD_FIELD_OVERFLOW here, since it seems
2540  * unlikely that "Feb 29" is a YMD-order error.
2541  */
2542  if (tm->tm_mday > day_tab[isleap(tm->tm_year)][tm->tm_mon - 1])
2543  return DTERR_FIELD_OVERFLOW;
2544  }
2545 
2546  return 0;
2547 }
2548 
2549 
2550 /* DecodeTime()
2551  * Decode time string which includes delimiters.
2552  * Return 0 if okay, a DTERR code if not.
2553  *
2554  * Only check the lower limit on hours, since this same code can be
2555  * used to represent time spans.
2556  */
2557 static int
2558 DecodeTime(char *str, int fmask, int range,
2559  int *tmask, struct pg_tm * tm, fsec_t *fsec)
2560 {
2561  char *cp;
2562  int dterr;
2563 
2564  *tmask = DTK_TIME_M;
2565 
2566  errno = 0;
2567  tm->tm_hour = strtoint(str, &cp, 10);
2568  if (errno == ERANGE)
2569  return DTERR_FIELD_OVERFLOW;
2570  if (*cp != ':')
2571  return DTERR_BAD_FORMAT;
2572  errno = 0;
2573  tm->tm_min = strtoint(cp + 1, &cp, 10);
2574  if (errno == ERANGE)
2575  return DTERR_FIELD_OVERFLOW;
2576  if (*cp == '\0')
2577  {
2578  tm->tm_sec = 0;
2579  *fsec = 0;
2580  /* If it's a MINUTE TO SECOND interval, take 2 fields as being mm:ss */
2581  if (range == (INTERVAL_MASK(MINUTE) | INTERVAL_MASK(SECOND)))
2582  {
2583  tm->tm_sec = tm->tm_min;
2584  tm->tm_min = tm->tm_hour;
2585  tm->tm_hour = 0;
2586  }
2587  }
2588  else if (*cp == '.')
2589  {
2590  /* always assume mm:ss.sss is MINUTE TO SECOND */
2591  dterr = ParseFractionalSecond(cp, fsec);
2592  if (dterr)
2593  return dterr;
2594  tm->tm_sec = tm->tm_min;
2595  tm->tm_min = tm->tm_hour;
2596  tm->tm_hour = 0;
2597  }
2598  else if (*cp == ':')
2599  {
2600  errno = 0;
2601  tm->tm_sec = strtoint(cp + 1, &cp, 10);
2602  if (errno == ERANGE)
2603  return DTERR_FIELD_OVERFLOW;
2604  if (*cp == '\0')
2605  *fsec = 0;
2606  else if (*cp == '.')
2607  {
2608  dterr = ParseFractionalSecond(cp, fsec);
2609  if (dterr)
2610  return dterr;
2611  }
2612  else
2613  return DTERR_BAD_FORMAT;
2614  }
2615  else
2616  return DTERR_BAD_FORMAT;
2617 
2618  /* do a sanity check */
2619  if (tm->tm_hour < 0 || tm->tm_min < 0 || tm->tm_min > MINS_PER_HOUR - 1 ||
2620  tm->tm_sec < 0 || tm->tm_sec > SECS_PER_MINUTE ||
2621  *fsec < INT64CONST(0) ||
2622  *fsec > USECS_PER_SEC)
2623  return DTERR_FIELD_OVERFLOW;
2624 
2625  return 0;
2626 }
2627 
2628 
2629 /* DecodeNumber()
2630  * Interpret plain numeric field as a date value in context.
2631  * Return 0 if okay, a DTERR code if not.
2632  */
2633 static int
2634 DecodeNumber(int flen, char *str, bool haveTextMonth, int fmask,
2635  int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits)
2636 {
2637  int val;
2638  char *cp;
2639  int dterr;
2640 
2641  *tmask = 0;
2642 
2643  errno = 0;
2644  val = strtoint(str, &cp, 10);
2645  if (errno == ERANGE)
2646  return DTERR_FIELD_OVERFLOW;
2647  if (cp == str)
2648  return DTERR_BAD_FORMAT;
2649 
2650  if (*cp == '.')
2651  {
2652  /*
2653  * More than two digits before decimal point? Then could be a date or
2654  * a run-together time: 2001.360 20011225 040506.789
2655  */
2656  if (cp - str > 2)
2657  {
2658  dterr = DecodeNumberField(flen, str,
2659  (fmask | DTK_DATE_M),
2660  tmask, tm,
2661  fsec, is2digits);
2662  if (dterr < 0)
2663  return dterr;
2664  return 0;
2665  }
2666 
2667  dterr = ParseFractionalSecond(cp, fsec);
2668  if (dterr)
2669  return dterr;
2670  }
2671  else if (*cp != '\0')
2672  return DTERR_BAD_FORMAT;
2673 
2674  /* Special case for day of year */
2675  if (flen == 3 && (fmask & DTK_DATE_M) == DTK_M(YEAR) && val >= 1 &&
2676  val <= 366)
2677  {
2678  *tmask = (DTK_M(DOY) | DTK_M(MONTH) | DTK_M(DAY));
2679  tm->tm_yday = val;
2680  /* tm_mon and tm_mday can't actually be set yet ... */
2681  return 0;
2682  }
2683 
2684  /* Switch based on what we have so far */
2685  switch (fmask & DTK_DATE_M)
2686  {
2687  case 0:
2688 
2689  /*
2690  * Nothing so far; make a decision about what we think the input
2691  * is. There used to be lots of heuristics here, but the
2692  * consensus now is to be paranoid. It *must* be either
2693  * YYYY-MM-DD (with a more-than-two-digit year field), or the
2694  * field order defined by DateOrder.
2695  */
2696  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2697  {
2698  *tmask = DTK_M(YEAR);
2699  tm->tm_year = val;
2700  }
2701  else if (DateOrder == DATEORDER_DMY)
2702  {
2703  *tmask = DTK_M(DAY);
2704  tm->tm_mday = val;
2705  }
2706  else
2707  {
2708  *tmask = DTK_M(MONTH);
2709  tm->tm_mon = val;
2710  }
2711  break;
2712 
2713  case (DTK_M(YEAR)):
2714  /* Must be at second field of YY-MM-DD */
2715  *tmask = DTK_M(MONTH);
2716  tm->tm_mon = val;
2717  break;
2718 
2719  case (DTK_M(MONTH)):
2720  if (haveTextMonth)
2721  {
2722  /*
2723  * We are at the first numeric field of a date that included a
2724  * textual month name. We want to support the variants
2725  * MON-DD-YYYY, DD-MON-YYYY, and YYYY-MON-DD as unambiguous
2726  * inputs. We will also accept MON-DD-YY or DD-MON-YY in
2727  * either DMY or MDY modes, as well as YY-MON-DD in YMD mode.
2728  */
2729  if (flen >= 3 || DateOrder == DATEORDER_YMD)
2730  {
2731  *tmask = DTK_M(YEAR);
2732  tm->tm_year = val;
2733  }
2734  else
2735  {
2736  *tmask = DTK_M(DAY);
2737  tm->tm_mday = val;
2738  }
2739  }
2740  else
2741  {
2742  /* Must be at second field of MM-DD-YY */
2743  *tmask = DTK_M(DAY);
2744  tm->tm_mday = val;
2745  }
2746  break;
2747 
2748  case (DTK_M(YEAR) | DTK_M(MONTH)):
2749  if (haveTextMonth)
2750  {
2751  /* Need to accept DD-MON-YYYY even in YMD mode */
2752  if (flen >= 3 && *is2digits)
2753  {
2754  /* Guess that first numeric field is day was wrong */
2755  *tmask = DTK_M(DAY); /* YEAR is already set */
2756  tm->tm_mday = tm->tm_year;
2757  tm->tm_year = val;
2758  *is2digits = FALSE;
2759  }
2760  else
2761  {
2762  *tmask = DTK_M(DAY);
2763  tm->tm_mday = val;
2764  }
2765  }
2766  else
2767  {
2768  /* Must be at third field of YY-MM-DD */
2769  *tmask = DTK_M(DAY);
2770  tm->tm_mday = val;
2771  }
2772  break;
2773 
2774  case (DTK_M(DAY)):
2775  /* Must be at second field of DD-MM-YY */
2776  *tmask = DTK_M(MONTH);
2777  tm->tm_mon = val;
2778  break;
2779 
2780  case (DTK_M(MONTH) | DTK_M(DAY)):
2781  /* Must be at third field of DD-MM-YY or MM-DD-YY */
2782  *tmask = DTK_M(YEAR);
2783  tm->tm_year = val;
2784  break;
2785 
2786  case (DTK_M(YEAR) | DTK_M(MONTH) | DTK_M(DAY)):
2787  /* we have all the date, so it must be a time field */
2788  dterr = DecodeNumberField(flen, str, fmask,
2789  tmask, tm,
2790  fsec, is2digits);
2791  if (dterr < 0)
2792  return dterr;
2793  return 0;
2794 
2795  default:
2796  /* Anything else is bogus input */
2797  return DTERR_BAD_FORMAT;
2798  }
2799 
2800  /*
2801  * When processing a year field, mark it for adjustment if it's only one
2802  * or two digits.
2803  */
2804  if (*tmask == DTK_M(YEAR))
2805  *is2digits = (flen <= 2);
2806 
2807  return 0;
2808 }
2809 
2810 
2811 /* DecodeNumberField()
2812  * Interpret numeric string as a concatenated date or time field.
2813  * Return a DTK token (>= 0) if successful, a DTERR code (< 0) if not.
2814  *
2815  * Use the context of previously decoded fields to help with
2816  * the interpretation.
2817  */
2818 static int
2819 DecodeNumberField(int len, char *str, int fmask,
2820  int *tmask, struct pg_tm * tm, fsec_t *fsec, bool *is2digits)
2821 {
2822  char *cp;
2823 
2824  /*
2825  * Have a decimal point? Then this is a date or something with a seconds
2826  * field...
2827  */
2828  if ((cp = strchr(str, '.')) != NULL)
2829  {
2830  /*
2831  * Can we use ParseFractionalSecond here? Not clear whether trailing
2832  * junk should be rejected ...
2833  */
2834  double frac;
2835 
2836  errno = 0;
2837  frac = strtod(cp, NULL);
2838  if (errno != 0)
2839  return DTERR_BAD_FORMAT;
2840  *fsec = rint(frac * 1000000);
2841  /* Now truncate off the fraction for further processing */
2842  *cp = '\0';
2843  len = strlen(str);
2844  }
2845  /* No decimal point and no complete date yet? */
2846  else if ((fmask & DTK_DATE_M) != DTK_DATE_M)
2847  {
2848  if (len >= 6)
2849  {
2850  *tmask = DTK_DATE_M;
2851 
2852  /*
2853  * Start from end and consider first 2 as Day, next 2 as Month,
2854  * and the rest as Year.
2855  */
2856  tm->tm_mday = atoi(str + (len - 2));
2857  *(str + (len - 2)) = '\0';
2858  tm->tm_mon = atoi(str + (len - 4));
2859  *(str + (len - 4)) = '\0';
2860  tm->tm_year = atoi(str);
2861  if ((len - 4) == 2)
2862  *is2digits = TRUE;
2863 
2864  return DTK_DATE;
2865  }
2866  }
2867 
2868  /* not all time fields are specified? */
2869  if ((fmask & DTK_TIME_M) != DTK_TIME_M)
2870  {
2871  /* hhmmss */
2872  if (len == 6)
2873  {
2874  *tmask = DTK_TIME_M;
2875  tm->tm_sec = atoi(str + 4);
2876  *(str + 4) = '\0';
2877  tm->tm_min = atoi(str + 2);
2878  *(str + 2) = '\0';
2879  tm->tm_hour = atoi(str);
2880 
2881  return DTK_TIME;
2882  }
2883  /* hhmm? */
2884  else if (len == 4)
2885  {
2886  *tmask = DTK_TIME_M;
2887  tm->tm_sec = 0;
2888  tm->tm_min = atoi(str + 2);
2889  *(str + 2) = '\0';
2890  tm->tm_hour = atoi(str);
2891 
2892  return DTK_TIME;
2893  }
2894  }
2895 
2896  return DTERR_BAD_FORMAT;
2897 }
2898 
2899 
2900 /* DecodeTimezone()
2901  * Interpret string as a numeric timezone.
2902  *
2903  * Return 0 if okay (and set *tzp), a DTERR code if not okay.
2904  */
2905 int
2906 DecodeTimezone(char *str, int *tzp)
2907 {
2908  int tz;
2909  int hr,
2910  min,
2911  sec = 0;
2912  char *cp;
2913 
2914  /* leading character must be "+" or "-" */
2915  if (*str != '+' && *str != '-')
2916  return DTERR_BAD_FORMAT;
2917 
2918  errno = 0;
2919  hr = strtoint(str + 1, &cp, 10);
2920  if (errno == ERANGE)
2921  return DTERR_TZDISP_OVERFLOW;
2922 
2923  /* explicit delimiter? */
2924  if (*cp == ':')
2925  {
2926  errno = 0;
2927  min = strtoint(cp + 1, &cp, 10);
2928  if (errno == ERANGE)
2929  return DTERR_TZDISP_OVERFLOW;
2930  if (*cp == ':')
2931  {
2932  errno = 0;
2933  sec = strtoint(cp + 1, &cp, 10);
2934  if (errno == ERANGE)
2935  return DTERR_TZDISP_OVERFLOW;
2936  }
2937  }
2938  /* otherwise, might have run things together... */
2939  else if (*cp == '\0' && strlen(str) > 3)
2940  {
2941  min = hr % 100;
2942  hr = hr / 100;
2943  /* we could, but don't, support a run-together hhmmss format */
2944  }
2945  else
2946  min = 0;
2947 
2948  /* Range-check the values; see notes in datatype/timestamp.h */
2949  if (hr < 0 || hr > MAX_TZDISP_HOUR)
2950  return DTERR_TZDISP_OVERFLOW;
2951  if (min < 0 || min >= MINS_PER_HOUR)
2952  return DTERR_TZDISP_OVERFLOW;
2953  if (sec < 0 || sec >= SECS_PER_MINUTE)
2954  return DTERR_TZDISP_OVERFLOW;
2955 
2956  tz = (hr * MINS_PER_HOUR + min) * SECS_PER_MINUTE + sec;
2957  if (*str == '-')
2958  tz = -tz;
2959 
2960  *tzp = -tz;
2961 
2962  if (*cp != '\0')
2963  return DTERR_BAD_FORMAT;
2964 
2965  return 0;
2966 }
2967 
2968 
2969 /* DecodeTimezoneAbbrev()
2970  * Interpret string as a timezone abbreviation, if possible.
2971  *
2972  * Returns an abbreviation type (TZ, DTZ, or DYNTZ), or UNKNOWN_FIELD if
2973  * string is not any known abbreviation. On success, set *offset and *tz to
2974  * represent the UTC offset (for TZ or DTZ) or underlying zone (for DYNTZ).
2975  * Note that full timezone names (such as America/New_York) are not handled
2976  * here, mostly for historical reasons.
2977  *
2978  * Given string must be lowercased already.
2979  *
2980  * Implement a cache lookup since it is likely that dates
2981  * will be related in format.
2982  */
2983 int
2984 DecodeTimezoneAbbrev(int field, char *lowtoken,
2985  int *offset, pg_tz **tz)
2986 {
2987  int type;
2988  const datetkn *tp;
2989 
2990  tp = abbrevcache[field];
2991  /* use strncmp so that we match truncated tokens */
2992  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
2993  {
2994  if (zoneabbrevtbl)
2995  tp = datebsearch(lowtoken, zoneabbrevtbl->abbrevs,
2996  zoneabbrevtbl->numabbrevs);
2997  else
2998  tp = NULL;
2999  }
3000  if (tp == NULL)
3001  {
3002  type = UNKNOWN_FIELD;
3003  *offset = 0;
3004  *tz = NULL;
3005  }
3006  else
3007  {
3008  abbrevcache[field] = tp;
3009  type = tp->type;
3010  if (type == DYNTZ)
3011  {
3012  *offset = 0;
3013  *tz = FetchDynamicTimeZone(zoneabbrevtbl, tp);
3014  }
3015  else
3016  {
3017  *offset = tp->value;
3018  *tz = NULL;
3019  }
3020  }
3021 
3022  return type;
3023 }
3024 
3025 
3026 /* DecodeSpecial()
3027  * Decode text string using lookup table.
3028  *
3029  * Recognizes the keywords listed in datetktbl.
3030  * Note: at one time this would also recognize timezone abbreviations,
3031  * but no more; use DecodeTimezoneAbbrev for that.
3032  *
3033  * Given string must be lowercased already.
3034  *
3035  * Implement a cache lookup since it is likely that dates
3036  * will be related in format.
3037  */
3038 int
3039 DecodeSpecial(int field, char *lowtoken, int *val)
3040 {
3041  int type;
3042  const datetkn *tp;
3043 
3044  tp = datecache[field];
3045  /* use strncmp so that we match truncated tokens */
3046  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3047  {
3048  tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
3049  }
3050  if (tp == NULL)
3051  {
3052  type = UNKNOWN_FIELD;
3053  *val = 0;
3054  }
3055  else
3056  {
3057  datecache[field] = tp;
3058  type = tp->type;
3059  *val = tp->value;
3060  }
3061 
3062  return type;
3063 }
3064 
3065 
3066 /* ClearPgTM
3067  *
3068  * Zero out a pg_tm and associated fsec_t
3069  */
3070 static inline void
3071 ClearPgTm(struct pg_tm * tm, fsec_t *fsec)
3072 {
3073  tm->tm_year = 0;
3074  tm->tm_mon = 0;
3075  tm->tm_mday = 0;
3076  tm->tm_hour = 0;
3077  tm->tm_min = 0;
3078  tm->tm_sec = 0;
3079  *fsec = 0;
3080 }
3081 
3082 
3083 /* DecodeInterval()
3084  * Interpret previously parsed fields for general time interval.
3085  * Returns 0 if successful, DTERR code if bogus input detected.
3086  * dtype, tm, fsec are output parameters.
3087  *
3088  * Allow "date" field DTK_DATE since this could be just
3089  * an unsigned floating point number. - thomas 1997-11-16
3090  *
3091  * Allow ISO-style time span, with implicit units on number of days
3092  * preceding an hh:mm:ss field. - thomas 1998-04-30
3093  */
3094 int
3095 DecodeInterval(char **field, int *ftype, int nf, int range,
3096  int *dtype, struct pg_tm * tm, fsec_t *fsec)
3097 {
3098  bool is_before = FALSE;
3099  char *cp;
3100  int fmask = 0,
3101  tmask,
3102  type;
3103  int i;
3104  int dterr;
3105  int val;
3106  double fval;
3107 
3108  *dtype = DTK_DELTA;
3109  type = IGNORE_DTF;
3110  ClearPgTm(tm, fsec);
3111 
3112  /* read through list backwards to pick up units before values */
3113  for (i = nf - 1; i >= 0; i--)
3114  {
3115  switch (ftype[i])
3116  {
3117  case DTK_TIME:
3118  dterr = DecodeTime(field[i], fmask, range,
3119  &tmask, tm, fsec);
3120  if (dterr)
3121  return dterr;
3122  type = DTK_DAY;
3123  break;
3124 
3125  case DTK_TZ:
3126 
3127  /*
3128  * Timezone means a token with a leading sign character and at
3129  * least one digit; there could be ':', '.', '-' embedded in
3130  * it as well.
3131  */
3132  Assert(*field[i] == '-' || *field[i] == '+');
3133 
3134  /*
3135  * Check for signed hh:mm or hh:mm:ss. If so, process exactly
3136  * like DTK_TIME case above, plus handling the sign.
3137  */
3138  if (strchr(field[i] + 1, ':') != NULL &&
3139  DecodeTime(field[i] + 1, fmask, range,
3140  &tmask, tm, fsec) == 0)
3141  {
3142  if (*field[i] == '-')
3143  {
3144  /* flip the sign on all fields */
3145  tm->tm_hour = -tm->tm_hour;
3146  tm->tm_min = -tm->tm_min;
3147  tm->tm_sec = -tm->tm_sec;
3148  *fsec = -(*fsec);
3149  }
3150 
3151  /*
3152  * Set the next type to be a day, if units are not
3153  * specified. This handles the case of '1 +02:03' since we
3154  * are reading right to left.
3155  */
3156  type = DTK_DAY;
3157  break;
3158  }
3159 
3160  /*
3161  * Otherwise, fall through to DTK_NUMBER case, which can
3162  * handle signed float numbers and signed year-month values.
3163  */
3164 
3165  /* FALL THROUGH */
3166 
3167  case DTK_DATE:
3168  case DTK_NUMBER:
3169  if (type == IGNORE_DTF)
3170  {
3171  /* use typmod to decide what rightmost field is */
3172  switch (range)
3173  {
3174  case INTERVAL_MASK(YEAR):
3175  type = DTK_YEAR;
3176  break;
3177  case INTERVAL_MASK(MONTH):
3179  type = DTK_MONTH;
3180  break;
3181  case INTERVAL_MASK(DAY):
3182  type = DTK_DAY;
3183  break;
3184  case INTERVAL_MASK(HOUR):
3186  type = DTK_HOUR;
3187  break;
3188  case INTERVAL_MASK(MINUTE):
3191  type = DTK_MINUTE;
3192  break;
3193  case INTERVAL_MASK(SECOND):
3197  type = DTK_SECOND;
3198  break;
3199  default:
3200  type = DTK_SECOND;
3201  break;
3202  }
3203  }
3204 
3205  errno = 0;
3206  val = strtoint(field[i], &cp, 10);
3207  if (errno == ERANGE)
3208  return DTERR_FIELD_OVERFLOW;
3209 
3210  if (*cp == '-')
3211  {
3212  /* SQL "years-months" syntax */
3213  int val2;
3214 
3215  val2 = strtoint(cp + 1, &cp, 10);
3216  if (errno == ERANGE || val2 < 0 || val2 >= MONTHS_PER_YEAR)
3217  return DTERR_FIELD_OVERFLOW;
3218  if (*cp != '\0')
3219  return DTERR_BAD_FORMAT;
3220  type = DTK_MONTH;
3221  if (*field[i] == '-')
3222  val2 = -val2;
3223  if (((double) val * MONTHS_PER_YEAR + val2) > INT_MAX ||
3224  ((double) val * MONTHS_PER_YEAR + val2) < INT_MIN)
3225  return DTERR_FIELD_OVERFLOW;
3226  val = val * MONTHS_PER_YEAR + val2;
3227  fval = 0;
3228  }
3229  else if (*cp == '.')
3230  {
3231  errno = 0;
3232  fval = strtod(cp, &cp);
3233  if (*cp != '\0' || errno != 0)
3234  return DTERR_BAD_FORMAT;
3235 
3236  if (*field[i] == '-')
3237  fval = -fval;
3238  }
3239  else if (*cp == '\0')
3240  fval = 0;
3241  else
3242  return DTERR_BAD_FORMAT;
3243 
3244  tmask = 0; /* DTK_M(type); */
3245 
3246  switch (type)
3247  {
3248  case DTK_MICROSEC:
3249  *fsec += rint(val + fval);
3250  tmask = DTK_M(MICROSECOND);
3251  break;
3252 
3253  case DTK_MILLISEC:
3254  /* avoid overflowing the fsec field */
3255  tm->tm_sec += val / 1000;
3256  val -= (val / 1000) * 1000;
3257  *fsec += rint((val + fval) * 1000);
3258  tmask = DTK_M(MILLISECOND);
3259  break;
3260 
3261  case DTK_SECOND:
3262  tm->tm_sec += val;
3263  *fsec += rint(fval * 1000000);
3264 
3265  /*
3266  * If any subseconds were specified, consider this
3267  * microsecond and millisecond input as well.
3268  */
3269  if (fval == 0)
3270  tmask = DTK_M(SECOND);
3271  else
3272  tmask = DTK_ALL_SECS_M;
3273  break;
3274 
3275  case DTK_MINUTE:
3276  tm->tm_min += val;
3277  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3278  tmask = DTK_M(MINUTE);
3279  break;
3280 
3281  case DTK_HOUR:
3282  tm->tm_hour += val;
3283  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3284  tmask = DTK_M(HOUR);
3285  type = DTK_DAY; /* set for next field */
3286  break;
3287 
3288  case DTK_DAY:
3289  tm->tm_mday += val;
3290  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3291  tmask = DTK_M(DAY);
3292  break;
3293 
3294  case DTK_WEEK:
3295  tm->tm_mday += val * 7;
3296  AdjustFractDays(fval, tm, fsec, 7);
3297  tmask = DTK_M(WEEK);
3298  break;
3299 
3300  case DTK_MONTH:
3301  tm->tm_mon += val;
3302  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3303  tmask = DTK_M(MONTH);
3304  break;
3305 
3306  case DTK_YEAR:
3307  tm->tm_year += val;
3308  if (fval != 0)
3309  tm->tm_mon += fval * MONTHS_PER_YEAR;
3310  tmask = DTK_M(YEAR);
3311  break;
3312 
3313  case DTK_DECADE:
3314  tm->tm_year += val * 10;
3315  if (fval != 0)
3316  tm->tm_mon += fval * MONTHS_PER_YEAR * 10;
3317  tmask = DTK_M(DECADE);
3318  break;
3319 
3320  case DTK_CENTURY:
3321  tm->tm_year += val * 100;
3322  if (fval != 0)
3323  tm->tm_mon += fval * MONTHS_PER_YEAR * 100;
3324  tmask = DTK_M(CENTURY);
3325  break;
3326 
3327  case DTK_MILLENNIUM:
3328  tm->tm_year += val * 1000;
3329  if (fval != 0)
3330  tm->tm_mon += fval * MONTHS_PER_YEAR * 1000;
3331  tmask = DTK_M(MILLENNIUM);
3332  break;
3333 
3334  default:
3335  return DTERR_BAD_FORMAT;
3336  }
3337  break;
3338 
3339  case DTK_STRING:
3340  case DTK_SPECIAL:
3341  type = DecodeUnits(i, field[i], &val);
3342  if (type == IGNORE_DTF)
3343  continue;
3344 
3345  tmask = 0; /* DTK_M(type); */
3346  switch (type)
3347  {
3348  case UNITS:
3349  type = val;
3350  break;
3351 
3352  case AGO:
3353  is_before = TRUE;
3354  type = val;
3355  break;
3356 
3357  case RESERV:
3358  tmask = (DTK_DATE_M | DTK_TIME_M);
3359  *dtype = val;
3360  break;
3361 
3362  default:
3363  return DTERR_BAD_FORMAT;
3364  }
3365  break;
3366 
3367  default:
3368  return DTERR_BAD_FORMAT;
3369  }
3370 
3371  if (tmask & fmask)
3372  return DTERR_BAD_FORMAT;
3373  fmask |= tmask;
3374  }
3375 
3376  /* ensure that at least one time field has been found */
3377  if (fmask == 0)
3378  return DTERR_BAD_FORMAT;
3379 
3380  /* ensure fractional seconds are fractional */
3381  if (*fsec != 0)
3382  {
3383  int sec;
3384 
3385  sec = *fsec / USECS_PER_SEC;
3386  *fsec -= sec * USECS_PER_SEC;
3387  tm->tm_sec += sec;
3388  }
3389 
3390  /*----------
3391  * The SQL standard defines the interval literal
3392  * '-1 1:00:00'
3393  * to mean "negative 1 days and negative 1 hours", while Postgres
3394  * traditionally treats this as meaning "negative 1 days and positive
3395  * 1 hours". In SQL_STANDARD intervalstyle, we apply the leading sign
3396  * to all fields if there are no other explicit signs.
3397  *
3398  * We leave the signs alone if there are additional explicit signs.
3399  * This protects us against misinterpreting postgres-style dump output,
3400  * since the postgres-style output code has always put an explicit sign on
3401  * all fields following a negative field. But note that SQL-spec output
3402  * is ambiguous and can be misinterpreted on load! (So it's best practice
3403  * to dump in postgres style, not SQL style.)
3404  *----------
3405  */
3406  if (IntervalStyle == INTSTYLE_SQL_STANDARD && *field[0] == '-')
3407  {
3408  /* Check for additional explicit signs */
3409  bool more_signs = false;
3410 
3411  for (i = 1; i < nf; i++)
3412  {
3413  if (*field[i] == '-' || *field[i] == '+')
3414  {
3415  more_signs = true;
3416  break;
3417  }
3418  }
3419 
3420  if (!more_signs)
3421  {
3422  /*
3423  * Rather than re-determining which field was field[0], just force
3424  * 'em all negative.
3425  */
3426  if (*fsec > 0)
3427  *fsec = -(*fsec);
3428  if (tm->tm_sec > 0)
3429  tm->tm_sec = -tm->tm_sec;
3430  if (tm->tm_min > 0)
3431  tm->tm_min = -tm->tm_min;
3432  if (tm->tm_hour > 0)
3433  tm->tm_hour = -tm->tm_hour;
3434  if (tm->tm_mday > 0)
3435  tm->tm_mday = -tm->tm_mday;
3436  if (tm->tm_mon > 0)
3437  tm->tm_mon = -tm->tm_mon;
3438  if (tm->tm_year > 0)
3439  tm->tm_year = -tm->tm_year;
3440  }
3441  }
3442 
3443  /* finally, AGO negates everything */
3444  if (is_before)
3445  {
3446  *fsec = -(*fsec);
3447  tm->tm_sec = -tm->tm_sec;
3448  tm->tm_min = -tm->tm_min;
3449  tm->tm_hour = -tm->tm_hour;
3450  tm->tm_mday = -tm->tm_mday;
3451  tm->tm_mon = -tm->tm_mon;
3452  tm->tm_year = -tm->tm_year;
3453  }
3454 
3455  return 0;
3456 }
3457 
3458 
3459 /*
3460  * Helper functions to avoid duplicated code in DecodeISO8601Interval.
3461  *
3462  * Parse a decimal value and break it into integer and fractional parts.
3463  * Returns 0 or DTERR code.
3464  */
3465 static int
3466 ParseISO8601Number(char *str, char **endptr, int *ipart, double *fpart)
3467 {
3468  double val;
3469 
3470  if (!(isdigit((unsigned char) *str) || *str == '-' || *str == '.'))
3471  return DTERR_BAD_FORMAT;
3472  errno = 0;
3473  val = strtod(str, endptr);
3474  /* did we not see anything that looks like a double? */
3475  if (*endptr == str || errno != 0)
3476  return DTERR_BAD_FORMAT;
3477  /* watch out for overflow */
3478  if (val < INT_MIN || val > INT_MAX)
3479  return DTERR_FIELD_OVERFLOW;
3480  /* be very sure we truncate towards zero (cf dtrunc()) */
3481  if (val >= 0)
3482  *ipart = (int) floor(val);
3483  else
3484  *ipart = (int) -floor(-val);
3485  *fpart = val - *ipart;
3486  return 0;
3487 }
3488 
3489 /*
3490  * Determine number of integral digits in a valid ISO 8601 number field
3491  * (we should ignore sign and any fraction part)
3492  */
3493 static int
3494 ISO8601IntegerWidth(char *fieldstart)
3495 {
3496  /* We might have had a leading '-' */
3497  if (*fieldstart == '-')
3498  fieldstart++;
3499  return strspn(fieldstart, "0123456789");
3500 }
3501 
3502 
3503 /* DecodeISO8601Interval()
3504  * Decode an ISO 8601 time interval of the "format with designators"
3505  * (section 4.4.3.2) or "alternative format" (section 4.4.3.3)
3506  * Examples: P1D for 1 day
3507  * PT1H for 1 hour
3508  * P2Y6M7DT1H30M for 2 years, 6 months, 7 days 1 hour 30 min
3509  * P0002-06-07T01:30:00 the same value in alternative format
3510  *
3511  * Returns 0 if successful, DTERR code if bogus input detected.
3512  * Note: error code should be DTERR_BAD_FORMAT if input doesn't look like
3513  * ISO8601, otherwise this could cause unexpected error messages.
3514  * dtype, tm, fsec are output parameters.
3515  *
3516  * A couple exceptions from the spec:
3517  * - a week field ('W') may coexist with other units
3518  * - allows decimals in fields other than the least significant unit.
3519  */
3520 int
3522  int *dtype, struct pg_tm * tm, fsec_t *fsec)
3523 {
3524  bool datepart = true;
3525  bool havefield = false;
3526 
3527  *dtype = DTK_DELTA;
3528  ClearPgTm(tm, fsec);
3529 
3530  if (strlen(str) < 2 || str[0] != 'P')
3531  return DTERR_BAD_FORMAT;
3532 
3533  str++;
3534  while (*str)
3535  {
3536  char *fieldstart;
3537  int val;
3538  double fval;
3539  char unit;
3540  int dterr;
3541 
3542  if (*str == 'T') /* T indicates the beginning of the time part */
3543  {
3544  datepart = false;
3545  havefield = false;
3546  str++;
3547  continue;
3548  }
3549 
3550  fieldstart = str;
3551  dterr = ParseISO8601Number(str, &str, &val, &fval);
3552  if (dterr)
3553  return dterr;
3554 
3555  /*
3556  * Note: we could step off the end of the string here. Code below
3557  * *must* exit the loop if unit == '\0'.
3558  */
3559  unit = *str++;
3560 
3561  if (datepart)
3562  {
3563  switch (unit) /* before T: Y M W D */
3564  {
3565  case 'Y':
3566  tm->tm_year += val;
3567  tm->tm_mon += (fval * MONTHS_PER_YEAR);
3568  break;
3569  case 'M':
3570  tm->tm_mon += val;
3571  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3572  break;
3573  case 'W':
3574  tm->tm_mday += val * 7;
3575  AdjustFractDays(fval, tm, fsec, 7);
3576  break;
3577  case 'D':
3578  tm->tm_mday += val;
3579  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3580  break;
3581  case 'T': /* ISO 8601 4.4.3.3 Alternative Format / Basic */
3582  case '\0':
3583  if (ISO8601IntegerWidth(fieldstart) == 8 && !havefield)
3584  {
3585  tm->tm_year += val / 10000;
3586  tm->tm_mon += (val / 100) % 100;
3587  tm->tm_mday += val % 100;
3588  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3589  if (unit == '\0')
3590  return 0;
3591  datepart = false;
3592  havefield = false;
3593  continue;
3594  }
3595  /* Else fall through to extended alternative format */
3596  case '-': /* ISO 8601 4.4.3.3 Alternative Format,
3597  * Extended */
3598  if (havefield)
3599  return DTERR_BAD_FORMAT;
3600 
3601  tm->tm_year += val;
3602  tm->tm_mon += (fval * MONTHS_PER_YEAR);
3603  if (unit == '\0')
3604  return 0;
3605  if (unit == 'T')
3606  {
3607  datepart = false;
3608  havefield = false;
3609  continue;
3610  }
3611 
3612  dterr = ParseISO8601Number(str, &str, &val, &fval);
3613  if (dterr)
3614  return dterr;
3615  tm->tm_mon += val;
3616  AdjustFractDays(fval, tm, fsec, DAYS_PER_MONTH);
3617  if (*str == '\0')
3618  return 0;
3619  if (*str == 'T')
3620  {
3621  datepart = false;
3622  havefield = false;
3623  continue;
3624  }
3625  if (*str != '-')
3626  return DTERR_BAD_FORMAT;
3627  str++;
3628 
3629  dterr = ParseISO8601Number(str, &str, &val, &fval);
3630  if (dterr)
3631  return dterr;
3632  tm->tm_mday += val;
3633  AdjustFractSeconds(fval, tm, fsec, SECS_PER_DAY);
3634  if (*str == '\0')
3635  return 0;
3636  if (*str == 'T')
3637  {
3638  datepart = false;
3639  havefield = false;
3640  continue;
3641  }
3642  return DTERR_BAD_FORMAT;
3643  default:
3644  /* not a valid date unit suffix */
3645  return DTERR_BAD_FORMAT;
3646  }
3647  }
3648  else
3649  {
3650  switch (unit) /* after T: H M S */
3651  {
3652  case 'H':
3653  tm->tm_hour += val;
3654  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3655  break;
3656  case 'M':
3657  tm->tm_min += val;
3658  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3659  break;
3660  case 'S':
3661  tm->tm_sec += val;
3662  AdjustFractSeconds(fval, tm, fsec, 1);
3663  break;
3664  case '\0': /* ISO 8601 4.4.3.3 Alternative Format */
3665  if (ISO8601IntegerWidth(fieldstart) == 6 && !havefield)
3666  {
3667  tm->tm_hour += val / 10000;
3668  tm->tm_min += (val / 100) % 100;
3669  tm->tm_sec += val % 100;
3670  AdjustFractSeconds(fval, tm, fsec, 1);
3671  return 0;
3672  }
3673  /* Else fall through to extended alternative format */
3674  case ':': /* ISO 8601 4.4.3.3 Alternative Format,
3675  * Extended */
3676  if (havefield)
3677  return DTERR_BAD_FORMAT;
3678 
3679  tm->tm_hour += val;
3680  AdjustFractSeconds(fval, tm, fsec, SECS_PER_HOUR);
3681  if (unit == '\0')
3682  return 0;
3683 
3684  dterr = ParseISO8601Number(str, &str, &val, &fval);
3685  if (dterr)
3686  return dterr;
3687  tm->tm_min += val;
3688  AdjustFractSeconds(fval, tm, fsec, SECS_PER_MINUTE);
3689  if (*str == '\0')
3690  return 0;
3691  if (*str != ':')
3692  return DTERR_BAD_FORMAT;
3693  str++;
3694 
3695  dterr = ParseISO8601Number(str, &str, &val, &fval);
3696  if (dterr)
3697  return dterr;
3698  tm->tm_sec += val;
3699  AdjustFractSeconds(fval, tm, fsec, 1);
3700  if (*str == '\0')
3701  return 0;
3702  return DTERR_BAD_FORMAT;
3703 
3704  default:
3705  /* not a valid time unit suffix */
3706  return DTERR_BAD_FORMAT;
3707  }
3708  }
3709 
3710  havefield = true;
3711  }
3712 
3713  return 0;
3714 }
3715 
3716 
3717 /* DecodeUnits()
3718  * Decode text string using lookup table.
3719  *
3720  * This routine recognizes keywords associated with time interval units.
3721  *
3722  * Given string must be lowercased already.
3723  *
3724  * Implement a cache lookup since it is likely that dates
3725  * will be related in format.
3726  */
3727 int
3728 DecodeUnits(int field, char *lowtoken, int *val)
3729 {
3730  int type;
3731  const datetkn *tp;
3732 
3733  tp = deltacache[field];
3734  /* use strncmp so that we match truncated tokens */
3735  if (tp == NULL || strncmp(lowtoken, tp->token, TOKMAXLEN) != 0)
3736  {
3737  tp = datebsearch(lowtoken, deltatktbl, szdeltatktbl);
3738  }
3739  if (tp == NULL)
3740  {
3741  type = UNKNOWN_FIELD;
3742  *val = 0;
3743  }
3744  else
3745  {
3746  deltacache[field] = tp;
3747  type = tp->type;
3748  *val = tp->value;
3749  }
3750 
3751  return type;
3752 } /* DecodeUnits() */
3753 
3754 /*
3755  * Report an error detected by one of the datetime input processing routines.
3756  *
3757  * dterr is the error code, str is the original input string, datatype is
3758  * the name of the datatype we were trying to accept.
3759  *
3760  * Note: it might seem useless to distinguish DTERR_INTERVAL_OVERFLOW and
3761  * DTERR_TZDISP_OVERFLOW from DTERR_FIELD_OVERFLOW, but SQL99 mandates three
3762  * separate SQLSTATE codes, so ...
3763  */
3764 void
3765 DateTimeParseError(int dterr, const char *str, const char *datatype)
3766 {
3767  switch (dterr)
3768  {
3769  case DTERR_FIELD_OVERFLOW:
3770  ereport(ERROR,
3771  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3772  errmsg("date/time field value out of range: \"%s\"",
3773  str)));
3774  break;
3776  /* <nanny>same as above, but add hint about DateStyle</nanny> */
3777  ereport(ERROR,
3778  (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3779  errmsg("date/time field value out of range: \"%s\"",
3780  str),
3781  errhint("Perhaps you need a different \"datestyle\" setting.")));
3782  break;
3784  ereport(ERROR,
3785  (errcode(ERRCODE_INTERVAL_FIELD_OVERFLOW),
3786  errmsg("interval field value out of range: \"%s\"",
3787  str)));
3788  break;
3789  case DTERR_TZDISP_OVERFLOW:
3790  ereport(ERROR,
3791  (errcode(ERRCODE_INVALID_TIME_ZONE_DISPLACEMENT_VALUE),
3792  errmsg("time zone displacement out of range: \"%s\"",
3793  str)));
3794  break;
3795  case DTERR_BAD_FORMAT:
3796  default:
3797  ereport(ERROR,
3798  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3799  errmsg("invalid input syntax for type %s: \"%s\"",
3800  datatype, str)));
3801  break;
3802  }
3803 }
3804 
3805 /* datebsearch()
3806  * Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
3807  * is WAY faster than the generic bsearch().
3808  */
3809 static const datetkn *
3810 datebsearch(const char *key, const datetkn *base, int nel)
3811 {
3812  if (nel > 0)
3813  {
3814  const datetkn *last = base + nel - 1,
3815  *position;
3816  int result;
3817 
3818  while (last >= base)
3819  {
3820  position = base + ((last - base) >> 1);
3821  /* precheck the first character for a bit of extra speed */
3822  result = (int) key[0] - (int) position->token[0];
3823  if (result == 0)
3824  {
3825  /* use strncmp so that we match truncated tokens */
3826  result = strncmp(key, position->token, TOKMAXLEN);
3827  if (result == 0)
3828  return position;
3829  }
3830  if (result < 0)
3831  last = position - 1;
3832  else
3833  base = position + 1;
3834  }
3835  }
3836  return NULL;
3837 }
3838 
3839 /* EncodeTimezone()
3840  * Copies representation of a numeric timezone offset to str.
3841  *
3842  * Returns a pointer to the new end of string. No NUL terminator is put
3843  * there; callers are responsible for NUL terminating str themselves.
3844  */
3845 static char *
3846 EncodeTimezone(char *str, int tz, int style)
3847 {
3848  int hour,
3849  min,
3850  sec;
3851 
3852  sec = abs(tz);
3853  min = sec / SECS_PER_MINUTE;
3854  sec -= min * SECS_PER_MINUTE;
3855  hour = min / MINS_PER_HOUR;
3856  min -= hour * MINS_PER_HOUR;
3857 
3858  /* TZ is negated compared to sign we wish to display ... */
3859  *str++ = (tz <= 0 ? '+' : '-');
3860 
3861  if (sec != 0)
3862  {
3863  str = pg_ltostr_zeropad(str, hour, 2);
3864  *str++ = ':';
3865  str = pg_ltostr_zeropad(str, min, 2);
3866  *str++ = ':';
3867  str = pg_ltostr_zeropad(str, sec, 2);
3868  }
3869  else if (min != 0 || style == USE_XSD_DATES)
3870  {
3871  str = pg_ltostr_zeropad(str, hour, 2);
3872  *str++ = ':';
3873  str = pg_ltostr_zeropad(str, min, 2);
3874  }
3875  else
3876  str = pg_ltostr_zeropad(str, hour, 2);
3877  return str;
3878 }
3879 
3880 /* EncodeDateOnly()
3881  * Encode date as local time.
3882  */
3883 void
3884 EncodeDateOnly(struct pg_tm * tm, int style, char *str)
3885 {
3886  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
3887 
3888  switch (style)
3889  {
3890  case USE_ISO_DATES:
3891  case USE_XSD_DATES:
3892  /* compatible with ISO date formats */
3893  str = pg_ltostr_zeropad(str,
3894  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3895  *str++ = '-';
3896  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3897  *str++ = '-';
3898  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3899  break;
3900 
3901  case USE_SQL_DATES:
3902  /* compatible with Oracle/Ingres date formats */
3903  if (DateOrder == DATEORDER_DMY)
3904  {
3905  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3906  *str++ = '/';
3907  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3908  }
3909  else
3910  {
3911  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3912  *str++ = '/';
3913  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3914  }
3915  *str++ = '/';
3916  str = pg_ltostr_zeropad(str,
3917  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3918  break;
3919 
3920  case USE_GERMAN_DATES:
3921  /* German-style date format */
3922  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3923  *str++ = '.';
3924  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3925  *str++ = '.';
3926  str = pg_ltostr_zeropad(str,
3927  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3928  break;
3929 
3930  case USE_POSTGRES_DATES:
3931  default:
3932  /* traditional date-only style for Postgres */
3933  if (DateOrder == DATEORDER_DMY)
3934  {
3935  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3936  *str++ = '-';
3937  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3938  }
3939  else
3940  {
3941  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
3942  *str++ = '-';
3943  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
3944  }
3945  *str++ = '-';
3946  str = pg_ltostr_zeropad(str,
3947  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
3948  break;
3949  }
3950 
3951  if (tm->tm_year <= 0)
3952  {
3953  memcpy(str, " BC", 3); /* Don't copy NUL */
3954  str += 3;
3955  }
3956  *str = '\0';
3957 }
3958 
3959 
3960 /* EncodeTimeOnly()
3961  * Encode time fields only.
3962  *
3963  * tm and fsec are the value to encode, print_tz determines whether to include
3964  * a time zone (the difference between time and timetz types), tz is the
3965  * numeric time zone offset, style is the date style, str is where to write the
3966  * output.
3967  */
3968 void
3969 EncodeTimeOnly(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
3970 {
3971  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
3972  *str++ = ':';
3973  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
3974  *str++ = ':';
3975  str = AppendSeconds(str, tm->tm_sec, fsec, MAX_TIME_PRECISION, true);
3976  if (print_tz)
3977  str = EncodeTimezone(str, tz, style);
3978  *str = '\0';
3979 }
3980 
3981 
3982 /* EncodeDateTime()
3983  * Encode date and time interpreted as local time.
3984  *
3985  * tm and fsec are the value to encode, print_tz determines whether to include
3986  * a time zone (the difference between timestamp and timestamptz types), tz is
3987  * the numeric time zone offset, tzn is the textual time zone, which if
3988  * specified will be used instead of tz by some styles, style is the date
3989  * style, str is where to write the output.
3990  *
3991  * Supported date styles:
3992  * Postgres - day mon hh:mm:ss yyyy tz
3993  * SQL - mm/dd/yyyy hh:mm:ss.ss tz
3994  * ISO - yyyy-mm-dd hh:mm:ss+/-tz
3995  * German - dd.mm.yyyy hh:mm:ss tz
3996  * XSD - yyyy-mm-ddThh:mm:ss.ss+/-tz
3997  */
3998 void
3999 EncodeDateTime(struct pg_tm * tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
4000 {
4001  int day;
4002 
4003  Assert(tm->tm_mon >= 1 && tm->tm_mon <= MONTHS_PER_YEAR);
4004 
4005  /*
4006  * Negative tm_isdst means we have no valid time zone translation.
4007  */
4008  if (tm->tm_isdst < 0)
4009  print_tz = false;
4010 
4011  switch (style)
4012  {
4013  case USE_ISO_DATES:
4014  case USE_XSD_DATES:
4015  /* Compatible with ISO-8601 date formats */
4016  str = pg_ltostr_zeropad(str,
4017  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4018  *str++ = '-';
4019  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4020  *str++ = '-';
4021  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4022  *str++ = (style == USE_ISO_DATES) ? ' ' : 'T';
4023  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4024  *str++ = ':';
4025  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4026  *str++ = ':';
4027  str = AppendTimestampSeconds(str, tm, fsec);
4028  if (print_tz)
4029  str = EncodeTimezone(str, tz, style);
4030  break;
4031 
4032  case USE_SQL_DATES:
4033  /* Compatible with Oracle/Ingres date formats */
4034  if (DateOrder == DATEORDER_DMY)
4035  {
4036  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4037  *str++ = '/';
4038  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4039  }
4040  else
4041  {
4042  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4043  *str++ = '/';
4044  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4045  }
4046  *str++ = '/';
4047  str = pg_ltostr_zeropad(str,
4048  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4049  *str++ = ' ';
4050  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4051  *str++ = ':';
4052  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4053  *str++ = ':';
4054  str = AppendTimestampSeconds(str, tm, fsec);
4055 
4056  /*
4057  * Note: the uses of %.*s in this function would be risky if the
4058  * timezone names ever contain non-ASCII characters. However, all
4059  * TZ abbreviations in the IANA database are plain ASCII.
4060  */
4061  if (print_tz)
4062  {
4063  if (tzn)
4064  {
4065  sprintf(str, " %.*s", MAXTZLEN, tzn);
4066  str += strlen(str);
4067  }
4068  else
4069  str = EncodeTimezone(str, tz, style);
4070  }
4071  break;
4072 
4073  case USE_GERMAN_DATES:
4074  /* German variant on European style */
4075  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4076  *str++ = '.';
4077  str = pg_ltostr_zeropad(str, tm->tm_mon, 2);
4078  *str++ = '.';
4079  str = pg_ltostr_zeropad(str,
4080  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4081  *str++ = ' ';
4082  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4083  *str++ = ':';
4084  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4085  *str++ = ':';
4086  str = AppendTimestampSeconds(str, tm, fsec);
4087 
4088  if (print_tz)
4089  {
4090  if (tzn)
4091  {
4092  sprintf(str, " %.*s", MAXTZLEN, tzn);
4093  str += strlen(str);
4094  }
4095  else
4096  str = EncodeTimezone(str, tz, style);
4097  }
4098  break;
4099 
4100  case USE_POSTGRES_DATES:
4101  default:
4102  /* Backward-compatible with traditional Postgres abstime dates */
4103  day = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
4104  tm->tm_wday = j2day(day);
4105  memcpy(str, days[tm->tm_wday], 3);
4106  str += 3;
4107  *str++ = ' ';
4108  if (DateOrder == DATEORDER_DMY)
4109  {
4110  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4111  *str++ = ' ';
4112  memcpy(str, months[tm->tm_mon - 1], 3);
4113  str += 3;
4114  }
4115  else
4116  {
4117  memcpy(str, months[tm->tm_mon - 1], 3);
4118  str += 3;
4119  *str++ = ' ';
4120  str = pg_ltostr_zeropad(str, tm->tm_mday, 2);
4121  }
4122  *str++ = ' ';
4123  str = pg_ltostr_zeropad(str, tm->tm_hour, 2);
4124  *str++ = ':';
4125  str = pg_ltostr_zeropad(str, tm->tm_min, 2);
4126  *str++ = ':';
4127  str = AppendTimestampSeconds(str, tm, fsec);
4128  *str++ = ' ';
4129  str = pg_ltostr_zeropad(str,
4130  (tm->tm_year > 0) ? tm->tm_year : -(tm->tm_year - 1), 4);
4131 
4132  if (print_tz)
4133  {
4134  if (tzn)
4135  {
4136  sprintf(str, " %.*s", MAXTZLEN, tzn);
4137  str += strlen(str);
4138  }
4139  else
4140  {
4141  /*
4142  * We have a time zone, but no string version. Use the
4143  * numeric form, but be sure to include a leading space to
4144  * avoid formatting something which would be rejected by
4145  * the date/time parser later. - thomas 2001-10-19
4146  */
4147  *str++ = ' ';
4148  str = EncodeTimezone(str, tz, style);
4149  }
4150  }
4151  break;
4152  }
4153 
4154  if (tm->tm_year <= 0)
4155  {
4156  memcpy(str, " BC", 3); /* Don't copy NUL */
4157  str += 3;
4158  }
4159  *str = '\0';
4160 }
4161 
4162 
4163 /*
4164  * Helper functions to avoid duplicated code in EncodeInterval.
4165  */
4166 
4167 /* Append an ISO-8601-style interval field, but only if value isn't zero */
4168 static char *
4169 AddISO8601IntPart(char *cp, int value, char units)
4170 {
4171  if (value == 0)
4172  return cp;
4173  sprintf(cp, "%d%c", value, units);
4174  return cp + strlen(cp);
4175 }
4176 
4177 /* Append a postgres-style interval field, but only if value isn't zero */
4178 static char *
4179 AddPostgresIntPart(char *cp, int value, const char *units,
4180  bool *is_zero, bool *is_before)
4181 {
4182  if (value == 0)
4183  return cp;
4184  sprintf(cp, "%s%s%d %s%s",
4185  (!*is_zero) ? " " : "",
4186  (*is_before && value > 0) ? "+" : "",
4187  value,
4188  units,
4189  (value != 1) ? "s" : "");
4190 
4191  /*
4192  * Each nonzero field sets is_before for (only) the next one. This is a
4193  * tad bizarre but it's how it worked before...
4194  */
4195  *is_before = (value < 0);
4196  *is_zero = FALSE;
4197  return cp + strlen(cp);
4198 }
4199 
4200 /* Append a verbose-style interval field, but only if value isn't zero */
4201 static char *
4202 AddVerboseIntPart(char *cp, int value, const char *units,
4203  bool *is_zero, bool *is_before)
4204 {
4205  if (value == 0)
4206  return cp;
4207  /* first nonzero value sets is_before */
4208  if (*is_zero)
4209  {
4210  *is_before = (value < 0);
4211  value = abs(value);
4212  }
4213  else if (*is_before)
4214  value = -value;
4215  sprintf(cp, " %d %s%s", value, units, (value == 1) ? "" : "s");
4216  *is_zero = FALSE;
4217  return cp + strlen(cp);
4218 }
4219 
4220 
4221 /* EncodeInterval()
4222  * Interpret time structure as a delta time and convert to string.
4223  *
4224  * Support "traditional Postgres" and ISO-8601 styles.
4225  * Actually, afaik ISO does not address time interval formatting,
4226  * but this looks similar to the spec for absolute date/time.
4227  * - thomas 1998-04-30
4228  *
4229  * Actually, afaik, ISO 8601 does specify formats for "time
4230  * intervals...[of the]...format with time-unit designators", which
4231  * are pretty ugly. The format looks something like
4232  * P1Y1M1DT1H1M1.12345S
4233  * but useful for exchanging data with computers instead of humans.
4234  * - ron 2003-07-14
4235  *
4236  * And ISO's SQL 2008 standard specifies standards for
4237  * "year-month literal"s (that look like '2-3') and
4238  * "day-time literal"s (that look like ('4 5:6:7')
4239  */
4240 void
4241 EncodeInterval(struct pg_tm * tm, fsec_t fsec, int style, char *str)
4242 {
4243  char *cp = str;
4244  int year = tm->tm_year;
4245  int mon = tm->tm_mon;
4246  int mday = tm->tm_mday;
4247  int hour = tm->tm_hour;
4248  int min = tm->tm_min;
4249  int sec = tm->tm_sec;
4250  bool is_before = FALSE;
4251  bool is_zero = TRUE;
4252 
4253  /*
4254  * The sign of year and month are guaranteed to match, since they are
4255  * stored internally as "month". But we'll need to check for is_before and
4256  * is_zero when determining the signs of day and hour/minute/seconds
4257  * fields.
4258  */
4259  switch (style)
4260  {
4261  /* SQL Standard interval format */
4262  case INTSTYLE_SQL_STANDARD:
4263  {
4264  bool has_negative = year < 0 || mon < 0 ||
4265  mday < 0 || hour < 0 ||
4266  min < 0 || sec < 0 || fsec < 0;
4267  bool has_positive = year > 0 || mon > 0 ||
4268  mday > 0 || hour > 0 ||
4269  min > 0 || sec > 0 || fsec > 0;
4270  bool has_year_month = year != 0 || mon != 0;
4271  bool has_day_time = mday != 0 || hour != 0 ||
4272  min != 0 || sec != 0 || fsec != 0;
4273  bool has_day = mday != 0;
4274  bool sql_standard_value = !(has_negative && has_positive) &&
4275  !(has_year_month && has_day_time);
4276 
4277  /*
4278  * SQL Standard wants only 1 "<sign>" preceding the whole
4279  * interval ... but can't do that if mixed signs.
4280  */
4281  if (has_negative && sql_standard_value)
4282  {
4283  *cp++ = '-';
4284  year = -year;
4285  mon = -mon;
4286  mday = -mday;
4287  hour = -hour;
4288  min = -min;
4289  sec = -sec;
4290  fsec = -fsec;
4291  }
4292 
4293  if (!has_negative && !has_positive)
4294  {
4295  sprintf(cp, "0");
4296  }
4297  else if (!sql_standard_value)
4298  {
4299  /*
4300  * For non sql-standard interval values, force outputting
4301  * the signs to avoid ambiguities with intervals with
4302  * mixed sign components.
4303  */
4304  char year_sign = (year < 0 || mon < 0) ? '-' : '+';
4305  char day_sign = (mday < 0) ? '-' : '+';
4306  char sec_sign = (hour < 0 || min < 0 ||
4307  sec < 0 || fsec < 0) ? '-' : '+';
4308 
4309  sprintf(cp, "%c%d-%d %c%d %c%d:%02d:",
4310  year_sign, abs(year), abs(mon),
4311  day_sign, abs(mday),
4312  sec_sign, abs(hour), abs(min));
4313  cp += strlen(cp);
4314  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4315  *cp = '\0';
4316  }
4317  else if (has_year_month)
4318  {
4319  sprintf(cp, "%d-%d", year, mon);
4320  }
4321  else if (has_day)
4322  {
4323  sprintf(cp, "%d %d:%02d:", mday, hour, min);
4324  cp += strlen(cp);
4325  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4326  *cp = '\0';
4327  }
4328  else
4329  {
4330  sprintf(cp, "%d:%02d:", hour, min);
4331  cp += strlen(cp);
4332  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4333  *cp = '\0';
4334  }
4335  }
4336  break;
4337 
4338  /* ISO 8601 "time-intervals by duration only" */
4339  case INTSTYLE_ISO_8601:
4340  /* special-case zero to avoid printing nothing */
4341  if (year == 0 && mon == 0 && mday == 0 &&
4342  hour == 0 && min == 0 && sec == 0 && fsec == 0)
4343  {
4344  sprintf(cp, "PT0S");
4345  break;
4346  }
4347  *cp++ = 'P';
4348  cp = AddISO8601IntPart(cp, year, 'Y');
4349  cp = AddISO8601IntPart(cp, mon, 'M');
4350  cp = AddISO8601IntPart(cp, mday, 'D');
4351  if (hour != 0 || min != 0 || sec != 0 || fsec != 0)
4352  *cp++ = 'T';
4353  cp = AddISO8601IntPart(cp, hour, 'H');
4354  cp = AddISO8601IntPart(cp, min, 'M');
4355  if (sec != 0 || fsec != 0)
4356  {
4357  if (sec < 0 || fsec < 0)
4358  *cp++ = '-';
4359  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4360  *cp++ = 'S';
4361  *cp++ = '\0';
4362  }
4363  break;
4364 
4365  /* Compatible with postgresql < 8.4 when DateStyle = 'iso' */
4366  case INTSTYLE_POSTGRES:
4367  cp = AddPostgresIntPart(cp, year, "year", &is_zero, &is_before);
4368 
4369  /*
4370  * Ideally we should spell out "month" like we do for "year" and
4371  * "day". However, for backward compatibility, we can't easily
4372  * fix this. bjm 2011-05-24
4373  */
4374  cp = AddPostgresIntPart(cp, mon, "mon", &is_zero, &is_before);
4375  cp = AddPostgresIntPart(cp, mday, "day", &is_zero, &is_before);
4376  if (is_zero || hour != 0 || min != 0 || sec != 0 || fsec != 0)
4377  {
4378  bool minus = (hour < 0 || min < 0 || sec < 0 || fsec < 0);
4379 
4380  sprintf(cp, "%s%s%02d:%02d:",
4381  is_zero ? "" : " ",
4382  (minus ? "-" : (is_before ? "+" : "")),
4383  abs(hour), abs(min));
4384  cp += strlen(cp);
4385  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, true);
4386  *cp = '\0';
4387  }
4388  break;
4389 
4390  /* Compatible with postgresql < 8.4 when DateStyle != 'iso' */
4392  default:
4393  strcpy(cp, "@");
4394  cp++;
4395  cp = AddVerboseIntPart(cp, year, "year", &is_zero, &is_before);
4396  cp = AddVerboseIntPart(cp, mon, "mon", &is_zero, &is_before);
4397  cp = AddVerboseIntPart(cp, mday, "day", &is_zero, &is_before);
4398  cp = AddVerboseIntPart(cp, hour, "hour", &is_zero, &is_before);
4399  cp = AddVerboseIntPart(cp, min, "min", &is_zero, &is_before);
4400  if (sec != 0 || fsec != 0)
4401  {
4402  *cp++ = ' ';
4403  if (sec < 0 || (sec == 0 && fsec < 0))
4404  {
4405  if (is_zero)
4406  is_before = TRUE;
4407  else if (!is_before)
4408  *cp++ = '-';
4409  }
4410  else if (is_before)
4411  *cp++ = '-';
4412  cp = AppendSeconds(cp, sec, fsec, MAX_INTERVAL_PRECISION, false);
4413  sprintf(cp, " sec%s",
4414  (abs(sec) != 1 || fsec != 0) ? "s" : "");
4415  is_zero = FALSE;
4416  }
4417  /* identically zero? then put in a unitless zero... */
4418  if (is_zero)
4419  strcat(cp, " 0");
4420  if (is_before)
4421  strcat(cp, " ago");
4422  break;
4423  }
4424 }
4425 
4426 
4427 /*
4428  * We've been burnt by stupid errors in the ordering of the datetkn tables
4429  * once too often. Arrange to check them during postmaster start.
4430  */
4431 static bool
4432 CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
4433 {
4434  bool ok = true;
4435  int i;
4436 
4437  for (i = 0; i < nel; i++)
4438  {
4439  /* check for token strings that don't fit */
4440  if (strlen(base[i].token) > TOKMAXLEN)
4441  {
4442  /* %.*s is safe since all our tokens are ASCII */
4443  elog(LOG, "token too long in %s table: \"%.*s\"",
4444  tablename,
4445  TOKMAXLEN + 1, base[i].token);
4446  ok = false;
4447  break; /* don't risk applying strcmp */
4448  }
4449  /* check for out of order */
4450  if (i > 0 &&
4451  strcmp(base[i - 1].token, base[i].token) >= 0)
4452  {
4453  elog(LOG, "ordering error in %s table: \"%s\" >= \"%s\"",
4454  tablename,
4455  base[i - 1].token,
4456  base[i].token);
4457  ok = false;
4458  }
4459  }
4460  return ok;
4461 }
4462 
4463 bool
4465 {
4466  bool ok = true;
4467 
4468  Assert(UNIX_EPOCH_JDATE == date2j(1970, 1, 1));
4469  Assert(POSTGRES_EPOCH_JDATE == date2j(2000, 1, 1));
4470 
4471  ok &= CheckDateTokenTable("datetktbl", datetktbl, szdatetktbl);
4472  ok &= CheckDateTokenTable("deltatktbl", deltatktbl, szdeltatktbl);
4473  return ok;
4474 }
4475 
4476 /*
4477  * Common code for temporal protransform functions. Types time, timetz,
4478  * timestamp and timestamptz each have a range of allowed precisions. An
4479  * unspecified precision is rigorously equivalent to the highest specifiable
4480  * precision.
4481  *
4482  * Note: timestamp_scale throws an error when the typmod is out of range, but
4483  * we can't get there from a cast: our typmodin will have caught it already.
4484  */
4485 Node *
4486 TemporalTransform(int32 max_precis, Node *node)
4487 {
4488  FuncExpr *expr = castNode(FuncExpr, node);
4489  Node *ret = NULL;
4490  Node *typmod;
4491 
4492  Assert(list_length(expr->args) >= 2);
4493 
4494  typmod = (Node *) lsecond(expr->args);
4495 
4496  if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
4497  {
4498  Node *source = (Node *) linitial(expr->args);
4499  int32 old_precis = exprTypmod(source);
4500  int32 new_precis = DatumGetInt32(((Const *) typmod)->constvalue);
4501 
4502  if (new_precis < 0 || new_precis == max_precis ||
4503  (old_precis >= 0 && new_precis >= old_precis))
4504  ret = relabel_to_typmod(source, new_precis);
4505  }
4506 
4507  return ret;
4508 }
4509 
4510 /*
4511  * This function gets called during timezone config file load or reload
4512  * to create the final array of timezone tokens. The argument array
4513  * is already sorted in name order.
4514  *
4515  * The result is a TimeZoneAbbrevTable (which must be a single malloc'd chunk)
4516  * or NULL on malloc failure. No other error conditions are defined.
4517  */
4519 ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
4520 {
4521  TimeZoneAbbrevTable *tbl;
4522  Size tbl_size;
4523  int i;
4524 
4525  /* Space for fixed fields and datetkn array */
4526  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4527  n * sizeof(datetkn);
4528  tbl_size = MAXALIGN(tbl_size);
4529  /* Count up space for dynamic abbreviations */
4530  for (i = 0; i < n; i++)
4531  {
4532  struct tzEntry *abbr = abbrevs + i;
4533 
4534  if (abbr->zone != NULL)
4535  {
4536  Size dsize;
4537 
4538  dsize = offsetof(DynamicZoneAbbrev, zone) +
4539  strlen(abbr->zone) + 1;
4540  tbl_size += MAXALIGN(dsize);
4541  }
4542  }
4543 
4544  /* Alloc the result ... */
4545  tbl = malloc(tbl_size);
4546  if (!tbl)
4547  return NULL;
4548 
4549  /* ... and fill it in */
4550  tbl->tblsize = tbl_size;
4551  tbl->numabbrevs = n;
4552  /* in this loop, tbl_size reprises the space calculation above */
4553  tbl_size = offsetof(TimeZoneAbbrevTable, abbrevs) +
4554  n * sizeof(datetkn);
4555  tbl_size = MAXALIGN(tbl_size);
4556  for (i = 0; i < n; i++)
4557  {
4558  struct tzEntry *abbr = abbrevs + i;
4559  datetkn *dtoken = tbl->abbrevs + i;
4560 
4561  /* use strlcpy to truncate name if necessary */
4562  strlcpy(dtoken->token, abbr->abbrev, TOKMAXLEN + 1);
4563  if (abbr->zone != NULL)
4564  {
4565  /* Allocate a DynamicZoneAbbrev for this abbreviation */
4566  DynamicZoneAbbrev *dtza;
4567  Size dsize;
4568 
4569  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tbl_size);
4570  dtza->tz = NULL;
4571  strcpy(dtza->zone, abbr->zone);
4572 
4573  dtoken->type = DYNTZ;
4574  /* value is offset from table start to DynamicZoneAbbrev */
4575  dtoken->value = (int32) tbl_size;
4576 
4577  dsize = offsetof(DynamicZoneAbbrev, zone) +
4578  strlen(abbr->zone) + 1;
4579  tbl_size += MAXALIGN(dsize);
4580  }
4581  else
4582  {
4583  dtoken->type = abbr->is_dst ? DTZ : TZ;
4584  dtoken->value = abbr->offset;
4585  }
4586  }
4587 
4588  /* Assert the two loops above agreed on size calculations */
4589  Assert(tbl->tblsize == tbl_size);
4590 
4591  /* Check the ordering, if testing */
4592  Assert(CheckDateTokenTable("timezone abbreviations", tbl->abbrevs, n));
4593 
4594  return tbl;
4595 }
4596 
4597 /*
4598  * Install a TimeZoneAbbrevTable as the active table.
4599  *
4600  * Caller is responsible that the passed table doesn't go away while in use.
4601  */
4602 void
4604 {
4605  zoneabbrevtbl = tbl;
4606  /* reset abbrevcache, which may contain pointers into old table */
4607  memset(abbrevcache, 0, sizeof(abbrevcache));
4608 }
4609 
4610 /*
4611  * Helper subroutine to locate pg_tz timezone for a dynamic abbreviation.
4612  */
4613 static pg_tz *
4615 {
4616  DynamicZoneAbbrev *dtza;
4617 
4618  /* Just some sanity checks to prevent indexing off into nowhere */
4619  Assert(tp->type == DYNTZ);
4620  Assert(tp->value > 0 && tp->value < tbl->tblsize);
4621 
4622  dtza = (DynamicZoneAbbrev *) ((char *) tbl + tp->value);
4623 
4624  /* Look up the underlying zone if we haven't already */
4625  if (dtza->tz == NULL)
4626  {
4627  dtza->tz = pg_tzset(dtza->zone);
4628 
4629  /*
4630  * Ideally we'd let the caller ereport instead of doing it here, but
4631  * then there is no way to report the bad time zone name.
4632  */
4633  if (dtza->tz == NULL)
4634  ereport(ERROR,
4635  (errcode(ERRCODE_CONFIG_FILE_ERROR),
4636  errmsg("time zone \"%s\" not recognized",
4637  dtza->zone),
4638  errdetail("This time zone name appears in the configuration file for time zone abbreviation \"%s\".",
4639  tp->token)));
4640  }
4641  return dtza->tz;
4642 }
4643 
4644 
4645 /*
4646  * This set-returning function reads all the available time zone abbreviations
4647  * and returns a set of (abbrev, utc_offset, is_dst).
4648  */
4649 Datum
4651 {
4652  FuncCallContext *funcctx;
4653  int *pindex;
4654  Datum result;
4655  HeapTuple tuple;
4656  Datum values[3];
4657  bool nulls[3];
4658  const datetkn *tp;
4659  char buffer[TOKMAXLEN + 1];
4660  int gmtoffset;
4661  bool is_dst;
4662  unsigned char *p;
4663  struct pg_tm tm;
4664  Interval *resInterval;
4665 
4666  /* stuff done only on the first call of the function */
4667  if (SRF_IS_FIRSTCALL())
4668  {
4669  TupleDesc tupdesc;
4670  MemoryContext oldcontext;
4671 
4672  /* create a function context for cross-call persistence */
4673  funcctx = SRF_FIRSTCALL_INIT();
4674 
4675  /*
4676  * switch to memory context appropriate for multiple function calls
4677  */
4678  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4679 
4680  /* allocate memory for user context */
4681  pindex = (int *) palloc(sizeof(int));
4682  *pindex = 0;
4683  funcctx->user_fctx = (void *) pindex;
4684 
4685  /*
4686  * build tupdesc for result tuples. This must match this function's
4687  * pg_proc entry!
4688  */
4689  tupdesc = CreateTemplateTupleDesc(3, false);
4690  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "abbrev",
4691  TEXTOID, -1, 0);
4692  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "utc_offset",
4693  INTERVALOID, -1, 0);
4694  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "is_dst",
4695  BOOLOID, -1, 0);
4696 
4697  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
4698  MemoryContextSwitchTo(oldcontext);
4699  }
4700 
4701  /* stuff done on every call of the function */
4702  funcctx = SRF_PERCALL_SETUP();
4703  pindex = (int *) funcctx->user_fctx;
4704 
4705  if (zoneabbrevtbl == NULL ||
4706  *pindex >= zoneabbrevtbl->numabbrevs)
4707  SRF_RETURN_DONE(funcctx);
4708 
4709  tp = zoneabbrevtbl->abbrevs + *pindex;
4710 
4711  switch (tp->type)
4712  {
4713  case TZ:
4714  gmtoffset = tp->value;
4715  is_dst = false;
4716  break;
4717  case DTZ:
4718  gmtoffset = tp->value;
4719  is_dst = true;
4720  break;
4721  case DYNTZ:
4722  {
4723  /* Determine the current meaning of the abbrev */
4724  pg_tz *tzp;
4725  TimestampTz now;
4726  int isdst;
4727 
4728  tzp = FetchDynamicTimeZone(zoneabbrevtbl, tp);
4730  gmtoffset = -DetermineTimeZoneAbbrevOffsetTS(now,
4731  tp->token,
4732  tzp,
4733  &isdst);
4734  is_dst = (bool) isdst;
4735  break;
4736  }
4737  default:
4738  elog(ERROR, "unrecognized timezone type %d", (int) tp->type);
4739  gmtoffset = 0; /* keep compiler quiet */
4740  is_dst = false;
4741  break;
4742  }
4743 
4744  MemSet(nulls, 0, sizeof(nulls));
4745 
4746  /*
4747  * Convert name to text, using upcasing conversion that is the inverse of
4748  * what ParseDateTime() uses.
4749  */
4750  strlcpy(buffer, tp->token, sizeof(buffer));
4751  for (p = (unsigned char *) buffer; *p; p++)
4752  *p = pg_toupper(*p);
4753 
4754  values[0] = CStringGetTextDatum(buffer);
4755 
4756  /* Convert offset (in seconds) to an interval */
4757  MemSet(&tm, 0, sizeof(struct pg_tm));
4758  tm.tm_sec = gmtoffset;
4759  resInterval = (Interval *) palloc(sizeof(Interval));
4760  tm2interval(&tm, 0, resInterval);
4761  values[1] = IntervalPGetDatum(resInterval);
4762 
4763  values[2] = BoolGetDatum(is_dst);
4764 
4765  (*pindex)++;
4766 
4767  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
4768  result = HeapTupleGetDatum(tuple);
4769 
4770  SRF_RETURN_NEXT(funcctx, result);
4771 }
4772 
4773 /*
4774  * This set-returning function reads all the available full time zones
4775  * and returns a set of (name, abbrev, utc_offset, is_dst).
4776  */
4777 Datum
4779 {
4780  MemoryContext oldcontext;
4781  FuncCallContext *funcctx;
4782  pg_tzenum *tzenum;
4783  pg_tz *tz;
4784  Datum result;
4785  HeapTuple tuple;
4786  Datum values[4];
4787  bool nulls[4];
4788  int tzoff;
4789  struct pg_tm tm;
4790  fsec_t fsec;
4791  const char *tzn;
4792  Interval *resInterval;
4793  struct pg_tm itm;
4794 
4795  /* stuff done only on the first call of the function */
4796  if (SRF_IS_FIRSTCALL())
4797  {
4798  TupleDesc tupdesc;
4799 
4800  /* create a function context for cross-call persistence */
4801  funcctx = SRF_FIRSTCALL_INIT();
4802 
4803  /*
4804  * switch to memory context appropriate for multiple function calls
4805  */
4806  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4807 
4808  /* initialize timezone scanning code */
4809  tzenum = pg_tzenumerate_start();
4810  funcctx->user_fctx = (void *) tzenum;
4811 
4812  /*
4813  * build tupdesc for result tuples. This must match this function's
4814  * pg_proc entry!
4815  */
4816  tupdesc = CreateTemplateTupleDesc(4, false);
4817  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
4818  TEXTOID, -1, 0);
4819  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "abbrev",
4820  TEXTOID, -1, 0);
4821  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "utc_offset",
4822  INTERVALOID, -1, 0);
4823  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "is_dst",
4824  BOOLOID, -1, 0);
4825 
4826  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
4827  MemoryContextSwitchTo(oldcontext);
4828  }
4829 
4830  /* stuff done on every call of the function */
4831  funcctx = SRF_PERCALL_SETUP();
4832  tzenum = (pg_tzenum *) funcctx->user_fctx;
4833 
4834  /* search for another zone to display */
4835  for (;;)
4836  {
4837  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
4838  tz = pg_tzenumerate_next(tzenum);
4839  MemoryContextSwitchTo(oldcontext);
4840 
4841  if (!tz)
4842  {
4843  pg_tzenumerate_end(tzenum);
4844  funcctx->user_fctx = NULL;
4845  SRF_RETURN_DONE(funcctx);
4846  }
4847 
4848  /* Convert now() to local time in this zone */
4850  &tzoff, &tm, &fsec, &tzn, tz) != 0)
4851  continue; /* ignore if conversion fails */
4852 
4853  /*
4854  * Ignore zic's rather silly "Factory" time zone. The long string
4855  * about "see zic manual page" is used in tzdata versions before
4856  * 2016g; we can drop it someday when we're pretty sure no such data
4857  * exists in the wild on platforms using --with-system-tzdata. In
4858  * 2016g and later, the time zone abbreviation "-00" is used for
4859  * "Factory" as well as some invalid cases, all of which we can
4860  * reasonably omit from the pg_timezone_names view.
4861  */
4862  if (tzn && (strcmp(tzn, "-00") == 0 ||
4863  strcmp(tzn, "Local time zone must be set--see zic manual page") == 0))
4864  continue;
4865 
4866  /* Found a displayable zone */
4867  break;
4868  }
4869 
4870  MemSet(nulls, 0, sizeof(nulls));
4871 
4872  values[0] = CStringGetTextDatum(pg_get_timezone_name(tz));
4873  values[1] = CStringGetTextDatum(tzn ? tzn : "");
4874 
4875  MemSet(&itm, 0, sizeof(struct pg_tm));
4876  itm.tm_sec = -tzoff;
4877  resInterval = (Interval *) palloc(sizeof(Interval));
4878  tm2interval(&itm, 0, resInterval);
4879  values[2] = IntervalPGetDatum(resInterval);
4880 
4881  values[3] = BoolGetDatum(tm.tm_isdst > 0);
4882 
4883  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
4884  result = HeapTupleGetDatum(tuple);
4885 
4886  SRF_RETURN_NEXT(funcctx, result);
4887 }
void EncodeDateOnly(struct pg_tm *tm, int style, char *str)
Definition: datetime.c:3884
#define INTSTYLE_POSTGRES_VERBOSE
Definition: miscadmin.h:231
#define DYEAR
Definition: datetime.h:57
#define DTERR_BAD_FORMAT
Definition: datetime.h:282
#define DTK_TZ_HOUR
Definition: datetime.h:180
#define DTK_CENTURY
Definition: datetime.h:172
static struct @76 value
void GetCurrentDateTime(struct pg_tm *tm)
Definition: datetime.c:370
#define PM
Definition: datetime.h:73
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
#define DAY
Definition: datetime.h:94
#define UNITS
Definition: datetime.h:108
int errhint(const char *fmt,...)
Definition: elog.c:987
#define DAGO
Definition: datetime.h:36
void DateTimeParseError(int dterr, const char *str, const char *datatype)
Definition: datetime.c:3765
#define IGNORE_DTF
Definition: datetime.h:99
int64 pg_time_t
Definition: pgtime.h:23
#define APPEND_CHAR(bufptr, end, newchar)
int tm_wday
Definition: pgtime.h:33
int pg_next_dst_boundary(const pg_time_t *timep, long int *before_gmtoff, int *before_isdst, pg_time_t *boundary, long int *after_gmtoff, int *after_isdst, const pg_tz *tz)
Definition: localtime.c:1505
List * args
Definition: primnodes.h:434
static const datetkn * deltacache[MAXDATEFIELDS]
Definition: datetime.c:249
#define DWEEK
Definition: datetime.h:54
#define DatumGetInt32(X)
Definition: postgres.h:480
#define DTK_JULIAN
Definition: datetime.h:176
#define DTK_WEEK
Definition: datetime.h:167
#define DTK_YEAR
Definition: datetime.h:170
int tm_isdst
Definition: pgtime.h:35
#define MILLENNIUM
Definition: datetime.h:121
#define LATE
Definition: datetime.h:41
#define USECS_PER_SEC
Definition: timestamp.h:94
Definition: isn.c:33
#define YEAR
Definition: datetime.h:93
#define castNode(_type_, nodeptr)
Definition: nodes.h:578
#define CENTURY
Definition: datetime.h:120
#define DTK_DELTA
Definition: datetime.h:162
void InstallTimeZoneAbbrevs(TimeZoneAbbrevTable *tbl)
Definition: datetime.c:4603
#define TEXTOID
Definition: pg_type.h:324
int32 exprTypmod(const Node *expr)
Definition: nodeFuncs.c:273
int64 TimestampTz
Definition: timestamp.h:39
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:285
static const datetkn datetktbl[]
Definition: datetime.c:90
Datum pg_timezone_abbrevs(PG_FUNCTION_ARGS)
Definition: datetime.c:4650
int tm_hour
Definition: pgtime.h:29
static char * EncodeTimezone(char *str, int tz, int style)
Definition: datetime.c:3846
#define NOW
Definition: datetime.h:42
#define DECADE
Definition: datetime.h:119
#define DTK_QUARTER
Definition: datetime.h:169
#define isleap(y)
Definition: datetime.h:273
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1757
static pg_tz * FetchDynamicTimeZone(TimeZoneAbbrevTable *tbl, const datetkn *tp)
Definition: datetime.c:4614
static int DetermineTimeZoneOffsetInternal(struct pg_tm *tm, pg_tz *tzp, pg_time_t *tp)
Definition: datetime.c:1493
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
bool CheckDateTokenTables(void)
Definition: datetime.c:4464
Definition: nodes.h:509
#define AGO
Definition: datetime.h:111
#define DTK_TIME_M
Definition: datetime.h:195
void EncodeTimeOnly(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, int style, char *str)
Definition: datetime.c:3969
#define DTK_MILLENNIUM
Definition: datetime.h:173
unsigned char pg_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:122
void pg_tzenumerate_end(pg_tzenum *dir)
Definition: pgtz.c:398
int errcode(int sqlerrcode)
Definition: elog.c:575
int offset
Definition: tzparser.h:29
int scale
Definition: pgbench.c:106
int IntervalStyle
Definition: globals.c:108
#define MemSet(start, val, len)
Definition: c.h:853
#define DTK_ISODOW
Definition: datetime.h:183
#define TZ
Definition: datetime.h:96
#define USE_SQL_DATES
Definition: miscadmin.h:211
#define UNKNOWN_FIELD
Definition: datetime.h:125
long date
Definition: pgtypes_date.h:8
#define SECOND
Definition: datetime.h:103
int32 value
Definition: datetime.h:214
static int DecodeNumberField(int len, char *str, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2819
int DecodeUnits(int field, char *lowtoken, int *val)
Definition: datetime.c:3728
#define DTK_TODAY
Definition: datetime.h:158
#define DTK_TOMORROW
Definition: datetime.h:159
#define MAXTZLEN
Definition: miscadmin.h:237
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
#define ADBC
Definition: datetime.h:109
Definition: pgtime.h:25
#define LOG
Definition: elog.h:26
#define AD
Definition: datetime.h:76
#define DTK_CURRENT
Definition: datetime.h:152
#define INTERVAL_FULL_RANGE
Definition: timestamp.h:48
#define EPOCH
Definition: datetime.h:38
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:289
static void AdjustFractSeconds(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:484
int DecodeTimeOnly(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:1744
#define lsecond(l)
Definition: pg_list.h:114
#define DTK_DATE_M
Definition: datetime.h:194
#define MINS_PER_HOUR
Definition: timestamp.h:89
TupleDesc tuple_desc
Definition: funcapi.h:120
#define DTK_INVALID
Definition: datetime.h:151
char bool
Definition: c.h:199
signed int int32
Definition: c.h:253
#define USE_ISO_DATES
Definition: miscadmin.h:210
#define TOMORROW
Definition: datetime.h:44
#define DHOUR
Definition: datetime.h:52
#define MAX_TZDISP_HOUR
Definition: timestamp.h:103
char * zone
Definition: tzparser.h:27
#define DA_D
Definition: datetime.h:61
static struct pg_tm tm
Definition: localtime.c:103
#define Abs(x)
Definition: c.h:808
bool is_dst
Definition: tzparser.h:30
#define malloc(a)
Definition: header.h:45
static int szdatetktbl
Definition: datetime.c:168
#define DMILLISEC
Definition: datetime.h:49
pg_tz * pg_tzset(const char *tzname)
Definition: pgtz.c:218
#define DSECOND
Definition: datetime.h:50
#define DTK_MONTH
Definition: datetime.h:168
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:291
#define DTK_MILLISEC
Definition: datetime.h:174
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
#define DMICROSEC
Definition: datetime.h:48
#define DTK_DECADE
Definition: datetime.h:171
#define TODAY
Definition: datetime.h:43
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:783
#define TZ_STRLEN_MAX
Definition: pgtime.h:44
const char *const months[]
Definition: datetime.c:66
#define linitial(l)
Definition: pg_list.h:110
#define DTK_TZ
Definition: datetime.h:147
#define DTK_HOUR
Definition: datetime.h:165
#define ERROR
Definition: elog.h:43
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
#define DOW
Definition: datetime.h:107
#define AM
Definition: datetime.h:72
#define DCURRENT
Definition: datetime.h:37
int DecodeTimezoneAbbrev(int field, char *lowtoken, int *offset, pg_tz **tz)
Definition: datetime.c:2984
#define MAX_INTERVAL_PRECISION
Definition: timestamp.h:54
char token[TOKMAXLEN+1]
Definition: datetime.h:212
#define MILLISECOND
Definition: datetime.h:104
#define IntervalPGetDatum(X)
Definition: timestamp.h:33
#define SECS_PER_DAY
Definition: timestamp.h:86
static bool CheckDateTokenTable(const char *tablename, const datetkn *base, int nel)
Definition: datetime.c:4432
static char * AddISO8601IntPart(char *cp, int value, char units)
Definition: datetime.c:4169
#define FALSE
Definition: c.h:218
#define DTERR_INTERVAL_OVERFLOW
Definition: datetime.h:285
#define DTK_SECOND
Definition: datetime.h:163
bool pg_interpret_timezone_abbrev(const char *abbrev, const pg_time_t *timep, long int *gmtoff, int *isdst, const pg_tz *tz)
Definition: localtime.c:1652
#define DCENTURY
Definition: datetime.h:59
int j2day(int date)
Definition: datetime.c:352
int DecodeTimezone(char *str, int *tzp)
Definition: datetime.c:2906
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:1031
const char * pg_get_timezone_name(pg_tz *tz)
Definition: localtime.c:1770
datetkn abbrevs[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:222
int tm_mday
Definition: pgtime.h:30
static const datetkn * datebsearch(const char *key, const datetkn *base, int nel)
Definition: datetime.c:3810
#define HOURS_PER_DAY
Definition: timestamp.h:78
static const datetkn deltatktbl[]
Definition: datetime.c:174
int tm_mon
Definition: pgtime.h:31
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1471
#define DMILLENNIUM
Definition: datetime.h:60
#define SECS_PER_MINUTE
Definition: timestamp.h:88
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define DMINUTE
Definition: datetime.h:51
#define INTERVALOID
Definition: pg_type.h:517
#define USE_POSTGRES_DATES
Definition: miscadmin.h:209
pg_time_t timestamptz_to_time_t(TimestampTz t)
Definition: timestamp.c:1691
void EncodeDateTime(struct pg_tm *tm, fsec_t fsec, bool print_tz, int tz, const char *tzn, int style, char *str)
Definition: datetime.c:3999
#define MAX_TIMESTAMP_PRECISION
Definition: timestamp.h:53
static int DecodeDate(char *str, int fmask, int *tmask, bool *is2digits, struct pg_tm *tm)
Definition: datetime.c:2369
#define DTK_ISOYEAR
Definition: datetime.h:182
const char *const days[]
Definition: datetime.c:69
void GetCurrentTimeUsec(struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:387
int32 fsec_t
Definition: timestamp.h:41
#define DTK_YESTERDAY
Definition: datetime.h:157
#define DTK_NUMBER
Definition: datetime.h:142
#define MINUTE
Definition: datetime.h:102
static struct cvec * range(struct vars *v, chr a, chr b, int cases)
Definition: regc_locale.c:416
double rint(double x)
Definition: rint.c:22
#define IS_VALID_JULIAN(y, m, d)
Definition: timestamp.h:155
#define USECS_PER_DAY
Definition: timestamp.h:91
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:493
#define DTK_TZ_MINUTE
Definition: datetime.h:181
#define ereport(elevel, rest)
Definition: elog.h:122
int DateOrder
Definition: globals.c:107
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:317
#define SECS_PER_HOUR
Definition: timestamp.h:87
static char * AddPostgresIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4179
#define MONTH
Definition: datetime.h:92
#define DTK_MINUTE
Definition: datetime.h:164
int DecodeISO8601Interval(char *str, int *dtype, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:3521
#define DATEORDER_YMD
Definition: miscadmin.h:216
static int ParseFractionalSecond(char *cp, fsec_t *fsec)
Definition: datetime.c:514
#define BC
Definition: datetime.h:77
TimestampTz GetCurrentTransactionStartTimestamp(void)
Definition: xact.c:707
char * abbrev
Definition: tzparser.h:26
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:286
void EncodeInterval(struct pg_tm *tm, fsec_t fsec, int style, char *str)
Definition: datetime.c:4241
char zone[FLEXIBLE_ARRAY_MEMBER]
Definition: datetime.h:230
#define DTK_DOW
Definition: datetime.h:178
#define DTK_LATE
Definition: datetime.h:154
int DetermineTimeZoneAbbrevOffsetTS(TimestampTz ts, const char *abbr, pg_tz *tzp, int *isdst)
Definition: datetime.c:1667
#define DTK_MICROSEC
Definition: datetime.h:175
#define DAYS_PER_MONTH
Definition: timestamp.h:77
uintptr_t Datum
Definition: postgres.h:374
char * pg_ltostr_zeropad(char *str, int32 value, int32 minwidth)
Definition: numutils.c:257
#define INTSTYLE_ISO_8601
Definition: miscadmin.h:233
Definition: pgtz.h:59
const int day_tab[2][13]
Definition: datetime.c:60
#define DMONTH
Definition: datetime.h:55
static char * AppendTimestampSeconds(char *cp, struct pg_tm *tm, fsec_t fsec)
Definition: datetime.c:474
#define DATEORDER_DMY
Definition: miscadmin.h:217
#define BoolGetDatum(X)
Definition: postgres.h:410
static void AdjustFractDays(double frac, struct pg_tm *tm, fsec_t *fsec, int scale)
Definition: datetime.c:499
static char * AddVerboseIntPart(char *cp, int value, const char *units, bool *is_zero, bool *is_before)
Definition: datetime.c:4202
#define WEEK
Definition: datetime.h:118
#define ISOTIME
Definition: datetime.h:116
#define DTK_TIME
Definition: datetime.h:146
int date2j(int y, int m, int d)
Definition: datetime.c:292
static int DecodeTime(char *str, int fmask, int range, int *tmask, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:2558
#define DTK_DOY
Definition: datetime.h:179
#define YESTERDAY
Definition: datetime.h:45
static void ClearPgTm(struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:3071
static int szdeltatktbl
Definition: datetime.c:241
void dt2time(Timestamp jd, int *hour, int *min, int *sec, fsec_t *fsec)
Definition: timestamp.c:1730
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
static int strtoint(const char *nptr, char **endptr, int base)
Definition: datetime.c:258
char type
Definition: datetime.h:213
char * pg_ltostr(char *str, int32 value)
Definition: numutils.c:334
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#define AMPM
Definition: datetime.h:100
Node * TemporalTransform(int32 max_precis, Node *node)
Definition: datetime.c:4486
pg_tzenum * pg_tzenumerate_start(void)
Definition: pgtz.c:381
#define INT64CONST(x)
Definition: c.h:307
#define DTIMEZONE
Definition: datetime.h:63
static int ISO8601IntegerWidth(char *fieldstart)
Definition: datetime.c:3494
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:109
size_t Size
Definition: c.h:353
#define DTK_EARLY
Definition: datetime.h:153
#define MAXDATEFIELDS
Definition: datetime.h:205
#define DTK_STRING
Definition: datetime.h:143
static int list_length(const List *l)
Definition: pg_list.h:89
#define DTK_DAY
Definition: datetime.h:166
#define MAXALIGN(LEN)
Definition: c.h:584
static int DecodeNumber(int flen, char *field, bool haveTextMonth, int fmask, int *tmask, struct pg_tm *tm, fsec_t *fsec, bool *is2digits)
Definition: datetime.c:2634
#define RESERV
Definition: datetime.h:91
#define DDAY
Definition: datetime.h:53
int DecodeSpecial(int field, char *lowtoken, int *val)
Definition: datetime.c:3039
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:222
#define BOOLOID
Definition: pg_type.h:288
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:41
#define DTK_ALL_SECS_M
Definition: datetime.h:193
#define INTERVAL_MASK(b)
Definition: timestamp.h:45
#define DTZ
Definition: datetime.h:97
#define DTK_EPOCH
Definition: datetime.h:155
static TimeZoneAbbrevTable * zoneabbrevtbl
Definition: datetime.c:243
Datum pg_timezone_names(PG_FUNCTION_ARGS)
Definition: datetime.c:4778
static Datum values[MAXATTR]
Definition: bootstrap.c:162
Definition: zic.c:90
static char * AppendSeconds(char *cp, int sec, fsec_t fsec, int precision, bool fillzeros)
Definition: datetime.c:411
pg_tz * pg_tzenumerate_next(pg_tzenum *dir)
Definition: pgtz.c:410
#define INTSTYLE_SQL_STANDARD
Definition: miscadmin.h:232
#define USE_XSD_DATES
Definition: miscadmin.h:213
void * user_fctx
Definition: funcapi.h:90
int tm_year
Definition: pgtime.h:32
void * palloc(Size size)
Definition: mcxt.c:891
static const datetkn * datecache[MAXDATEFIELDS]
Definition: datetime.c:247
int errmsg(const char *fmt,...)
Definition: elog.c:797
static const datetkn * abbrevcache[MAXDATEFIELDS]
Definition: datetime.c:251
static int ParseISO8601Number(char *str, char **endptr, int *ipart, double *fpart)
Definition: datetime.c:3466
#define USE_GERMAN_DATES
Definition: miscadmin.h:212
#define DYNTZ
Definition: datetime.h:98
#define DTK_NOW
Definition: datetime.h:156
int DecodeInterval(char **field, int *ftype, int nf, int range, int *dtype, struct pg_tm *tm, fsec_t *fsec)
Definition: datetime.c:3095
int i
#define TOKMAXLEN
Definition: datetime.h:207
#define CStringGetTextDatum(s)
Definition: builtins.h:90
#define DTK_M(t)
Definition: datetime.h:190
static bool DetermineTimeZoneAbbrevOffsetInternal(pg_time_t t, const char *abbr, pg_tz *tzp, int *offset, int *isdst)
Definition: datetime.c:1704
int tm_yday
Definition: pgtime.h:34
#define PG_FUNCTION_ARGS
Definition: fmgr.h:150
pg_tz * session_timezone
Definition: pgtz.c:27
#define UNIX_EPOCH_JDATE
Definition: timestamp.h:162
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:163
#define TRUE
Definition: c.h:214
#define elog
Definition: elog.h:219
#define HOUR
Definition: datetime.h:101
bool pg_get_timezone_offset(const pg_tz *tz, long int *gmtoff)
Definition: localtime.c:1746
#define DTK_ZULU
Definition: datetime.h:160
int tm_sec
Definition: pgtime.h:27
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:562
#define DQUARTER
Definition: datetime.h:56
#define DTZMOD
Definition: datetime.h:123
#define DTERR_MD_FIELD_OVERFLOW
Definition: datetime.h:284
unsigned char pg_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:105
#define DOY
Definition: datetime.h:106
#define EARLY
Definition: datetime.h:40
int tm_min
Definition: pgtime.h:28
int16 AttrNumber
Definition: attnum.h:21
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1629
TimeZoneAbbrevTable * ConvertTimeZoneAbbrevs(struct tzEntry *abbrevs, int n)
Definition: datetime.c:4519
long val
Definition: informix.c:689
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1533
Node * relabel_to_typmod(Node *expr, int32 typmod)
Definition: nodeFuncs.c:585
#define DDECADE
Definition: datetime.h:58
#define DTK_DATE
Definition: datetime.h:145
#define offsetof(type, field)
Definition: c.h:551
#define HR24
Definition: datetime.h:74
#define DTK_SPECIAL
Definition: datetime.h:150
#define MAX_TIME_PRECISION
Definition: date.h:50
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:309
#define MICROSECOND
Definition: datetime.h:105
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2479
#define INTSTYLE_POSTGRES
Definition: miscadmin.h:230
#define DB_C
Definition: datetime.h:62
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:287
int tm2interval(struct pg_tm *tm, fsec_t fsec, Interval *span)
Definition: timestamp.c:1929