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