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