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