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