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