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