LCOV - code coverage report
Current view: top level - src/backend/utils/adt - datetime.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 1918 2209 86.8 %
Date: 2025-01-18 04:15:08 Functions: 65 65 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14