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