LCOV - code coverage report
Current view: top level - src/backend/utils/adt - formatting.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 85.8 % 2419 2075
Test Date: 2026-04-26 13:16:39 Functions: 94.4 % 72 68
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  * formatting.c
       3              :  *
       4              :  * src/backend/utils/adt/formatting.c
       5              :  *
       6              :  *
       7              :  *   Portions Copyright (c) 1999-2026, PostgreSQL Global Development Group
       8              :  *
       9              :  *
      10              :  *   TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER();
      11              :  *
      12              :  *   The PostgreSQL routines for a timestamp/int/float/numeric formatting,
      13              :  *   inspired by the Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines.
      14              :  *
      15              :  *
      16              :  *   Cache & Memory:
      17              :  *  Routines use (itself) internal cache for format pictures.
      18              :  *
      19              :  *  The cache uses a static buffer and is persistent across transactions.  If
      20              :  *  the format-picture is bigger than the cache buffer, the parser is called
      21              :  *  always.
      22              :  *
      23              :  *   NOTE for Number version:
      24              :  *  All in this version is implemented as keywords ( => not used
      25              :  *  suffixes), because a format picture is for *one* item (number)
      26              :  *  only. It not is as a timestamp version, where each keyword (can)
      27              :  *  has suffix.
      28              :  *
      29              :  *   NOTE for Timestamp routines:
      30              :  *  In this module the POSIX 'struct tm' type is *not* used, but rather
      31              :  *  PgSQL type, which has tm_mon based on one (*non* zero) and
      32              :  *  year *not* based on 1900, but is used full year number.
      33              :  *  Module supports AD / BC / AM / PM.
      34              :  *
      35              :  *  Supported types for to_char():
      36              :  *
      37              :  *      Timestamp, Numeric, int4, int8, float4, float8
      38              :  *
      39              :  *  Supported types for reverse conversion:
      40              :  *
      41              :  *      Timestamp   - to_timestamp()
      42              :  *      Date        - to_date()
      43              :  *      Numeric     - to_number()
      44              :  *
      45              :  *
      46              :  *  Karel Zak
      47              :  *
      48              :  * TODO
      49              :  *  - better number building (formatting) / parsing, now it isn't
      50              :  *        ideal code
      51              :  *  - use Assert()
      52              :  *  - add support for number spelling
      53              :  *  - add support for string to string formatting (we must be better
      54              :  *    than Oracle :-),
      55              :  *      to_char('Hello', 'X X X X X') -> 'H e l l o'
      56              :  *
      57              :  *-------------------------------------------------------------------------
      58              :  */
      59              : 
      60              : #ifdef DEBUG_TO_FROM_CHAR
      61              : #define DEBUG_elog_output   DEBUG3
      62              : #endif
      63              : 
      64              : #include "postgres.h"
      65              : 
      66              : #include <ctype.h>
      67              : #include <unistd.h>
      68              : #include <math.h>
      69              : #include <float.h>
      70              : #include <limits.h>
      71              : 
      72              : #include "catalog/pg_type.h"
      73              : #include "common/int.h"
      74              : #include "mb/pg_wchar.h"
      75              : #include "nodes/miscnodes.h"
      76              : #include "parser/scansup.h"
      77              : #include "utils/builtins.h"
      78              : #include "utils/date.h"
      79              : #include "utils/datetime.h"
      80              : #include "utils/formatting.h"
      81              : #include "utils/memutils.h"
      82              : #include "utils/numeric.h"
      83              : #include "utils/pg_locale.h"
      84              : #include "varatt.h"
      85              : 
      86              : 
      87              : /*
      88              :  * Routines flags
      89              :  */
      90              : #define DCH_FLAG        0x1     /* DATE-TIME flag   */
      91              : #define NUM_FLAG        0x2     /* NUMBER flag  */
      92              : #define STD_FLAG        0x4     /* STANDARD flag    */
      93              : 
      94              : /*
      95              :  * KeyWord Index (ascii from position 32 (' ') to 126 (~))
      96              :  */
      97              : #define KeyWord_INDEX_SIZE      ('~' - ' ')
      98              : #define KeyWord_INDEX_FILTER(_c)    ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
      99              : 
     100              : /*
     101              :  * Maximal length of one node
     102              :  */
     103              : #define DCH_MAX_ITEM_SIZ       12   /* max localized day name       */
     104              : #define NUM_MAX_ITEM_SIZ        8   /* roman number (RN has 15 chars)   */
     105              : 
     106              : 
     107              : /*
     108              :  * Format parser structs
     109              :  */
     110              : 
     111              : enum KeySuffixType
     112              : {
     113              :     SUFFTYPE_PREFIX = 1,
     114              :     SUFFTYPE_POSTFIX = 2,
     115              : };
     116              : 
     117              : typedef struct
     118              : {
     119              :     const char *name;           /* suffix string        */
     120              :     size_t      len;            /* suffix length        */
     121              :     int         id;             /* used in node->suffix */
     122              :     enum KeySuffixType type;    /* prefix / postfix     */
     123              : } KeySuffix;
     124              : 
     125              : /*
     126              :  * FromCharDateMode
     127              :  *
     128              :  * This value is used to nominate one of several distinct (and mutually
     129              :  * exclusive) date conventions that a keyword can belong to.
     130              :  */
     131              : typedef enum
     132              : {
     133              :     FROM_CHAR_DATE_NONE = 0,    /* Value does not affect date mode. */
     134              :     FROM_CHAR_DATE_GREGORIAN,   /* Gregorian (day, month, year) style date */
     135              :     FROM_CHAR_DATE_ISOWEEK,     /* ISO 8601 week date */
     136              : } FromCharDateMode;
     137              : 
     138              : typedef struct
     139              : {
     140              :     const char *name;
     141              :     size_t      len;
     142              :     int         id;
     143              :     bool        is_digit;
     144              :     FromCharDateMode date_mode;
     145              : } KeyWord;
     146              : 
     147              : enum FormatNodeType
     148              : {
     149              :     NODE_TYPE_END = 1,
     150              :     NODE_TYPE_ACTION = 2,
     151              :     NODE_TYPE_CHAR = 3,
     152              :     NODE_TYPE_SEPARATOR = 4,
     153              :     NODE_TYPE_SPACE = 5,
     154              : };
     155              : 
     156              : typedef struct
     157              : {
     158              :     enum FormatNodeType type;
     159              :     char        character[MAX_MULTIBYTE_CHAR_LEN + 1];  /* if type is CHAR */
     160              :     uint8       suffix;         /* keyword prefix/suffix code, if any
     161              :                                  * (DCH_SUFFIX_*) */
     162              :     const KeyWord *key;         /* if type is ACTION */
     163              : } FormatNode;
     164              : 
     165              : 
     166              : /*
     167              :  * Full months
     168              :  */
     169              : static const char *const months_full[] = {
     170              :     "January", "February", "March", "April", "May", "June", "July",
     171              :     "August", "September", "October", "November", "December", NULL
     172              : };
     173              : 
     174              : static const char *const days_short[] = {
     175              :     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
     176              : };
     177              : 
     178              : /*
     179              :  * AD / BC
     180              :  *
     181              :  *  There is no 0 AD.  Years go from 1 BC to 1 AD, so we make it
     182              :  *  positive and map year == -1 to year zero, and shift all negative
     183              :  *  years up one.  For interval years, we just return the year.
     184              :  */
     185              : #define ADJUST_YEAR(year, is_interval)  ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
     186              : 
     187              : #define A_D_STR     "A.D."
     188              : #define a_d_STR     "a.d."
     189              : #define AD_STR      "AD"
     190              : #define ad_STR      "ad"
     191              : 
     192              : #define B_C_STR     "B.C."
     193              : #define b_c_STR     "b.c."
     194              : #define BC_STR      "BC"
     195              : #define bc_STR      "bc"
     196              : 
     197              : /*
     198              :  * AD / BC strings for seq_search.
     199              :  *
     200              :  * These are given in two variants, a long form with periods and a standard
     201              :  * form without.
     202              :  *
     203              :  * The array is laid out such that matches for AD have an even index, and
     204              :  * matches for BC have an odd index.  So the boolean value for BC is given by
     205              :  * taking the array index of the match, modulo 2.
     206              :  */
     207              : static const char *const adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL};
     208              : static const char *const adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL};
     209              : 
     210              : /*
     211              :  * AM / PM
     212              :  */
     213              : #define A_M_STR     "A.M."
     214              : #define a_m_STR     "a.m."
     215              : #define AM_STR      "AM"
     216              : #define am_STR      "am"
     217              : 
     218              : #define P_M_STR     "P.M."
     219              : #define p_m_STR     "p.m."
     220              : #define PM_STR      "PM"
     221              : #define pm_STR      "pm"
     222              : 
     223              : /*
     224              :  * AM / PM strings for seq_search.
     225              :  *
     226              :  * These are given in two variants, a long form with periods and a standard
     227              :  * form without.
     228              :  *
     229              :  * The array is laid out such that matches for AM have an even index, and
     230              :  * matches for PM have an odd index.  So the boolean value for PM is given by
     231              :  * taking the array index of the match, modulo 2.
     232              :  */
     233              : static const char *const ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL};
     234              : static const char *const ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL};
     235              : 
     236              : /*
     237              :  * Months in roman-numeral
     238              :  * (Must be in reverse order for seq_search (in FROM_CHAR), because
     239              :  *  'VIII' must have higher precedence than 'V')
     240              :  */
     241              : static const char *const rm_months_upper[] =
     242              : {"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};
     243              : 
     244              : static const char *const rm_months_lower[] =
     245              : {"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};
     246              : 
     247              : /*
     248              :  * Roman numerals
     249              :  */
     250              : static const char *const rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};
     251              : static const char *const rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};
     252              : static const char *const rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};
     253              : 
     254              : /*
     255              :  * MACRO: Check if the current and next characters form a valid subtraction
     256              :  * combination for roman numerals.
     257              :  */
     258              : #define IS_VALID_SUB_COMB(curr, next) \
     259              :     (((curr) == 'I' && ((next) == 'V' || (next) == 'X')) || \
     260              :      ((curr) == 'X' && ((next) == 'L' || (next) == 'C')) || \
     261              :      ((curr) == 'C' && ((next) == 'D' || (next) == 'M')))
     262              : 
     263              : /*
     264              :  * MACRO: Roman numeral value, or 0 if character isn't a roman numeral.
     265              :  */
     266              : #define ROMAN_VAL(r) \
     267              :     ((r) == 'I' ? 1 : \
     268              :      (r) == 'V' ? 5 : \
     269              :      (r) == 'X' ? 10 : \
     270              :      (r) == 'L' ? 50 : \
     271              :      (r) == 'C' ? 100 : \
     272              :      (r) == 'D' ? 500 : \
     273              :      (r) == 'M' ? 1000 : 0)
     274              : 
     275              : /*
     276              :  * 'MMMDCCCLXXXVIII' (3888) is the longest valid roman numeral (15 characters).
     277              :  */
     278              : #define MAX_ROMAN_LEN   15
     279              : 
     280              : /*
     281              :  * Ordinal postfixes
     282              :  */
     283              : static const char *const numTH[] = {"ST", "ND", "RD", "TH", NULL};
     284              : static const char *const numth[] = {"st", "nd", "rd", "th", NULL};
     285              : 
     286              : /*
     287              :  * Flags & Options:
     288              :  */
     289              : enum TH_Case
     290              : {
     291              :     TH_UPPER = 1,
     292              :     TH_LOWER = 2,
     293              : };
     294              : 
     295              : enum NUMDesc_lsign
     296              : {
     297              :     NUM_LSIGN_PRE = -1,
     298              :     NUM_LSIGN_POST = 1,
     299              :     NUM_LSIGN_NONE = 0,
     300              : };
     301              : 
     302              : /*
     303              :  * Number description struct
     304              :  */
     305              : typedef struct
     306              : {
     307              :     int         pre;            /* (count) numbers before decimal */
     308              :     int         post;           /* (count) numbers after decimal */
     309              :     enum NUMDesc_lsign lsign;   /* want locales sign */
     310              :     int         flag;           /* number parameters (NUM_F_*) */
     311              :     int         pre_lsign_num;  /* tmp value for lsign */
     312              :     int         multi;          /* multiplier for 'V' */
     313              :     int         zero_start;     /* position of first zero */
     314              :     int         zero_end;       /* position of last zero */
     315              :     bool        need_locale;    /* needs it locale */
     316              : } NUMDesc;
     317              : 
     318              : /*
     319              :  * Flags for NUMBER version
     320              :  */
     321              : #define NUM_F_DECIMAL       (1 << 1)
     322              : #define NUM_F_LDECIMAL      (1 << 2)
     323              : #define NUM_F_ZERO          (1 << 3)
     324              : #define NUM_F_BLANK         (1 << 4)
     325              : #define NUM_F_FILLMODE      (1 << 5)
     326              : #define NUM_F_LSIGN         (1 << 6)
     327              : #define NUM_F_BRACKET       (1 << 7)
     328              : #define NUM_F_MINUS         (1 << 8)
     329              : #define NUM_F_PLUS          (1 << 9)
     330              : #define NUM_F_ROMAN         (1 << 10)
     331              : #define NUM_F_MULTI         (1 << 11)
     332              : #define NUM_F_PLUS_POST     (1 << 12)
     333              : #define NUM_F_MINUS_POST    (1 << 13)
     334              : #define NUM_F_EEEE          (1 << 14)
     335              : 
     336              : /*
     337              :  * Tests
     338              :  */
     339              : #define IS_DECIMAL(_f)  ((_f)->flag & NUM_F_DECIMAL)
     340              : #define IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL)
     341              : #define IS_ZERO(_f) ((_f)->flag & NUM_F_ZERO)
     342              : #define IS_BLANK(_f)    ((_f)->flag & NUM_F_BLANK)
     343              : #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE)
     344              : #define IS_BRACKET(_f)  ((_f)->flag & NUM_F_BRACKET)
     345              : #define IS_MINUS(_f)    ((_f)->flag & NUM_F_MINUS)
     346              : #define IS_LSIGN(_f)    ((_f)->flag & NUM_F_LSIGN)
     347              : #define IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
     348              : #define IS_ROMAN(_f)    ((_f)->flag & NUM_F_ROMAN)
     349              : #define IS_MULTI(_f)    ((_f)->flag & NUM_F_MULTI)
     350              : #define IS_EEEE(_f)     ((_f)->flag & NUM_F_EEEE)
     351              : 
     352              : /*
     353              :  * Format picture cache
     354              :  *
     355              :  * We will cache datetime format pictures up to DCH_CACHE_SIZE bytes long;
     356              :  * likewise number format pictures up to NUM_CACHE_SIZE bytes long.
     357              :  *
     358              :  * For simplicity, the cache entries are fixed-size, so they allow for the
     359              :  * worst case of a FormatNode for each byte in the picture string.
     360              :  *
     361              :  * The CACHE_SIZE constants are computed to make sizeof(DCHCacheEntry) and
     362              :  * sizeof(NUMCacheEntry) be powers of 2, or just less than that, so that
     363              :  * we don't waste too much space by palloc'ing them individually.  Be sure
     364              :  * to adjust those macros if you add fields to those structs.
     365              :  *
     366              :  * The max number of entries in each cache is DCH_CACHE_ENTRIES
     367              :  * resp. NUM_CACHE_ENTRIES.
     368              :  */
     369              : #define DCH_CACHE_OVERHEAD \
     370              :     MAXALIGN(sizeof(bool) + sizeof(int))
     371              : #define NUM_CACHE_OVERHEAD \
     372              :     MAXALIGN(sizeof(bool) + sizeof(int) + sizeof(NUMDesc))
     373              : 
     374              : #define DCH_CACHE_SIZE \
     375              :     ((2048 - DCH_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
     376              : #define NUM_CACHE_SIZE \
     377              :     ((1024 - NUM_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
     378              : 
     379              : #define DCH_CACHE_ENTRIES   20
     380              : #define NUM_CACHE_ENTRIES   20
     381              : 
     382              : typedef struct
     383              : {
     384              :     FormatNode  format[DCH_CACHE_SIZE + 1];
     385              :     char        str[DCH_CACHE_SIZE + 1];
     386              :     bool        std;
     387              :     bool        valid;
     388              :     int         age;
     389              : } DCHCacheEntry;
     390              : 
     391              : typedef struct
     392              : {
     393              :     FormatNode  format[NUM_CACHE_SIZE + 1];
     394              :     char        str[NUM_CACHE_SIZE + 1];
     395              :     bool        valid;
     396              :     int         age;
     397              :     NUMDesc     Num;
     398              : } NUMCacheEntry;
     399              : 
     400              : /* global cache for date/time format pictures */
     401              : static DCHCacheEntry *DCHCache[DCH_CACHE_ENTRIES];
     402              : static int  n_DCHCache = 0;     /* current number of entries */
     403              : static int  DCHCounter = 0;     /* aging-event counter */
     404              : 
     405              : /* global cache for number format pictures */
     406              : static NUMCacheEntry *NUMCache[NUM_CACHE_ENTRIES];
     407              : static int  n_NUMCache = 0;     /* current number of entries */
     408              : static int  NUMCounter = 0;     /* aging-event counter */
     409              : 
     410              : /*
     411              :  * For char->date/time conversion
     412              :  */
     413              : typedef struct
     414              : {
     415              :     FromCharDateMode mode;
     416              :     int         hh;
     417              :     int         pm;
     418              :     int         mi;
     419              :     int         ss;
     420              :     int         ssss;
     421              :     int         d;              /* stored as 1-7, Sunday = 1, 0 means missing */
     422              :     int         dd;
     423              :     int         ddd;
     424              :     int         mm;
     425              :     int         ms;
     426              :     int         year;
     427              :     int         bc;
     428              :     int         ww;
     429              :     int         w;
     430              :     int         cc;
     431              :     int         j;
     432              :     int         us;
     433              :     int         yysz;           /* is it YY or YYYY ? */
     434              :     bool        clock_12_hour;  /* 12 or 24 hour clock? */
     435              :     int         tzsign;         /* +1, -1, or 0 if no TZH/TZM fields */
     436              :     int         tzh;
     437              :     int         tzm;
     438              :     int         ff;             /* fractional precision */
     439              :     bool        has_tz;         /* was there a TZ field? */
     440              :     int         gmtoffset;      /* GMT offset of fixed-offset zone abbrev */
     441              :     pg_tz      *tzp;            /* pg_tz for dynamic abbrev */
     442              :     const char *abbrev;         /* dynamic abbrev */
     443              : } TmFromChar;
     444              : 
     445              : struct fmt_tz                   /* do_to_timestamp's timezone info output */
     446              : {
     447              :     bool        has_tz;         /* was there any TZ/TZH/TZM field? */
     448              :     int         gmtoffset;      /* GMT offset in seconds */
     449              : };
     450              : 
     451              : /*
     452              :  * Debug
     453              :  */
     454              : #ifdef DEBUG_TO_FROM_CHAR
     455              : #define DEBUG_TMFC(_X) \
     456              :         elog(DEBUG_elog_output, "TMFC:\nmode %d\nhh %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nms: %d\nyear %d\nbc %d\nww %d\nw %d\ncc %d\nj %d\nus: %d\nyysz: %d\nclock: %d", \
     457              :             (_X)->mode, (_X)->hh, (_X)->pm, (_X)->mi, (_X)->ss, (_X)->ssss, \
     458              :             (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, (_X)->year, \
     459              :             (_X)->bc, (_X)->ww, (_X)->w, (_X)->cc, (_X)->j, (_X)->us, \
     460              :             (_X)->yysz, (_X)->clock_12_hour)
     461              : #define DEBUG_TM(_X) \
     462              :         elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
     463              :             (_X)->tm_sec, (_X)->tm_year,\
     464              :             (_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\
     465              :             (_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)
     466              : #else
     467              : #define DEBUG_TMFC(_X)
     468              : #define DEBUG_TM(_X)
     469              : #endif
     470              : 
     471              : /*
     472              :  * Datetime to char conversion
     473              :  *
     474              :  * To support intervals as well as timestamps, we use a custom "tm" struct
     475              :  * that is almost like struct pg_tm, but has a 64-bit tm_hour field.
     476              :  * We omit the tm_isdst and tm_zone fields, which are not used here.
     477              :  */
     478              : struct fmt_tm
     479              : {
     480              :     int         tm_sec;
     481              :     int         tm_min;
     482              :     int64       tm_hour;
     483              :     int         tm_mday;
     484              :     int         tm_mon;
     485              :     int         tm_year;
     486              :     int         tm_wday;
     487              :     int         tm_yday;
     488              :     long int    tm_gmtoff;
     489              : };
     490              : 
     491              : typedef struct TmToChar
     492              : {
     493              :     struct fmt_tm tm;           /* almost the classic 'tm' struct */
     494              :     fsec_t      fsec;           /* fractional seconds */
     495              :     const char *tzn;            /* timezone */
     496              : } TmToChar;
     497              : 
     498              : #define tmtcTm(_X)  (&(_X)->tm)
     499              : #define tmtcTzn(_X) ((_X)->tzn)
     500              : #define tmtcFsec(_X)    ((_X)->fsec)
     501              : 
     502              : /* Note: this is used to copy pg_tm to fmt_tm, so not quite a bitwise copy */
     503              : #define COPY_tm(_DST, _SRC) \
     504              : do {    \
     505              :     (_DST)->tm_sec = (_SRC)->tm_sec; \
     506              :     (_DST)->tm_min = (_SRC)->tm_min; \
     507              :     (_DST)->tm_hour = (_SRC)->tm_hour; \
     508              :     (_DST)->tm_mday = (_SRC)->tm_mday; \
     509              :     (_DST)->tm_mon = (_SRC)->tm_mon; \
     510              :     (_DST)->tm_year = (_SRC)->tm_year; \
     511              :     (_DST)->tm_wday = (_SRC)->tm_wday; \
     512              :     (_DST)->tm_yday = (_SRC)->tm_yday; \
     513              :     (_DST)->tm_gmtoff = (_SRC)->tm_gmtoff; \
     514              : } while(0)
     515              : 
     516              : /* Caution: this is used to zero both pg_tm and fmt_tm structs */
     517              : #define ZERO_tm(_X) \
     518              : do {    \
     519              :     memset(_X, 0, sizeof(*(_X))); \
     520              :     (_X)->tm_mday = (_X)->tm_mon = 1; \
     521              : } while(0)
     522              : 
     523              : #define ZERO_tmtc(_X) \
     524              : do { \
     525              :     ZERO_tm( tmtcTm(_X) ); \
     526              :     tmtcFsec(_X) = 0; \
     527              :     tmtcTzn(_X) = NULL; \
     528              : } while(0)
     529              : 
     530              : /*
     531              :  *  to_char(time) appears to to_char() as an interval, so this check
     532              :  *  is really for interval and time data types.
     533              :  */
     534              : #define INVALID_FOR_INTERVAL  \
     535              : do { \
     536              :     if (is_interval) \
     537              :         ereport(ERROR, \
     538              :                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
     539              :                  errmsg("invalid format specification for an interval value"), \
     540              :                  errhint("Intervals are not tied to specific calendar dates."))); \
     541              : } while(0)
     542              : 
     543              : /*****************************************************************************
     544              :  *          KeyWord definitions
     545              :  *****************************************************************************/
     546              : 
     547              : /*
     548              :  * Suffixes (FormatNode.suffix is an OR of these codes)
     549              :  */
     550              : #define DCH_SUFFIX_FM   0x01
     551              : #define DCH_SUFFIX_TH   0x02
     552              : #define DCH_SUFFIX_th   0x04
     553              : #define DCH_SUFFIX_SP   0x08
     554              : #define DCH_SUFFIX_TM   0x10
     555              : 
     556              : /*
     557              :  * Suffix tests
     558              :  */
     559              : static inline bool
     560       196778 : IS_SUFFIX_TH(uint8 _s)
     561              : {
     562       196778 :     return (_s & DCH_SUFFIX_TH);
     563              : }
     564              : 
     565              : static inline bool
     566       196270 : IS_SUFFIX_th(uint8 _s)
     567              : {
     568       196270 :     return (_s & DCH_SUFFIX_th);
     569              : }
     570              : 
     571              : static inline bool
     572       196778 : IS_SUFFIX_THth(uint8 _s)
     573              : {
     574       196778 :     return IS_SUFFIX_TH(_s) || IS_SUFFIX_th(_s);
     575              : }
     576              : 
     577              : static inline enum TH_Case
     578         1524 : SUFFIX_TH_TYPE(uint8 _s)
     579              : {
     580         1524 :     return _s & DCH_SUFFIX_TH ? TH_UPPER : TH_LOWER;
     581              : }
     582              : 
     583              : /* Oracle toggles FM behavior, we don't; see docs. */
     584              : static inline bool
     585       116512 : IS_SUFFIX_FM(uint8 _s)
     586              : {
     587       116512 :     return (_s & DCH_SUFFIX_FM);
     588              : }
     589              : 
     590              : static inline bool
     591         9304 : IS_SUFFIX_TM(uint8 _s)
     592              : {
     593         9304 :     return (_s & DCH_SUFFIX_TM);
     594              : }
     595              : 
     596              : /*
     597              :  * Suffixes definition for DATE-TIME TO/FROM CHAR
     598              :  */
     599              : #define TM_SUFFIX_LEN   2
     600              : 
     601              : static const KeySuffix DCH_suff[] = {
     602              :     {"FM", 2, DCH_SUFFIX_FM, SUFFTYPE_PREFIX},
     603              :     {"fm", 2, DCH_SUFFIX_FM, SUFFTYPE_PREFIX},
     604              :     {"TM", TM_SUFFIX_LEN, DCH_SUFFIX_TM, SUFFTYPE_PREFIX},
     605              :     {"tm", 2, DCH_SUFFIX_TM, SUFFTYPE_PREFIX},
     606              :     {"TH", 2, DCH_SUFFIX_TH, SUFFTYPE_POSTFIX},
     607              :     {"th", 2, DCH_SUFFIX_th, SUFFTYPE_POSTFIX},
     608              :     {"SP", 2, DCH_SUFFIX_SP, SUFFTYPE_POSTFIX},
     609              :     /* last */
     610              :     {NULL, 0, 0, 0}
     611              : };
     612              : 
     613              : 
     614              : /*
     615              :  * Format-pictures (KeyWord).
     616              :  *
     617              :  * The KeyWord field; alphabetic sorted, *BUT* strings alike is sorted
     618              :  *        complicated -to-> easy:
     619              :  *
     620              :  *  (example: "DDD","DD","Day","D" )
     621              :  *
     622              :  * (this specific sort needs the algorithm for sequential search for strings,
     623              :  * which not has exact end; -> How keyword is in "HH12blabla" ? - "HH"
     624              :  * or "HH12"? You must first try "HH12", because "HH" is in string, but
     625              :  * it is not good.
     626              :  *
     627              :  * (!)
     628              :  *   - Position for the keyword is similar as position in the enum DCH/NUM_poz.
     629              :  * (!)
     630              :  *
     631              :  * For fast search is used the 'int index[]', index is ascii table from position
     632              :  * 32 (' ') to 126 (~), in this index is DCH_ / NUM_ enums for each ASCII
     633              :  * position or -1 if char is not used in the KeyWord. Search example for
     634              :  * string "MM":
     635              :  *  1)  see in index to index['M' - 32],
     636              :  *  2)  take keywords position (enum DCH_MI) from index
     637              :  *  3)  run sequential search in keywords[] from this position
     638              :  */
     639              : 
     640              : typedef enum
     641              : {
     642              :     DCH_A_D,
     643              :     DCH_A_M,
     644              :     DCH_AD,
     645              :     DCH_AM,
     646              :     DCH_B_C,
     647              :     DCH_BC,
     648              :     DCH_CC,
     649              :     DCH_DAY,
     650              :     DCH_DDD,
     651              :     DCH_DD,
     652              :     DCH_DY,
     653              :     DCH_Day,
     654              :     DCH_Dy,
     655              :     DCH_D,
     656              :     DCH_FF1,                    /* FFn codes must be consecutive */
     657              :     DCH_FF2,
     658              :     DCH_FF3,
     659              :     DCH_FF4,
     660              :     DCH_FF5,
     661              :     DCH_FF6,
     662              :     DCH_FX,                     /* global suffix */
     663              :     DCH_HH24,
     664              :     DCH_HH12,
     665              :     DCH_HH,
     666              :     DCH_IDDD,
     667              :     DCH_ID,
     668              :     DCH_IW,
     669              :     DCH_IYYY,
     670              :     DCH_IYY,
     671              :     DCH_IY,
     672              :     DCH_I,
     673              :     DCH_J,
     674              :     DCH_MI,
     675              :     DCH_MM,
     676              :     DCH_MONTH,
     677              :     DCH_MON,
     678              :     DCH_MS,
     679              :     DCH_Month,
     680              :     DCH_Mon,
     681              :     DCH_OF,
     682              :     DCH_P_M,
     683              :     DCH_PM,
     684              :     DCH_Q,
     685              :     DCH_RM,
     686              :     DCH_SSSSS,
     687              :     DCH_SSSS,
     688              :     DCH_SS,
     689              :     DCH_TZH,
     690              :     DCH_TZM,
     691              :     DCH_TZ,
     692              :     DCH_US,
     693              :     DCH_WW,
     694              :     DCH_W,
     695              :     DCH_Y_YYY,
     696              :     DCH_YYYY,
     697              :     DCH_YYY,
     698              :     DCH_YY,
     699              :     DCH_Y,
     700              :     DCH_a_d,
     701              :     DCH_a_m,
     702              :     DCH_ad,
     703              :     DCH_am,
     704              :     DCH_b_c,
     705              :     DCH_bc,
     706              :     DCH_cc,
     707              :     DCH_day,
     708              :     DCH_ddd,
     709              :     DCH_dd,
     710              :     DCH_dy,
     711              :     DCH_d,
     712              :     DCH_ff1,
     713              :     DCH_ff2,
     714              :     DCH_ff3,
     715              :     DCH_ff4,
     716              :     DCH_ff5,
     717              :     DCH_ff6,
     718              :     DCH_fx,
     719              :     DCH_hh24,
     720              :     DCH_hh12,
     721              :     DCH_hh,
     722              :     DCH_iddd,
     723              :     DCH_id,
     724              :     DCH_iw,
     725              :     DCH_iyyy,
     726              :     DCH_iyy,
     727              :     DCH_iy,
     728              :     DCH_i,
     729              :     DCH_j,
     730              :     DCH_mi,
     731              :     DCH_mm,
     732              :     DCH_month,
     733              :     DCH_mon,
     734              :     DCH_ms,
     735              :     DCH_of,
     736              :     DCH_p_m,
     737              :     DCH_pm,
     738              :     DCH_q,
     739              :     DCH_rm,
     740              :     DCH_sssss,
     741              :     DCH_ssss,
     742              :     DCH_ss,
     743              :     DCH_tzh,
     744              :     DCH_tzm,
     745              :     DCH_tz,
     746              :     DCH_us,
     747              :     DCH_ww,
     748              :     DCH_w,
     749              :     DCH_y_yyy,
     750              :     DCH_yyyy,
     751              :     DCH_yyy,
     752              :     DCH_yy,
     753              :     DCH_y,
     754              : 
     755              :     /* last */
     756              :     _DCH_last_
     757              : }           DCH_poz;
     758              : 
     759              : typedef enum
     760              : {
     761              :     NUM_COMMA,
     762              :     NUM_DEC,
     763              :     NUM_0,
     764              :     NUM_9,
     765              :     NUM_B,
     766              :     NUM_C,
     767              :     NUM_D,
     768              :     NUM_E,
     769              :     NUM_FM,
     770              :     NUM_G,
     771              :     NUM_L,
     772              :     NUM_MI,
     773              :     NUM_PL,
     774              :     NUM_PR,
     775              :     NUM_RN,
     776              :     NUM_SG,
     777              :     NUM_SP,
     778              :     NUM_S,
     779              :     NUM_TH,
     780              :     NUM_V,
     781              :     NUM_b,
     782              :     NUM_c,
     783              :     NUM_d,
     784              :     NUM_e,
     785              :     NUM_fm,
     786              :     NUM_g,
     787              :     NUM_l,
     788              :     NUM_mi,
     789              :     NUM_pl,
     790              :     NUM_pr,
     791              :     NUM_rn,
     792              :     NUM_sg,
     793              :     NUM_sp,
     794              :     NUM_s,
     795              :     NUM_th,
     796              :     NUM_v,
     797              : 
     798              :     /* last */
     799              :     _NUM_last_
     800              : }           NUM_poz;
     801              : 
     802              : /*
     803              :  * KeyWords for DATE-TIME version
     804              :  */
     805              : static const KeyWord DCH_keywords[] = {
     806              : /*  name, len, id, is_digit, date_mode */
     807              :     {"A.D.", 4, DCH_A_D, false, FROM_CHAR_DATE_NONE}, /* A */
     808              :     {"A.M.", 4, DCH_A_M, false, FROM_CHAR_DATE_NONE},
     809              :     {"AD", 2, DCH_AD, false, FROM_CHAR_DATE_NONE},
     810              :     {"AM", 2, DCH_AM, false, FROM_CHAR_DATE_NONE},
     811              :     {"B.C.", 4, DCH_B_C, false, FROM_CHAR_DATE_NONE}, /* B */
     812              :     {"BC", 2, DCH_BC, false, FROM_CHAR_DATE_NONE},
     813              :     {"CC", 2, DCH_CC, true, FROM_CHAR_DATE_NONE}, /* C */
     814              :     {"DAY", 3, DCH_DAY, false, FROM_CHAR_DATE_NONE},  /* D */
     815              :     {"DDD", 3, DCH_DDD, true, FROM_CHAR_DATE_GREGORIAN},
     816              :     {"DD", 2, DCH_DD, true, FROM_CHAR_DATE_GREGORIAN},
     817              :     {"DY", 2, DCH_DY, false, FROM_CHAR_DATE_NONE},
     818              :     {"Day", 3, DCH_Day, false, FROM_CHAR_DATE_NONE},
     819              :     {"Dy", 2, DCH_Dy, false, FROM_CHAR_DATE_NONE},
     820              :     {"D", 1, DCH_D, true, FROM_CHAR_DATE_GREGORIAN},
     821              :     {"FF1", 3, DCH_FF1, true, FROM_CHAR_DATE_NONE}, /* F */
     822              :     {"FF2", 3, DCH_FF2, true, FROM_CHAR_DATE_NONE},
     823              :     {"FF3", 3, DCH_FF3, true, FROM_CHAR_DATE_NONE},
     824              :     {"FF4", 3, DCH_FF4, true, FROM_CHAR_DATE_NONE},
     825              :     {"FF5", 3, DCH_FF5, true, FROM_CHAR_DATE_NONE},
     826              :     {"FF6", 3, DCH_FF6, true, FROM_CHAR_DATE_NONE},
     827              :     {"FX", 2, DCH_FX, false, FROM_CHAR_DATE_NONE},
     828              :     {"HH24", 4, DCH_HH24, true, FROM_CHAR_DATE_NONE}, /* H */
     829              :     {"HH12", 4, DCH_HH12, true, FROM_CHAR_DATE_NONE},
     830              :     {"HH", 2, DCH_HH, true, FROM_CHAR_DATE_NONE},
     831              :     {"IDDD", 4, DCH_IDDD, true, FROM_CHAR_DATE_ISOWEEK},  /* I */
     832              :     {"ID", 2, DCH_ID, true, FROM_CHAR_DATE_ISOWEEK},
     833              :     {"IW", 2, DCH_IW, true, FROM_CHAR_DATE_ISOWEEK},
     834              :     {"IYYY", 4, DCH_IYYY, true, FROM_CHAR_DATE_ISOWEEK},
     835              :     {"IYY", 3, DCH_IYY, true, FROM_CHAR_DATE_ISOWEEK},
     836              :     {"IY", 2, DCH_IY, true, FROM_CHAR_DATE_ISOWEEK},
     837              :     {"I", 1, DCH_I, true, FROM_CHAR_DATE_ISOWEEK},
     838              :     {"J", 1, DCH_J, true, FROM_CHAR_DATE_NONE}, /* J */
     839              :     {"MI", 2, DCH_MI, true, FROM_CHAR_DATE_NONE}, /* M */
     840              :     {"MM", 2, DCH_MM, true, FROM_CHAR_DATE_GREGORIAN},
     841              :     {"MONTH", 5, DCH_MONTH, false, FROM_CHAR_DATE_GREGORIAN},
     842              :     {"MON", 3, DCH_MON, false, FROM_CHAR_DATE_GREGORIAN},
     843              :     {"MS", 2, DCH_MS, true, FROM_CHAR_DATE_NONE},
     844              :     {"Month", 5, DCH_Month, false, FROM_CHAR_DATE_GREGORIAN},
     845              :     {"Mon", 3, DCH_Mon, false, FROM_CHAR_DATE_GREGORIAN},
     846              :     {"OF", 2, DCH_OF, false, FROM_CHAR_DATE_NONE},    /* O */
     847              :     {"P.M.", 4, DCH_P_M, false, FROM_CHAR_DATE_NONE}, /* P */
     848              :     {"PM", 2, DCH_PM, false, FROM_CHAR_DATE_NONE},
     849              :     {"Q", 1, DCH_Q, true, FROM_CHAR_DATE_NONE}, /* Q */
     850              :     {"RM", 2, DCH_RM, false, FROM_CHAR_DATE_GREGORIAN}, /* R */
     851              :     {"SSSSS", 5, DCH_SSSS, true, FROM_CHAR_DATE_NONE},    /* S */
     852              :     {"SSSS", 4, DCH_SSSS, true, FROM_CHAR_DATE_NONE},
     853              :     {"SS", 2, DCH_SS, true, FROM_CHAR_DATE_NONE},
     854              :     {"TZH", 3, DCH_TZH, false, FROM_CHAR_DATE_NONE},  /* T */
     855              :     {"TZM", 3, DCH_TZM, true, FROM_CHAR_DATE_NONE},
     856              :     {"TZ", 2, DCH_TZ, false, FROM_CHAR_DATE_NONE},
     857              :     {"US", 2, DCH_US, true, FROM_CHAR_DATE_NONE}, /* U */
     858              :     {"WW", 2, DCH_WW, true, FROM_CHAR_DATE_GREGORIAN},    /* W */
     859              :     {"W", 1, DCH_W, true, FROM_CHAR_DATE_GREGORIAN},
     860              :     {"Y,YYY", 5, DCH_Y_YYY, true, FROM_CHAR_DATE_GREGORIAN},  /* Y */
     861              :     {"YYYY", 4, DCH_YYYY, true, FROM_CHAR_DATE_GREGORIAN},
     862              :     {"YYY", 3, DCH_YYY, true, FROM_CHAR_DATE_GREGORIAN},
     863              :     {"YY", 2, DCH_YY, true, FROM_CHAR_DATE_GREGORIAN},
     864              :     {"Y", 1, DCH_Y, true, FROM_CHAR_DATE_GREGORIAN},
     865              :     {"a.d.", 4, DCH_a_d, false, FROM_CHAR_DATE_NONE}, /* a */
     866              :     {"a.m.", 4, DCH_a_m, false, FROM_CHAR_DATE_NONE},
     867              :     {"ad", 2, DCH_ad, false, FROM_CHAR_DATE_NONE},
     868              :     {"am", 2, DCH_am, false, FROM_CHAR_DATE_NONE},
     869              :     {"b.c.", 4, DCH_b_c, false, FROM_CHAR_DATE_NONE}, /* b */
     870              :     {"bc", 2, DCH_bc, false, FROM_CHAR_DATE_NONE},
     871              :     {"cc", 2, DCH_CC, true, FROM_CHAR_DATE_NONE}, /* c */
     872              :     {"day", 3, DCH_day, false, FROM_CHAR_DATE_NONE},  /* d */
     873              :     {"ddd", 3, DCH_DDD, true, FROM_CHAR_DATE_GREGORIAN},
     874              :     {"dd", 2, DCH_DD, true, FROM_CHAR_DATE_GREGORIAN},
     875              :     {"dy", 2, DCH_dy, false, FROM_CHAR_DATE_NONE},
     876              :     {"d", 1, DCH_D, true, FROM_CHAR_DATE_GREGORIAN},
     877              :     {"ff1", 3, DCH_FF1, true, FROM_CHAR_DATE_NONE}, /* f */
     878              :     {"ff2", 3, DCH_FF2, true, FROM_CHAR_DATE_NONE},
     879              :     {"ff3", 3, DCH_FF3, true, FROM_CHAR_DATE_NONE},
     880              :     {"ff4", 3, DCH_FF4, true, FROM_CHAR_DATE_NONE},
     881              :     {"ff5", 3, DCH_FF5, true, FROM_CHAR_DATE_NONE},
     882              :     {"ff6", 3, DCH_FF6, true, FROM_CHAR_DATE_NONE},
     883              :     {"fx", 2, DCH_FX, false, FROM_CHAR_DATE_NONE},
     884              :     {"hh24", 4, DCH_HH24, true, FROM_CHAR_DATE_NONE}, /* h */
     885              :     {"hh12", 4, DCH_HH12, true, FROM_CHAR_DATE_NONE},
     886              :     {"hh", 2, DCH_HH, true, FROM_CHAR_DATE_NONE},
     887              :     {"iddd", 4, DCH_IDDD, true, FROM_CHAR_DATE_ISOWEEK},  /* i */
     888              :     {"id", 2, DCH_ID, true, FROM_CHAR_DATE_ISOWEEK},
     889              :     {"iw", 2, DCH_IW, true, FROM_CHAR_DATE_ISOWEEK},
     890              :     {"iyyy", 4, DCH_IYYY, true, FROM_CHAR_DATE_ISOWEEK},
     891              :     {"iyy", 3, DCH_IYY, true, FROM_CHAR_DATE_ISOWEEK},
     892              :     {"iy", 2, DCH_IY, true, FROM_CHAR_DATE_ISOWEEK},
     893              :     {"i", 1, DCH_I, true, FROM_CHAR_DATE_ISOWEEK},
     894              :     {"j", 1, DCH_J, true, FROM_CHAR_DATE_NONE}, /* j */
     895              :     {"mi", 2, DCH_MI, true, FROM_CHAR_DATE_NONE}, /* m */
     896              :     {"mm", 2, DCH_MM, true, FROM_CHAR_DATE_GREGORIAN},
     897              :     {"month", 5, DCH_month, false, FROM_CHAR_DATE_GREGORIAN},
     898              :     {"mon", 3, DCH_mon, false, FROM_CHAR_DATE_GREGORIAN},
     899              :     {"ms", 2, DCH_MS, true, FROM_CHAR_DATE_NONE},
     900              :     {"of", 2, DCH_OF, false, FROM_CHAR_DATE_NONE},    /* o */
     901              :     {"p.m.", 4, DCH_p_m, false, FROM_CHAR_DATE_NONE}, /* p */
     902              :     {"pm", 2, DCH_pm, false, FROM_CHAR_DATE_NONE},
     903              :     {"q", 1, DCH_Q, true, FROM_CHAR_DATE_NONE}, /* q */
     904              :     {"rm", 2, DCH_rm, false, FROM_CHAR_DATE_GREGORIAN}, /* r */
     905              :     {"sssss", 5, DCH_SSSS, true, FROM_CHAR_DATE_NONE},    /* s */
     906              :     {"ssss", 4, DCH_SSSS, true, FROM_CHAR_DATE_NONE},
     907              :     {"ss", 2, DCH_SS, true, FROM_CHAR_DATE_NONE},
     908              :     {"tzh", 3, DCH_TZH, false, FROM_CHAR_DATE_NONE},  /* t */
     909              :     {"tzm", 3, DCH_TZM, true, FROM_CHAR_DATE_NONE},
     910              :     {"tz", 2, DCH_tz, false, FROM_CHAR_DATE_NONE},
     911              :     {"us", 2, DCH_US, true, FROM_CHAR_DATE_NONE}, /* u */
     912              :     {"ww", 2, DCH_WW, true, FROM_CHAR_DATE_GREGORIAN},    /* w */
     913              :     {"w", 1, DCH_W, true, FROM_CHAR_DATE_GREGORIAN},
     914              :     {"y,yyy", 5, DCH_Y_YYY, true, FROM_CHAR_DATE_GREGORIAN},  /* y */
     915              :     {"yyyy", 4, DCH_YYYY, true, FROM_CHAR_DATE_GREGORIAN},
     916              :     {"yyy", 3, DCH_YYY, true, FROM_CHAR_DATE_GREGORIAN},
     917              :     {"yy", 2, DCH_YY, true, FROM_CHAR_DATE_GREGORIAN},
     918              :     {"y", 1, DCH_Y, true, FROM_CHAR_DATE_GREGORIAN},
     919              : 
     920              :     /* last */
     921              :     {NULL, 0, 0, 0, 0}
     922              : };
     923              : 
     924              : /*
     925              :  * KeyWords for NUMBER version
     926              :  *
     927              :  * The is_digit and date_mode fields are not relevant here.
     928              :  */
     929              : static const KeyWord NUM_keywords[] = {
     930              : /*  name, len, id           is in Index */
     931              :     {",", 1, NUM_COMMA},      /* , */
     932              :     {".", 1, NUM_DEC},            /* . */
     933              :     {"0", 1, NUM_0},          /* 0 */
     934              :     {"9", 1, NUM_9},          /* 9 */
     935              :     {"B", 1, NUM_B},          /* B */
     936              :     {"C", 1, NUM_C},          /* C */
     937              :     {"D", 1, NUM_D},          /* D */
     938              :     {"EEEE", 4, NUM_E},           /* E */
     939              :     {"FM", 2, NUM_FM},            /* F */
     940              :     {"G", 1, NUM_G},          /* G */
     941              :     {"L", 1, NUM_L},          /* L */
     942              :     {"MI", 2, NUM_MI},            /* M */
     943              :     {"PL", 2, NUM_PL},            /* P */
     944              :     {"PR", 2, NUM_PR},
     945              :     {"RN", 2, NUM_RN},            /* R */
     946              :     {"SG", 2, NUM_SG},            /* S */
     947              :     {"SP", 2, NUM_SP},
     948              :     {"S", 1, NUM_S},
     949              :     {"TH", 2, NUM_TH},            /* T */
     950              :     {"V", 1, NUM_V},          /* V */
     951              :     {"b", 1, NUM_B},          /* b */
     952              :     {"c", 1, NUM_C},          /* c */
     953              :     {"d", 1, NUM_D},          /* d */
     954              :     {"eeee", 4, NUM_E},           /* e */
     955              :     {"fm", 2, NUM_FM},            /* f */
     956              :     {"g", 1, NUM_G},          /* g */
     957              :     {"l", 1, NUM_L},          /* l */
     958              :     {"mi", 2, NUM_MI},            /* m */
     959              :     {"pl", 2, NUM_PL},            /* p */
     960              :     {"pr", 2, NUM_PR},
     961              :     {"rn", 2, NUM_rn},            /* r */
     962              :     {"sg", 2, NUM_SG},            /* s */
     963              :     {"sp", 2, NUM_SP},
     964              :     {"s", 1, NUM_S},
     965              :     {"th", 2, NUM_th},            /* t */
     966              :     {"v", 1, NUM_V},          /* v */
     967              : 
     968              :     /* last */
     969              :     {NULL, 0, 0}
     970              : };
     971              : 
     972              : 
     973              : /*
     974              :  * KeyWords index for DATE-TIME version
     975              :  */
     976              : static const int DCH_index[KeyWord_INDEX_SIZE] = {
     977              : /*
     978              : 0   1   2   3   4   5   6   7   8   9
     979              : */
     980              :     /*---- first 0..31 chars are skipped ----*/
     981              : 
     982              :     -1, -1, -1, -1, -1, -1, -1, -1,
     983              :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     984              :     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
     985              :     -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
     986              :     DCH_FF1, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, DCH_OF,
     987              :     DCH_P_M, DCH_Q, DCH_RM, DCH_SSSSS, DCH_TZH, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY,
     988              :     -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
     989              :     DCH_day, -1, DCH_ff1, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
     990              :     -1, DCH_of, DCH_p_m, DCH_q, DCH_rm, DCH_sssss, DCH_tzh, DCH_us, -1, DCH_ww,
     991              :     -1, DCH_y_yyy, -1, -1, -1, -1
     992              : 
     993              :     /*---- chars over 126 are skipped ----*/
     994              : };
     995              : 
     996              : /*
     997              :  * KeyWords index for NUMBER version
     998              :  */
     999              : static const int NUM_index[KeyWord_INDEX_SIZE] = {
    1000              : /*
    1001              : 0   1   2   3   4   5   6   7   8   9
    1002              : */
    1003              :     /*---- first 0..31 chars are skipped ----*/
    1004              : 
    1005              :     -1, -1, -1, -1, -1, -1, -1, -1,
    1006              :     -1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
    1007              :     -1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
    1008              :     -1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
    1009              :     NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
    1010              :     NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
    1011              :     -1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
    1012              :     NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
    1013              :     -1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
    1014              :     -1, -1, -1, -1, -1, -1
    1015              : 
    1016              :     /*---- chars over 126 are skipped ----*/
    1017              : };
    1018              : 
    1019              : /*
    1020              :  * Number processor struct
    1021              :  */
    1022              : typedef struct NUMProc
    1023              : {
    1024              :     bool        is_to_char;
    1025              :     NUMDesc    *Num;            /* number description       */
    1026              : 
    1027              :     int         sign,           /* '-' or '+'           */
    1028              :                 sign_wrote,     /* was sign write       */
    1029              :                 num_count,      /* number of write digits   */
    1030              :                 num_in,         /* is inside number     */
    1031              :                 num_curr,       /* current position in number   */
    1032              :                 out_pre_spaces, /* spaces before first digit    */
    1033              : 
    1034              :                 read_dec,       /* to_number - was read dec. point  */
    1035              :                 read_post,      /* to_number - number of dec. digit */
    1036              :                 read_pre;       /* to_number - number non-dec. digit */
    1037              : 
    1038              :     char       *number,         /* string with number   */
    1039              :                *number_p,       /* pointer to current number position */
    1040              :                *inout,          /* in / out buffer  */
    1041              :                *inout_p;        /* pointer to current inout position */
    1042              : 
    1043              :     const char *last_relevant,  /* last relevant number after decimal point */
    1044              : 
    1045              :                *L_negative_sign,    /* Locale */
    1046              :                *L_positive_sign,
    1047              :                *decimal,
    1048              :                *L_thousands_sep,
    1049              :                *L_currency_symbol;
    1050              : } NUMProc;
    1051              : 
    1052              : /* Return flags for DCH_from_char() */
    1053              : #define DCH_DATED   0x01
    1054              : #define DCH_TIMED   0x02
    1055              : #define DCH_ZONED   0x04
    1056              : 
    1057              : /*
    1058              :  * These macros are used in NUM_processor() and its subsidiary routines.
    1059              :  * OVERLOAD_TEST: true if we've reached end of input string
    1060              :  * AMOUNT_TEST(s): true if at least s bytes remain in string
    1061              :  */
    1062              : #define OVERLOAD_TEST   (Np->inout_p >= Np->inout + input_len)
    1063              : #define AMOUNT_TEST(s)  (Np->inout_p <= Np->inout + (input_len - (s)))
    1064              : 
    1065              : 
    1066              : /*
    1067              :  * Functions
    1068              :  */
    1069              : static const KeyWord *index_seq_search(const char *str, const KeyWord *kw,
    1070              :                                        const int *index);
    1071              : static const KeySuffix *suff_search(const char *str, const KeySuffix *suf, enum KeySuffixType type);
    1072              : static bool is_separator_char(const char *str);
    1073              : static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
    1074              : static void parse_format(FormatNode *node, const char *str, const KeyWord *kw,
    1075              :                          const KeySuffix *suf, const int *index, uint32 flags, NUMDesc *Num);
    1076              : 
    1077              : static void DCH_to_char(FormatNode *node, bool is_interval,
    1078              :                         TmToChar *in, char *out, Oid collid);
    1079              : static void DCH_from_char(FormatNode *node, const char *in, TmFromChar *out,
    1080              :                           Oid collid, bool std, Node *escontext);
    1081              : 
    1082              : #ifdef DEBUG_TO_FROM_CHAR
    1083              : static void dump_index(const KeyWord *k, const int *index);
    1084              : static void dump_node(FormatNode *node, int max);
    1085              : #endif
    1086              : 
    1087              : static const char *get_th(const char *num, enum TH_Case type);
    1088              : static char *str_numth(char *dest, const char *num, enum TH_Case type);
    1089              : static int  adjust_partial_year_to_2020(int year);
    1090              : static size_t strspace_len(const char *str);
    1091              : static bool from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode,
    1092              :                                Node *escontext);
    1093              : static bool from_char_set_int(int *dest, const int value, const FormatNode *node,
    1094              :                               Node *escontext);
    1095              : static int  from_char_parse_int_len(int *dest, const char **src, const size_t len,
    1096              :                                     FormatNode *node, Node *escontext);
    1097              : static int  from_char_parse_int(int *dest, const char **src, FormatNode *node,
    1098              :                                 Node *escontext);
    1099              : static int  seq_search_ascii(const char *name, const char *const *array, size_t *len);
    1100              : static int  seq_search_localized(const char *name, char **array, size_t *len,
    1101              :                                  Oid collid);
    1102              : static bool from_char_seq_search(int *dest, const char **src,
    1103              :                                  const char *const *array,
    1104              :                                  char **localized_array, Oid collid,
    1105              :                                  FormatNode *node, Node *escontext);
    1106              : static bool do_to_timestamp(const text *date_txt, const text *fmt, Oid collid, bool std,
    1107              :                             struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz,
    1108              :                             int *fprec, uint32 *flags, Node *escontext);
    1109              : static void fill_str(char *str, int c, int max);
    1110              : static FormatNode *NUM_cache(int len, NUMDesc *Num, const text *pars_str, bool *shouldFree);
    1111              : static char *int_to_roman(int number);
    1112              : static int  roman_to_int(NUMProc *Np, size_t input_len);
    1113              : static void NUM_prepare_locale(NUMProc *Np);
    1114              : static const char *get_last_relevant_decnum(const char *num);
    1115              : static void NUM_numpart_from_char(NUMProc *Np, int id, size_t input_len);
    1116              : static void NUM_numpart_to_char(NUMProc *Np, int id);
    1117              : static void NUM_add_locale_symbol(NUMProc *Np, const char *pattern);
    1118              : static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout,
    1119              :                            char *number, size_t input_len, int to_char_out_pre_spaces,
    1120              :                            int sign, bool is_to_char, Oid collid);
    1121              : static DCHCacheEntry *DCH_cache_getnew(const char *str, bool std);
    1122              : static DCHCacheEntry *DCH_cache_search(const char *str, bool std);
    1123              : static DCHCacheEntry *DCH_cache_fetch(const char *str, bool std);
    1124              : static NUMCacheEntry *NUM_cache_getnew(const char *str);
    1125              : static NUMCacheEntry *NUM_cache_search(const char *str);
    1126              : static NUMCacheEntry *NUM_cache_fetch(const char *str);
    1127              : 
    1128              : 
    1129              : /*
    1130              :  * Fast sequential search, use index for data selection which
    1131              :  * go to seq. cycle (it is very fast for unwanted strings)
    1132              :  * (can't be used binary search in format parsing)
    1133              :  */
    1134              : static const KeyWord *
    1135        20541 : index_seq_search(const char *str, const KeyWord *kw, const int *index)
    1136              : {
    1137              :     int         poz;
    1138              : 
    1139        20541 :     if (!KeyWord_INDEX_FILTER(*str))
    1140         4726 :         return NULL;
    1141              : 
    1142        15815 :     if ((poz = index[*str - ' ']) > -1)
    1143              :     {
    1144        14420 :         const KeyWord *k = kw + poz;
    1145              : 
    1146              :         do
    1147              :         {
    1148        19192 :             if (strncmp(str, k->name, k->len) == 0)
    1149        14332 :                 return k;
    1150         4860 :             k++;
    1151         4860 :             if (!k->name)
    1152            0 :                 return NULL;
    1153         4860 :         } while (*str == *k->name);
    1154              :     }
    1155         1483 :     return NULL;
    1156              : }
    1157              : 
    1158              : static const KeySuffix *
    1159         7771 : suff_search(const char *str, const KeySuffix *suf, enum KeySuffixType type)
    1160              : {
    1161        60256 :     for (const KeySuffix *s = suf; s->name != NULL; s++)
    1162              :     {
    1163        52777 :         if (s->type != type)
    1164        24925 :             continue;
    1165              : 
    1166        27852 :         if (strncmp(str, s->name, s->len) == 0)
    1167          292 :             return s;
    1168              :     }
    1169         7479 :     return NULL;
    1170              : }
    1171              : 
    1172              : static bool
    1173         4357 : is_separator_char(const char *str)
    1174              : {
    1175              :     /* ASCII printable character, but not letter or digit */
    1176         3235 :     return (*str > 0x20 && *str < 0x7F &&
    1177         3235 :             !(*str >= 'A' && *str <= 'Z') &&
    1178        10639 :             !(*str >= 'a' && *str <= 'z') &&
    1179         3047 :             !(*str >= '0' && *str <= '9'));
    1180              : }
    1181              : 
    1182              : /*
    1183              :  * Prepare NUMDesc (number description struct) via FormatNode struct
    1184              :  */
    1185              : static void
    1186        11326 : NUMDesc_prepare(NUMDesc *num, FormatNode *n)
    1187              : {
    1188        11326 :     if (n->type != NODE_TYPE_ACTION)
    1189            0 :         return;
    1190              : 
    1191        11326 :     if (IS_EEEE(num) && n->key->id != NUM_E)
    1192            0 :         ereport(ERROR,
    1193              :                 (errcode(ERRCODE_SYNTAX_ERROR),
    1194              :                  errmsg("\"EEEE\" must be the last pattern used")));
    1195              : 
    1196        11326 :     switch (n->key->id)
    1197              :     {
    1198         9654 :         case NUM_9:
    1199         9654 :             if (IS_BRACKET(num))
    1200            0 :                 ereport(ERROR,
    1201              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1202              :                          errmsg("\"9\" must be ahead of \"PR\"")));
    1203         9654 :             if (IS_MULTI(num))
    1204              :             {
    1205           24 :                 ++num->multi;
    1206           24 :                 break;
    1207              :             }
    1208         9630 :             if (IS_DECIMAL(num))
    1209         3320 :                 ++num->post;
    1210              :             else
    1211         6310 :                 ++num->pre;
    1212         9630 :             break;
    1213              : 
    1214          345 :         case NUM_0:
    1215          345 :             if (IS_BRACKET(num))
    1216            0 :                 ereport(ERROR,
    1217              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1218              :                          errmsg("\"0\" must be ahead of \"PR\"")));
    1219          345 :             if (!IS_ZERO(num) && !IS_DECIMAL(num))
    1220              :             {
    1221           73 :                 num->flag |= NUM_F_ZERO;
    1222           73 :                 num->zero_start = num->pre + 1;
    1223              :             }
    1224          345 :             if (!IS_DECIMAL(num))
    1225          233 :                 ++num->pre;
    1226              :             else
    1227          112 :                 ++num->post;
    1228              : 
    1229          345 :             num->zero_end = num->pre + num->post;
    1230          345 :             break;
    1231              : 
    1232            0 :         case NUM_B:
    1233            0 :             if (num->pre == 0 && num->post == 0 && !IS_ZERO(num))
    1234            0 :                 num->flag |= NUM_F_BLANK;
    1235            0 :             break;
    1236              : 
    1237           59 :         case NUM_D:
    1238           59 :             num->flag |= NUM_F_LDECIMAL;
    1239           59 :             num->need_locale = true;
    1240              :             pg_fallthrough;
    1241          323 :         case NUM_DEC:
    1242          323 :             if (IS_DECIMAL(num))
    1243            0 :                 ereport(ERROR,
    1244              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1245              :                          errmsg("multiple decimal points")));
    1246          323 :             if (IS_MULTI(num))
    1247            0 :                 ereport(ERROR,
    1248              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1249              :                          errmsg("cannot use \"V\" and decimal point together")));
    1250          323 :             num->flag |= NUM_F_DECIMAL;
    1251          323 :             break;
    1252              : 
    1253          173 :         case NUM_FM:
    1254          173 :             num->flag |= NUM_F_FILLMODE;
    1255          173 :             break;
    1256              : 
    1257          150 :         case NUM_S:
    1258          150 :             if (IS_LSIGN(num))
    1259            0 :                 ereport(ERROR,
    1260              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1261              :                          errmsg("cannot use \"S\" twice")));
    1262          150 :             if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
    1263            0 :                 ereport(ERROR,
    1264              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1265              :                          errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
    1266          150 :             if (!IS_DECIMAL(num))
    1267              :             {
    1268          128 :                 num->lsign = NUM_LSIGN_PRE;
    1269          128 :                 num->pre_lsign_num = num->pre;
    1270          128 :                 num->need_locale = true;
    1271          128 :                 num->flag |= NUM_F_LSIGN;
    1272              :             }
    1273           22 :             else if (num->lsign == NUM_LSIGN_NONE)
    1274              :             {
    1275           22 :                 num->lsign = NUM_LSIGN_POST;
    1276           22 :                 num->need_locale = true;
    1277           22 :                 num->flag |= NUM_F_LSIGN;
    1278              :             }
    1279          150 :             break;
    1280              : 
    1281           24 :         case NUM_MI:
    1282           24 :             if (IS_LSIGN(num))
    1283            0 :                 ereport(ERROR,
    1284              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1285              :                          errmsg("cannot use \"S\" and \"MI\" together")));
    1286           24 :             num->flag |= NUM_F_MINUS;
    1287           24 :             if (IS_DECIMAL(num))
    1288            4 :                 num->flag |= NUM_F_MINUS_POST;
    1289           24 :             break;
    1290              : 
    1291            4 :         case NUM_PL:
    1292            4 :             if (IS_LSIGN(num))
    1293            0 :                 ereport(ERROR,
    1294              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1295              :                          errmsg("cannot use \"S\" and \"PL\" together")));
    1296            4 :             num->flag |= NUM_F_PLUS;
    1297            4 :             if (IS_DECIMAL(num))
    1298            0 :                 num->flag |= NUM_F_PLUS_POST;
    1299            4 :             break;
    1300              : 
    1301           16 :         case NUM_SG:
    1302           16 :             if (IS_LSIGN(num))
    1303            0 :                 ereport(ERROR,
    1304              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1305              :                          errmsg("cannot use \"S\" and \"SG\" together")));
    1306           16 :             num->flag |= NUM_F_MINUS;
    1307           16 :             num->flag |= NUM_F_PLUS;
    1308           16 :             break;
    1309              : 
    1310           24 :         case NUM_PR:
    1311           24 :             if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
    1312            0 :                 ereport(ERROR,
    1313              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1314              :                          errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
    1315           24 :             num->flag |= NUM_F_BRACKET;
    1316           24 :             break;
    1317              : 
    1318           44 :         case NUM_rn:
    1319              :         case NUM_RN:
    1320           44 :             if (IS_ROMAN(num))
    1321            4 :                 ereport(ERROR,
    1322              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1323              :                          errmsg("cannot use \"RN\" twice")));
    1324           40 :             num->flag |= NUM_F_ROMAN;
    1325           40 :             break;
    1326              : 
    1327          469 :         case NUM_L:
    1328              :         case NUM_G:
    1329          469 :             num->need_locale = true;
    1330          469 :             break;
    1331              : 
    1332           12 :         case NUM_V:
    1333           12 :             if (IS_DECIMAL(num))
    1334            0 :                 ereport(ERROR,
    1335              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1336              :                          errmsg("cannot use \"V\" and decimal point together")));
    1337           12 :             num->flag |= NUM_F_MULTI;
    1338           12 :             break;
    1339              : 
    1340           12 :         case NUM_E:
    1341           12 :             if (IS_EEEE(num))
    1342            0 :                 ereport(ERROR,
    1343              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1344              :                          errmsg("cannot use \"EEEE\" twice")));
    1345           12 :             if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) ||
    1346           12 :                 IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) ||
    1347           12 :                 IS_ROMAN(num) || IS_MULTI(num))
    1348            0 :                 ereport(ERROR,
    1349              :                         (errcode(ERRCODE_SYNTAX_ERROR),
    1350              :                          errmsg("\"EEEE\" is incompatible with other formats"),
    1351              :                          errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
    1352           12 :             num->flag |= NUM_F_EEEE;
    1353           12 :             break;
    1354              :     }
    1355              : 
    1356        11322 :     if (IS_ROMAN(num) &&
    1357           40 :         (num->flag & ~(NUM_F_ROMAN | NUM_F_FILLMODE)) != 0)
    1358            4 :         ereport(ERROR,
    1359              :                 (errcode(ERRCODE_SYNTAX_ERROR),
    1360              :                  errmsg("\"RN\" is incompatible with other formats"),
    1361              :                  errdetail("\"RN\" may only be used together with \"FM\".")));
    1362              : }
    1363              : 
    1364              : /*
    1365              :  * Format parser, search small keywords and keyword's suffixes, and make
    1366              :  * format-node tree.
    1367              :  *
    1368              :  * for DATE-TIME & NUMBER version
    1369              :  */
    1370              : static void
    1371         1232 : parse_format(FormatNode *node, const char *str, const KeyWord *kw,
    1372              :              const KeySuffix *suf, const int *index, uint32 flags, NUMDesc *Num)
    1373              : {
    1374              :     FormatNode *n;
    1375              : 
    1376              : #ifdef DEBUG_TO_FROM_CHAR
    1377              :     elog(DEBUG_elog_output, "to_char/number(): run parser");
    1378              : #endif
    1379              : 
    1380         1232 :     n = node;
    1381              : 
    1382        21761 :     while (*str)
    1383              :     {
    1384        20541 :         int         suffix = 0;
    1385              :         const KeySuffix *s;
    1386              : 
    1387              :         /*
    1388              :          * Prefix
    1389              :          */
    1390        25908 :         if ((flags & DCH_FLAG) &&
    1391         5367 :             (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
    1392              :         {
    1393          264 :             suffix |= s->id;
    1394          264 :             if (s->len)
    1395          264 :                 str += s->len;
    1396              :         }
    1397              : 
    1398              :         /*
    1399              :          * Keyword
    1400              :          */
    1401        20541 :         if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
    1402              :         {
    1403        14332 :             n->type = NODE_TYPE_ACTION;
    1404        14332 :             n->suffix = suffix;
    1405        14332 :             if (n->key->len)
    1406        14332 :                 str += n->key->len;
    1407              : 
    1408              :             /*
    1409              :              * NUM version: Prepare global NUMDesc struct
    1410              :              */
    1411        14332 :             if (flags & NUM_FLAG)
    1412        11326 :                 NUMDesc_prepare(Num, n);
    1413              : 
    1414              :             /*
    1415              :              * Postfix
    1416              :              */
    1417        16728 :             if ((flags & DCH_FLAG) && *str &&
    1418         2404 :                 (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
    1419              :             {
    1420           28 :                 n->suffix |= s->id;
    1421           28 :                 if (s->len)
    1422           28 :                     str += s->len;
    1423              :             }
    1424              : 
    1425        14324 :             n++;
    1426              :         }
    1427         6209 :         else if (*str)
    1428              :         {
    1429              :             int         chlen;
    1430              : 
    1431         6209 :             if ((flags & STD_FLAG) && *str != '"')
    1432              :             {
    1433              :                 /*
    1434              :                  * Standard mode, allow only following separators: "-./,':; ".
    1435              :                  * However, we support double quotes even in standard mode
    1436              :                  * (see below).  This is our extension of standard mode.
    1437              :                  */
    1438          380 :                 if (strchr("-./,':; ", *str) == NULL)
    1439            4 :                     ereport(ERROR,
    1440              :                             (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    1441              :                              errmsg("invalid datetime format separator: \"%s\"",
    1442              :                                     pnstrdup(str, pg_mblen_cstr(str)))));
    1443              : 
    1444          376 :                 if (*str == ' ')
    1445           60 :                     n->type = NODE_TYPE_SPACE;
    1446              :                 else
    1447          316 :                     n->type = NODE_TYPE_SEPARATOR;
    1448              : 
    1449          376 :                 n->character[0] = *str;
    1450          376 :                 n->character[1] = '\0';
    1451          376 :                 n->key = NULL;
    1452          376 :                 n->suffix = 0;
    1453          376 :                 n++;
    1454          376 :                 str++;
    1455              :             }
    1456         5829 :             else if (*str == '"')
    1457              :             {
    1458              :                 /*
    1459              :                  * Process double-quoted literal string, if any
    1460              :                  */
    1461          256 :                 str++;
    1462         2944 :                 while (*str)
    1463              :                 {
    1464         2940 :                     if (*str == '"')
    1465              :                     {
    1466          252 :                         str++;
    1467          252 :                         break;
    1468              :                     }
    1469              :                     /* backslash quotes the next character, if any */
    1470         2688 :                     if (*str == '\\' && *(str + 1))
    1471          160 :                         str++;
    1472         2688 :                     chlen = pg_mblen_cstr(str);
    1473         2688 :                     n->type = NODE_TYPE_CHAR;
    1474         2688 :                     memcpy(n->character, str, chlen);
    1475         2688 :                     n->character[chlen] = '\0';
    1476         2688 :                     n->key = NULL;
    1477         2688 :                     n->suffix = 0;
    1478         2688 :                     n++;
    1479         2688 :                     str += chlen;
    1480              :                 }
    1481              :             }
    1482              :             else
    1483              :             {
    1484              :                 /*
    1485              :                  * Outside double-quoted strings, backslash is only special if
    1486              :                  * it immediately precedes a double quote.
    1487              :                  */
    1488         5573 :                 if (*str == '\\' && *(str + 1) == '"')
    1489            8 :                     str++;
    1490         5573 :                 chlen = pg_mblen_cstr(str);
    1491              : 
    1492         5573 :                 if ((flags & DCH_FLAG) && is_separator_char(str))
    1493          716 :                     n->type = NODE_TYPE_SEPARATOR;
    1494         4857 :                 else if (isspace((unsigned char) *str))
    1495         4666 :                     n->type = NODE_TYPE_SPACE;
    1496              :                 else
    1497          191 :                     n->type = NODE_TYPE_CHAR;
    1498              : 
    1499         5573 :                 memcpy(n->character, str, chlen);
    1500         5573 :                 n->character[chlen] = '\0';
    1501         5573 :                 n->key = NULL;
    1502         5573 :                 n->suffix = 0;
    1503         5573 :                 n++;
    1504         5573 :                 str += chlen;
    1505              :             }
    1506              :         }
    1507              :     }
    1508              : 
    1509         1220 :     n->type = NODE_TYPE_END;
    1510         1220 :     n->suffix = 0;
    1511         1220 : }
    1512              : 
    1513              : /*
    1514              :  * DEBUG: Dump the FormatNode Tree (debug)
    1515              :  */
    1516              : #ifdef DEBUG_TO_FROM_CHAR
    1517              : 
    1518              : #define DUMP_THth(_suf) (IS_SUFFIX_TH(_suf) ? "TH" : (IS_SUFFIX_th(_suf) ? "th" : " "))
    1519              : #define DUMP_FM(_suf)   (IS_SUFFIX_FM(_suf) ? "FM" : " ")
    1520              : 
    1521              : static void
    1522              : dump_node(FormatNode *node, int max)
    1523              : {
    1524              :     FormatNode *n;
    1525              :     int         a;
    1526              : 
    1527              :     elog(DEBUG_elog_output, "to_from-char(): DUMP FORMAT");
    1528              : 
    1529              :     for (a = 0, n = node; a <= max; n++, a++)
    1530              :     {
    1531              :         if (n->type == NODE_TYPE_ACTION)
    1532              :             elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)",
    1533              :                  a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix));
    1534              :         else if (n->type == NODE_TYPE_CHAR)
    1535              :             elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%s'",
    1536              :                  a, n->character);
    1537              :         else if (n->type == NODE_TYPE_END)
    1538              :         {
    1539              :             elog(DEBUG_elog_output, "%d:\t NODE_TYPE_END", a);
    1540              :             return;
    1541              :         }
    1542              :         else
    1543              :             elog(DEBUG_elog_output, "%d:\t unknown NODE!", a);
    1544              :     }
    1545              : }
    1546              : #endif                          /* DEBUG */
    1547              : 
    1548              : /*****************************************************************************
    1549              :  *          Private utils
    1550              :  *****************************************************************************/
    1551              : 
    1552              : /*
    1553              :  * Return ST/ND/RD/TH for simple (1..9) numbers
    1554              :  */
    1555              : static const char *
    1556         1556 : get_th(const char *num, enum TH_Case type)
    1557              : {
    1558         1556 :     size_t      len = strlen(num);
    1559              :     char        last;
    1560              : 
    1561              :     Assert(len > 0);
    1562              : 
    1563         1556 :     last = num[len - 1];
    1564         1556 :     if (!isdigit((unsigned char) last))
    1565            0 :         ereport(ERROR,
    1566              :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1567              :                  errmsg("\"%s\" is not a number", num)));
    1568              : 
    1569              :     /*
    1570              :      * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
    1571              :      * 'ST/st', 'ND/nd', 'RD/rd', respectively
    1572              :      */
    1573         1556 :     if (len > 1 && num[len - 2] == '1')
    1574           88 :         last = 0;
    1575              : 
    1576         1556 :     switch (last)
    1577              :     {
    1578           64 :         case '1':
    1579           64 :             if (type == TH_UPPER)
    1580           16 :                 return numTH[0];
    1581           48 :             return numth[0];
    1582           32 :         case '2':
    1583           32 :             if (type == TH_UPPER)
    1584            0 :                 return numTH[1];
    1585           32 :             return numth[1];
    1586           24 :         case '3':
    1587           24 :             if (type == TH_UPPER)
    1588            4 :                 return numTH[2];
    1589           20 :             return numth[2];
    1590         1436 :         default:
    1591         1436 :             if (type == TH_UPPER)
    1592          504 :                 return numTH[3];
    1593          932 :             return numth[3];
    1594              :     }
    1595              : }
    1596              : 
    1597              : /*
    1598              :  * Convert string-number to ordinal string-number
    1599              :  */
    1600              : static char *
    1601         1524 : str_numth(char *dest, const char *num, enum TH_Case type)
    1602              : {
    1603         1524 :     if (dest != num)
    1604            0 :         strcpy(dest, num);
    1605         1524 :     strcat(dest, get_th(num, type));
    1606         1524 :     return dest;
    1607              : }
    1608              : 
    1609              : /*****************************************************************************
    1610              :  *          upper/lower/initcap functions
    1611              :  *****************************************************************************/
    1612              : 
    1613              : /*
    1614              :  * collation-aware, wide-character-aware lower function
    1615              :  *
    1616              :  * We pass the number of bytes so we can pass varlena and char*
    1617              :  * to this function.  The result is a palloc'd, null-terminated string.
    1618              :  */
    1619              : char *
    1620       227714 : str_tolower(const char *buff, size_t nbytes, Oid collid)
    1621              : {
    1622              :     char       *result;
    1623              :     pg_locale_t mylocale;
    1624              : 
    1625       227714 :     if (!buff)
    1626            0 :         return NULL;
    1627              : 
    1628       227714 :     if (!OidIsValid(collid))
    1629              :     {
    1630              :         /*
    1631              :          * This typically means that the parser could not resolve a conflict
    1632              :          * of implicit collations, so report it that way.
    1633              :          */
    1634            0 :         ereport(ERROR,
    1635              :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
    1636              :                  errmsg("could not determine which collation to use for %s function",
    1637              :                         "lower()"),
    1638              :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
    1639              :     }
    1640              : 
    1641       227714 :     mylocale = pg_newlocale_from_collation(collid);
    1642              : 
    1643              :     /* C/POSIX collations use this path regardless of database encoding */
    1644       227714 :     if (mylocale->ctype_is_c)
    1645              :     {
    1646          185 :         result = asc_tolower(buff, nbytes);
    1647              :     }
    1648              :     else
    1649              :     {
    1650       227529 :         const char *src = buff;
    1651       227529 :         size_t      srclen = nbytes;
    1652              :         size_t      dstsize;
    1653              :         char       *dst;
    1654              :         size_t      needed;
    1655              : 
    1656              :         /* first try buffer of equal size plus terminating NUL */
    1657       227529 :         dstsize = srclen + 1;
    1658       227529 :         dst = palloc(dstsize);
    1659              : 
    1660       227529 :         needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
    1661       227529 :         if (needed + 1 > dstsize)
    1662              :         {
    1663              :             /* grow buffer if needed and retry */
    1664           66 :             dstsize = needed + 1;
    1665           66 :             dst = repalloc(dst, dstsize);
    1666           66 :             needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
    1667              :             Assert(needed + 1 <= dstsize);
    1668              :         }
    1669              : 
    1670              :         Assert(dst[needed] == '\0');
    1671       227529 :         result = dst;
    1672              :     }
    1673              : 
    1674       227714 :     return result;
    1675              : }
    1676              : 
    1677              : /*
    1678              :  * collation-aware, wide-character-aware upper function
    1679              :  *
    1680              :  * We pass the number of bytes so we can pass varlena and char*
    1681              :  * to this function.  The result is a palloc'd, null-terminated string.
    1682              :  */
    1683              : char *
    1684       682991 : str_toupper(const char *buff, size_t nbytes, Oid collid)
    1685              : {
    1686              :     char       *result;
    1687              :     pg_locale_t mylocale;
    1688              : 
    1689       682991 :     if (!buff)
    1690            0 :         return NULL;
    1691              : 
    1692       682991 :     if (!OidIsValid(collid))
    1693              :     {
    1694              :         /*
    1695              :          * This typically means that the parser could not resolve a conflict
    1696              :          * of implicit collations, so report it that way.
    1697              :          */
    1698            0 :         ereport(ERROR,
    1699              :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
    1700              :                  errmsg("could not determine which collation to use for %s function",
    1701              :                         "upper()"),
    1702              :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
    1703              :     }
    1704              : 
    1705       682991 :     mylocale = pg_newlocale_from_collation(collid);
    1706              : 
    1707              :     /* C/POSIX collations use this path regardless of database encoding */
    1708       682991 :     if (mylocale->ctype_is_c)
    1709              :     {
    1710         2677 :         result = asc_toupper(buff, nbytes);
    1711              :     }
    1712              :     else
    1713              :     {
    1714       680314 :         const char *src = buff;
    1715       680314 :         size_t      srclen = nbytes;
    1716              :         size_t      dstsize;
    1717              :         char       *dst;
    1718              :         size_t      needed;
    1719              : 
    1720              :         /* first try buffer of equal size plus terminating NUL */
    1721       680314 :         dstsize = srclen + 1;
    1722       680314 :         dst = palloc(dstsize);
    1723              : 
    1724       680314 :         needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
    1725       680314 :         if (needed + 1 > dstsize)
    1726              :         {
    1727              :             /* grow buffer if needed and retry */
    1728            4 :             dstsize = needed + 1;
    1729            4 :             dst = repalloc(dst, dstsize);
    1730            4 :             needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
    1731              :             Assert(needed + 1 <= dstsize);
    1732              :         }
    1733              : 
    1734              :         Assert(dst[needed] == '\0');
    1735       680314 :         result = dst;
    1736              :     }
    1737              : 
    1738       682991 :     return result;
    1739              : }
    1740              : 
    1741              : /*
    1742              :  * collation-aware, wide-character-aware initcap function
    1743              :  *
    1744              :  * We pass the number of bytes so we can pass varlena and char*
    1745              :  * to this function.  The result is a palloc'd, null-terminated string.
    1746              :  */
    1747              : char *
    1748          167 : str_initcap(const char *buff, size_t nbytes, Oid collid)
    1749              : {
    1750              :     char       *result;
    1751              :     pg_locale_t mylocale;
    1752              : 
    1753          167 :     if (!buff)
    1754            0 :         return NULL;
    1755              : 
    1756          167 :     if (!OidIsValid(collid))
    1757              :     {
    1758              :         /*
    1759              :          * This typically means that the parser could not resolve a conflict
    1760              :          * of implicit collations, so report it that way.
    1761              :          */
    1762            0 :         ereport(ERROR,
    1763              :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
    1764              :                  errmsg("could not determine which collation to use for %s function",
    1765              :                         "initcap()"),
    1766              :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
    1767              :     }
    1768              : 
    1769          167 :     mylocale = pg_newlocale_from_collation(collid);
    1770              : 
    1771              :     /* C/POSIX collations use this path regardless of database encoding */
    1772          167 :     if (mylocale->ctype_is_c)
    1773              :     {
    1774           16 :         result = asc_initcap(buff, nbytes);
    1775              :     }
    1776              :     else
    1777              :     {
    1778          151 :         const char *src = buff;
    1779          151 :         size_t      srclen = nbytes;
    1780              :         size_t      dstsize;
    1781              :         char       *dst;
    1782              :         size_t      needed;
    1783              : 
    1784              :         /* first try buffer of equal size plus terminating NUL */
    1785          151 :         dstsize = srclen + 1;
    1786          151 :         dst = palloc(dstsize);
    1787              : 
    1788          151 :         needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
    1789          151 :         if (needed + 1 > dstsize)
    1790              :         {
    1791              :             /* grow buffer if needed and retry */
    1792           20 :             dstsize = needed + 1;
    1793           20 :             dst = repalloc(dst, dstsize);
    1794           20 :             needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
    1795              :             Assert(needed + 1 <= dstsize);
    1796              :         }
    1797              : 
    1798              :         Assert(dst[needed] == '\0');
    1799          151 :         result = dst;
    1800              :     }
    1801              : 
    1802          167 :     return result;
    1803              : }
    1804              : 
    1805              : /*
    1806              :  * collation-aware, wide-character-aware case folding
    1807              :  *
    1808              :  * We pass the number of bytes so we can pass varlena and char*
    1809              :  * to this function.  The result is a palloc'd, null-terminated string.
    1810              :  */
    1811              : char *
    1812           20 : str_casefold(const char *buff, size_t nbytes, Oid collid)
    1813              : {
    1814              :     char       *result;
    1815              :     pg_locale_t mylocale;
    1816              : 
    1817           20 :     if (!buff)
    1818            0 :         return NULL;
    1819              : 
    1820           20 :     if (!OidIsValid(collid))
    1821              :     {
    1822              :         /*
    1823              :          * This typically means that the parser could not resolve a conflict
    1824              :          * of implicit collations, so report it that way.
    1825              :          */
    1826            0 :         ereport(ERROR,
    1827              :                 (errcode(ERRCODE_INDETERMINATE_COLLATION),
    1828              :                  errmsg("could not determine which collation to use for %s function",
    1829              :                         "casefold()"),
    1830              :                  errhint("Use the COLLATE clause to set the collation explicitly.")));
    1831              :     }
    1832              : 
    1833           20 :     if (GetDatabaseEncoding() != PG_UTF8)
    1834            0 :         ereport(ERROR,
    1835              :                 (errcode(ERRCODE_SYNTAX_ERROR),
    1836              :                  errmsg("Unicode case folding can only be performed if server encoding is UTF8")));
    1837              : 
    1838           20 :     mylocale = pg_newlocale_from_collation(collid);
    1839              : 
    1840              :     /* C/POSIX collations use this path regardless of database encoding */
    1841           20 :     if (mylocale->ctype_is_c)
    1842              :     {
    1843            0 :         result = asc_tolower(buff, nbytes);
    1844              :     }
    1845              :     else
    1846              :     {
    1847           20 :         const char *src = buff;
    1848           20 :         size_t      srclen = nbytes;
    1849              :         size_t      dstsize;
    1850              :         char       *dst;
    1851              :         size_t      needed;
    1852              : 
    1853              :         /* first try buffer of equal size plus terminating NUL */
    1854           20 :         dstsize = srclen + 1;
    1855           20 :         dst = palloc(dstsize);
    1856              : 
    1857           20 :         needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
    1858           20 :         if (needed + 1 > dstsize)
    1859              :         {
    1860              :             /* grow buffer if needed and retry */
    1861            0 :             dstsize = needed + 1;
    1862            0 :             dst = repalloc(dst, dstsize);
    1863            0 :             needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
    1864              :             Assert(needed + 1 <= dstsize);
    1865              :         }
    1866              : 
    1867              :         Assert(dst[needed] == '\0');
    1868           20 :         result = dst;
    1869              :     }
    1870              : 
    1871           20 :     return result;
    1872              : }
    1873              : 
    1874              : /*
    1875              :  * ASCII-only lower function
    1876              :  *
    1877              :  * We pass the number of bytes so we can pass varlena and char*
    1878              :  * to this function.  The result is a palloc'd, null-terminated string.
    1879              :  */
    1880              : char *
    1881         3257 : asc_tolower(const char *buff, size_t nbytes)
    1882              : {
    1883              :     char       *result;
    1884              : 
    1885         3257 :     if (!buff)
    1886            0 :         return NULL;
    1887              : 
    1888         3257 :     result = pnstrdup(buff, nbytes);
    1889              : 
    1890        22403 :     for (char *p = result; *p; p++)
    1891        19146 :         *p = pg_ascii_tolower((unsigned char) *p);
    1892              : 
    1893         3257 :     return result;
    1894              : }
    1895              : 
    1896              : /*
    1897              :  * ASCII-only upper function
    1898              :  *
    1899              :  * We pass the number of bytes so we can pass varlena and char*
    1900              :  * to this function.  The result is a palloc'd, null-terminated string.
    1901              :  */
    1902              : char *
    1903         5725 : asc_toupper(const char *buff, size_t nbytes)
    1904              : {
    1905              :     char       *result;
    1906              : 
    1907         5725 :     if (!buff)
    1908            0 :         return NULL;
    1909              : 
    1910         5725 :     result = pnstrdup(buff, nbytes);
    1911              : 
    1912        45267 :     for (char *p = result; *p; p++)
    1913        39542 :         *p = pg_ascii_toupper((unsigned char) *p);
    1914              : 
    1915         5725 :     return result;
    1916              : }
    1917              : 
    1918              : /*
    1919              :  * ASCII-only initcap function
    1920              :  *
    1921              :  * We pass the number of bytes so we can pass varlena and char*
    1922              :  * to this function.  The result is a palloc'd, null-terminated string.
    1923              :  */
    1924              : char *
    1925           16 : asc_initcap(const char *buff, size_t nbytes)
    1926              : {
    1927              :     char       *result;
    1928           16 :     int         wasalnum = false;
    1929              : 
    1930           16 :     if (!buff)
    1931            0 :         return NULL;
    1932              : 
    1933           16 :     result = pnstrdup(buff, nbytes);
    1934              : 
    1935           64 :     for (char *p = result; *p; p++)
    1936              :     {
    1937              :         char        c;
    1938              : 
    1939           48 :         if (wasalnum)
    1940           32 :             *p = c = pg_ascii_tolower((unsigned char) *p);
    1941              :         else
    1942           16 :             *p = c = pg_ascii_toupper((unsigned char) *p);
    1943              :         /* we don't trust isalnum() here */
    1944           96 :         wasalnum = ((c >= 'A' && c <= 'Z') ||
    1945           96 :                     (c >= 'a' && c <= 'z') ||
    1946            0 :                     (c >= '0' && c <= '9'));
    1947              :     }
    1948              : 
    1949           16 :     return result;
    1950              : }
    1951              : 
    1952              : /* convenience routines for when the input is null-terminated */
    1953              : 
    1954              : static char *
    1955            0 : str_tolower_z(const char *buff, Oid collid)
    1956              : {
    1957            0 :     return str_tolower(buff, strlen(buff), collid);
    1958              : }
    1959              : 
    1960              : static char *
    1961            0 : str_toupper_z(const char *buff, Oid collid)
    1962              : {
    1963            0 :     return str_toupper(buff, strlen(buff), collid);
    1964              : }
    1965              : 
    1966              : static char *
    1967            0 : str_initcap_z(const char *buff, Oid collid)
    1968              : {
    1969            0 :     return str_initcap(buff, strlen(buff), collid);
    1970              : }
    1971              : 
    1972              : static char *
    1973         3072 : asc_tolower_z(const char *buff)
    1974              : {
    1975         3072 :     return asc_tolower(buff, strlen(buff));
    1976              : }
    1977              : 
    1978              : static char *
    1979         3048 : asc_toupper_z(const char *buff)
    1980              : {
    1981         3048 :     return asc_toupper(buff, strlen(buff));
    1982              : }
    1983              : 
    1984              : /* asc_initcap_z is not currently needed */
    1985              : 
    1986              : 
    1987              : /*
    1988              :  * Skip TM / th in FROM_CHAR
    1989              :  *
    1990              :  * If IS_SUFFIX_THth is on, skip two chars, assuming there are two available
    1991              :  */
    1992              : #define SKIP_THth(ptr, _suf) \
    1993              :     do { \
    1994              :         if (IS_SUFFIX_THth(_suf)) \
    1995              :         { \
    1996              :             if (*(ptr)) (ptr) += pg_mblen_cstr(ptr); \
    1997              :             if (*(ptr)) (ptr) += pg_mblen_cstr(ptr); \
    1998              :         } \
    1999              :     } while (0)
    2000              : 
    2001              : 
    2002              : #ifdef DEBUG_TO_FROM_CHAR
    2003              : /*
    2004              :  * DEBUG: Call for debug and for index checking; (Show ASCII char
    2005              :  * and defined keyword for each used position
    2006              :  */
    2007              : static void
    2008              : dump_index(const KeyWord *k, const int *index)
    2009              : {
    2010              :     int         count = 0,
    2011              :                 free_i = 0;
    2012              : 
    2013              :     elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:");
    2014              : 
    2015              :     for (int i = 0; i < KeyWord_INDEX_SIZE; i++)
    2016              :     {
    2017              :         if (index[i] != -1)
    2018              :         {
    2019              :             elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name);
    2020              :             count++;
    2021              :         }
    2022              :         else
    2023              :         {
    2024              :             free_i++;
    2025              :             elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]);
    2026              :         }
    2027              :     }
    2028              :     elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d",
    2029              :          count, free_i);
    2030              : }
    2031              : #endif                          /* DEBUG */
    2032              : 
    2033              : /*
    2034              :  * Return true if next format picture is not digit value
    2035              :  */
    2036              : static bool
    2037        82567 : is_next_separator(FormatNode *n)
    2038              : {
    2039        82567 :     if (n->type == NODE_TYPE_END)
    2040            0 :         return false;
    2041              : 
    2042        82567 :     if (n->type == NODE_TYPE_ACTION && IS_SUFFIX_THth(n->suffix))
    2043            0 :         return true;
    2044              : 
    2045              :     /*
    2046              :      * Next node
    2047              :      */
    2048        82567 :     n++;
    2049              : 
    2050              :     /* end of format string is treated like a non-digit separator */
    2051        82567 :     if (n->type == NODE_TYPE_END)
    2052         8571 :         return true;
    2053              : 
    2054        73996 :     if (n->type == NODE_TYPE_ACTION)
    2055              :     {
    2056         4304 :         if (n->key->is_digit)
    2057          320 :             return false;
    2058              : 
    2059         3984 :         return true;
    2060              :     }
    2061        69692 :     else if (n->character[1] == '\0' &&
    2062        69692 :              isdigit((unsigned char) n->character[0]))
    2063            0 :         return false;
    2064              : 
    2065        69692 :     return true;                /* some non-digit input (separator) */
    2066              : }
    2067              : 
    2068              : 
    2069              : static int
    2070           56 : adjust_partial_year_to_2020(int year)
    2071              : {
    2072              :     /*
    2073              :      * Adjust all dates toward 2020; this is effectively what happens when we
    2074              :      * assume '70' is 1970 and '69' is 2069.
    2075              :      */
    2076              :     /* Force 0-69 into the 2000's */
    2077           56 :     if (year < 70)
    2078           28 :         return year + 2000;
    2079              :     /* Force 70-99 into the 1900's */
    2080           28 :     else if (year < 100)
    2081           24 :         return year + 1900;
    2082              :     /* Force 100-519 into the 2000's */
    2083            4 :     else if (year < 520)
    2084            0 :         return year + 2000;
    2085              :     /* Force 520-999 into the 1000's */
    2086            4 :     else if (year < 1000)
    2087            4 :         return year + 1000;
    2088              :     else
    2089            0 :         return year;
    2090              : }
    2091              : 
    2092              : 
    2093              : static size_t
    2094        82595 : strspace_len(const char *str)
    2095              : {
    2096        82595 :     size_t      len = 0;
    2097              : 
    2098        82595 :     while (*str && isspace((unsigned char) *str))
    2099              :     {
    2100            0 :         str++;
    2101            0 :         len++;
    2102              :     }
    2103        82595 :     return len;
    2104              : }
    2105              : 
    2106              : /*
    2107              :  * Set the date mode of a from-char conversion.
    2108              :  *
    2109              :  * Puke if the date mode has already been set, and the caller attempts to set
    2110              :  * it to a conflicting mode.
    2111              :  *
    2112              :  * Returns true on success, false on failure (if escontext points to an
    2113              :  * ErrorSaveContext; otherwise errors are thrown).
    2114              :  */
    2115              : static bool
    2116        82577 : from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode,
    2117              :                    Node *escontext)
    2118              : {
    2119        82577 :     if (mode != FROM_CHAR_DATE_NONE)
    2120              :     {
    2121        36643 :         if (tmfc->mode == FROM_CHAR_DATE_NONE)
    2122        13535 :             tmfc->mode = mode;
    2123        23108 :         else if (tmfc->mode != mode)
    2124            4 :             ereturn(escontext, false,
    2125              :                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    2126              :                      errmsg("invalid combination of date conventions"),
    2127              :                      errhint("Do not mix Gregorian and ISO week date conventions in a formatting template.")));
    2128              :     }
    2129        82573 :     return true;
    2130              : }
    2131              : 
    2132              : /*
    2133              :  * Set the integer pointed to by 'dest' to the given value.
    2134              :  *
    2135              :  * Puke if the destination integer has previously been set to some other
    2136              :  * non-zero value.
    2137              :  *
    2138              :  * Returns true on success, false on failure (if escontext points to an
    2139              :  * ErrorSaveContext; otherwise errors are thrown).
    2140              :  */
    2141              : static bool
    2142        82174 : from_char_set_int(int *dest, const int value, const FormatNode *node,
    2143              :                   Node *escontext)
    2144              : {
    2145        82174 :     if (*dest != 0 && *dest != value)
    2146            4 :         ereturn(escontext, false,
    2147              :                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    2148              :                  errmsg("conflicting values for \"%s\" field in formatting string",
    2149              :                         node->key->name),
    2150              :                  errdetail("This value contradicts a previous setting for the same field type.")));
    2151        82170 :     *dest = value;
    2152        82170 :     return true;
    2153              : }
    2154              : 
    2155              : /*
    2156              :  * Read a single integer from the source string, into the int pointed to by
    2157              :  * 'dest'. If 'dest' is NULL, the result is discarded.
    2158              :  *
    2159              :  * In fixed-width mode (the node does not have the FM suffix), consume at most
    2160              :  * 'len' characters.  However, any leading whitespace isn't counted in 'len'.
    2161              :  *
    2162              :  * We use strtol() to recover the integer value from the source string, in
    2163              :  * accordance with the given FormatNode.
    2164              :  *
    2165              :  * If the conversion completes successfully, src will have been advanced to
    2166              :  * point at the character immediately following the last character used in the
    2167              :  * conversion.
    2168              :  *
    2169              :  * Returns the number of characters consumed, or -1 on error (if escontext
    2170              :  * points to an ErrorSaveContext; otherwise errors are thrown).
    2171              :  *
    2172              :  * Note that from_char_parse_int() provides a more convenient wrapper where
    2173              :  * the length of the field is the same as the length of the format keyword (as
    2174              :  * with DD and MI).
    2175              :  */
    2176              : static int
    2177        82595 : from_char_parse_int_len(int *dest, const char **src, const size_t len, FormatNode *node,
    2178              :                         Node *escontext)
    2179              : {
    2180              :     long        result;
    2181              :     char        copy[DCH_MAX_ITEM_SIZ + 1];
    2182        82595 :     const char *init = *src;
    2183              :     size_t      used;
    2184              : 
    2185              :     /*
    2186              :      * Skip any whitespace before parsing the integer.
    2187              :      */
    2188        82595 :     *src += strspace_len(*src);
    2189              : 
    2190              :     Assert(len <= DCH_MAX_ITEM_SIZ);
    2191        82595 :     used = strlcpy(copy, *src, len + 1);
    2192              : 
    2193        82595 :     if (IS_SUFFIX_FM(node->suffix) || is_next_separator(node))
    2194        82275 :     {
    2195              :         /*
    2196              :          * This node is in Fill Mode, or the next node is known to be a
    2197              :          * non-digit value, so we just slurp as many characters as we can get.
    2198              :          */
    2199              :         char       *endptr;
    2200              : 
    2201        82275 :         errno = 0;
    2202        82275 :         result = strtol(init, &endptr, 10);
    2203        82275 :         *src = endptr;
    2204              :     }
    2205              :     else
    2206              :     {
    2207              :         /*
    2208              :          * We need to pull exactly the number of characters given in 'len' out
    2209              :          * of the string, and convert those.
    2210              :          */
    2211              :         char       *last;
    2212              : 
    2213          320 :         if (used < len)
    2214            4 :             ereturn(escontext, -1,
    2215              :                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    2216              :                      errmsg("source string too short for \"%s\" formatting field",
    2217              :                             node->key->name),
    2218              :                      errdetail("Field requires %zu characters, but only %zu remain.",
    2219              :                                len, used),
    2220              :                      errhint("If your source string is not fixed-width, try using the \"FM\" modifier.")));
    2221              : 
    2222          316 :         errno = 0;
    2223          316 :         result = strtol(copy, &last, 10);
    2224          316 :         used = last - copy;
    2225              : 
    2226          316 :         if (used > 0 && used < len)
    2227            4 :             ereturn(escontext, -1,
    2228              :                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    2229              :                      errmsg("invalid value \"%s\" for \"%s\"",
    2230              :                             copy, node->key->name),
    2231              :                      errdetail("Field requires %zu characters, but only %zu could be parsed.",
    2232              :                                len, used),
    2233              :                      errhint("If your source string is not fixed-width, try using the \"FM\" modifier.")));
    2234              : 
    2235          312 :         *src += used;
    2236              :     }
    2237              : 
    2238        82587 :     if (*src == init)
    2239          557 :         ereturn(escontext, -1,
    2240              :                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    2241              :                  errmsg("invalid value \"%s\" for \"%s\"",
    2242              :                         copy, node->key->name),
    2243              :                  errdetail("Value must be an integer.")));
    2244              : 
    2245        82030 :     if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
    2246            4 :         ereturn(escontext, -1,
    2247              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2248              :                  errmsg("value for \"%s\" in source string is out of range",
    2249              :                         node->key->name),
    2250              :                  errdetail("Value must be in the range %d to %d.",
    2251              :                            INT_MIN, INT_MAX)));
    2252              : 
    2253        82026 :     if (dest != NULL)
    2254              :     {
    2255        82022 :         if (!from_char_set_int(dest, (int) result, node, escontext))
    2256            0 :             return -1;
    2257              :     }
    2258              : 
    2259        82026 :     return *src - init;
    2260              : }
    2261              : 
    2262              : /*
    2263              :  * Call from_char_parse_int_len(), using the length of the format keyword as
    2264              :  * the expected length of the field.
    2265              :  *
    2266              :  * Don't call this function if the field differs in length from the format
    2267              :  * keyword (as with HH24; the keyword length is 4, but the field length is 2).
    2268              :  * In such cases, call from_char_parse_int_len() instead to specify the
    2269              :  * required length explicitly.
    2270              :  */
    2271              : static int
    2272        58623 : from_char_parse_int(int *dest, const char **src, FormatNode *node,
    2273              :                     Node *escontext)
    2274              : {
    2275        58623 :     return from_char_parse_int_len(dest, src, node->key->len, node, escontext);
    2276              : }
    2277              : 
    2278              : /*
    2279              :  * Sequentially search null-terminated "array" for a case-insensitive match
    2280              :  * to the initial character(s) of "name".
    2281              :  *
    2282              :  * Returns array index of match, or -1 for no match.
    2283              :  *
    2284              :  * *len is set to the length of the match, or 0 for no match.
    2285              :  *
    2286              :  * Case-insensitivity is defined per pg_ascii_tolower, so this is only
    2287              :  * suitable for comparisons to ASCII strings.
    2288              :  */
    2289              : static int
    2290          156 : seq_search_ascii(const char *name, const char *const *array, size_t *len)
    2291              : {
    2292              :     unsigned char firstc;
    2293              : 
    2294          156 :     *len = 0;
    2295              : 
    2296              :     /* empty string can't match anything */
    2297          156 :     if (!*name)
    2298            0 :         return -1;
    2299              : 
    2300              :     /* we handle first char specially to gain some speed */
    2301          156 :     firstc = pg_ascii_tolower((unsigned char) *name);
    2302              : 
    2303          664 :     for (const char *const *a = array; *a != NULL; a++)
    2304              :     {
    2305              :         /* compare first chars */
    2306          656 :         if (pg_ascii_tolower((unsigned char) **a) != firstc)
    2307          476 :             continue;
    2308              : 
    2309              :         /* compare rest of string */
    2310          512 :         for (const char *p = *a + 1, *n = name + 1;; p++, n++)
    2311              :         {
    2312              :             /* return success if we matched whole array entry */
    2313          512 :             if (*p == '\0')
    2314              :             {
    2315          148 :                 *len = n - name;
    2316          148 :                 return a - array;
    2317              :             }
    2318              :             /* else, must have another character in "name" ... */
    2319          364 :             if (*n == '\0')
    2320            0 :                 break;
    2321              :             /* ... and it must match */
    2322          728 :             if (pg_ascii_tolower((unsigned char) *p) !=
    2323          364 :                 pg_ascii_tolower((unsigned char) *n))
    2324           32 :                 break;
    2325              :         }
    2326              :     }
    2327              : 
    2328            8 :     return -1;
    2329              : }
    2330              : 
    2331              : /*
    2332              :  * Sequentially search an array of possibly non-English words for
    2333              :  * a case-insensitive match to the initial character(s) of "name".
    2334              :  *
    2335              :  * This has the same API as seq_search_ascii(), but we use a more general
    2336              :  * case-folding transformation to achieve case-insensitivity.  Case folding
    2337              :  * is done per the rules of the collation identified by "collid".
    2338              :  *
    2339              :  * The array is treated as const, but we don't declare it that way because
    2340              :  * the arrays exported by pg_locale.c aren't const.
    2341              :  */
    2342              : static int
    2343            0 : seq_search_localized(const char *name, char **array, size_t *len, Oid collid)
    2344              : {
    2345              :     char       *upper_name;
    2346              :     char       *lower_name;
    2347              : 
    2348            0 :     *len = 0;
    2349              : 
    2350              :     /* empty string can't match anything */
    2351            0 :     if (!*name)
    2352            0 :         return -1;
    2353              : 
    2354              :     /*
    2355              :      * The case-folding processing done below is fairly expensive, so before
    2356              :      * doing that, make a quick pass to see if there is an exact match.
    2357              :      */
    2358            0 :     for (char **a = array; *a != NULL; a++)
    2359              :     {
    2360            0 :         size_t      element_len = strlen(*a);
    2361              : 
    2362            0 :         if (strncmp(name, *a, element_len) == 0)
    2363              :         {
    2364            0 :             *len = element_len;
    2365            0 :             return a - array;
    2366              :         }
    2367              :     }
    2368              : 
    2369              :     /*
    2370              :      * Fold to upper case, then to lower case, so that we can match reliably
    2371              :      * even in languages in which case conversions are not injective.
    2372              :      */
    2373            0 :     upper_name = str_toupper(name, strlen(name), collid);
    2374            0 :     lower_name = str_tolower(upper_name, strlen(upper_name), collid);
    2375            0 :     pfree(upper_name);
    2376              : 
    2377            0 :     for (char **a = array; *a != NULL; a++)
    2378              :     {
    2379              :         char       *upper_element;
    2380              :         char       *lower_element;
    2381              :         size_t      element_len;
    2382              : 
    2383              :         /* Likewise upper/lower-case array element */
    2384            0 :         upper_element = str_toupper(*a, strlen(*a), collid);
    2385            0 :         lower_element = str_tolower(upper_element, strlen(upper_element),
    2386              :                                     collid);
    2387            0 :         pfree(upper_element);
    2388            0 :         element_len = strlen(lower_element);
    2389              : 
    2390              :         /* Match? */
    2391            0 :         if (strncmp(lower_name, lower_element, element_len) == 0)
    2392              :         {
    2393            0 :             *len = element_len;
    2394            0 :             pfree(lower_element);
    2395            0 :             pfree(lower_name);
    2396            0 :             return a - array;
    2397              :         }
    2398            0 :         pfree(lower_element);
    2399              :     }
    2400              : 
    2401            0 :     pfree(lower_name);
    2402            0 :     return -1;
    2403              : }
    2404              : 
    2405              : /*
    2406              :  * Perform a sequential search in 'array' (or 'localized_array', if that's
    2407              :  * not NULL) for an entry matching the first character(s) of the 'src'
    2408              :  * string case-insensitively.
    2409              :  *
    2410              :  * The 'array' is presumed to be English words (all-ASCII), but
    2411              :  * if 'localized_array' is supplied, that might be non-English
    2412              :  * so we need a more expensive case-folding transformation
    2413              :  * (which will follow the rules of the collation 'collid').
    2414              :  *
    2415              :  * If a match is found, copy the array index of the match into the integer
    2416              :  * pointed to by 'dest' and advance 'src' to the end of the part of the string
    2417              :  * which matched.
    2418              :  *
    2419              :  * Returns true on match, false on failure (if escontext points to an
    2420              :  * ErrorSaveContext; otherwise errors are thrown).
    2421              :  *
    2422              :  * 'node' is used only for error reports: node->key->name identifies the
    2423              :  * field type we were searching for.
    2424              :  */
    2425              : static bool
    2426          156 : from_char_seq_search(int *dest, const char **src, const char *const *array,
    2427              :                      char **localized_array, Oid collid,
    2428              :                      FormatNode *node, Node *escontext)
    2429              : {
    2430              :     size_t      len;
    2431              : 
    2432          156 :     if (localized_array == NULL)
    2433          156 :         *dest = seq_search_ascii(*src, array, &len);
    2434              :     else
    2435            0 :         *dest = seq_search_localized(*src, localized_array, &len, collid);
    2436              : 
    2437          156 :     if (len <= 0)
    2438              :     {
    2439              :         /*
    2440              :          * In the error report, truncate the string at the next whitespace (if
    2441              :          * any) to avoid including irrelevant data.
    2442              :          */
    2443            8 :         char       *copy = pstrdup(*src);
    2444              : 
    2445           40 :         for (char *c = copy; *c; c++)
    2446              :         {
    2447           36 :             if (scanner_isspace(*c))
    2448              :             {
    2449            4 :                 *c = '\0';
    2450            4 :                 break;
    2451              :             }
    2452              :         }
    2453              : 
    2454            8 :         ereturn(escontext, false,
    2455              :                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    2456              :                  errmsg("invalid value \"%s\" for \"%s\"",
    2457              :                         copy, node->key->name),
    2458              :                  errdetail("The given value did not match any of the allowed values for this field.")));
    2459              :     }
    2460          148 :     *src += len;
    2461          148 :     return true;
    2462              : }
    2463              : 
    2464              : /*
    2465              :  * Process a TmToChar struct as denoted by a list of FormatNodes.
    2466              :  * The formatted data is written to the string pointed to by 'out'.
    2467              :  */
    2468              : static void
    2469         6308 : DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
    2470              : {
    2471              :     char       *s;
    2472         6308 :     struct fmt_tm *tm = &in->tm;
    2473              :     int         i;
    2474              : 
    2475              :     /* cache localized days and months */
    2476         6308 :     cache_locale_time();
    2477              : 
    2478         6308 :     s = out;
    2479       124390 :     for (FormatNode *n = node; n->type != NODE_TYPE_END; n++)
    2480              :     {
    2481       118082 :         if (n->type != NODE_TYPE_ACTION)
    2482              :         {
    2483        69261 :             strcpy(s, n->character);
    2484        69261 :             s += strlen(s);
    2485        69261 :             continue;
    2486              :         }
    2487              : 
    2488        48821 :         switch (n->key->id)
    2489              :         {
    2490          508 :             case DCH_A_M:
    2491              :             case DCH_P_M:
    2492          508 :                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
    2493              :                        ? P_M_STR : A_M_STR);
    2494          508 :                 s += strlen(s);
    2495          508 :                 break;
    2496            0 :             case DCH_AM:
    2497              :             case DCH_PM:
    2498            0 :                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
    2499              :                        ? PM_STR : AM_STR);
    2500            0 :                 s += strlen(s);
    2501            0 :                 break;
    2502          508 :             case DCH_a_m:
    2503              :             case DCH_p_m:
    2504          508 :                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
    2505              :                        ? p_m_STR : a_m_STR);
    2506          508 :                 s += strlen(s);
    2507          508 :                 break;
    2508          508 :             case DCH_am:
    2509              :             case DCH_pm:
    2510          508 :                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
    2511              :                        ? pm_STR : am_STR);
    2512          508 :                 s += strlen(s);
    2513          508 :                 break;
    2514         3066 :             case DCH_HH:
    2515              :             case DCH_HH12:
    2516              : 
    2517              :                 /*
    2518              :                  * display time as shown on a 12-hour clock, even for
    2519              :                  * intervals
    2520              :                  */
    2521         3066 :                 sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
    2522         3066 :                         tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ?
    2523              :                         (long long) (HOURS_PER_DAY / 2) :
    2524         2954 :                         (long long) (tm->tm_hour % (HOURS_PER_DAY / 2)));
    2525         3066 :                 if (IS_SUFFIX_THth(n->suffix))
    2526            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2527         3066 :                 s += strlen(s);
    2528         3066 :                 break;
    2529         1017 :             case DCH_HH24:
    2530         1017 :                 sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
    2531         1017 :                         (long long) tm->tm_hour);
    2532         1017 :                 if (IS_SUFFIX_THth(n->suffix))
    2533            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2534         1017 :                 s += strlen(s);
    2535         1017 :                 break;
    2536         3067 :             case DCH_MI:
    2537         3067 :                 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
    2538              :                         tm->tm_min);
    2539         3067 :                 if (IS_SUFFIX_THth(n->suffix))
    2540            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2541         3067 :                 s += strlen(s);
    2542         3067 :                 break;
    2543         3067 :             case DCH_SS:
    2544         3067 :                 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
    2545              :                         tm->tm_sec);
    2546         3067 :                 if (IS_SUFFIX_THth(n->suffix))
    2547            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2548         3067 :                 s += strlen(s);
    2549         3067 :                 break;
    2550              : 
    2551              : #define DCH_to_char_fsec(frac_fmt, frac_val) \
    2552              :                 sprintf(s, frac_fmt, (int) (frac_val)); \
    2553              :                 if (IS_SUFFIX_THth(n->suffix)) \
    2554              :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); \
    2555              :                 s += strlen(s)
    2556              : 
    2557           64 :             case DCH_FF1:       /* tenth of second */
    2558           64 :                 DCH_to_char_fsec("%01d", in->fsec / 100000);
    2559           64 :                 break;
    2560           64 :             case DCH_FF2:       /* hundredth of second */
    2561           64 :                 DCH_to_char_fsec("%02d", in->fsec / 10000);
    2562           64 :                 break;
    2563           96 :             case DCH_FF3:
    2564              :             case DCH_MS:        /* millisecond */
    2565           96 :                 DCH_to_char_fsec("%03d", in->fsec / 1000);
    2566           96 :                 break;
    2567           64 :             case DCH_FF4:       /* tenth of a millisecond */
    2568           64 :                 DCH_to_char_fsec("%04d", in->fsec / 100);
    2569           64 :                 break;
    2570           64 :             case DCH_FF5:       /* hundredth of a millisecond */
    2571           64 :                 DCH_to_char_fsec("%05d", in->fsec / 10);
    2572           64 :                 break;
    2573           96 :             case DCH_FF6:
    2574              :             case DCH_US:        /* microsecond */
    2575           96 :                 DCH_to_char_fsec("%06d", in->fsec);
    2576           96 :                 break;
    2577              : #undef DCH_to_char_fsec
    2578          516 :             case DCH_SSSS:
    2579          516 :                 sprintf(s, "%lld",
    2580          516 :                         (long long) (tm->tm_hour * SECS_PER_HOUR +
    2581          516 :                                      tm->tm_min * SECS_PER_MINUTE +
    2582          516 :                                      tm->tm_sec));
    2583          516 :                 if (IS_SUFFIX_THth(n->suffix))
    2584            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2585          516 :                 s += strlen(s);
    2586          516 :                 break;
    2587            4 :             case DCH_tz:
    2588            4 :                 INVALID_FOR_INTERVAL;
    2589            4 :                 if (tmtcTzn(in))
    2590              :                 {
    2591              :                     /* We assume here that timezone names aren't localized */
    2592            4 :                     char       *p = asc_tolower_z(tmtcTzn(in));
    2593              : 
    2594            4 :                     strcpy(s, p);
    2595            4 :                     pfree(p);
    2596            4 :                     s += strlen(s);
    2597              :                 }
    2598            4 :                 break;
    2599           12 :             case DCH_TZ:
    2600           12 :                 INVALID_FOR_INTERVAL;
    2601           12 :                 if (tmtcTzn(in))
    2602              :                 {
    2603           12 :                     strcpy(s, tmtcTzn(in));
    2604           12 :                     s += strlen(s);
    2605              :                 }
    2606           12 :                 break;
    2607           72 :             case DCH_TZH:
    2608           72 :                 INVALID_FOR_INTERVAL;
    2609           72 :                 sprintf(s, "%c%02d",
    2610           72 :                         (tm->tm_gmtoff >= 0) ? '+' : '-',
    2611           72 :                         abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
    2612           72 :                 s += strlen(s);
    2613           72 :                 break;
    2614           72 :             case DCH_TZM:
    2615           72 :                 INVALID_FOR_INTERVAL;
    2616           72 :                 sprintf(s, "%02d",
    2617           72 :                         (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
    2618           72 :                 s += strlen(s);
    2619           72 :                 break;
    2620           72 :             case DCH_OF:
    2621           72 :                 INVALID_FOR_INTERVAL;
    2622          144 :                 sprintf(s, "%c%0*d",
    2623           72 :                         (tm->tm_gmtoff >= 0) ? '+' : '-',
    2624           72 :                         IS_SUFFIX_FM(n->suffix) ? 0 : 2,
    2625           72 :                         abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
    2626           72 :                 s += strlen(s);
    2627           72 :                 if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
    2628              :                 {
    2629           48 :                     sprintf(s, ":%02d",
    2630           48 :                             (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
    2631           48 :                     s += strlen(s);
    2632              :                 }
    2633           72 :                 break;
    2634          508 :             case DCH_A_D:
    2635              :             case DCH_B_C:
    2636          508 :                 INVALID_FOR_INTERVAL;
    2637          508 :                 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
    2638          508 :                 s += strlen(s);
    2639          508 :                 break;
    2640            0 :             case DCH_AD:
    2641              :             case DCH_BC:
    2642            0 :                 INVALID_FOR_INTERVAL;
    2643            0 :                 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
    2644            0 :                 s += strlen(s);
    2645            0 :                 break;
    2646          508 :             case DCH_a_d:
    2647              :             case DCH_b_c:
    2648          508 :                 INVALID_FOR_INTERVAL;
    2649          508 :                 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
    2650          508 :                 s += strlen(s);
    2651          508 :                 break;
    2652          508 :             case DCH_ad:
    2653              :             case DCH_bc:
    2654          508 :                 INVALID_FOR_INTERVAL;
    2655          508 :                 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
    2656          508 :                 s += strlen(s);
    2657          508 :                 break;
    2658         1016 :             case DCH_MONTH:
    2659         1016 :                 INVALID_FOR_INTERVAL;
    2660         1016 :                 if (!tm->tm_mon)
    2661            0 :                     break;
    2662         1016 :                 if (IS_SUFFIX_TM(n->suffix))
    2663              :                 {
    2664            0 :                     char       *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid);
    2665              : 
    2666            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2667            0 :                         strcpy(s, str);
    2668              :                     else
    2669            0 :                         ereport(ERROR,
    2670              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2671              :                                  errmsg("localized string format value too long")));
    2672              :                 }
    2673              :                 else
    2674         1016 :                     sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
    2675         1016 :                             asc_toupper_z(months_full[tm->tm_mon - 1]));
    2676         1016 :                 s += strlen(s);
    2677         1016 :                 break;
    2678         1016 :             case DCH_Month:
    2679         1016 :                 INVALID_FOR_INTERVAL;
    2680         1016 :                 if (!tm->tm_mon)
    2681            0 :                     break;
    2682         1016 :                 if (IS_SUFFIX_TM(n->suffix))
    2683              :                 {
    2684            0 :                     char       *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid);
    2685              : 
    2686            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2687            0 :                         strcpy(s, str);
    2688              :                     else
    2689            0 :                         ereport(ERROR,
    2690              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2691              :                                  errmsg("localized string format value too long")));
    2692              :                 }
    2693              :                 else
    2694         1016 :                     sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
    2695         1016 :                             months_full[tm->tm_mon - 1]);
    2696         1016 :                 s += strlen(s);
    2697         1016 :                 break;
    2698         1016 :             case DCH_month:
    2699         1016 :                 INVALID_FOR_INTERVAL;
    2700         1016 :                 if (!tm->tm_mon)
    2701            0 :                     break;
    2702         1016 :                 if (IS_SUFFIX_TM(n->suffix))
    2703              :                 {
    2704            0 :                     char       *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid);
    2705              : 
    2706            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2707            0 :                         strcpy(s, str);
    2708              :                     else
    2709            0 :                         ereport(ERROR,
    2710              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2711              :                                  errmsg("localized string format value too long")));
    2712              :                 }
    2713              :                 else
    2714         1016 :                     sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
    2715         1016 :                             asc_tolower_z(months_full[tm->tm_mon - 1]));
    2716         1016 :                 s += strlen(s);
    2717         1016 :                 break;
    2718          508 :             case DCH_MON:
    2719          508 :                 INVALID_FOR_INTERVAL;
    2720          508 :                 if (!tm->tm_mon)
    2721            0 :                     break;
    2722          508 :                 if (IS_SUFFIX_TM(n->suffix))
    2723              :                 {
    2724            0 :                     char       *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid);
    2725              : 
    2726            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2727            0 :                         strcpy(s, str);
    2728              :                     else
    2729            0 :                         ereport(ERROR,
    2730              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2731              :                                  errmsg("localized string format value too long")));
    2732              :                 }
    2733              :                 else
    2734          508 :                     strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
    2735          508 :                 s += strlen(s);
    2736          508 :                 break;
    2737          564 :             case DCH_Mon:
    2738          564 :                 INVALID_FOR_INTERVAL;
    2739          564 :                 if (!tm->tm_mon)
    2740            0 :                     break;
    2741          564 :                 if (IS_SUFFIX_TM(n->suffix))
    2742              :                 {
    2743            0 :                     char       *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid);
    2744              : 
    2745            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2746            0 :                         strcpy(s, str);
    2747              :                     else
    2748            0 :                         ereport(ERROR,
    2749              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2750              :                                  errmsg("localized string format value too long")));
    2751              :                 }
    2752              :                 else
    2753          564 :                     strcpy(s, months[tm->tm_mon - 1]);
    2754          564 :                 s += strlen(s);
    2755          564 :                 break;
    2756          508 :             case DCH_mon:
    2757          508 :                 INVALID_FOR_INTERVAL;
    2758          508 :                 if (!tm->tm_mon)
    2759            0 :                     break;
    2760          508 :                 if (IS_SUFFIX_TM(n->suffix))
    2761              :                 {
    2762            0 :                     char       *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid);
    2763              : 
    2764            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2765            0 :                         strcpy(s, str);
    2766              :                     else
    2767            0 :                         ereport(ERROR,
    2768              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2769              :                                  errmsg("localized string format value too long")));
    2770              :                 }
    2771              :                 else
    2772          508 :                     strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
    2773          508 :                 s += strlen(s);
    2774          508 :                 break;
    2775         1284 :             case DCH_MM:
    2776         1284 :                 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
    2777              :                         tm->tm_mon);
    2778         1284 :                 if (IS_SUFFIX_THth(n->suffix))
    2779            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2780         1284 :                 s += strlen(s);
    2781         1284 :                 break;
    2782         1016 :             case DCH_DAY:
    2783         1016 :                 INVALID_FOR_INTERVAL;
    2784         1016 :                 if (IS_SUFFIX_TM(n->suffix))
    2785              :                 {
    2786            0 :                     char       *str = str_toupper_z(localized_full_days[tm->tm_wday], collid);
    2787              : 
    2788            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2789            0 :                         strcpy(s, str);
    2790              :                     else
    2791            0 :                         ereport(ERROR,
    2792              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2793              :                                  errmsg("localized string format value too long")));
    2794              :                 }
    2795              :                 else
    2796         1016 :                     sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
    2797         1016 :                             asc_toupper_z(days[tm->tm_wday]));
    2798         1016 :                 s += strlen(s);
    2799         1016 :                 break;
    2800         1016 :             case DCH_Day:
    2801         1016 :                 INVALID_FOR_INTERVAL;
    2802         1016 :                 if (IS_SUFFIX_TM(n->suffix))
    2803              :                 {
    2804            0 :                     char       *str = str_initcap_z(localized_full_days[tm->tm_wday], collid);
    2805              : 
    2806            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2807            0 :                         strcpy(s, str);
    2808              :                     else
    2809            0 :                         ereport(ERROR,
    2810              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2811              :                                  errmsg("localized string format value too long")));
    2812              :                 }
    2813              :                 else
    2814         1016 :                     sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
    2815         1016 :                             days[tm->tm_wday]);
    2816         1016 :                 s += strlen(s);
    2817         1016 :                 break;
    2818         1016 :             case DCH_day:
    2819         1016 :                 INVALID_FOR_INTERVAL;
    2820         1016 :                 if (IS_SUFFIX_TM(n->suffix))
    2821              :                 {
    2822            0 :                     char       *str = str_tolower_z(localized_full_days[tm->tm_wday], collid);
    2823              : 
    2824            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2825            0 :                         strcpy(s, str);
    2826              :                     else
    2827            0 :                         ereport(ERROR,
    2828              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2829              :                                  errmsg("localized string format value too long")));
    2830              :                 }
    2831              :                 else
    2832         1016 :                     sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
    2833         1016 :                             asc_tolower_z(days[tm->tm_wday]));
    2834         1016 :                 s += strlen(s);
    2835         1016 :                 break;
    2836          508 :             case DCH_DY:
    2837          508 :                 INVALID_FOR_INTERVAL;
    2838          508 :                 if (IS_SUFFIX_TM(n->suffix))
    2839              :                 {
    2840            0 :                     char       *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid);
    2841              : 
    2842            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2843            0 :                         strcpy(s, str);
    2844              :                     else
    2845            0 :                         ereport(ERROR,
    2846              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2847              :                                  errmsg("localized string format value too long")));
    2848              :                 }
    2849              :                 else
    2850          508 :                     strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
    2851          508 :                 s += strlen(s);
    2852          508 :                 break;
    2853          508 :             case DCH_Dy:
    2854          508 :                 INVALID_FOR_INTERVAL;
    2855          508 :                 if (IS_SUFFIX_TM(n->suffix))
    2856              :                 {
    2857            0 :                     char       *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid);
    2858              : 
    2859            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2860            0 :                         strcpy(s, str);
    2861              :                     else
    2862            0 :                         ereport(ERROR,
    2863              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2864              :                                  errmsg("localized string format value too long")));
    2865              :                 }
    2866              :                 else
    2867          508 :                     strcpy(s, days_short[tm->tm_wday]);
    2868          508 :                 s += strlen(s);
    2869          508 :                 break;
    2870          508 :             case DCH_dy:
    2871          508 :                 INVALID_FOR_INTERVAL;
    2872          508 :                 if (IS_SUFFIX_TM(n->suffix))
    2873              :                 {
    2874            0 :                     char       *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid);
    2875              : 
    2876            0 :                     if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
    2877            0 :                         strcpy(s, str);
    2878              :                     else
    2879            0 :                         ereport(ERROR,
    2880              :                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    2881              :                                  errmsg("localized string format value too long")));
    2882              :                 }
    2883              :                 else
    2884          508 :                     strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
    2885          508 :                 s += strlen(s);
    2886          508 :                 break;
    2887         2032 :             case DCH_DDD:
    2888              :             case DCH_IDDD:
    2889         2032 :                 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 3,
    2890         2032 :                         (n->key->id == DCH_DDD) ?
    2891              :                         tm->tm_yday :
    2892         1016 :                         date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday));
    2893         2032 :                 if (IS_SUFFIX_THth(n->suffix))
    2894            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2895         2032 :                 s += strlen(s);
    2896         2032 :                 break;
    2897         1040 :             case DCH_DD:
    2898         1040 :                 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2, tm->tm_mday);
    2899         1040 :                 if (IS_SUFFIX_THth(n->suffix))
    2900            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2901         1040 :                 s += strlen(s);
    2902         1040 :                 break;
    2903         1016 :             case DCH_D:
    2904         1016 :                 INVALID_FOR_INTERVAL;
    2905         1016 :                 sprintf(s, "%d", tm->tm_wday + 1);
    2906         1016 :                 if (IS_SUFFIX_THth(n->suffix))
    2907            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2908         1016 :                 s += strlen(s);
    2909         1016 :                 break;
    2910         1016 :             case DCH_ID:
    2911         1016 :                 INVALID_FOR_INTERVAL;
    2912         1016 :                 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
    2913         1016 :                 if (IS_SUFFIX_THth(n->suffix))
    2914            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2915         1016 :                 s += strlen(s);
    2916         1016 :                 break;
    2917         1016 :             case DCH_WW:
    2918         1016 :                 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2,
    2919         1016 :                         (tm->tm_yday - 1) / 7 + 1);
    2920         1016 :                 if (IS_SUFFIX_THth(n->suffix))
    2921            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2922         1016 :                 s += strlen(s);
    2923         1016 :                 break;
    2924         1016 :             case DCH_IW:
    2925         1016 :                 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2,
    2926              :                         date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
    2927         1016 :                 if (IS_SUFFIX_THth(n->suffix))
    2928            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2929         1016 :                 s += strlen(s);
    2930         1016 :                 break;
    2931         1016 :             case DCH_Q:
    2932         1016 :                 if (!tm->tm_mon)
    2933            0 :                     break;
    2934         1016 :                 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
    2935         1016 :                 if (IS_SUFFIX_THth(n->suffix))
    2936            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2937         1016 :                 s += strlen(s);
    2938         1016 :                 break;
    2939         1016 :             case DCH_CC:
    2940         1016 :                 if (is_interval)    /* straight calculation */
    2941            0 :                     i = tm->tm_year / 100;
    2942              :                 else
    2943              :                 {
    2944         1016 :                     if (tm->tm_year > 0)
    2945              :                         /* Century 20 == 1901 - 2000 */
    2946         1000 :                         i = (tm->tm_year - 1) / 100 + 1;
    2947              :                     else
    2948              :                         /* Century 6BC == 600BC - 501BC */
    2949           16 :                         i = tm->tm_year / 100 - 1;
    2950              :                 }
    2951         1016 :                 if (i <= 99 && i >= -99)
    2952         1016 :                     sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
    2953              :                 else
    2954            0 :                     sprintf(s, "%d", i);
    2955         1016 :                 if (IS_SUFFIX_THth(n->suffix))
    2956            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2957         1016 :                 s += strlen(s);
    2958         1016 :                 break;
    2959         1016 :             case DCH_Y_YYY:
    2960         1016 :                 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
    2961         1016 :                 sprintf(s, "%d,%03d", i,
    2962         1016 :                         ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
    2963         1016 :                 if (IS_SUFFIX_THth(n->suffix))
    2964            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2965         1016 :                 s += strlen(s);
    2966         1016 :                 break;
    2967         4840 :             case DCH_YYYY:
    2968              :             case DCH_IYYY:
    2969        13504 :                 sprintf(s, "%0*d",
    2970         4840 :                         IS_SUFFIX_FM(n->suffix) ? 0 :
    2971         3824 :                         (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
    2972         4840 :                         (n->key->id == DCH_YYYY ?
    2973         3824 :                          ADJUST_YEAR(tm->tm_year, is_interval) :
    2974         1016 :                          ADJUST_YEAR(date2isoyear(tm->tm_year,
    2975              :                                                   tm->tm_mon,
    2976              :                                                   tm->tm_mday),
    2977              :                                      is_interval)));
    2978         4840 :                 if (IS_SUFFIX_THth(n->suffix))
    2979         1016 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2980         4840 :                 s += strlen(s);
    2981         4840 :                 break;
    2982         2032 :             case DCH_YYY:
    2983              :             case DCH_IYY:
    2984         5080 :                 sprintf(s, "%0*d",
    2985         2032 :                         IS_SUFFIX_FM(n->suffix) ? 0 :
    2986         1016 :                         (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
    2987         2032 :                         (n->key->id == DCH_YYY ?
    2988         2032 :                          ADJUST_YEAR(tm->tm_year, is_interval) :
    2989         2032 :                          ADJUST_YEAR(date2isoyear(tm->tm_year,
    2990              :                                                   tm->tm_mon,
    2991              :                                                   tm->tm_mday),
    2992         4064 :                                      is_interval)) % 1000);
    2993         2032 :                 if (IS_SUFFIX_THth(n->suffix))
    2994            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    2995         2032 :                 s += strlen(s);
    2996         2032 :                 break;
    2997         2032 :             case DCH_YY:
    2998              :             case DCH_IY:
    2999         5080 :                 sprintf(s, "%0*d",
    3000         2032 :                         IS_SUFFIX_FM(n->suffix) ? 0 :
    3001         1016 :                         (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
    3002         2032 :                         (n->key->id == DCH_YY ?
    3003         2032 :                          ADJUST_YEAR(tm->tm_year, is_interval) :
    3004         2032 :                          ADJUST_YEAR(date2isoyear(tm->tm_year,
    3005              :                                                   tm->tm_mon,
    3006              :                                                   tm->tm_mday),
    3007         4064 :                                      is_interval)) % 100);
    3008         2032 :                 if (IS_SUFFIX_THth(n->suffix))
    3009            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    3010         2032 :                 s += strlen(s);
    3011         2032 :                 break;
    3012         2032 :             case DCH_Y:
    3013              :             case DCH_I:
    3014         2032 :                 sprintf(s, "%1d",
    3015         2032 :                         (n->key->id == DCH_Y ?
    3016         2032 :                          ADJUST_YEAR(tm->tm_year, is_interval) :
    3017         2032 :                          ADJUST_YEAR(date2isoyear(tm->tm_year,
    3018              :                                                   tm->tm_mon,
    3019              :                                                   tm->tm_mday),
    3020         4064 :                                      is_interval)) % 10);
    3021         2032 :                 if (IS_SUFFIX_THth(n->suffix))
    3022            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    3023         2032 :                 s += strlen(s);
    3024         2032 :                 break;
    3025         1232 :             case DCH_RM:
    3026              :                 pg_fallthrough;
    3027              :             case DCH_rm:
    3028              : 
    3029              :                 /*
    3030              :                  * For intervals, values like '12 month' will be reduced to 0
    3031              :                  * month and some years.  These should be processed.
    3032              :                  */
    3033         1232 :                 if (!tm->tm_mon && !tm->tm_year)
    3034              :                     break;
    3035              :                 else
    3036              :                 {
    3037         1224 :                     int         mon = 0;
    3038              :                     const char *const *months;
    3039              : 
    3040         1224 :                     if (n->key->id == DCH_RM)
    3041         1120 :                         months = rm_months_upper;
    3042              :                     else
    3043          104 :                         months = rm_months_lower;
    3044              : 
    3045              :                     /*
    3046              :                      * Compute the position in the roman-numeral array.  Note
    3047              :                      * that the contents of the array are reversed, December
    3048              :                      * being first and January last.
    3049              :                      */
    3050         1224 :                     if (tm->tm_mon == 0)
    3051              :                     {
    3052              :                         /*
    3053              :                          * This case is special, and tracks the case of full
    3054              :                          * interval years.
    3055              :                          */
    3056           16 :                         mon = tm->tm_year >= 0 ? 0 : MONTHS_PER_YEAR - 1;
    3057              :                     }
    3058         1208 :                     else if (tm->tm_mon < 0)
    3059              :                     {
    3060              :                         /*
    3061              :                          * Negative case.  In this case, the calculation is
    3062              :                          * reversed, where -1 means December, -2 November,
    3063              :                          * etc.
    3064              :                          */
    3065           96 :                         mon = -1 * (tm->tm_mon + 1);
    3066              :                     }
    3067              :                     else
    3068              :                     {
    3069              :                         /*
    3070              :                          * Common case, with a strictly positive value.  The
    3071              :                          * position in the array matches with the value of
    3072              :                          * tm_mon.
    3073              :                          */
    3074         1112 :                         mon = MONTHS_PER_YEAR - tm->tm_mon;
    3075              :                     }
    3076              : 
    3077         1224 :                     sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -4,
    3078         1224 :                             months[mon]);
    3079         1224 :                     s += strlen(s);
    3080              :                 }
    3081         1224 :                 break;
    3082            0 :             case DCH_W:
    3083            0 :                 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
    3084            0 :                 if (IS_SUFFIX_THth(n->suffix))
    3085            0 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    3086            0 :                 s += strlen(s);
    3087            0 :                 break;
    3088         1524 :             case DCH_J:
    3089         1524 :                 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
    3090         1524 :                 if (IS_SUFFIX_THth(n->suffix))
    3091          508 :                     str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
    3092         1524 :                 s += strlen(s);
    3093         1524 :                 break;
    3094              :         }
    3095              :     }
    3096              : 
    3097         6308 :     *s = '\0';
    3098         6308 : }
    3099              : 
    3100              : /*
    3101              :  * Process the string 'in' as denoted by the array of FormatNodes 'node[]'.
    3102              :  * The TmFromChar struct pointed to by 'out' is populated with the results.
    3103              :  *
    3104              :  * 'collid' identifies the collation to use, if needed.
    3105              :  * 'std' specifies standard parsing mode.
    3106              :  *
    3107              :  * If escontext points to an ErrorSaveContext, data errors will be reported
    3108              :  * by filling that struct; the caller must test SOFT_ERROR_OCCURRED() to see
    3109              :  * whether an error occurred.  Otherwise, errors are thrown.
    3110              :  *
    3111              :  * Note: we currently don't have any to_interval() function, so there
    3112              :  * is no need here for INVALID_FOR_INTERVAL checks.
    3113              :  */
    3114              : static void
    3115        26989 : DCH_from_char(FormatNode *node, const char *in, TmFromChar *out,
    3116              :               Oid collid, bool std, Node *escontext)
    3117              : {
    3118              :     FormatNode *n;
    3119              :     const char *s;
    3120              :     int         len,
    3121              :                 value;
    3122        26989 :     bool        fx_mode = std;
    3123              : 
    3124              :     /* number of extra skipped characters (more than given in format string) */
    3125        26989 :     int         extra_skip = 0;
    3126              : 
    3127              :     /* cache localized days and months */
    3128        26989 :     cache_locale_time();
    3129              : 
    3130       162275 :     for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
    3131              :     {
    3132              :         /*
    3133              :          * Ignore spaces at the beginning of the string and before fields when
    3134              :          * not in FX (fixed width) mode.
    3135              :          */
    3136       149581 :         if (!fx_mode && (n->type != NODE_TYPE_ACTION || n->key->id != DCH_FX) &&
    3137         6217 :             (n->type == NODE_TYPE_ACTION || n == node))
    3138              :         {
    3139         3509 :             while (*s != '\0' && isspace((unsigned char) *s))
    3140              :             {
    3141           56 :                 s++;
    3142           56 :                 extra_skip++;
    3143              :             }
    3144              :         }
    3145              : 
    3146       149581 :         if (n->type == NODE_TYPE_SPACE || n->type == NODE_TYPE_SEPARATOR)
    3147              :         {
    3148        64878 :             if (std)
    3149              :             {
    3150              :                 /*
    3151              :                  * Standard mode requires strict matching between format
    3152              :                  * string separators/spaces and input string.
    3153              :                  */
    3154              :                 Assert(n->character[0] && !n->character[1]);
    3155              : 
    3156        62386 :                 if (*s == n->character[0])
    3157        50494 :                     s++;
    3158              :                 else
    3159        20750 :                     ereturn(escontext,,
    3160              :                             (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    3161              :                              errmsg("unmatched format separator \"%c\"",
    3162              :                                     n->character[0])));
    3163              :             }
    3164         2492 :             else if (!fx_mode)
    3165              :             {
    3166              :                 /*
    3167              :                  * In non FX (fixed format) mode one format string space or
    3168              :                  * separator match to one space or separator in input string.
    3169              :                  * Or match nothing if there is no space or separator in the
    3170              :                  * current position of input string.
    3171              :                  */
    3172         2476 :                 extra_skip--;
    3173         2476 :                 if (isspace((unsigned char) *s) || is_separator_char(s))
    3174              :                 {
    3175         1772 :                     s++;
    3176         1772 :                     extra_skip++;
    3177              :                 }
    3178              :             }
    3179              :             else
    3180              :             {
    3181              :                 /*
    3182              :                  * In FX mode, on format string space or separator we consume
    3183              :                  * exactly one character from input string.  Notice we don't
    3184              :                  * insist that the consumed character match the format's
    3185              :                  * character.
    3186              :                  */
    3187           16 :                 s += pg_mblen_cstr(s);
    3188              :             }
    3189        52986 :             continue;
    3190              :         }
    3191        84703 :         else if (n->type != NODE_TYPE_ACTION)
    3192              :         {
    3193              :             /*
    3194              :              * Text character, so consume one character from input string.
    3195              :              * Notice we don't insist that the consumed character match the
    3196              :              * format's character.
    3197              :              */
    3198         2126 :             if (!fx_mode)
    3199              :             {
    3200              :                 /*
    3201              :                  * In non FX mode we might have skipped some extra characters
    3202              :                  * (more than specified in format string) before.  In this
    3203              :                  * case we don't skip input string character, because it might
    3204              :                  * be part of field.
    3205              :                  */
    3206          292 :                 if (extra_skip > 0)
    3207           16 :                     extra_skip--;
    3208              :                 else
    3209          276 :                     s += pg_mblen_cstr(s);
    3210              :             }
    3211              :             else
    3212              :             {
    3213         1834 :                 int         chlen = pg_mblen_cstr(s);
    3214              : 
    3215              :                 /*
    3216              :                  * Standard mode requires strict match of format characters.
    3217              :                  */
    3218         1834 :                 if (std && n->type == NODE_TYPE_CHAR &&
    3219         1834 :                     strncmp(s, n->character, chlen) != 0)
    3220         1810 :                     ereturn(escontext,,
    3221              :                             (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    3222              :                              errmsg("unmatched format character \"%s\"",
    3223              :                                     n->character)));
    3224              : 
    3225           24 :                 s += chlen;
    3226              :             }
    3227          316 :             continue;
    3228              :         }
    3229              : 
    3230        82577 :         if (!from_char_set_mode(out, n->key->date_mode, escontext))
    3231            0 :             return;
    3232              : 
    3233        82573 :         switch (n->key->id)
    3234              :         {
    3235            8 :             case DCH_FX:
    3236            8 :                 fx_mode = true;
    3237            8 :                 break;
    3238            8 :             case DCH_A_M:
    3239              :             case DCH_P_M:
    3240              :             case DCH_a_m:
    3241              :             case DCH_p_m:
    3242            8 :                 if (!from_char_seq_search(&value, &s, ampm_strings_long,
    3243              :                                           NULL, InvalidOid,
    3244              :                                           n, escontext))
    3245            0 :                     return;
    3246            8 :                 if (!from_char_set_int(&out->pm, value % 2, n, escontext))
    3247            0 :                     return;
    3248            8 :                 out->clock_12_hour = true;
    3249            8 :                 break;
    3250            8 :             case DCH_AM:
    3251              :             case DCH_PM:
    3252              :             case DCH_am:
    3253              :             case DCH_pm:
    3254            8 :                 if (!from_char_seq_search(&value, &s, ampm_strings,
    3255              :                                           NULL, InvalidOid,
    3256              :                                           n, escontext))
    3257            0 :                     return;
    3258            8 :                 if (!from_char_set_int(&out->pm, value % 2, n, escontext))
    3259            0 :                     return;
    3260            8 :                 out->clock_12_hour = true;
    3261            8 :                 break;
    3262           96 :             case DCH_HH:
    3263              :             case DCH_HH12:
    3264           96 :                 if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
    3265            0 :                     return;
    3266           96 :                 out->clock_12_hour = true;
    3267           96 :                 SKIP_THth(s, n->suffix);
    3268           96 :                 break;
    3269        19808 :             case DCH_HH24:
    3270        19808 :                 if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
    3271           96 :                     return;
    3272        19708 :                 SKIP_THth(s, n->suffix);
    3273        19708 :                 break;
    3274        11492 :             case DCH_MI:
    3275        11492 :                 if (from_char_parse_int(&out->mi, &s, n, escontext) < 0)
    3276            0 :                     return;
    3277        11492 :                 SKIP_THth(s, n->suffix);
    3278        11492 :                 break;
    3279        10568 :             case DCH_SS:
    3280        10568 :                 if (from_char_parse_int(&out->ss, &s, n, escontext) < 0)
    3281            0 :                     return;
    3282        10568 :                 SKIP_THth(s, n->suffix);
    3283        10568 :                 break;
    3284            8 :             case DCH_MS:        /* millisecond */
    3285            8 :                 len = from_char_parse_int_len(&out->ms, &s, 3, n, escontext);
    3286            8 :                 if (len < 0)
    3287            0 :                     return;
    3288              : 
    3289              :                 /*
    3290              :                  * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
    3291              :                  */
    3292           16 :                 out->ms *= len == 1 ? 100 :
    3293            8 :                     len == 2 ? 10 : 1;
    3294              : 
    3295            8 :                 SKIP_THth(s, n->suffix);
    3296            8 :                 break;
    3297          172 :             case DCH_FF1:
    3298              :             case DCH_FF2:
    3299              :             case DCH_FF3:
    3300              :             case DCH_FF4:
    3301              :             case DCH_FF5:
    3302              :             case DCH_FF6:
    3303          172 :                 out->ff = n->key->id - DCH_FF1 + 1;
    3304              :                 pg_fallthrough;
    3305          888 :             case DCH_US:        /* microsecond */
    3306          888 :                 len = from_char_parse_int_len(&out->us, &s,
    3307          888 :                                               n->key->id == DCH_US ? 6 :
    3308          172 :                                               out->ff, n, escontext);
    3309          888 :                 if (len < 0)
    3310            0 :                     return;
    3311              : 
    3312         1724 :                 out->us *= len == 1 ? 100000 :
    3313         1648 :                     len == 2 ? 10000 :
    3314         1016 :                     len == 3 ? 1000 :
    3315          304 :                     len == 4 ? 100 :
    3316          100 :                     len == 5 ? 10 : 1;
    3317              : 
    3318          888 :                 SKIP_THth(s, n->suffix);
    3319          888 :                 break;
    3320           16 :             case DCH_SSSS:
    3321           16 :                 if (from_char_parse_int(&out->ssss, &s, n, escontext) < 0)
    3322            0 :                     return;
    3323           16 :                 SKIP_THth(s, n->suffix);
    3324           16 :                 break;
    3325         2374 :             case DCH_tz:
    3326              :             case DCH_TZ:
    3327              :                 {
    3328              :                     int         tzlen;
    3329              : 
    3330         2374 :                     tzlen = DecodeTimezoneAbbrevPrefix(s,
    3331              :                                                        &out->gmtoffset,
    3332              :                                                        &out->tzp);
    3333         2374 :                     if (tzlen > 0)
    3334              :                     {
    3335           24 :                         out->has_tz = true;
    3336              :                         /* we only need the zone abbrev for DYNTZ case */
    3337           24 :                         if (out->tzp)
    3338            4 :                             out->abbrev = pnstrdup(s, tzlen);
    3339           24 :                         out->tzsign = 0; /* drop any earlier TZH/TZM info */
    3340           24 :                         s += tzlen;
    3341           24 :                         break;
    3342              :                     }
    3343         2350 :                     else if (isalpha((unsigned char) *s))
    3344              :                     {
    3345              :                         /*
    3346              :                          * It doesn't match any abbreviation, but it starts
    3347              :                          * with a letter.  OF format certainly won't succeed;
    3348              :                          * assume it's a misspelled abbreviation and complain
    3349              :                          * accordingly.
    3350              :                          */
    3351            4 :                         ereturn(escontext,,
    3352              :                                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    3353              :                                  errmsg("invalid value \"%s\" for \"%s\"", s, n->key->name),
    3354              :                                  errdetail("Time zone abbreviation is not recognized.")));
    3355              :                     }
    3356              :                     /* otherwise parse it like OF */
    3357              :                 }
    3358              :                 pg_fallthrough;
    3359              :             case DCH_OF:
    3360              :                 /* OF is equivalent to TZH or TZH:TZM */
    3361              :                 /* see TZH comments below */
    3362         2362 :                 if (*s == '+' || *s == '-' || *s == ' ')
    3363              :                 {
    3364         2122 :                     out->tzsign = *s == '-' ? -1 : +1;
    3365         2122 :                     s++;
    3366              :                 }
    3367              :                 else
    3368              :                 {
    3369          240 :                     if (extra_skip > 0 && *(s - 1) == '-')
    3370            8 :                         out->tzsign = -1;
    3371              :                     else
    3372          232 :                         out->tzsign = +1;
    3373              :                 }
    3374         2362 :                 if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
    3375          212 :                     return;
    3376         2142 :                 if (*s == ':')
    3377              :                 {
    3378          222 :                     s++;
    3379          222 :                     if (from_char_parse_int_len(&out->tzm, &s, 2, n,
    3380              :                                                 escontext) < 0)
    3381            0 :                         return;
    3382              :                 }
    3383         2138 :                 break;
    3384          516 :             case DCH_TZH:
    3385              : 
    3386              :                 /*
    3387              :                  * Value of TZH might be negative.  And the issue is that we
    3388              :                  * might swallow minus sign as the separator.  So, if we have
    3389              :                  * skipped more characters than specified in the format
    3390              :                  * string, then we consider prepending last skipped minus to
    3391              :                  * TZH.
    3392              :                  */
    3393          516 :                 if (*s == '+' || *s == '-' || *s == ' ')
    3394              :                 {
    3395          492 :                     out->tzsign = *s == '-' ? -1 : +1;
    3396          492 :                     s++;
    3397              :                 }
    3398              :                 else
    3399              :                 {
    3400           24 :                     if (extra_skip > 0 && *(s - 1) == '-')
    3401           12 :                         out->tzsign = -1;
    3402              :                     else
    3403           12 :                         out->tzsign = +1;
    3404              :                 }
    3405              : 
    3406          516 :                 if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
    3407            0 :                     return;
    3408          516 :                 break;
    3409           52 :             case DCH_TZM:
    3410              :                 /* assign positive timezone sign if TZH was not seen before */
    3411           52 :                 if (!out->tzsign)
    3412            4 :                     out->tzsign = +1;
    3413           52 :                 if (from_char_parse_int_len(&out->tzm, &s, 2, n, escontext) < 0)
    3414            0 :                     return;
    3415           52 :                 break;
    3416            8 :             case DCH_A_D:
    3417              :             case DCH_B_C:
    3418              :             case DCH_a_d:
    3419              :             case DCH_b_c:
    3420            8 :                 if (!from_char_seq_search(&value, &s, adbc_strings_long,
    3421              :                                           NULL, InvalidOid,
    3422              :                                           n, escontext))
    3423            0 :                     return;
    3424            8 :                 if (!from_char_set_int(&out->bc, value % 2, n, escontext))
    3425            0 :                     return;
    3426            8 :                 break;
    3427           24 :             case DCH_AD:
    3428              :             case DCH_BC:
    3429              :             case DCH_ad:
    3430              :             case DCH_bc:
    3431           24 :                 if (!from_char_seq_search(&value, &s, adbc_strings,
    3432              :                                           NULL, InvalidOid,
    3433              :                                           n, escontext))
    3434            0 :                     return;
    3435           24 :                 if (!from_char_set_int(&out->bc, value % 2, n, escontext))
    3436            0 :                     return;
    3437           24 :                 break;
    3438           12 :             case DCH_MONTH:
    3439              :             case DCH_Month:
    3440              :             case DCH_month:
    3441           12 :                 if (!from_char_seq_search(&value, &s, months_full,
    3442           12 :                                           IS_SUFFIX_TM(n->suffix) ? localized_full_months : NULL,
    3443              :                                           collid,
    3444              :                                           n, escontext))
    3445            0 :                     return;
    3446           12 :                 if (!from_char_set_int(&out->mm, value + 1, n, escontext))
    3447            0 :                     return;
    3448           12 :                 break;
    3449           76 :             case DCH_MON:
    3450              :             case DCH_Mon:
    3451              :             case DCH_mon:
    3452           76 :                 if (!from_char_seq_search(&value, &s, months,
    3453           76 :                                           IS_SUFFIX_TM(n->suffix) ? localized_abbrev_months : NULL,
    3454              :                                           collid,
    3455              :                                           n, escontext))
    3456            0 :                     return;
    3457           68 :                 if (!from_char_set_int(&out->mm, value + 1, n, escontext))
    3458            0 :                     return;
    3459           64 :                 break;
    3460        11448 :             case DCH_MM:
    3461        11448 :                 if (from_char_parse_int(&out->mm, &s, n, escontext) < 0)
    3462            0 :                     return;
    3463        11436 :                 SKIP_THth(s, n->suffix);
    3464        11436 :                 break;
    3465            4 :             case DCH_DAY:
    3466              :             case DCH_Day:
    3467              :             case DCH_day:
    3468            4 :                 if (!from_char_seq_search(&value, &s, days,
    3469            4 :                                           IS_SUFFIX_TM(n->suffix) ? localized_full_days : NULL,
    3470              :                                           collid,
    3471              :                                           n, escontext))
    3472            0 :                     return;
    3473            4 :                 if (!from_char_set_int(&out->d, value, n, escontext))
    3474            0 :                     return;
    3475            4 :                 out->d++;
    3476            4 :                 break;
    3477           12 :             case DCH_DY:
    3478              :             case DCH_Dy:
    3479              :             case DCH_dy:
    3480           12 :                 if (!from_char_seq_search(&value, &s, days_short,
    3481           12 :                                           IS_SUFFIX_TM(n->suffix) ? localized_abbrev_days : NULL,
    3482              :                                           collid,
    3483              :                                           n, escontext))
    3484            0 :                     return;
    3485           12 :                 if (!from_char_set_int(&out->d, value, n, escontext))
    3486            0 :                     return;
    3487           12 :                 out->d++;
    3488           12 :                 break;
    3489           24 :             case DCH_DDD:
    3490           24 :                 if (from_char_parse_int(&out->ddd, &s, n, escontext) < 0)
    3491            0 :                     return;
    3492           24 :                 SKIP_THth(s, n->suffix);
    3493           24 :                 break;
    3494            4 :             case DCH_IDDD:
    3495            4 :                 if (from_char_parse_int_len(&out->ddd, &s, 3, n, escontext) < 0)
    3496            0 :                     return;
    3497            4 :                 SKIP_THth(s, n->suffix);
    3498            4 :                 break;
    3499        11489 :             case DCH_DD:
    3500        11489 :                 if (from_char_parse_int(&out->dd, &s, n, escontext) < 0)
    3501            0 :                     return;
    3502        11480 :                 SKIP_THth(s, n->suffix);
    3503        11480 :                 break;
    3504            8 :             case DCH_D:
    3505            8 :                 if (from_char_parse_int(&out->d, &s, n, escontext) < 0)
    3506            0 :                     return;
    3507            8 :                 SKIP_THth(s, n->suffix);
    3508            8 :                 break;
    3509           16 :             case DCH_ID:
    3510           16 :                 if (from_char_parse_int_len(&out->d, &s, 1, n, escontext) < 0)
    3511            0 :                     return;
    3512              :                 /* Shift numbering to match Gregorian where Sunday = 1 */
    3513           16 :                 if (++out->d > 7)
    3514           16 :                     out->d = 1;
    3515           16 :                 SKIP_THth(s, n->suffix);
    3516           16 :                 break;
    3517           24 :             case DCH_WW:
    3518              :             case DCH_IW:
    3519           24 :                 if (from_char_parse_int(&out->ww, &s, n, escontext) < 0)
    3520            0 :                     return;
    3521           24 :                 SKIP_THth(s, n->suffix);
    3522           24 :                 break;
    3523            4 :             case DCH_Q:
    3524              : 
    3525              :                 /*
    3526              :                  * We ignore 'Q' when converting to date because it is unclear
    3527              :                  * which date in the quarter to use, and some people specify
    3528              :                  * both quarter and month, so if it was honored it might
    3529              :                  * conflict with the supplied month. That is also why we don't
    3530              :                  * throw an error.
    3531              :                  *
    3532              :                  * We still parse the source string for an integer, but it
    3533              :                  * isn't stored anywhere in 'out'.
    3534              :                  */
    3535            4 :                 if (from_char_parse_int((int *) NULL, &s, n, escontext) < 0)
    3536            0 :                     return;
    3537            4 :                 SKIP_THth(s, n->suffix);
    3538            4 :                 break;
    3539           20 :             case DCH_CC:
    3540           20 :                 if (from_char_parse_int(&out->cc, &s, n, escontext) < 0)
    3541            0 :                     return;
    3542           20 :                 SKIP_THth(s, n->suffix);
    3543           20 :                 break;
    3544            8 :             case DCH_Y_YYY:
    3545              :                 {
    3546              :                     int         matched,
    3547              :                                 years,
    3548              :                                 millennia,
    3549              :                                 nch;
    3550              : 
    3551            8 :                     matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch);
    3552            8 :                     if (matched < 2)
    3553            0 :                         ereturn(escontext,,
    3554              :                                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    3555              :                                  errmsg("invalid value \"%s\" for \"%s\"", s, "Y,YYY")));
    3556              : 
    3557              :                     /* years += (millennia * 1000); */
    3558           12 :                     if (pg_mul_s32_overflow(millennia, 1000, &millennia) ||
    3559            4 :                         pg_add_s32_overflow(years, millennia, &years))
    3560            4 :                         ereturn(escontext,,
    3561              :                                 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
    3562              :                                  errmsg("value for \"%s\" in source string is out of range", "Y,YYY")));
    3563              : 
    3564            4 :                     if (!from_char_set_int(&out->year, years, n, escontext))
    3565            0 :                         return;
    3566            4 :                     out->yysz = 4;
    3567            4 :                     s += nch;
    3568            4 :                     SKIP_THth(s, n->suffix);
    3569              :                 }
    3570            4 :                 break;
    3571        13462 :             case DCH_YYYY:
    3572              :             case DCH_IYYY:
    3573        13462 :                 if (from_char_parse_int(&out->year, &s, n, escontext) < 0)
    3574          216 :                     return;
    3575        13238 :                 out->yysz = 4;
    3576        13238 :                 SKIP_THth(s, n->suffix);
    3577        13238 :                 break;
    3578            8 :             case DCH_YYY:
    3579              :             case DCH_IYY:
    3580            8 :                 len = from_char_parse_int(&out->year, &s, n, escontext);
    3581            8 :                 if (len < 0)
    3582            0 :                     return;
    3583            8 :                 if (len < 4)
    3584            8 :                     out->year = adjust_partial_year_to_2020(out->year);
    3585            8 :                 out->yysz = 3;
    3586            8 :                 SKIP_THth(s, n->suffix);
    3587            8 :                 break;
    3588           40 :             case DCH_YY:
    3589              :             case DCH_IY:
    3590           40 :                 len = from_char_parse_int(&out->year, &s, n, escontext);
    3591           40 :                 if (len < 0)
    3592            0 :                     return;
    3593           40 :                 if (len < 4)
    3594           40 :                     out->year = adjust_partial_year_to_2020(out->year);
    3595           40 :                 out->yysz = 2;
    3596           40 :                 SKIP_THth(s, n->suffix);
    3597           40 :                 break;
    3598            8 :             case DCH_Y:
    3599              :             case DCH_I:
    3600            8 :                 len = from_char_parse_int(&out->year, &s, n, escontext);
    3601            8 :                 if (len < 0)
    3602            0 :                     return;
    3603            8 :                 if (len < 4)
    3604            8 :                     out->year = adjust_partial_year_to_2020(out->year);
    3605            8 :                 out->yysz = 1;
    3606            8 :                 SKIP_THth(s, n->suffix);
    3607            8 :                 break;
    3608            4 :             case DCH_RM:
    3609              :             case DCH_rm:
    3610            4 :                 if (!from_char_seq_search(&value, &s, rm_months_lower,
    3611              :                                           NULL, InvalidOid,
    3612              :                                           n, escontext))
    3613            0 :                     return;
    3614            4 :                 if (!from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n,
    3615              :                                        escontext))
    3616            0 :                     return;
    3617            4 :                 break;
    3618            8 :             case DCH_W:
    3619            8 :                 if (from_char_parse_int(&out->w, &s, n, escontext) < 0)
    3620            0 :                     return;
    3621            8 :                 SKIP_THth(s, n->suffix);
    3622            8 :                 break;
    3623            4 :             case DCH_J:
    3624            4 :                 if (from_char_parse_int(&out->j, &s, n, escontext) < 0)
    3625            0 :                     return;
    3626            4 :                 SKIP_THth(s, n->suffix);
    3627            4 :                 break;
    3628              :         }
    3629              : 
    3630              :         /* Ignore all spaces after fields */
    3631        81984 :         if (!fx_mode)
    3632              :         {
    3633         3384 :             extra_skip = 0;
    3634         4180 :             while (*s != '\0' && isspace((unsigned char) *s))
    3635              :             {
    3636          796 :                 s++;
    3637          796 :                 extra_skip++;
    3638              :             }
    3639              :         }
    3640              :     }
    3641              : 
    3642              :     /*
    3643              :      * Standard parsing mode doesn't allow unmatched format patterns or
    3644              :      * trailing characters in the input string.
    3645              :      */
    3646        12694 :     if (std)
    3647              :     {
    3648        12010 :         if (n->type != NODE_TYPE_END)
    3649         4470 :             ereturn(escontext,,
    3650              :                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    3651              :                      errmsg("input string is too short for datetime format")));
    3652              : 
    3653         9602 :         while (*s != '\0' && isspace((unsigned char) *s))
    3654         2062 :             s++;
    3655              : 
    3656         7540 :         if (*s != '\0')
    3657         2086 :             ereturn(escontext,,
    3658              :                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    3659              :                      errmsg("trailing characters remain in input string after datetime format")));
    3660              :     }
    3661              : }
    3662              : 
    3663              : /*
    3664              :  * The invariant for DCH cache entry management is that DCHCounter is equal
    3665              :  * to the maximum age value among the existing entries, and we increment it
    3666              :  * whenever an access occurs.  If we approach overflow, deal with that by
    3667              :  * halving all the age values, so that we retain a fairly accurate idea of
    3668              :  * which entries are oldest.
    3669              :  */
    3670              : static inline void
    3671        33968 : DCH_prevent_counter_overflow(void)
    3672              : {
    3673        33968 :     if (DCHCounter >= (INT_MAX - 1))
    3674              :     {
    3675            0 :         for (int i = 0; i < n_DCHCache; i++)
    3676            0 :             DCHCache[i]->age >>= 1;
    3677            0 :         DCHCounter >>= 1;
    3678              :     }
    3679        33968 : }
    3680              : 
    3681              : /*
    3682              :  * Get mask of date/time/zone components present in format nodes.
    3683              :  */
    3684              : static int
    3685         5498 : DCH_datetime_type(FormatNode *node)
    3686              : {
    3687         5498 :     int         flags = 0;
    3688              : 
    3689        50574 :     for (FormatNode *n = node; n->type != NODE_TYPE_END; n++)
    3690              :     {
    3691        45076 :         if (n->type != NODE_TYPE_ACTION)
    3692        18726 :             continue;
    3693              : 
    3694        26350 :         switch (n->key->id)
    3695              :         {
    3696            0 :             case DCH_FX:
    3697            0 :                 break;
    3698        13540 :             case DCH_A_M:
    3699              :             case DCH_P_M:
    3700              :             case DCH_a_m:
    3701              :             case DCH_p_m:
    3702              :             case DCH_AM:
    3703              :             case DCH_PM:
    3704              :             case DCH_am:
    3705              :             case DCH_pm:
    3706              :             case DCH_HH:
    3707              :             case DCH_HH12:
    3708              :             case DCH_HH24:
    3709              :             case DCH_MI:
    3710              :             case DCH_SS:
    3711              :             case DCH_MS:        /* millisecond */
    3712              :             case DCH_US:        /* microsecond */
    3713              :             case DCH_FF1:
    3714              :             case DCH_FF2:
    3715              :             case DCH_FF3:
    3716              :             case DCH_FF4:
    3717              :             case DCH_FF5:
    3718              :             case DCH_FF6:
    3719              :             case DCH_SSSS:
    3720        13540 :                 flags |= DCH_TIMED;
    3721        13540 :                 break;
    3722         2682 :             case DCH_tz:
    3723              :             case DCH_TZ:
    3724              :             case DCH_OF:
    3725              :             case DCH_TZH:
    3726              :             case DCH_TZM:
    3727         2682 :                 flags |= DCH_ZONED;
    3728         2682 :                 break;
    3729        10128 :             case DCH_A_D:
    3730              :             case DCH_B_C:
    3731              :             case DCH_a_d:
    3732              :             case DCH_b_c:
    3733              :             case DCH_AD:
    3734              :             case DCH_BC:
    3735              :             case DCH_ad:
    3736              :             case DCH_bc:
    3737              :             case DCH_MONTH:
    3738              :             case DCH_Month:
    3739              :             case DCH_month:
    3740              :             case DCH_MON:
    3741              :             case DCH_Mon:
    3742              :             case DCH_mon:
    3743              :             case DCH_MM:
    3744              :             case DCH_DAY:
    3745              :             case DCH_Day:
    3746              :             case DCH_day:
    3747              :             case DCH_DY:
    3748              :             case DCH_Dy:
    3749              :             case DCH_dy:
    3750              :             case DCH_DDD:
    3751              :             case DCH_IDDD:
    3752              :             case DCH_DD:
    3753              :             case DCH_D:
    3754              :             case DCH_ID:
    3755              :             case DCH_WW:
    3756              :             case DCH_Q:
    3757              :             case DCH_CC:
    3758              :             case DCH_Y_YYY:
    3759              :             case DCH_YYYY:
    3760              :             case DCH_IYYY:
    3761              :             case DCH_YYY:
    3762              :             case DCH_IYY:
    3763              :             case DCH_YY:
    3764              :             case DCH_IY:
    3765              :             case DCH_Y:
    3766              :             case DCH_I:
    3767              :             case DCH_RM:
    3768              :             case DCH_rm:
    3769              :             case DCH_W:
    3770              :             case DCH_J:
    3771        10128 :                 flags |= DCH_DATED;
    3772        10128 :                 break;
    3773              :         }
    3774              :     }
    3775              : 
    3776         5498 :     return flags;
    3777              : }
    3778              : 
    3779              : /* select a DCHCacheEntry to hold the given format picture */
    3780              : static DCHCacheEntry *
    3781          623 : DCH_cache_getnew(const char *str, bool std)
    3782              : {
    3783              :     DCHCacheEntry *ent;
    3784              : 
    3785              :     /* Ensure we can advance DCHCounter below */
    3786          623 :     DCH_prevent_counter_overflow();
    3787              : 
    3788              :     /*
    3789              :      * If cache is full, remove oldest entry (or recycle first not-valid one)
    3790              :      */
    3791          623 :     if (n_DCHCache >= DCH_CACHE_ENTRIES)
    3792              :     {
    3793          308 :         DCHCacheEntry *old = DCHCache[0];
    3794              : 
    3795              : #ifdef DEBUG_TO_FROM_CHAR
    3796              :         elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
    3797              : #endif
    3798          308 :         if (old->valid)
    3799              :         {
    3800         6132 :             for (int i = 1; i < DCH_CACHE_ENTRIES; i++)
    3801              :             {
    3802         5828 :                 ent = DCHCache[i];
    3803         5828 :                 if (!ent->valid)
    3804              :                 {
    3805            4 :                     old = ent;
    3806            4 :                     break;
    3807              :                 }
    3808         5824 :                 if (ent->age < old->age)
    3809          512 :                     old = ent;
    3810              :             }
    3811              :         }
    3812              : #ifdef DEBUG_TO_FROM_CHAR
    3813              :         elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
    3814              : #endif
    3815          308 :         old->valid = false;
    3816          308 :         strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
    3817          308 :         old->age = (++DCHCounter);
    3818              :         /* caller is expected to fill format, then set valid */
    3819          308 :         return old;
    3820              :     }
    3821              :     else
    3822              :     {
    3823              : #ifdef DEBUG_TO_FROM_CHAR
    3824              :         elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
    3825              : #endif
    3826              :         Assert(DCHCache[n_DCHCache] == NULL);
    3827          315 :         DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
    3828          315 :             MemoryContextAllocZero(TopMemoryContext, sizeof(DCHCacheEntry));
    3829          315 :         ent->valid = false;
    3830          315 :         strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
    3831          315 :         ent->std = std;
    3832          315 :         ent->age = (++DCHCounter);
    3833              :         /* caller is expected to fill format, then set valid */
    3834          315 :         ++n_DCHCache;
    3835          315 :         return ent;
    3836              :     }
    3837              : }
    3838              : 
    3839              : /* look for an existing DCHCacheEntry matching the given format picture */
    3840              : static DCHCacheEntry *
    3841        33345 : DCH_cache_search(const char *str, bool std)
    3842              : {
    3843              :     /* Ensure we can advance DCHCounter below */
    3844        33345 :     DCH_prevent_counter_overflow();
    3845              : 
    3846       176868 :     for (int i = 0; i < n_DCHCache; i++)
    3847              :     {
    3848       176245 :         DCHCacheEntry *ent = DCHCache[i];
    3849              : 
    3850       176245 :         if (ent->valid && strcmp(ent->str, str) == 0 && ent->std == std)
    3851              :         {
    3852        32722 :             ent->age = (++DCHCounter);
    3853        32722 :             return ent;
    3854              :         }
    3855              :     }
    3856              : 
    3857          623 :     return NULL;
    3858              : }
    3859              : 
    3860              : /* Find or create a DCHCacheEntry for the given format picture */
    3861              : static DCHCacheEntry *
    3862        33345 : DCH_cache_fetch(const char *str, bool std)
    3863              : {
    3864              :     DCHCacheEntry *ent;
    3865              : 
    3866        33345 :     if ((ent = DCH_cache_search(str, std)) == NULL)
    3867              :     {
    3868              :         /*
    3869              :          * Not in the cache, must run parser and save a new format-picture to
    3870              :          * the cache.  Do not mark the cache entry valid until parsing
    3871              :          * succeeds.
    3872              :          */
    3873          623 :         ent = DCH_cache_getnew(str, std);
    3874              : 
    3875          623 :         parse_format(ent->format, str, DCH_keywords, DCH_suff, DCH_index,
    3876              :                      DCH_FLAG | (std ? STD_FLAG : 0), NULL);
    3877              : 
    3878          619 :         ent->valid = true;
    3879              :     }
    3880        33341 :     return ent;
    3881              : }
    3882              : 
    3883              : /*
    3884              :  * Format a date/time or interval into a string according to fmt.
    3885              :  * We parse fmt into a list of FormatNodes.  This is then passed to DCH_to_char
    3886              :  * for formatting.
    3887              :  */
    3888              : static text *
    3889         6308 : datetime_to_char_body(TmToChar *tmtc, const text *fmt, bool is_interval, Oid collid)
    3890              : {
    3891              :     FormatNode *format;
    3892              :     char       *fmt_str,
    3893              :                *result;
    3894              :     bool        incache;
    3895              :     size_t      fmt_len;
    3896              :     text       *res;
    3897              : 
    3898              :     /*
    3899              :      * Convert fmt to C string
    3900              :      */
    3901         6308 :     fmt_str = text_to_cstring(fmt);
    3902         6308 :     fmt_len = strlen(fmt_str);
    3903              : 
    3904              :     /*
    3905              :      * Allocate workspace for result as C string
    3906              :      */
    3907         6308 :     result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
    3908         6308 :     *result = '\0';
    3909              : 
    3910         6308 :     if (fmt_len > DCH_CACHE_SIZE)
    3911              :     {
    3912              :         /*
    3913              :          * Allocate new memory if format picture is bigger than static cache
    3914              :          * and do not use cache (call parser always)
    3915              :          */
    3916            0 :         incache = false;
    3917              : 
    3918            0 :         format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
    3919              : 
    3920            0 :         parse_format(format, fmt_str, DCH_keywords,
    3921              :                      DCH_suff, DCH_index, DCH_FLAG, NULL);
    3922              :     }
    3923              :     else
    3924              :     {
    3925              :         /*
    3926              :          * Use cache buffers
    3927              :          */
    3928         6308 :         DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
    3929              : 
    3930         6308 :         incache = true;
    3931         6308 :         format = ent->format;
    3932              :     }
    3933              : 
    3934              :     /* The real work is here */
    3935         6308 :     DCH_to_char(format, is_interval, tmtc, result, collid);
    3936              : 
    3937         6308 :     if (!incache)
    3938            0 :         pfree(format);
    3939              : 
    3940         6308 :     pfree(fmt_str);
    3941              : 
    3942              :     /* convert C-string result to TEXT format */
    3943         6308 :     res = cstring_to_text(result);
    3944              : 
    3945         6308 :     pfree(result);
    3946         6308 :     return res;
    3947              : }
    3948              : 
    3949              : /****************************************************************************
    3950              :  *              Public routines
    3951              :  ***************************************************************************/
    3952              : 
    3953              : /*
    3954              :  * TIMESTAMP to_char()
    3955              :  */
    3956              : Datum
    3957         3121 : timestamp_to_char(PG_FUNCTION_ARGS)
    3958              : {
    3959         3121 :     Timestamp   dt = PG_GETARG_TIMESTAMP(0);
    3960         3121 :     text       *fmt = PG_GETARG_TEXT_PP(1),
    3961              :                *res;
    3962              :     TmToChar    tmtc;
    3963              :     struct pg_tm tt;
    3964              :     struct fmt_tm *tm;
    3965              :     int         thisdate;
    3966              : 
    3967         3121 :     if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
    3968           88 :         PG_RETURN_NULL();
    3969              : 
    3970         3033 :     ZERO_tmtc(&tmtc);
    3971         3033 :     tm = tmtcTm(&tmtc);
    3972              : 
    3973         3033 :     if (timestamp2tm(dt, NULL, &tt, &tmtcFsec(&tmtc), NULL, NULL) != 0)
    3974            0 :         ereport(ERROR,
    3975              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    3976              :                  errmsg("timestamp out of range")));
    3977              : 
    3978              :     /* calculate wday and yday, because timestamp2tm doesn't */
    3979         3033 :     thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
    3980         3033 :     tt.tm_wday = (thisdate + 1) % 7;
    3981         3033 :     tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
    3982              : 
    3983         3033 :     COPY_tm(tm, &tt);
    3984              : 
    3985         3033 :     if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
    3986            0 :         PG_RETURN_NULL();
    3987              : 
    3988         3033 :     PG_RETURN_TEXT_P(res);
    3989              : }
    3990              : 
    3991              : Datum
    3992         3146 : timestamptz_to_char(PG_FUNCTION_ARGS)
    3993              : {
    3994         3146 :     TimestampTz dt = PG_GETARG_TIMESTAMP(0);
    3995         3146 :     text       *fmt = PG_GETARG_TEXT_PP(1),
    3996              :                *res;
    3997              :     TmToChar    tmtc;
    3998              :     int         tz;
    3999              :     struct pg_tm tt;
    4000              :     struct fmt_tm *tm;
    4001              :     int         thisdate;
    4002              : 
    4003         3146 :     if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
    4004           88 :         PG_RETURN_NULL();
    4005              : 
    4006         3058 :     ZERO_tmtc(&tmtc);
    4007         3058 :     tm = tmtcTm(&tmtc);
    4008              : 
    4009         3058 :     if (timestamp2tm(dt, &tz, &tt, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
    4010            0 :         ereport(ERROR,
    4011              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4012              :                  errmsg("timestamp out of range")));
    4013              : 
    4014              :     /* calculate wday and yday, because timestamp2tm doesn't */
    4015         3058 :     thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
    4016         3058 :     tt.tm_wday = (thisdate + 1) % 7;
    4017         3058 :     tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
    4018              : 
    4019         3058 :     COPY_tm(tm, &tt);
    4020              : 
    4021         3058 :     if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
    4022            0 :         PG_RETURN_NULL();
    4023              : 
    4024         3058 :     PG_RETURN_TEXT_P(res);
    4025              : }
    4026              : 
    4027              : 
    4028              : /*
    4029              :  * INTERVAL to_char()
    4030              :  */
    4031              : Datum
    4032          225 : interval_to_char(PG_FUNCTION_ARGS)
    4033              : {
    4034          225 :     Interval   *it = PG_GETARG_INTERVAL_P(0);
    4035          225 :     text       *fmt = PG_GETARG_TEXT_PP(1),
    4036              :                *res;
    4037              :     TmToChar    tmtc;
    4038              :     struct fmt_tm *tm;
    4039              :     struct pg_itm tt,
    4040          225 :                *itm = &tt;
    4041              : 
    4042          225 :     if (VARSIZE_ANY_EXHDR(fmt) <= 0 || INTERVAL_NOT_FINITE(it))
    4043            8 :         PG_RETURN_NULL();
    4044              : 
    4045          217 :     ZERO_tmtc(&tmtc);
    4046          217 :     tm = tmtcTm(&tmtc);
    4047              : 
    4048          217 :     interval2itm(*it, itm);
    4049          217 :     tmtc.fsec = itm->tm_usec;
    4050          217 :     tm->tm_sec = itm->tm_sec;
    4051          217 :     tm->tm_min = itm->tm_min;
    4052          217 :     tm->tm_hour = itm->tm_hour;
    4053          217 :     tm->tm_mday = itm->tm_mday;
    4054          217 :     tm->tm_mon = itm->tm_mon;
    4055          217 :     tm->tm_year = itm->tm_year;
    4056              : 
    4057              :     /* wday is meaningless, yday approximates the total span in days */
    4058          217 :     tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
    4059              : 
    4060          217 :     if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
    4061            0 :         PG_RETURN_NULL();
    4062              : 
    4063          217 :     PG_RETURN_TEXT_P(res);
    4064              : }
    4065              : 
    4066              : /*
    4067              :  * TO_TIMESTAMP()
    4068              :  *
    4069              :  * Make Timestamp from date_str which is formatted at argument 'fmt'
    4070              :  * ( to_timestamp is reverse to_char() )
    4071              :  */
    4072              : Datum
    4073          614 : to_timestamp(PG_FUNCTION_ARGS)
    4074              : {
    4075          614 :     text       *date_txt = PG_GETARG_TEXT_PP(0);
    4076          614 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    4077          614 :     Oid         collid = PG_GET_COLLATION();
    4078              :     Timestamp   result;
    4079              :     int         tz;
    4080              :     struct pg_tm tm;
    4081              :     struct fmt_tz ftz;
    4082              :     fsec_t      fsec;
    4083              :     int         fprec;
    4084              : 
    4085          614 :     do_to_timestamp(date_txt, fmt, collid, false,
    4086              :                     &tm, &fsec, &ftz, &fprec, NULL, NULL);
    4087              : 
    4088              :     /* Use the specified time zone, if any. */
    4089          502 :     if (ftz.has_tz)
    4090           64 :         tz = ftz.gmtoffset;
    4091              :     else
    4092          438 :         tz = DetermineTimeZoneOffset(&tm, session_timezone);
    4093              : 
    4094          502 :     if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
    4095            0 :         ereport(ERROR,
    4096              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4097              :                  errmsg("timestamp out of range")));
    4098              : 
    4099              :     /* Use the specified fractional precision, if any. */
    4100          502 :     if (fprec)
    4101          168 :         AdjustTimestampForTypmod(&result, fprec, NULL);
    4102              : 
    4103          502 :     PG_RETURN_TIMESTAMP(result);
    4104              : }
    4105              : 
    4106              : /*
    4107              :  * TO_DATE
    4108              :  *  Make Date from date_str which is formatted at argument 'fmt'
    4109              :  */
    4110              : Datum
    4111          135 : to_date(PG_FUNCTION_ARGS)
    4112              : {
    4113          135 :     text       *date_txt = PG_GETARG_TEXT_PP(0);
    4114          135 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    4115          135 :     Oid         collid = PG_GET_COLLATION();
    4116              :     DateADT     result;
    4117              :     struct pg_tm tm;
    4118              :     struct fmt_tz ftz;
    4119              :     fsec_t      fsec;
    4120              : 
    4121          135 :     do_to_timestamp(date_txt, fmt, collid, false,
    4122              :                     &tm, &fsec, &ftz, NULL, NULL, NULL);
    4123              : 
    4124              :     /* Prevent overflow in Julian-day routines */
    4125           94 :     if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
    4126            0 :         ereport(ERROR,
    4127              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4128              :                  errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
    4129              : 
    4130           94 :     result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
    4131              : 
    4132              :     /* Now check for just-out-of-range dates */
    4133           94 :     if (!IS_VALID_DATE(result))
    4134            0 :         ereport(ERROR,
    4135              :                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4136              :                  errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
    4137              : 
    4138           94 :     PG_RETURN_DATEADT(result);
    4139              : }
    4140              : 
    4141              : /*
    4142              :  * Convert the 'date_txt' input to a datetime type using argument 'fmt'
    4143              :  * as a format string.  The collation 'collid' may be used for case-folding
    4144              :  * rules in some cases.  'strict' specifies standard parsing mode.
    4145              :  *
    4146              :  * The actual data type (returned in 'typid', 'typmod') is determined by
    4147              :  * the presence of date/time/zone components in the format string.
    4148              :  *
    4149              :  * When a timezone component is present, the corresponding offset is
    4150              :  * returned in '*tz'.
    4151              :  *
    4152              :  * If escontext points to an ErrorSaveContext, data errors will be reported
    4153              :  * by filling that struct; the caller must test SOFT_ERROR_OCCURRED() to see
    4154              :  * whether an error occurred.  Otherwise, errors are thrown.
    4155              :  */
    4156              : Datum
    4157        26244 : parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
    4158              :                Oid *typid, int32 *typmod, int *tz,
    4159              :                Node *escontext)
    4160              : {
    4161              :     struct pg_tm tm;
    4162              :     struct fmt_tz ftz;
    4163              :     fsec_t      fsec;
    4164              :     int         fprec;
    4165              :     uint32      flags;
    4166              : 
    4167        26244 :     if (!do_to_timestamp(date_txt, fmt, collid, strict,
    4168              :                          &tm, &fsec, &ftz, &fprec, &flags, escontext))
    4169        20750 :         return (Datum) 0;
    4170              : 
    4171         5454 :     *typmod = fprec ? fprec : -1;   /* fractional part precision */
    4172              : 
    4173         5454 :     if (flags & DCH_DATED)
    4174              :     {
    4175         3364 :         if (flags & DCH_TIMED)
    4176              :         {
    4177         2506 :             if (flags & DCH_ZONED)
    4178              :             {
    4179              :                 TimestampTz result;
    4180              : 
    4181         1437 :                 if (ftz.has_tz)
    4182              :                 {
    4183         1437 :                     *tz = ftz.gmtoffset;
    4184              :                 }
    4185              :                 else
    4186              :                 {
    4187              :                     /*
    4188              :                      * Time zone is present in format string, but not in input
    4189              :                      * string.  Assuming do_to_timestamp() triggers no error
    4190              :                      * this should be possible only in non-strict case.
    4191              :                      */
    4192              :                     Assert(!strict);
    4193              : 
    4194            0 :                     ereturn(escontext, (Datum) 0,
    4195              :                             (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    4196              :                              errmsg("missing time zone in input string for type timestamptz")));
    4197              :                 }
    4198              : 
    4199         1437 :                 if (tm2timestamp(&tm, fsec, tz, &result) != 0)
    4200            0 :                     ereturn(escontext, (Datum) 0,
    4201              :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4202              :                              errmsg("timestamptz out of range")));
    4203              : 
    4204         1437 :                 AdjustTimestampForTypmod(&result, *typmod, escontext);
    4205              : 
    4206         1437 :                 *typid = TIMESTAMPTZOID;
    4207         1437 :                 return TimestampTzGetDatum(result);
    4208              :             }
    4209              :             else
    4210              :             {
    4211              :                 Timestamp   result;
    4212              : 
    4213         1069 :                 if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
    4214            0 :                     ereturn(escontext, (Datum) 0,
    4215              :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4216              :                              errmsg("timestamp out of range")));
    4217              : 
    4218         1069 :                 AdjustTimestampForTypmod(&result, *typmod, escontext);
    4219              : 
    4220         1069 :                 *typid = TIMESTAMPOID;
    4221         1069 :                 return TimestampGetDatum(result);
    4222              :             }
    4223              :         }
    4224              :         else
    4225              :         {
    4226          858 :             if (flags & DCH_ZONED)
    4227              :             {
    4228            0 :                 ereturn(escontext, (Datum) 0,
    4229              :                         (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    4230              :                          errmsg("datetime format is zoned but not timed")));
    4231              :             }
    4232              :             else
    4233              :             {
    4234              :                 DateADT     result;
    4235              : 
    4236              :                 /* Prevent overflow in Julian-day routines */
    4237          858 :                 if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
    4238            0 :                     ereturn(escontext, (Datum) 0,
    4239              :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4240              :                              errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
    4241              : 
    4242          858 :                 result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) -
    4243              :                     POSTGRES_EPOCH_JDATE;
    4244              : 
    4245              :                 /* Now check for just-out-of-range dates */
    4246          858 :                 if (!IS_VALID_DATE(result))
    4247            0 :                     ereturn(escontext, (Datum) 0,
    4248              :                             (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4249              :                              errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
    4250              : 
    4251          858 :                 *typid = DATEOID;
    4252          858 :                 return DateADTGetDatum(result);
    4253              :             }
    4254              :         }
    4255              :     }
    4256         2090 :     else if (flags & DCH_TIMED)
    4257              :     {
    4258         2090 :         if (flags & DCH_ZONED)
    4259              :         {
    4260         1181 :             TimeTzADT  *result = palloc_object(TimeTzADT);
    4261              : 
    4262         1181 :             if (ftz.has_tz)
    4263              :             {
    4264         1181 :                 *tz = ftz.gmtoffset;
    4265              :             }
    4266              :             else
    4267              :             {
    4268              :                 /*
    4269              :                  * Time zone is present in format string, but not in input
    4270              :                  * string.  Assuming do_to_timestamp() triggers no error this
    4271              :                  * should be possible only in non-strict case.
    4272              :                  */
    4273              :                 Assert(!strict);
    4274              : 
    4275            0 :                 ereturn(escontext, (Datum) 0,
    4276              :                         (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    4277              :                          errmsg("missing time zone in input string for type timetz")));
    4278              :             }
    4279              : 
    4280         1181 :             if (tm2timetz(&tm, fsec, *tz, result) != 0)
    4281            0 :                 ereturn(escontext, (Datum) 0,
    4282              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4283              :                          errmsg("timetz out of range")));
    4284              : 
    4285         1181 :             AdjustTimeForTypmod(&result->time, *typmod);
    4286              : 
    4287         1181 :             *typid = TIMETZOID;
    4288         1181 :             return TimeTzADTPGetDatum(result);
    4289              :         }
    4290              :         else
    4291              :         {
    4292              :             TimeADT     result;
    4293              : 
    4294          909 :             if (tm2time(&tm, fsec, &result) != 0)
    4295            0 :                 ereturn(escontext, (Datum) 0,
    4296              :                         (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
    4297              :                          errmsg("time out of range")));
    4298              : 
    4299          909 :             AdjustTimeForTypmod(&result, *typmod);
    4300              : 
    4301          909 :             *typid = TIMEOID;
    4302          909 :             return TimeADTGetDatum(result);
    4303              :         }
    4304              :     }
    4305              :     else
    4306              :     {
    4307            0 :         ereturn(escontext, (Datum) 0,
    4308              :                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    4309              :                  errmsg("datetime format is not dated and not timed")));
    4310              :     }
    4311              : }
    4312              : 
    4313              : /*
    4314              :  * Parses the datetime format string in 'fmt_str' and returns true if it
    4315              :  * contains a timezone specifier, false if not.
    4316              :  */
    4317              : bool
    4318           44 : datetime_format_has_tz(const char *fmt_str)
    4319              : {
    4320              :     bool        incache;
    4321           44 :     size_t      fmt_len = strlen(fmt_str);
    4322              :     int         result;
    4323              :     FormatNode *format;
    4324              : 
    4325           44 :     if (fmt_len > DCH_CACHE_SIZE)
    4326              :     {
    4327              :         /*
    4328              :          * Allocate new memory if format picture is bigger than static cache
    4329              :          * and do not use cache (call parser always)
    4330              :          */
    4331            0 :         incache = false;
    4332              : 
    4333            0 :         format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
    4334              : 
    4335            0 :         parse_format(format, fmt_str, DCH_keywords,
    4336              :                      DCH_suff, DCH_index, DCH_FLAG, NULL);
    4337              :     }
    4338              :     else
    4339              :     {
    4340              :         /*
    4341              :          * Use cache buffers
    4342              :          */
    4343           44 :         DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
    4344              : 
    4345           44 :         incache = true;
    4346           44 :         format = ent->format;
    4347              :     }
    4348              : 
    4349           44 :     result = DCH_datetime_type(format);
    4350              : 
    4351           44 :     if (!incache)
    4352            0 :         pfree(format);
    4353              : 
    4354           44 :     return result & DCH_ZONED;
    4355              : }
    4356              : 
    4357              : /*
    4358              :  * do_to_timestamp: shared code for to_timestamp and to_date
    4359              :  *
    4360              :  * Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm,
    4361              :  * fractional seconds, struct fmt_tz, and fractional precision.
    4362              :  *
    4363              :  * 'collid' identifies the collation to use, if needed.
    4364              :  * 'std' specifies standard parsing mode.
    4365              :  *
    4366              :  * Bit mask of date/time/zone components found in 'fmt' is returned in 'flags',
    4367              :  * if that is not NULL.
    4368              :  *
    4369              :  * Returns true on success, false on failure (if escontext points to an
    4370              :  * ErrorSaveContext; otherwise errors are thrown).  Note that currently,
    4371              :  * soft-error behavior is provided for bad data but not bad format.
    4372              :  *
    4373              :  * We parse 'fmt' into a list of FormatNodes, which is then passed to
    4374              :  * DCH_from_char to populate a TmFromChar with the parsed contents of
    4375              :  * 'date_txt'.
    4376              :  *
    4377              :  * The TmFromChar is then analysed and converted into the final results in
    4378              :  * struct 'tm', 'fsec', struct 'tz', and 'fprec'.
    4379              :  */
    4380              : static bool
    4381        26993 : do_to_timestamp(const text *date_txt, const text *fmt, Oid collid, bool std,
    4382              :                 struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz,
    4383              :                 int *fprec, uint32 *flags, Node *escontext)
    4384              : {
    4385        26993 :     FormatNode *format = NULL;
    4386        26993 :     TmFromChar  tmfc = {0};
    4387              :     int         fmt_len;
    4388              :     char       *date_str;
    4389              :     int         fmask;
    4390        26993 :     bool        incache = false;
    4391              : 
    4392              :     Assert(tm != NULL);
    4393              :     Assert(fsec != NULL);
    4394              : 
    4395        26993 :     date_str = text_to_cstring(date_txt);
    4396              : 
    4397        26993 :     ZERO_tm(tm);
    4398        26993 :     *fsec = 0;
    4399        26993 :     tz->has_tz = false;
    4400        26993 :     if (fprec)
    4401        26858 :         *fprec = 0;
    4402        26993 :     if (flags)
    4403        26244 :         *flags = 0;
    4404        26993 :     fmask = 0;                  /* bit mask for ValidateDate() */
    4405              : 
    4406        26993 :     fmt_len = VARSIZE_ANY_EXHDR(fmt);
    4407              : 
    4408        26993 :     if (fmt_len)
    4409              :     {
    4410              :         char       *fmt_str;
    4411              : 
    4412        26993 :         fmt_str = text_to_cstring(fmt);
    4413              : 
    4414        26993 :         if (fmt_len > DCH_CACHE_SIZE)
    4415              :         {
    4416              :             /*
    4417              :              * Allocate new memory if format picture is bigger than static
    4418              :              * cache and do not use cache (call parser always)
    4419              :              */
    4420            0 :             format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
    4421              : 
    4422            0 :             parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index,
    4423              :                          DCH_FLAG | (std ? STD_FLAG : 0), NULL);
    4424              :         }
    4425              :         else
    4426              :         {
    4427              :             /*
    4428              :              * Use cache buffers
    4429              :              */
    4430        26993 :             DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, std);
    4431              : 
    4432        26989 :             incache = true;
    4433        26989 :             format = ent->format;
    4434              :         }
    4435              : 
    4436              : #ifdef DEBUG_TO_FROM_CHAR
    4437              :         /* dump_node(format, fmt_len); */
    4438              :         /* dump_index(DCH_keywords, DCH_index); */
    4439              : #endif
    4440              : 
    4441        26989 :         DCH_from_char(format, date_str, &tmfc, collid, std, escontext);
    4442        26888 :         pfree(fmt_str);
    4443        26888 :         if (SOFT_ERROR_OCCURRED(escontext))
    4444        20750 :             goto fail;
    4445              : 
    4446         6138 :         if (flags)
    4447         5454 :             *flags = DCH_datetime_type(format);
    4448              : 
    4449         6138 :         if (!incache)
    4450              :         {
    4451            0 :             pfree(format);
    4452            0 :             format = NULL;
    4453              :         }
    4454              :     }
    4455              : 
    4456              :     DEBUG_TMFC(&tmfc);
    4457              : 
    4458              :     /*
    4459              :      * Convert to_date/to_timestamp input fields to standard 'tm'
    4460              :      */
    4461         6138 :     if (tmfc.ssss)
    4462              :     {
    4463           16 :         int         x = tmfc.ssss;
    4464              : 
    4465           16 :         tm->tm_hour = x / SECS_PER_HOUR;
    4466           16 :         x %= SECS_PER_HOUR;
    4467           16 :         tm->tm_min = x / SECS_PER_MINUTE;
    4468           16 :         x %= SECS_PER_MINUTE;
    4469           16 :         tm->tm_sec = x;
    4470              :     }
    4471              : 
    4472         6138 :     if (tmfc.ss)
    4473          908 :         tm->tm_sec = tmfc.ss;
    4474         6138 :     if (tmfc.mi)
    4475         4852 :         tm->tm_min = tmfc.mi;
    4476         6138 :     if (tmfc.hh)
    4477         4896 :         tm->tm_hour = tmfc.hh;
    4478              : 
    4479         6138 :     if (tmfc.clock_12_hour)
    4480              :     {
    4481           80 :         if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
    4482              :         {
    4483            4 :             errsave(escontext,
    4484              :                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    4485              :                      errmsg("hour \"%d\" is invalid for the 12-hour clock", tm->tm_hour),
    4486              :                      errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
    4487            0 :             goto fail;
    4488              :         }
    4489              : 
    4490           76 :         if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
    4491            8 :             tm->tm_hour += HOURS_PER_DAY / 2;
    4492           68 :         else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
    4493            0 :             tm->tm_hour = 0;
    4494              :     }
    4495              : 
    4496         6134 :     if (tmfc.year)
    4497              :     {
    4498              :         /*
    4499              :          * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
    4500              :          * the year in the given century.  Keep in mind that the 21st century
    4501              :          * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
    4502              :          * 600BC to 501BC.
    4503              :          */
    4504         4020 :         if (tmfc.cc && tmfc.yysz <= 2)
    4505              :         {
    4506           12 :             if (tmfc.bc)
    4507            0 :                 tmfc.cc = -tmfc.cc;
    4508           12 :             tm->tm_year = tmfc.year % 100;
    4509           12 :             if (tm->tm_year)
    4510              :             {
    4511              :                 int         tmp;
    4512              : 
    4513           12 :                 if (tmfc.cc >= 0)
    4514              :                 {
    4515              :                     /* tm->tm_year += (tmfc.cc - 1) * 100; */
    4516            8 :                     tmp = tmfc.cc - 1;
    4517           12 :                     if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
    4518            4 :                         pg_add_s32_overflow(tm->tm_year, tmp, &tm->tm_year))
    4519              :                     {
    4520            4 :                         DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4521            4 :                                            text_to_cstring(date_txt), "timestamp",
    4522              :                                            escontext);
    4523            0 :                         goto fail;
    4524              :                     }
    4525              :                 }
    4526              :                 else
    4527              :                 {
    4528              :                     /* tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1; */
    4529            4 :                     tmp = tmfc.cc + 1;
    4530            4 :                     if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
    4531            0 :                         pg_sub_s32_overflow(tmp, tm->tm_year, &tmp) ||
    4532            0 :                         pg_add_s32_overflow(tmp, 1, &tm->tm_year))
    4533              :                     {
    4534            4 :                         DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4535            4 :                                            text_to_cstring(date_txt), "timestamp",
    4536              :                                            escontext);
    4537            0 :                         goto fail;
    4538              :                     }
    4539              :                 }
    4540              :             }
    4541              :             else
    4542              :             {
    4543              :                 /* find century year for dates ending in "00" */
    4544            0 :                 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
    4545              :             }
    4546              :         }
    4547              :         else
    4548              :         {
    4549              :             /* If a 4-digit year is provided, we use that and ignore CC. */
    4550         4008 :             tm->tm_year = tmfc.year;
    4551         4008 :             if (tmfc.bc)
    4552           24 :                 tm->tm_year = -tm->tm_year;
    4553              :             /* correct for our representation of BC years */
    4554         4008 :             if (tm->tm_year < 0)
    4555           24 :                 tm->tm_year++;
    4556              :         }
    4557         4012 :         fmask |= DTK_M(YEAR);
    4558              :     }
    4559         2114 :     else if (tmfc.cc)
    4560              :     {
    4561              :         /* use first year of century */
    4562            8 :         if (tmfc.bc)
    4563            0 :             tmfc.cc = -tmfc.cc;
    4564            8 :         if (tmfc.cc >= 0)
    4565              :         {
    4566              :             /* +1 because 21st century started in 2001 */
    4567              :             /* tm->tm_year = (tmfc.cc - 1) * 100 + 1; */
    4568            4 :             if (pg_mul_s32_overflow(tmfc.cc - 1, 100, &tm->tm_year) ||
    4569            0 :                 pg_add_s32_overflow(tm->tm_year, 1, &tm->tm_year))
    4570              :             {
    4571            4 :                 DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4572            4 :                                    text_to_cstring(date_txt), "timestamp",
    4573              :                                    escontext);
    4574            0 :                 goto fail;
    4575              :             }
    4576              :         }
    4577              :         else
    4578              :         {
    4579              :             /* +1 because year == 599 is 600 BC */
    4580              :             /* tm->tm_year = tmfc.cc * 100 + 1; */
    4581            4 :             if (pg_mul_s32_overflow(tmfc.cc, 100, &tm->tm_year) ||
    4582            0 :                 pg_add_s32_overflow(tm->tm_year, 1, &tm->tm_year))
    4583              :             {
    4584            4 :                 DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4585            4 :                                    text_to_cstring(date_txt), "timestamp",
    4586              :                                    escontext);
    4587            0 :                 goto fail;
    4588              :             }
    4589              :         }
    4590            0 :         fmask |= DTK_M(YEAR);
    4591              :     }
    4592              : 
    4593         6118 :     if (tmfc.j)
    4594              :     {
    4595            4 :         j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    4596            4 :         fmask |= DTK_DATE_M;
    4597              :     }
    4598              : 
    4599         6118 :     if (tmfc.ww)
    4600              :     {
    4601           24 :         if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
    4602              :         {
    4603              :             /*
    4604              :              * If tmfc.d is not set, then the date is left at the beginning of
    4605              :              * the ISO week (Monday).
    4606              :              */
    4607           16 :             if (tmfc.d)
    4608           16 :                 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    4609              :             else
    4610            0 :                 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    4611           16 :             fmask |= DTK_DATE_M;
    4612              :         }
    4613              :         else
    4614              :         {
    4615              :             /* tmfc.ddd = (tmfc.ww - 1) * 7 + 1; */
    4616           16 :             if (pg_sub_s32_overflow(tmfc.ww, 1, &tmfc.ddd) ||
    4617           12 :                 pg_mul_s32_overflow(tmfc.ddd, 7, &tmfc.ddd) ||
    4618            4 :                 pg_add_s32_overflow(tmfc.ddd, 1, &tmfc.ddd))
    4619              :             {
    4620            4 :                 DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4621              :                                    date_str, "timestamp", escontext);
    4622            0 :                 goto fail;
    4623              :             }
    4624              :         }
    4625              :     }
    4626              : 
    4627         6114 :     if (tmfc.w)
    4628              :     {
    4629              :         /* tmfc.dd = (tmfc.w - 1) * 7 + 1; */
    4630           16 :         if (pg_sub_s32_overflow(tmfc.w, 1, &tmfc.dd) ||
    4631           12 :             pg_mul_s32_overflow(tmfc.dd, 7, &tmfc.dd) ||
    4632            4 :             pg_add_s32_overflow(tmfc.dd, 1, &tmfc.dd))
    4633              :         {
    4634            4 :             DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4635              :                                date_str, "timestamp", escontext);
    4636            0 :             goto fail;
    4637              :         }
    4638              :     }
    4639         6110 :     if (tmfc.dd)
    4640              :     {
    4641         3920 :         tm->tm_mday = tmfc.dd;
    4642         3920 :         fmask |= DTK_M(DAY);
    4643              :     }
    4644         6110 :     if (tmfc.mm)
    4645              :     {
    4646         3944 :         tm->tm_mon = tmfc.mm;
    4647         3944 :         fmask |= DTK_M(MONTH);
    4648              :     }
    4649              : 
    4650         6110 :     if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
    4651              :     {
    4652              :         /*
    4653              :          * The month and day field have not been set, so we use the
    4654              :          * day-of-year field to populate them.  Depending on the date mode,
    4655              :          * this field may be interpreted as a Gregorian day-of-year, or an ISO
    4656              :          * week date day-of-year.
    4657              :          */
    4658              : 
    4659           32 :         if (!tm->tm_year && !tmfc.bc)
    4660              :         {
    4661            0 :             errsave(escontext,
    4662              :                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
    4663              :                      errmsg("cannot calculate day of year without year information")));
    4664            0 :             goto fail;
    4665              :         }
    4666              : 
    4667           32 :         if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
    4668              :         {
    4669              :             int         j0;     /* zeroth day of the ISO year, in Julian */
    4670              : 
    4671            4 :             j0 = isoweek2j(tm->tm_year, 1) - 1;
    4672              : 
    4673            4 :             j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
    4674            4 :             fmask |= DTK_DATE_M;
    4675              :         }
    4676              :         else
    4677              :         {
    4678              :             const int  *y;
    4679              :             int         i;
    4680              : 
    4681              :             static const int ysum[2][13] = {
    4682              :                 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
    4683              :             {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
    4684              : 
    4685           28 :             y = ysum[isleap(tm->tm_year)];
    4686              : 
    4687          328 :             for (i = 1; i <= MONTHS_PER_YEAR; i++)
    4688              :             {
    4689          320 :                 if (tmfc.ddd <= y[i])
    4690           20 :                     break;
    4691              :             }
    4692           28 :             if (tm->tm_mon <= 1)
    4693           28 :                 tm->tm_mon = i;
    4694              : 
    4695           28 :             if (tm->tm_mday <= 1)
    4696           28 :                 tm->tm_mday = tmfc.ddd - y[i - 1];
    4697              : 
    4698           28 :             fmask |= DTK_M(MONTH) | DTK_M(DAY);
    4699              :         }
    4700              :     }
    4701              : 
    4702         6110 :     if (tmfc.ms)
    4703              :     {
    4704            8 :         int         tmp = 0;
    4705              : 
    4706              :         /* *fsec += tmfc.ms * 1000; */
    4707           12 :         if (pg_mul_s32_overflow(tmfc.ms, 1000, &tmp) ||
    4708            4 :             pg_add_s32_overflow(*fsec, tmp, fsec))
    4709              :         {
    4710            4 :             DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4711              :                                date_str, "timestamp", escontext);
    4712            0 :             goto fail;
    4713              :         }
    4714              :     }
    4715         6106 :     if (tmfc.us)
    4716          676 :         *fsec += tmfc.us;
    4717         6106 :     if (fprec)
    4718         5992 :         *fprec = tmfc.ff;       /* fractional precision, if specified */
    4719              : 
    4720              :     /* Range-check date fields according to bit mask computed above */
    4721         6106 :     if (fmask != 0)
    4722              :     {
    4723              :         /* We already dealt with AD/BC, so pass isjulian = true */
    4724         4016 :         int         dterr = ValidateDate(fmask, true, false, false, tm);
    4725              : 
    4726         4016 :         if (dterr != 0)
    4727              :         {
    4728              :             /*
    4729              :              * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
    4730              :              * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
    4731              :              * irrelevant hint about datestyle.
    4732              :              */
    4733           32 :             DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4734              :                                date_str, "timestamp", escontext);
    4735            0 :             goto fail;
    4736              :         }
    4737              :     }
    4738              : 
    4739              :     /* Range-check time fields too */
    4740         6074 :     if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY ||
    4741         6062 :         tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR ||
    4742         6058 :         tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
    4743         6054 :         *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
    4744              :     {
    4745           24 :         DateTimeParseError(DTERR_FIELD_OVERFLOW, NULL,
    4746              :                            date_str, "timestamp", escontext);
    4747            0 :         goto fail;
    4748              :     }
    4749              : 
    4750              :     /*
    4751              :      * If timezone info was present, reduce it to a GMT offset.  (We cannot do
    4752              :      * this until we've filled all of the tm struct, since the zone's offset
    4753              :      * might be time-varying.)
    4754              :      */
    4755         6050 :     if (tmfc.tzsign)
    4756              :     {
    4757              :         /* TZH and/or TZM fields */
    4758         2658 :         if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
    4759         2658 :             tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
    4760              :         {
    4761            0 :             DateTimeParseError(DTERR_TZDISP_OVERFLOW, NULL,
    4762              :                                date_str, "timestamp", escontext);
    4763            0 :             goto fail;
    4764              :         }
    4765              : 
    4766         2658 :         tz->has_tz = true;
    4767         2658 :         tz->gmtoffset = (tmfc.tzh * MINS_PER_HOUR + tmfc.tzm) * SECS_PER_MINUTE;
    4768              :         /* note we are flipping the sign convention here */
    4769         2658 :         if (tmfc.tzsign > 0)
    4770         2426 :             tz->gmtoffset = -tz->gmtoffset;
    4771              :     }
    4772         3392 :     else if (tmfc.has_tz)
    4773              :     {
    4774              :         /* TZ field */
    4775           24 :         tz->has_tz = true;
    4776           24 :         if (tmfc.tzp == NULL)
    4777              :         {
    4778              :             /* fixed-offset abbreviation; flip the sign convention */
    4779           20 :             tz->gmtoffset = -tmfc.gmtoffset;
    4780              :         }
    4781              :         else
    4782              :         {
    4783              :             /* dynamic-offset abbreviation, resolve using specified time */
    4784            4 :             tz->gmtoffset = DetermineTimeZoneAbbrevOffset(tm, tmfc.abbrev,
    4785              :                                                           tmfc.tzp);
    4786              :         }
    4787              :     }
    4788              : 
    4789              :     DEBUG_TM(tm);
    4790              : 
    4791         6050 :     if (format && !incache)
    4792            0 :         pfree(format);
    4793         6050 :     pfree(date_str);
    4794              : 
    4795         6050 :     return true;
    4796              : 
    4797        20750 : fail:
    4798        20750 :     if (format && !incache)
    4799            0 :         pfree(format);
    4800        20750 :     pfree(date_str);
    4801              : 
    4802        20750 :     return false;
    4803              : }
    4804              : 
    4805              : 
    4806              : /**********************************************************************
    4807              :  *  the NUMBER version part
    4808              :  *********************************************************************/
    4809              : 
    4810              : 
    4811              : /*
    4812              :  * Fill str with character c max times, and add terminating \0.  (So max+1
    4813              :  * bytes are written altogether!)
    4814              :  */
    4815              : static void
    4816          152 : fill_str(char *str, int c, int max)
    4817              : {
    4818          152 :     memset(str, c, max);
    4819          152 :     str[max] = '\0';
    4820          152 : }
    4821              : 
    4822              : /* This works the same as DCH_prevent_counter_overflow */
    4823              : static inline void
    4824       699753 : NUM_prevent_counter_overflow(void)
    4825              : {
    4826       699753 :     if (NUMCounter >= (INT_MAX - 1))
    4827              :     {
    4828            0 :         for (int i = 0; i < n_NUMCache; i++)
    4829            0 :             NUMCache[i]->age >>= 1;
    4830            0 :         NUMCounter >>= 1;
    4831              :     }
    4832       699753 : }
    4833              : 
    4834              : /* select a NUMCacheEntry to hold the given format picture */
    4835              : static NUMCacheEntry *
    4836          409 : NUM_cache_getnew(const char *str)
    4837              : {
    4838              :     NUMCacheEntry *ent;
    4839              : 
    4840              :     /* Ensure we can advance NUMCounter below */
    4841          409 :     NUM_prevent_counter_overflow();
    4842              : 
    4843              :     /*
    4844              :      * If cache is full, remove oldest entry (or recycle first not-valid one)
    4845              :      */
    4846          409 :     if (n_NUMCache >= NUM_CACHE_ENTRIES)
    4847              :     {
    4848          196 :         NUMCacheEntry *old = NUMCache[0];
    4849              : 
    4850              : #ifdef DEBUG_TO_FROM_CHAR
    4851              :         elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
    4852              : #endif
    4853          196 :         if (old->valid)
    4854              :         {
    4855         3852 :             for (int i = 1; i < NUM_CACHE_ENTRIES; i++)
    4856              :             {
    4857         3660 :                 ent = NUMCache[i];
    4858         3660 :                 if (!ent->valid)
    4859              :                 {
    4860            4 :                     old = ent;
    4861            4 :                     break;
    4862              :                 }
    4863         3656 :                 if (ent->age < old->age)
    4864          196 :                     old = ent;
    4865              :             }
    4866              :         }
    4867              : #ifdef DEBUG_TO_FROM_CHAR
    4868              :         elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
    4869              : #endif
    4870          196 :         old->valid = false;
    4871          196 :         strlcpy(old->str, str, NUM_CACHE_SIZE + 1);
    4872          196 :         old->age = (++NUMCounter);
    4873              :         /* caller is expected to fill format and Num, then set valid */
    4874          196 :         return old;
    4875              :     }
    4876              :     else
    4877              :     {
    4878              : #ifdef DEBUG_TO_FROM_CHAR
    4879              :         elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
    4880              : #endif
    4881              :         Assert(NUMCache[n_NUMCache] == NULL);
    4882          213 :         NUMCache[n_NUMCache] = ent = (NUMCacheEntry *)
    4883          213 :             MemoryContextAllocZero(TopMemoryContext, sizeof(NUMCacheEntry));
    4884          213 :         ent->valid = false;
    4885          213 :         strlcpy(ent->str, str, NUM_CACHE_SIZE + 1);
    4886          213 :         ent->age = (++NUMCounter);
    4887              :         /* caller is expected to fill format and Num, then set valid */
    4888          213 :         ++n_NUMCache;
    4889          213 :         return ent;
    4890              :     }
    4891              : }
    4892              : 
    4893              : /* look for an existing NUMCacheEntry matching the given format picture */
    4894              : static NUMCacheEntry *
    4895       699344 : NUM_cache_search(const char *str)
    4896              : {
    4897              :     /* Ensure we can advance NUMCounter below */
    4898       699344 :     NUM_prevent_counter_overflow();
    4899              : 
    4900       878910 :     for (int i = 0; i < n_NUMCache; i++)
    4901              :     {
    4902       878501 :         NUMCacheEntry *ent = NUMCache[i];
    4903              : 
    4904       878501 :         if (ent->valid && strcmp(ent->str, str) == 0)
    4905              :         {
    4906       698935 :             ent->age = (++NUMCounter);
    4907       698935 :             return ent;
    4908              :         }
    4909              :     }
    4910              : 
    4911          409 :     return NULL;
    4912              : }
    4913              : 
    4914              : /* Find or create a NUMCacheEntry for the given format picture */
    4915              : static NUMCacheEntry *
    4916       699344 : NUM_cache_fetch(const char *str)
    4917              : {
    4918              :     NUMCacheEntry *ent;
    4919              : 
    4920       699344 :     if ((ent = NUM_cache_search(str)) == NULL)
    4921              :     {
    4922              :         /*
    4923              :          * Not in the cache, must run parser and save a new format-picture to
    4924              :          * the cache.  Do not mark the cache entry valid until parsing
    4925              :          * succeeds.
    4926              :          */
    4927          409 :         ent = NUM_cache_getnew(str);
    4928              : 
    4929          409 :         memset(&ent->Num, 0, sizeof ent->Num);
    4930              : 
    4931          409 :         parse_format(ent->format, str, NUM_keywords,
    4932              :                      NULL, NUM_index, NUM_FLAG, &ent->Num);
    4933              : 
    4934          401 :         ent->valid = true;
    4935              :     }
    4936       699336 :     return ent;
    4937              : }
    4938              : 
    4939              : /*
    4940              :  * Cache routine for NUM to_char version
    4941              :  */
    4942              : static FormatNode *
    4943       699544 : NUM_cache(int len, NUMDesc *Num, const text *pars_str, bool *shouldFree)
    4944              : {
    4945       699544 :     FormatNode *format = NULL;
    4946              :     char       *str;
    4947              : 
    4948       699544 :     str = text_to_cstring(pars_str);
    4949              : 
    4950       699544 :     if (len > NUM_CACHE_SIZE)
    4951              :     {
    4952              :         /*
    4953              :          * Allocate new memory if format picture is bigger than static cache
    4954              :          * and do not use cache (call parser always)
    4955              :          */
    4956          200 :         format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
    4957              : 
    4958          200 :         *shouldFree = true;
    4959              : 
    4960          200 :         memset(Num, 0, sizeof *Num);
    4961              : 
    4962          200 :         parse_format(format, str, NUM_keywords,
    4963              :                      NULL, NUM_index, NUM_FLAG, Num);
    4964              :     }
    4965              :     else
    4966              :     {
    4967              :         /*
    4968              :          * Use cache buffers
    4969              :          */
    4970       699344 :         NUMCacheEntry *ent = NUM_cache_fetch(str);
    4971              : 
    4972       699336 :         *shouldFree = false;
    4973              : 
    4974       699336 :         format = ent->format;
    4975              : 
    4976              :         /*
    4977              :          * Copy cache to used struct
    4978              :          */
    4979       699336 :         Num->flag = ent->Num.flag;
    4980       699336 :         Num->lsign = ent->Num.lsign;
    4981       699336 :         Num->pre = ent->Num.pre;
    4982       699336 :         Num->post = ent->Num.post;
    4983       699336 :         Num->pre_lsign_num = ent->Num.pre_lsign_num;
    4984       699336 :         Num->need_locale = ent->Num.need_locale;
    4985       699336 :         Num->multi = ent->Num.multi;
    4986       699336 :         Num->zero_start = ent->Num.zero_start;
    4987       699336 :         Num->zero_end = ent->Num.zero_end;
    4988              :     }
    4989              : 
    4990              : #ifdef DEBUG_TO_FROM_CHAR
    4991              :     /* dump_node(format, len); */
    4992              :     dump_index(NUM_keywords, NUM_index);
    4993              : #endif
    4994              : 
    4995       699536 :     pfree(str);
    4996       699536 :     return format;
    4997              : }
    4998              : 
    4999              : 
    5000              : /*
    5001              :  * Convert integer to Roman numerals
    5002              :  * Result is upper-case and not blank-padded (NUM_processor converts as needed)
    5003              :  * If input is out-of-range, produce '###############'
    5004              :  */
    5005              : static char *
    5006        16088 : int_to_roman(int number)
    5007              : {
    5008              :     int         len,
    5009              :                 num;
    5010              :     char       *result,
    5011              :                 numstr[12];
    5012              : 
    5013        16088 :     result = (char *) palloc(MAX_ROMAN_LEN + 1);
    5014        16088 :     *result = '\0';
    5015              : 
    5016              :     /*
    5017              :      * This range limit is the same as in Oracle(TM).  The difficulty with
    5018              :      * handling 4000 or more is that we'd need to use more than 3 "M"'s, and
    5019              :      * more than 3 of the same digit isn't considered a valid Roman string.
    5020              :      */
    5021        16088 :     if (number > 3999 || number < 1)
    5022              :     {
    5023           60 :         fill_str(result, '#', MAX_ROMAN_LEN);
    5024           60 :         return result;
    5025              :     }
    5026              : 
    5027              :     /* Convert to decimal, then examine each digit */
    5028        16028 :     len = snprintf(numstr, sizeof(numstr), "%d", number);
    5029              :     Assert(len > 0 && len <= 4);
    5030              : 
    5031        75688 :     for (char *p = numstr; *p != '\0'; p++, --len)
    5032              :     {
    5033        59660 :         num = *p - ('0' + 1);
    5034        59660 :         if (num < 0)
    5035         4364 :             continue;           /* ignore zeroes */
    5036              :         /* switch on current column position */
    5037        55296 :         switch (len)
    5038              :         {
    5039        12016 :             case 4:
    5040        36032 :                 while (num-- >= 0)
    5041        24016 :                     strcat(result, "M");
    5042        12016 :                 break;
    5043        14428 :             case 3:
    5044        14428 :                 strcat(result, rm100[num]);
    5045        14428 :                 break;
    5046        14424 :             case 2:
    5047        14424 :                 strcat(result, rm10[num]);
    5048        14424 :                 break;
    5049        14428 :             case 1:
    5050        14428 :                 strcat(result, rm1[num]);
    5051        14428 :                 break;
    5052              :         }
    5053              :     }
    5054        16028 :     return result;
    5055              : }
    5056              : 
    5057              : /*
    5058              :  * Convert a roman numeral (standard form) to an integer.
    5059              :  * Result is an integer between 1 and 3999.
    5060              :  * Np->inout_p is advanced past the characters consumed.
    5061              :  *
    5062              :  * If input is invalid, return -1.
    5063              :  */
    5064              : static int
    5065        16072 : roman_to_int(NUMProc *Np, size_t input_len)
    5066              : {
    5067        16072 :     int         result = 0;
    5068              :     size_t      len;
    5069              :     char        romanChars[MAX_ROMAN_LEN];
    5070              :     int         romanValues[MAX_ROMAN_LEN];
    5071        16072 :     int         repeatCount = 1;
    5072        16072 :     int         vCount = 0,
    5073        16072 :                 lCount = 0,
    5074        16072 :                 dCount = 0;
    5075        16072 :     bool        subtractionEncountered = false;
    5076        16072 :     int         lastSubtractedValue = 0;
    5077              : 
    5078              :     /*
    5079              :      * Skip any leading whitespace.  Perhaps we should limit the amount of
    5080              :      * space skipped to MAX_ROMAN_LEN, but that seems unnecessarily picky.
    5081              :      */
    5082       136016 :     while (!OVERLOAD_TEST && isspace((unsigned char) *Np->inout_p))
    5083       119944 :         Np->inout_p++;
    5084              : 
    5085              :     /*
    5086              :      * Collect and decode valid roman numerals, consuming at most
    5087              :      * MAX_ROMAN_LEN characters.  We do this in a separate loop to avoid
    5088              :      * repeated decoding and because the main loop needs to know when it's at
    5089              :      * the last numeral.
    5090              :      */
    5091       136308 :     for (len = 0; len < MAX_ROMAN_LEN && !OVERLOAD_TEST; len++)
    5092              :     {
    5093       120252 :         char        currChar = pg_ascii_toupper(*Np->inout_p);
    5094       120252 :         int         currValue = ROMAN_VAL(currChar);
    5095              : 
    5096       120252 :         if (currValue == 0)
    5097           16 :             break;              /* Not a valid roman numeral. */
    5098       120236 :         romanChars[len] = currChar;
    5099       120236 :         romanValues[len] = currValue;
    5100       120236 :         Np->inout_p++;
    5101              :     }
    5102              : 
    5103        16072 :     if (len == 0)
    5104            8 :         return -1;              /* No valid roman numerals. */
    5105              : 
    5106              :     /* Check for valid combinations and compute the represented value. */
    5107       126600 :     for (size_t i = 0; i < len; i++)
    5108              :     {
    5109       110584 :         char        currChar = romanChars[i];
    5110       110584 :         int         currValue = romanValues[i];
    5111              : 
    5112              :         /*
    5113              :          * Ensure no numeral greater than or equal to the subtracted numeral
    5114              :          * appears after a subtraction.
    5115              :          */
    5116       110584 :         if (subtractionEncountered && currValue >= lastSubtractedValue)
    5117            4 :             return -1;
    5118              : 
    5119              :         /*
    5120              :          * V, L, and D should not appear before a larger numeral, nor should
    5121              :          * they be repeated.
    5122              :          */
    5123       110580 :         if ((vCount && currValue >= ROMAN_VAL('V')) ||
    5124       110576 :             (lCount && currValue >= ROMAN_VAL('L')) ||
    5125        38420 :             (dCount && currValue >= ROMAN_VAL('D')))
    5126            4 :             return -1;
    5127       110576 :         if (currChar == 'V')
    5128         6416 :             vCount++;
    5129       104160 :         else if (currChar == 'L')
    5130         6408 :             lCount++;
    5131        97752 :         else if (currChar == 'D')
    5132         6412 :             dCount++;
    5133              : 
    5134       110576 :         if (i < len - 1)
    5135              :         {
    5136              :             /* Compare current numeral to next numeral. */
    5137        98120 :             char        nextChar = romanChars[i + 1];
    5138        98120 :             int         nextValue = romanValues[i + 1];
    5139              : 
    5140              :             /*
    5141              :              * If the current value is less than the next value, handle
    5142              :              * subtraction. Verify valid subtractive combinations and update
    5143              :              * the result accordingly.
    5144              :              */
    5145        98120 :             if (currValue < nextValue)
    5146              :             {
    5147         9648 :                 if (!IS_VALID_SUB_COMB(currChar, nextChar))
    5148            4 :                     return -1;
    5149              : 
    5150              :                 /*
    5151              :                  * Reject cases where same numeral is repeated with
    5152              :                  * subtraction (e.g. 'MCCM' or 'DCCCD').
    5153              :                  */
    5154         9644 :                 if (repeatCount > 1)
    5155            8 :                     return -1;
    5156              : 
    5157              :                 /*
    5158              :                  * We are going to skip nextChar, so first make checks needed
    5159              :                  * for V, L, and D.  These are the same as we'd have applied
    5160              :                  * if we reached nextChar without a subtraction.
    5161              :                  */
    5162         9636 :                 if ((vCount && nextValue >= ROMAN_VAL('V')) ||
    5163         9628 :                     (lCount && nextValue >= ROMAN_VAL('L')) ||
    5164         3208 :                     (dCount && nextValue >= ROMAN_VAL('D')))
    5165           24 :                     return -1;
    5166         9612 :                 if (nextChar == 'V')
    5167         1608 :                     vCount++;
    5168         8004 :                 else if (nextChar == 'L')
    5169         1600 :                     lCount++;
    5170         6404 :                 else if (nextChar == 'D')
    5171         1600 :                     dCount++;
    5172              : 
    5173              :                 /*
    5174              :                  * Skip the next numeral as it is part of the subtractive
    5175              :                  * combination.
    5176              :                  */
    5177         9612 :                 i++;
    5178              : 
    5179              :                 /* Update state. */
    5180         9612 :                 repeatCount = 1;
    5181         9612 :                 subtractionEncountered = true;
    5182         9612 :                 lastSubtractedValue = currValue;
    5183         9612 :                 result += (nextValue - currValue);
    5184              :             }
    5185              :             else
    5186              :             {
    5187              :                 /* For same numerals, check for repetition. */
    5188        88472 :                 if (currChar == nextChar)
    5189              :                 {
    5190        40852 :                     repeatCount++;
    5191        40852 :                     if (repeatCount > 3)
    5192            4 :                         return -1;
    5193              :                 }
    5194              :                 else
    5195        47620 :                     repeatCount = 1;
    5196        88468 :                 result += currValue;
    5197              :             }
    5198              :         }
    5199              :         else
    5200              :         {
    5201              :             /* This is the last numeral; just add it to the result. */
    5202        12456 :             result += currValue;
    5203              :         }
    5204              :     }
    5205              : 
    5206        16016 :     return result;
    5207              : }
    5208              : 
    5209              : 
    5210              : /*
    5211              :  * Locale
    5212              :  */
    5213              : static void
    5214       699312 : NUM_prepare_locale(NUMProc *Np)
    5215              : {
    5216       699312 :     if (Np->Num->need_locale)
    5217              :     {
    5218              :         struct lconv *lconv;
    5219              : 
    5220              :         /*
    5221              :          * Get locales
    5222              :          */
    5223          558 :         lconv = PGLC_localeconv();
    5224              : 
    5225              :         /*
    5226              :          * Positive / Negative number sign
    5227              :          */
    5228          558 :         if (lconv->negative_sign && *lconv->negative_sign)
    5229            0 :             Np->L_negative_sign = lconv->negative_sign;
    5230              :         else
    5231          558 :             Np->L_negative_sign = "-";
    5232              : 
    5233          558 :         if (lconv->positive_sign && *lconv->positive_sign)
    5234            0 :             Np->L_positive_sign = lconv->positive_sign;
    5235              :         else
    5236          558 :             Np->L_positive_sign = "+";
    5237              : 
    5238              :         /*
    5239              :          * Number decimal point
    5240              :          */
    5241          558 :         if (lconv->decimal_point && *lconv->decimal_point)
    5242          558 :             Np->decimal = lconv->decimal_point;
    5243              : 
    5244              :         else
    5245            0 :             Np->decimal = ".";
    5246              : 
    5247          558 :         if (!IS_LDECIMAL(Np->Num))
    5248          472 :             Np->decimal = ".";
    5249              : 
    5250              :         /*
    5251              :          * Number thousands separator
    5252              :          *
    5253              :          * Some locales (e.g. broken glibc pt_BR), have a comma for decimal,
    5254              :          * but "" for thousands_sep, so we set the thousands_sep too.
    5255              :          * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php
    5256              :          */
    5257          558 :         if (lconv->thousands_sep && *lconv->thousands_sep)
    5258            0 :             Np->L_thousands_sep = lconv->thousands_sep;
    5259              :         /* Make sure thousands separator doesn't match decimal point symbol. */
    5260          558 :         else if (strcmp(Np->decimal, ",") != 0)
    5261          558 :             Np->L_thousands_sep = ",";
    5262              :         else
    5263            0 :             Np->L_thousands_sep = ".";
    5264              : 
    5265              :         /*
    5266              :          * Currency symbol
    5267              :          */
    5268          558 :         if (lconv->currency_symbol && *lconv->currency_symbol)
    5269            0 :             Np->L_currency_symbol = lconv->currency_symbol;
    5270              :         else
    5271          558 :             Np->L_currency_symbol = " ";
    5272              :     }
    5273              :     else
    5274              :     {
    5275              :         /*
    5276              :          * Default values
    5277              :          */
    5278       698754 :         Np->L_negative_sign = "-";
    5279       698754 :         Np->L_positive_sign = "+";
    5280       698754 :         Np->decimal = ".";
    5281              : 
    5282       698754 :         Np->L_thousands_sep = ",";
    5283       698754 :         Np->L_currency_symbol = " ";
    5284              :     }
    5285       699312 : }
    5286              : 
    5287              : /*
    5288              :  * Return pointer of last relevant number after decimal point
    5289              :  *  12.0500 --> last relevant is '5'
    5290              :  *  12.0000 --> last relevant is '.'
    5291              :  * If there is no decimal point, return NULL (which will result in same
    5292              :  * behavior as if FM hadn't been specified).
    5293              :  */
    5294              : static const char *
    5295          452 : get_last_relevant_decnum(const char *num)
    5296              : {
    5297              :     const char *result,
    5298          452 :                *p = strchr(num, '.');
    5299              : 
    5300              : #ifdef DEBUG_TO_FROM_CHAR
    5301              :     elog(DEBUG_elog_output, "get_last_relevant_decnum()");
    5302              : #endif
    5303              : 
    5304          452 :     if (!p)
    5305            4 :         return NULL;
    5306              : 
    5307          448 :     result = p;
    5308              : 
    5309         6628 :     while (*(++p))
    5310              :     {
    5311         6180 :         if (*p != '0')
    5312         1296 :             result = p;
    5313              :     }
    5314              : 
    5315          448 :     return result;
    5316              : }
    5317              : 
    5318              : /*
    5319              :  * Number extraction for TO_NUMBER()
    5320              :  */
    5321              : static void
    5322          582 : NUM_numpart_from_char(NUMProc *Np, int id, size_t input_len)
    5323              : {
    5324          582 :     bool        isread = false;
    5325              : 
    5326              : #ifdef DEBUG_TO_FROM_CHAR
    5327              :     elog(DEBUG_elog_output, " --- scan start --- id=%s",
    5328              :          (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
    5329              : #endif
    5330              : 
    5331          582 :     if (OVERLOAD_TEST)
    5332            0 :         return;
    5333              : 
    5334          582 :     if (*Np->inout_p == ' ')
    5335            0 :         Np->inout_p++;
    5336              : 
    5337          582 :     if (OVERLOAD_TEST)
    5338            0 :         return;
    5339              : 
    5340              :     /*
    5341              :      * read sign before number
    5342              :      */
    5343          582 :     if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
    5344          392 :         (Np->read_pre + Np->read_post) == 0)
    5345              :     {
    5346              : #ifdef DEBUG_TO_FROM_CHAR
    5347              :         elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
    5348              :              *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
    5349              : #endif
    5350              : 
    5351              :         /*
    5352              :          * locale sign
    5353              :          */
    5354          114 :         if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
    5355            8 :         {
    5356            8 :             size_t      x = 0;
    5357              : 
    5358              : #ifdef DEBUG_TO_FROM_CHAR
    5359              :             elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
    5360              : #endif
    5361            8 :             if ((x = strlen(Np->L_negative_sign)) &&
    5362            8 :                 AMOUNT_TEST(x) &&
    5363            8 :                 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
    5364              :             {
    5365            4 :                 Np->inout_p += x;
    5366            4 :                 *Np->number = '-';
    5367              :             }
    5368            4 :             else if ((x = strlen(Np->L_positive_sign)) &&
    5369            4 :                      AMOUNT_TEST(x) &&
    5370            4 :                      strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
    5371              :             {
    5372            0 :                 Np->inout_p += x;
    5373            0 :                 *Np->number = '+';
    5374              :             }
    5375              :         }
    5376              :         else
    5377              :         {
    5378              : #ifdef DEBUG_TO_FROM_CHAR
    5379              :             elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
    5380              : #endif
    5381              : 
    5382              :             /*
    5383              :              * simple + - < >
    5384              :              */
    5385          106 :             if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
    5386            4 :                                         *Np->inout_p == '<'))
    5387              :             {
    5388           12 :                 *Np->number = '-';   /* set - */
    5389           12 :                 Np->inout_p++;
    5390              :             }
    5391           94 :             else if (*Np->inout_p == '+')
    5392              :             {
    5393            0 :                 *Np->number = '+';   /* set + */
    5394            0 :                 Np->inout_p++;
    5395              :             }
    5396              :         }
    5397              :     }
    5398              : 
    5399          582 :     if (OVERLOAD_TEST)
    5400            0 :         return;
    5401              : 
    5402              : #ifdef DEBUG_TO_FROM_CHAR
    5403              :     elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
    5404              : #endif
    5405              : 
    5406              :     /*
    5407              :      * read digit or decimal point
    5408              :      */
    5409          582 :     if (isdigit((unsigned char) *Np->inout_p))
    5410              :     {
    5411          496 :         if (Np->read_dec && Np->read_post == Np->Num->post)
    5412            0 :             return;
    5413              : 
    5414          496 :         *Np->number_p = *Np->inout_p;
    5415          496 :         Np->number_p++;
    5416              : 
    5417          496 :         if (Np->read_dec)
    5418          174 :             Np->read_post++;
    5419              :         else
    5420          322 :             Np->read_pre++;
    5421              : 
    5422          496 :         isread = true;
    5423              : 
    5424              : #ifdef DEBUG_TO_FROM_CHAR
    5425              :         elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
    5426              : #endif
    5427              :     }
    5428           86 :     else if (IS_DECIMAL(Np->Num) && Np->read_dec == false)
    5429              :     {
    5430              :         /*
    5431              :          * We need not test IS_LDECIMAL(Np->Num) explicitly here, because
    5432              :          * Np->decimal is always just "." if we don't have a D format token.
    5433              :          * So we just unconditionally match to Np->decimal.
    5434              :          */
    5435           78 :         size_t      x = strlen(Np->decimal);
    5436              : 
    5437              : #ifdef DEBUG_TO_FROM_CHAR
    5438              :         elog(DEBUG_elog_output, "Try read decimal point (%c)",
    5439              :              *Np->inout_p);
    5440              : #endif
    5441           78 :         if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
    5442              :         {
    5443           70 :             Np->inout_p += x - 1;
    5444           70 :             *Np->number_p = '.';
    5445           70 :             Np->number_p++;
    5446           70 :             Np->read_dec = true;
    5447           70 :             isread = true;
    5448              :         }
    5449              :     }
    5450              : 
    5451          582 :     if (OVERLOAD_TEST)
    5452            0 :         return;
    5453              : 
    5454              :     /*
    5455              :      * Read sign behind "last" number
    5456              :      *
    5457              :      * We need sign detection because determine exact position of post-sign is
    5458              :      * difficult:
    5459              :      *
    5460              :      * FM9999.9999999S     -> 123.001- 9.9S             -> .5- FM9.999999MI ->
    5461              :      * 5.01-
    5462              :      */
    5463          582 :     if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
    5464              :     {
    5465              :         /*
    5466              :          * locale sign (NUM_S) is always anchored behind a last number, if: -
    5467              :          * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
    5468              :          * next char is not digit
    5469              :          */
    5470          410 :         if (IS_LSIGN(Np->Num) && isread &&
    5471          102 :             (Np->inout_p + 1) < Np->inout + input_len &&
    5472          102 :             !isdigit((unsigned char) *(Np->inout_p + 1)))
    5473           46 :         {
    5474              :             size_t      x;
    5475           46 :             char       *tmp = Np->inout_p++;
    5476              : 
    5477              : #ifdef DEBUG_TO_FROM_CHAR
    5478              :             elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
    5479              : #endif
    5480           46 :             if ((x = strlen(Np->L_negative_sign)) &&
    5481           46 :                 AMOUNT_TEST(x) &&
    5482           46 :                 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
    5483              :             {
    5484           22 :                 Np->inout_p += x - 1;    /* -1 .. NUM_processor() do inout_p++ */
    5485           22 :                 *Np->number = '-';
    5486              :             }
    5487           24 :             else if ((x = strlen(Np->L_positive_sign)) &&
    5488           24 :                      AMOUNT_TEST(x) &&
    5489           24 :                      strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
    5490              :             {
    5491            0 :                 Np->inout_p += x - 1;    /* -1 .. NUM_processor() do inout_p++ */
    5492            0 :                 *Np->number = '+';
    5493              :             }
    5494           46 :             if (*Np->number == ' ')
    5495              :                 /* no sign read */
    5496           24 :                 Np->inout_p = tmp;
    5497              :         }
    5498              : 
    5499              :         /*
    5500              :          * try read non-locale sign, which happens only if format is not exact
    5501              :          * and we cannot determine sign position of MI/PL/SG, an example:
    5502              :          *
    5503              :          * FM9.999999MI            -> 5.01-
    5504              :          *
    5505              :          * if (.... && IS_LSIGN(Np->Num)==false) prevents read wrong formats
    5506              :          * like to_number('1 -', '9S') where sign is not anchored to last
    5507              :          * number.
    5508              :          */
    5509          364 :         else if (isread == false && IS_LSIGN(Np->Num) == false &&
    5510           16 :                  (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
    5511              :         {
    5512              : #ifdef DEBUG_TO_FROM_CHAR
    5513              :             elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
    5514              : #endif
    5515              : 
    5516              :             /*
    5517              :              * simple + -
    5518              :              */
    5519            4 :             if (*Np->inout_p == '-' || *Np->inout_p == '+')
    5520              :                 /* NUM_processor() do inout_p++ */
    5521            4 :                 *Np->number = *Np->inout_p;
    5522              :         }
    5523              :     }
    5524              : }
    5525              : 
    5526              : #define IS_PREDEC_SPACE(_n) \
    5527              :         (IS_ZERO((_n)->Num)==false && \
    5528              :          (_n)->number == (_n)->number_p && \
    5529              :          *(_n)->number == '0' && \
    5530              :                  (_n)->Num->post != 0)
    5531              : 
    5532              : /*
    5533              :  * Add digit or sign to number-string
    5534              :  */
    5535              : static void
    5536      5898865 : NUM_numpart_to_char(NUMProc *Np, int id)
    5537              : {
    5538              :     int         end;
    5539              : 
    5540      5898865 :     if (IS_ROMAN(Np->Num))
    5541            0 :         return;
    5542              : 
    5543              :     /* Note: in this elog() output not set '\0' in 'inout' */
    5544              : 
    5545              : #ifdef DEBUG_TO_FROM_CHAR
    5546              : 
    5547              :     /*
    5548              :      * Np->num_curr is number of current item in format-picture, it is not
    5549              :      * current position in inout!
    5550              :      */
    5551              :     elog(DEBUG_elog_output,
    5552              :          "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
    5553              :          Np->sign_wrote,
    5554              :          Np->num_curr,
    5555              :          Np->number_p,
    5556              :          Np->inout);
    5557              : #endif
    5558      5898865 :     Np->num_in = false;
    5559              : 
    5560              :     /*
    5561              :      * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
    5562              :      * handle "9.9" --> " .1"
    5563              :      */
    5564      5898865 :     if (Np->sign_wrote == false &&
    5565         9966 :         (Np->num_curr >= Np->out_pre_spaces || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
    5566         2027 :         (IS_PREDEC_SPACE(Np) == false || (Np->last_relevant && *Np->last_relevant == '.')))
    5567              :     {
    5568         1931 :         if (IS_LSIGN(Np->Num))
    5569              :         {
    5570         1290 :             if (Np->Num->lsign == NUM_LSIGN_PRE)
    5571              :             {
    5572          240 :                 NUM_add_locale_symbol(Np, (Np->sign == '-') ?
    5573              :                                       Np->L_negative_sign :
    5574              :                                       Np->L_positive_sign);
    5575          240 :                 Np->sign_wrote = true;
    5576              :             }
    5577              :         }
    5578          641 :         else if (IS_BRACKET(Np->Num))
    5579              :         {
    5580           96 :             *Np->inout_p = Np->sign == '+' ? ' ' : '<';
    5581           96 :             ++Np->inout_p;
    5582           96 :             Np->sign_wrote = true;
    5583              :         }
    5584          545 :         else if (Np->sign == '+')
    5585              :         {
    5586          365 :             if (!IS_FILLMODE(Np->Num))
    5587              :             {
    5588          365 :                 *Np->inout_p = ' '; /* Write + */
    5589          365 :                 ++Np->inout_p;
    5590              :             }
    5591          365 :             Np->sign_wrote = true;
    5592              :         }
    5593          180 :         else if (Np->sign == '-')
    5594              :         {                       /* Write - */
    5595          180 :             *Np->inout_p = '-';
    5596          180 :             ++Np->inout_p;
    5597          180 :             Np->sign_wrote = true;
    5598              :         }
    5599              :     }
    5600              : 
    5601              : 
    5602              :     /*
    5603              :      * digits / FM / Zero / Dec. point
    5604              :      */
    5605      5898865 :     if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
    5606              :     {
    5607      5898865 :         if (Np->num_curr < Np->out_pre_spaces &&
    5608      3567839 :             (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
    5609              :         {
    5610              :             /*
    5611              :              * Write blank space
    5612              :              */
    5613        10428 :             if (!IS_FILLMODE(Np->Num))
    5614              :             {
    5615         6592 :                 *Np->inout_p = ' '; /* Write ' ' */
    5616         6592 :                 ++Np->inout_p;
    5617              :             }
    5618              :         }
    5619      5888437 :         else if (IS_ZERO(Np->Num) &&
    5620      5870462 :                  Np->num_curr < Np->out_pre_spaces &&
    5621      3557411 :                  Np->Num->zero_start <= Np->num_curr)
    5622              :         {
    5623              :             /*
    5624              :              * Write ZERO
    5625              :              */
    5626      3557411 :             *Np->inout_p = '0'; /* Write '0' */
    5627      3557411 :             ++Np->inout_p;
    5628      3557411 :             Np->num_in = true;
    5629              :         }
    5630              :         else
    5631              :         {
    5632              :             /*
    5633              :              * Write Decimal point
    5634              :              */
    5635      2331026 :             if (*Np->number_p == '.')
    5636              :             {
    5637         1044 :                 if (!Np->last_relevant || *Np->last_relevant != '.')
    5638              :                 {
    5639          924 :                     NUM_add_locale_symbol(Np, Np->decimal); /* Write DEC/D */
    5640              :                 }
    5641              : 
    5642              :                 /*
    5643              :                  * Ora 'n' -- FM9.9 --> 'n.'
    5644              :                  */
    5645          120 :                 else if (IS_FILLMODE(Np->Num) &&
    5646          120 :                          Np->last_relevant && *Np->last_relevant == '.')
    5647              :                 {
    5648          120 :                     NUM_add_locale_symbol(Np, Np->decimal); /* Write DEC/D */
    5649              :                 }
    5650              :             }
    5651              :             else
    5652              :             {
    5653              :                 /*
    5654              :                  * Write Digits
    5655              :                  */
    5656      2329982 :                 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
    5657              :                     id != NUM_0)
    5658              :                     ;
    5659              : 
    5660              :                 /*
    5661              :                  * '0.1' -- 9.9 --> '  .1'
    5662              :                  */
    5663      2325534 :                 else if (IS_PREDEC_SPACE(Np))
    5664              :                 {
    5665          152 :                     if (!IS_FILLMODE(Np->Num))
    5666              :                     {
    5667          104 :                         *Np->inout_p = ' ';
    5668          104 :                         ++Np->inout_p;
    5669              :                     }
    5670              : 
    5671              :                     /*
    5672              :                      * '0' -- FM9.9 --> '0.'
    5673              :                      */
    5674           48 :                     else if (Np->last_relevant && *Np->last_relevant == '.')
    5675              :                     {
    5676           40 :                         *Np->inout_p = '0';
    5677           40 :                         ++Np->inout_p;
    5678              :                     }
    5679              :                 }
    5680              :                 else
    5681              :                 {
    5682      2325382 :                     *Np->inout_p = *Np->number_p; /* Write DIGIT */
    5683      2325382 :                     ++Np->inout_p;
    5684      2325382 :                     Np->num_in = true;
    5685              :                 }
    5686              :             }
    5687              :             /* do no exceed string length */
    5688      2331026 :             if (*Np->number_p)
    5689      2330798 :                 ++Np->number_p;
    5690              :         }
    5691              : 
    5692      5898865 :         end = Np->num_count + (Np->out_pre_spaces ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
    5693              : 
    5694      5898865 :         if (Np->last_relevant && Np->last_relevant == Np->number_p)
    5695          448 :             end = Np->num_curr;
    5696              : 
    5697      5898865 :         if (Np->num_curr + 1 == end)
    5698              :         {
    5699       667034 :             if (Np->sign_wrote == true && IS_BRACKET(Np->Num))
    5700              :             {
    5701           96 :                 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
    5702           96 :                 ++Np->inout_p;
    5703              :             }
    5704       666938 :             else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
    5705              :             {
    5706           61 :                 NUM_add_locale_symbol(Np, (Np->sign == '-') ?
    5707              :                                       Np->L_negative_sign :
    5708              :                                       Np->L_positive_sign);
    5709              :             }
    5710              :         }
    5711              :     }
    5712              : 
    5713      5898865 :     ++Np->num_curr;
    5714              : }
    5715              : 
    5716              : /*
    5717              :  * Append locale-specific symbol to Np->inout.
    5718              :  * Note we don't null-terminate the output
    5719              :  */
    5720              : static void
    5721         1345 : NUM_add_locale_symbol(NUMProc *Np, const char *pattern)
    5722              : {
    5723         1345 :     size_t      pattern_len = strlen(pattern);
    5724              : 
    5725              :     /* Truncate symbol if it's potentially too long */
    5726         1345 :     if (unlikely(pattern_len > NUM_MAX_ITEM_SIZ))
    5727            0 :         pattern_len = pg_mbcliplen(pattern, pattern_len,
    5728              :                                    NUM_MAX_ITEM_SIZ);
    5729         1345 :     memcpy(Np->inout_p, pattern, pattern_len);
    5730         1345 :     Np->inout_p += pattern_len;
    5731         1345 : }
    5732              : 
    5733              : /*
    5734              :  * Skip over "n" input characters, but only if they aren't numeric data
    5735              :  */
    5736              : static void
    5737           24 : NUM_eat_non_data_chars(NUMProc *Np, int n, size_t input_len)
    5738              : {
    5739           24 :     const char *end = Np->inout + input_len;
    5740              : 
    5741           44 :     while (n-- > 0)
    5742              :     {
    5743           28 :         if (OVERLOAD_TEST)
    5744            0 :             break;              /* end of input */
    5745           28 :         if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
    5746            8 :             break;              /* it's a data character */
    5747           20 :         Np->inout_p += pg_mblen_range(Np->inout_p, end);
    5748              :     }
    5749           24 : }
    5750              : 
    5751              : static char *
    5752       699536 : NUM_processor(FormatNode *node, NUMDesc *Num, char *inout,
    5753              :               char *number, size_t input_len, int to_char_out_pre_spaces,
    5754              :               int sign, bool is_to_char, Oid collid)
    5755              : {
    5756              :     FormatNode *n;
    5757              :     NUMProc     _Np,
    5758       699536 :                *Np = &_Np;
    5759              :     const char *pattern;
    5760              :     size_t      pattern_len;
    5761              : 
    5762     12591648 :     MemSet(Np, 0, sizeof(NUMProc));
    5763              : 
    5764       699536 :     Np->Num = Num;
    5765       699536 :     Np->is_to_char = is_to_char;
    5766       699536 :     Np->number = number;
    5767       699536 :     Np->inout = inout;
    5768       699536 :     Np->last_relevant = NULL;
    5769       699536 :     Np->read_post = 0;
    5770       699536 :     Np->read_pre = 0;
    5771       699536 :     Np->read_dec = false;
    5772              : 
    5773       699536 :     if (Np->Num->zero_start)
    5774       665752 :         --Np->Num->zero_start;
    5775              : 
    5776       699536 :     if (IS_EEEE(Np->Num))
    5777              :     {
    5778          224 :         if (!Np->is_to_char)
    5779            0 :             ereport(ERROR,
    5780              :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    5781              :                      errmsg("\"EEEE\" not supported for input")));
    5782          224 :         return strcpy(inout, number);
    5783              :     }
    5784              : 
    5785              :     /*
    5786              :      * Sign
    5787              :      */
    5788       699312 :     if (is_to_char)
    5789              :     {
    5790       683138 :         Np->sign = sign;
    5791              : 
    5792              :         /* MI/PL/SG - write sign itself and not in number */
    5793       683138 :         if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
    5794              :         {
    5795          368 :             if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == false)
    5796           20 :                 Np->sign_wrote = false; /* need sign */
    5797              :             else
    5798          348 :                 Np->sign_wrote = true;   /* needn't sign */
    5799              :         }
    5800              :         else
    5801              :         {
    5802       682770 :             if (Np->sign != '-')
    5803              :             {
    5804       682421 :                 if (IS_FILLMODE(Np->Num))
    5805       665892 :                     Np->Num->flag &= ~NUM_F_BRACKET;
    5806              :             }
    5807              : 
    5808       682770 :             if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == false)
    5809       665756 :                 Np->sign_wrote = true;   /* needn't sign */
    5810              :             else
    5811        17014 :                 Np->sign_wrote = false; /* need sign */
    5812              : 
    5813       682770 :             if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
    5814           20 :                 Np->Num->lsign = NUM_LSIGN_POST;
    5815              :         }
    5816              :     }
    5817              :     else
    5818        16174 :         Np->sign = false;
    5819              : 
    5820              :     /*
    5821              :      * Count
    5822              :      */
    5823       699312 :     Np->num_count = Np->Num->post + Np->Num->pre - 1;
    5824              : 
    5825       699312 :     if (is_to_char)
    5826              :     {
    5827       683138 :         Np->out_pre_spaces = to_char_out_pre_spaces;
    5828              : 
    5829       683138 :         if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
    5830              :         {
    5831          452 :             Np->last_relevant = get_last_relevant_decnum(Np->number);
    5832              : 
    5833              :             /*
    5834              :              * If any '0' specifiers are present, make sure we don't strip
    5835              :              * those digits.  But don't advance last_relevant beyond the last
    5836              :              * character of the Np->number string, which is a hazard if the
    5837              :              * number got shortened due to precision limitations.
    5838              :              */
    5839          452 :             if (Np->last_relevant && Np->Num->zero_end > Np->out_pre_spaces)
    5840              :             {
    5841              :                 size_t      last_zero_pos;
    5842              :                 char       *last_zero;
    5843              : 
    5844              :                 /* note that Np->number cannot be zero-length here */
    5845          184 :                 last_zero_pos = strlen(Np->number) - 1;
    5846          184 :                 last_zero_pos = Min(last_zero_pos,
    5847              :                                     Np->Num->zero_end - Np->out_pre_spaces);
    5848          184 :                 last_zero = Np->number + last_zero_pos;
    5849          184 :                 if (Np->last_relevant < last_zero)
    5850           96 :                     Np->last_relevant = last_zero;
    5851              :             }
    5852              :         }
    5853              : 
    5854       683138 :         if (Np->sign_wrote == false && Np->out_pre_spaces == 0)
    5855        16354 :             ++Np->num_count;
    5856              :     }
    5857              :     else
    5858              :     {
    5859        16174 :         Np->out_pre_spaces = 0;
    5860        16174 :         *Np->number = ' ';       /* sign space */
    5861        16174 :         *(Np->number + 1) = '\0';
    5862              :     }
    5863              : 
    5864       699312 :     Np->num_in = 0;
    5865       699312 :     Np->num_curr = 0;
    5866              : 
    5867              : #ifdef DEBUG_TO_FROM_CHAR
    5868              :     elog(DEBUG_elog_output,
    5869              :          "\n\tSIGN: '%c'\n\tNUM: '%s'\n\tPRE: %d\n\tPOST: %d\n\tNUM_COUNT: %d\n\tNUM_PRE: %d\n\tSIGN_WROTE: %s\n\tZERO: %s\n\tZERO_START: %d\n\tZERO_END: %d\n\tLAST_RELEVANT: %s\n\tBRACKET: %s\n\tPLUS: %s\n\tMINUS: %s\n\tFILLMODE: %s\n\tROMAN: %s\n\tEEEE: %s",
    5870              :          Np->sign,
    5871              :          Np->number,
    5872              :          Np->Num->pre,
    5873              :          Np->Num->post,
    5874              :          Np->num_count,
    5875              :          Np->out_pre_spaces,
    5876              :          Np->sign_wrote ? "Yes" : "No",
    5877              :          IS_ZERO(Np->Num) ? "Yes" : "No",
    5878              :          Np->Num->zero_start,
    5879              :          Np->Num->zero_end,
    5880              :          Np->last_relevant ? Np->last_relevant : "<not set>",
    5881              :          IS_BRACKET(Np->Num) ? "Yes" : "No",
    5882              :          IS_PLUS(Np->Num) ? "Yes" : "No",
    5883              :          IS_MINUS(Np->Num) ? "Yes" : "No",
    5884              :          IS_FILLMODE(Np->Num) ? "Yes" : "No",
    5885              :          IS_ROMAN(Np->Num) ? "Yes" : "No",
    5886              :          IS_EEEE(Np->Num) ? "Yes" : "No"
    5887              :         );
    5888              : #endif
    5889              : 
    5890              :     /*
    5891              :      * Locale
    5892              :      */
    5893       699312 :     NUM_prepare_locale(Np);
    5894              : 
    5895              :     /*
    5896              :      * Processor direct cycle
    5897              :      */
    5898       699312 :     if (Np->is_to_char)
    5899       683138 :         Np->number_p = Np->number;
    5900              :     else
    5901        16174 :         Np->number_p = Np->number + 1;    /* first char is space for sign */
    5902              : 
    5903      7304778 :     for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
    5904              :     {
    5905      6605580 :         if (!Np->is_to_char)
    5906              :         {
    5907              :             /*
    5908              :              * Check at least one byte remains to be scanned.  (In actions
    5909              :              * below, must use AMOUNT_TEST if we want to read more bytes than
    5910              :              * that.)
    5911              :              */
    5912        16878 :             if (OVERLOAD_TEST)
    5913           58 :                 break;
    5914              :         }
    5915              : 
    5916              :         /*
    5917              :          * Format pictures actions
    5918              :          */
    5919      6605522 :         if (n->type == NODE_TYPE_ACTION)
    5920              :         {
    5921              :             /*
    5922              :              * Create/read digit/zero/blank/sign/special-case
    5923              :              *
    5924              :              * 'NUM_S' note: The locale sign is anchored to number and we
    5925              :              * read/write it when we work with first or last number
    5926              :              * (NUM_0/NUM_9).  This is why NUM_S is missing in switch().
    5927              :              *
    5928              :              * Notice the "Np->inout_p++" at the bottom of the loop.  This is
    5929              :              * why most of the actions advance inout_p one less than you might
    5930              :              * expect.  In cases where we don't want that increment to happen,
    5931              :              * a switch case ends with "continue" not "break".
    5932              :              */
    5933      6599754 :             switch (n->key->id)
    5934              :             {
    5935      5899447 :                 case NUM_9:
    5936              :                 case NUM_0:
    5937              :                 case NUM_DEC:
    5938              :                 case NUM_D:
    5939      5899447 :                     if (Np->is_to_char)
    5940              :                     {
    5941      5898865 :                         NUM_numpart_to_char(Np, n->key->id);
    5942      5898865 :                         continue;   /* for() */
    5943              :                     }
    5944              :                     else
    5945              :                     {
    5946          582 :                         NUM_numpart_from_char(Np, n->key->id, input_len);
    5947          582 :                         break;  /* switch() case: */
    5948              :                     }
    5949              : 
    5950          244 :                 case NUM_COMMA:
    5951          244 :                     if (Np->is_to_char)
    5952              :                     {
    5953          220 :                         if (!Np->num_in)
    5954              :                         {
    5955           80 :                             if (IS_FILLMODE(Np->Num))
    5956            0 :                                 continue;
    5957              :                             else
    5958           80 :                                 *Np->inout_p = ' ';
    5959              :                         }
    5960              :                         else
    5961          140 :                             *Np->inout_p = ',';
    5962              :                     }
    5963              :                     else
    5964              :                     {
    5965           24 :                         if (!Np->num_in)
    5966              :                         {
    5967           24 :                             if (IS_FILLMODE(Np->Num))
    5968            0 :                                 continue;
    5969              :                         }
    5970           24 :                         if (*Np->inout_p != ',')
    5971           24 :                             continue;
    5972              :                     }
    5973          220 :                     break;
    5974              : 
    5975          814 :                 case NUM_G:
    5976          814 :                     pattern = Np->L_thousands_sep;
    5977          814 :                     pattern_len = strlen(pattern);
    5978          814 :                     if (Np->is_to_char)
    5979              :                     {
    5980              :                         /* Truncate symbol if it's potentially too long */
    5981          780 :                         if (unlikely(pattern_len > NUM_MAX_ITEM_SIZ))
    5982            0 :                             pattern_len = pg_mbcliplen(pattern, pattern_len,
    5983              :                                                        NUM_MAX_ITEM_SIZ);
    5984          780 :                         if (!Np->num_in)
    5985              :                         {
    5986          392 :                             if (IS_FILLMODE(Np->Num))
    5987            0 :                                 continue;
    5988              :                             else
    5989              :                             {
    5990              :                                 /* just in case there are MB chars */
    5991          392 :                                 pattern_len = pg_mbstrlen_with_len(pattern,
    5992              :                                                                    pattern_len);
    5993          392 :                                 memset(Np->inout_p, ' ', pattern_len);
    5994          392 :                                 Np->inout_p += pattern_len - 1;
    5995              :                             }
    5996              :                         }
    5997              :                         else
    5998              :                         {
    5999          388 :                             memcpy(Np->inout_p, pattern, pattern_len);
    6000          388 :                             Np->inout_p += pattern_len - 1;
    6001              :                         }
    6002              :                     }
    6003              :                     else
    6004              :                     {
    6005              :                         /* Here we do not truncate the symbol ... */
    6006           34 :                         if (!Np->num_in)
    6007              :                         {
    6008           34 :                             if (IS_FILLMODE(Np->Num))
    6009            0 :                                 continue;
    6010              :                         }
    6011              : 
    6012              :                         /*
    6013              :                          * Because L_thousands_sep typically contains data
    6014              :                          * characters (either '.' or ','), we can't use
    6015              :                          * NUM_eat_non_data_chars here.  Instead skip only if
    6016              :                          * the input matches L_thousands_sep.
    6017              :                          */
    6018           34 :                         if (AMOUNT_TEST(pattern_len) &&
    6019           34 :                             strncmp(Np->inout_p, pattern, pattern_len) == 0)
    6020           30 :                             Np->inout_p += pattern_len - 1;
    6021              :                         else
    6022            4 :                             continue;
    6023              :                     }
    6024          810 :                     break;
    6025              : 
    6026           80 :                 case NUM_L:
    6027           80 :                     pattern = Np->L_currency_symbol;
    6028           80 :                     if (Np->is_to_char)
    6029              :                     {
    6030              :                         /* Truncate symbol if it's potentially too long */
    6031           60 :                         pattern_len = strlen(pattern);
    6032           60 :                         if (unlikely(pattern_len > NUM_MAX_ITEM_SIZ))
    6033            0 :                             pattern_len = pg_mbcliplen(pattern, pattern_len,
    6034              :                                                        NUM_MAX_ITEM_SIZ);
    6035              : 
    6036           60 :                         memcpy(Np->inout_p, pattern, pattern_len);
    6037           60 :                         Np->inout_p += pattern_len - 1;
    6038              :                     }
    6039              :                     else
    6040              :                     {
    6041              :                         /* Here we do not truncate the symbol ... */
    6042           20 :                         NUM_eat_non_data_chars(Np, pg_mbstrlen(pattern), input_len);
    6043           20 :                         continue;
    6044              :                     }
    6045           60 :                     break;
    6046              : 
    6047        32160 :                 case NUM_RN:
    6048              :                 case NUM_rn:
    6049        32160 :                     if (Np->is_to_char)
    6050              :                     {
    6051              :                         const char *number_p;
    6052              : 
    6053        16088 :                         if (n->key->id == NUM_rn)
    6054           20 :                             number_p = asc_tolower_z(Np->number_p);
    6055              :                         else
    6056        16068 :                             number_p = Np->number_p;
    6057        16088 :                         if (IS_FILLMODE(Np->Num))
    6058           64 :                             strcpy(Np->inout_p, number_p);
    6059              :                         else
    6060        16024 :                             sprintf(Np->inout_p, "%15s", number_p);
    6061        16088 :                         Np->inout_p += strlen(Np->inout_p) - 1;
    6062              :                     }
    6063              :                     else
    6064        16016 :                     {
    6065        16072 :                         int         roman_result = roman_to_int(Np, input_len);
    6066              :                         int         numlen;
    6067              : 
    6068        16072 :                         if (roman_result < 0)
    6069           56 :                             ereport(ERROR,
    6070              :                                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    6071              :                                      errmsg("invalid Roman numeral")));
    6072        16016 :                         numlen = sprintf(Np->number_p, "%d", roman_result);
    6073        16016 :                         Np->number_p += numlen;
    6074        16016 :                         Np->Num->pre = numlen;
    6075        16016 :                         Np->Num->post = 0;
    6076        16016 :                         continue;   /* roman_to_int ate all the chars */
    6077              :                     }
    6078        16088 :                     break;
    6079              : 
    6080           64 :                 case NUM_th:
    6081           64 :                     if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
    6082           64 :                         Np->sign == '-' || IS_DECIMAL(Np->Num))
    6083           44 :                         continue;
    6084              : 
    6085           20 :                     if (Np->is_to_char)
    6086              :                     {
    6087           16 :                         strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
    6088           16 :                         Np->inout_p += 1;
    6089              :                     }
    6090              :                     else
    6091              :                     {
    6092              :                         /* All variants of 'th' occupy 2 characters */
    6093            4 :                         NUM_eat_non_data_chars(Np, 2, input_len);
    6094            4 :                         continue;
    6095              :                     }
    6096           16 :                     break;
    6097              : 
    6098           60 :                 case NUM_TH:
    6099           60 :                     if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
    6100           60 :                         Np->sign == '-' || IS_DECIMAL(Np->Num))
    6101           44 :                         continue;
    6102              : 
    6103           16 :                     if (Np->is_to_char)
    6104              :                     {
    6105           16 :                         strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
    6106           16 :                         Np->inout_p += 1;
    6107              :                     }
    6108              :                     else
    6109              :                     {
    6110              :                         /* All variants of 'TH' occupy 2 characters */
    6111            0 :                         NUM_eat_non_data_chars(Np, 2, input_len);
    6112            0 :                         continue;
    6113              :                     }
    6114           16 :                     break;
    6115              : 
    6116          228 :                 case NUM_MI:
    6117          228 :                     if (Np->is_to_char)
    6118              :                     {
    6119          228 :                         if (Np->sign == '-')
    6120           64 :                             *Np->inout_p = '-';
    6121          164 :                         else if (IS_FILLMODE(Np->Num))
    6122            0 :                             continue;
    6123              :                         else
    6124          164 :                             *Np->inout_p = ' ';
    6125              :                     }
    6126              :                     else
    6127              :                     {
    6128            0 :                         if (*Np->inout_p == '-')
    6129            0 :                             *Np->number = '-';
    6130              :                         else
    6131              :                         {
    6132            0 :                             NUM_eat_non_data_chars(Np, 1, input_len);
    6133            0 :                             continue;
    6134              :                         }
    6135              :                     }
    6136          228 :                     break;
    6137              : 
    6138           20 :                 case NUM_PL:
    6139           20 :                     if (Np->is_to_char)
    6140              :                     {
    6141           20 :                         if (Np->sign == '+')
    6142           16 :                             *Np->inout_p = '+';
    6143            4 :                         else if (IS_FILLMODE(Np->Num))
    6144            0 :                             continue;
    6145              :                         else
    6146            4 :                             *Np->inout_p = ' ';
    6147              :                     }
    6148              :                     else
    6149              :                     {
    6150            0 :                         if (*Np->inout_p == '+')
    6151            0 :                             *Np->number = '+';
    6152              :                         else
    6153              :                         {
    6154            0 :                             NUM_eat_non_data_chars(Np, 1, input_len);
    6155            0 :                             continue;
    6156              :                         }
    6157              :                     }
    6158           20 :                     break;
    6159              : 
    6160          120 :                 case NUM_SG:
    6161          120 :                     if (Np->is_to_char)
    6162          120 :                         *Np->inout_p = Np->sign;
    6163              :                     else
    6164              :                     {
    6165            0 :                         if (*Np->inout_p == '-')
    6166            0 :                             *Np->number = '-';
    6167            0 :                         else if (*Np->inout_p == '+')
    6168            0 :                             *Np->number = '+';
    6169              :                         else
    6170              :                         {
    6171            0 :                             NUM_eat_non_data_chars(Np, 1, input_len);
    6172            0 :                             continue;
    6173              :                         }
    6174              :                     }
    6175          120 :                     break;
    6176              : 
    6177       666517 :                 default:
    6178       666517 :                     continue;
    6179              :                     break;
    6180              :             }
    6181              :         }
    6182              :         else
    6183              :         {
    6184              :             /*
    6185              :              * In TO_CHAR, non-pattern characters in the format are copied to
    6186              :              * the output.  In TO_NUMBER, we skip one input character for each
    6187              :              * non-pattern format character, whether or not it matches the
    6188              :              * format character.
    6189              :              */
    6190         5768 :             if (Np->is_to_char)
    6191              :             {
    6192         5708 :                 strcpy(Np->inout_p, n->character);
    6193         5708 :                 Np->inout_p += strlen(Np->inout_p);
    6194              :             }
    6195              :             else
    6196              :             {
    6197           60 :                 Np->inout_p += pg_mblen_range(Np->inout_p, Np->inout + input_len);
    6198              :             }
    6199         5768 :             continue;
    6200              :         }
    6201        18160 :         Np->inout_p++;
    6202              :     }
    6203              : 
    6204       699256 :     if (Np->is_to_char)
    6205              :     {
    6206       683138 :         *Np->inout_p = '\0';
    6207       683138 :         return Np->inout;
    6208              :     }
    6209              :     else
    6210              :     {
    6211        16118 :         if (*(Np->number_p - 1) == '.')
    6212            0 :             *(Np->number_p - 1) = '\0';
    6213              :         else
    6214        16118 :             *Np->number_p = '\0';
    6215              : 
    6216              :         /*
    6217              :          * Correction - precision of dec. number
    6218              :          */
    6219        16118 :         Np->Num->post = Np->read_post;
    6220              : 
    6221              : #ifdef DEBUG_TO_FROM_CHAR
    6222              :         elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
    6223              : #endif
    6224        16118 :         return Np->number;
    6225              :     }
    6226              : }
    6227              : 
    6228              : /*
    6229              :  * MACRO: Start part of NUM - for all NUM's to_char variants
    6230              :  *  (sorry, but I hate copy same code - macro is better..)
    6231              :  */
    6232              : #define NUM_TOCHAR_prepare \
    6233              : do { \
    6234              :     int len = VARSIZE_ANY_EXHDR(fmt); \
    6235              :     if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ)       \
    6236              :         PG_RETURN_TEXT_P(cstring_to_text("")); \
    6237              :     result  = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ);    \
    6238              :     format  = NUM_cache(len, &Num, fmt, &shouldFree);       \
    6239              : } while (0)
    6240              : 
    6241              : /*
    6242              :  * MACRO: Finish part of NUM
    6243              :  */
    6244              : #define NUM_TOCHAR_finish \
    6245              : do { \
    6246              :     size_t  len; \
    6247              :                                     \
    6248              :     NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \
    6249              :                                     \
    6250              :     if (shouldFree)                 \
    6251              :         pfree(format);              \
    6252              :                                     \
    6253              :     /*                              \
    6254              :      * Convert null-terminated representation of result to standard text. \
    6255              :      * The result is usually much bigger than it needs to be, but there \
    6256              :      * seems little point in realloc'ing it smaller. \
    6257              :      */                             \
    6258              :     len = strlen(VARDATA(result));  \
    6259              :     SET_VARSIZE(result, len + VARHDRSZ); \
    6260              : } while (0)
    6261              : 
    6262              : /*
    6263              :  * NUMERIC to_number() (convert string to numeric)
    6264              :  */
    6265              : Datum
    6266        16182 : numeric_to_number(PG_FUNCTION_ARGS)
    6267              : {
    6268        16182 :     text       *value = PG_GETARG_TEXT_PP(0);
    6269        16182 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    6270              :     NUMDesc     Num;
    6271              :     Datum       result;
    6272              :     FormatNode *format;
    6273              :     char       *numstr;
    6274              :     bool        shouldFree;
    6275        16182 :     int         len = 0;
    6276              :     int         scale,
    6277              :                 precision;
    6278              : 
    6279        16182 :     len = VARSIZE_ANY_EXHDR(fmt);
    6280              : 
    6281        16182 :     if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
    6282            0 :         PG_RETURN_NULL();
    6283              : 
    6284        16182 :     format = NUM_cache(len, &Num, fmt, &shouldFree);
    6285              : 
    6286        16174 :     numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
    6287              : 
    6288        16174 :     NUM_processor(format, &Num, VARDATA_ANY(value), numstr,
    6289              :                   VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
    6290              : 
    6291        16118 :     scale = Num.post;
    6292        16118 :     precision = Num.pre + Num.multi + scale;
    6293              : 
    6294        16118 :     if (shouldFree)
    6295            0 :         pfree(format);
    6296              : 
    6297        16118 :     result = DirectFunctionCall3(numeric_in,
    6298              :                                  CStringGetDatum(numstr),
    6299              :                                  ObjectIdGetDatum(InvalidOid),
    6300              :                                  Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
    6301              : 
    6302        16114 :     if (IS_MULTI(&Num))
    6303              :     {
    6304              :         Numeric     x;
    6305            4 :         Numeric     a = int64_to_numeric(10);
    6306            4 :         Numeric     b = int64_to_numeric(-Num.multi);
    6307              : 
    6308            4 :         x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
    6309              :                                                 NumericGetDatum(a),
    6310              :                                                 NumericGetDatum(b)));
    6311            4 :         result = DirectFunctionCall2(numeric_mul,
    6312              :                                      result,
    6313              :                                      NumericGetDatum(x));
    6314              :     }
    6315              : 
    6316        16114 :     pfree(numstr);
    6317        16114 :     return result;
    6318              : }
    6319              : 
    6320              : /*
    6321              :  * NUMERIC to_char()
    6322              :  */
    6323              : Datum
    6324         1201 : numeric_to_char(PG_FUNCTION_ARGS)
    6325              : {
    6326         1201 :     Numeric     value = PG_GETARG_NUMERIC(0);
    6327         1201 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    6328              :     NUMDesc     Num;
    6329              :     FormatNode *format;
    6330              :     text       *result;
    6331              :     bool        shouldFree;
    6332         1201 :     int         out_pre_spaces = 0,
    6333         1201 :                 sign = 0;
    6334              :     char       *numstr,
    6335              :                *orgnum,
    6336              :                *p;
    6337              : 
    6338         1201 :     NUM_TOCHAR_prepare;
    6339              : 
    6340              :     /*
    6341              :      * On DateType depend part (numeric)
    6342              :      */
    6343         1201 :     if (IS_ROMAN(&Num))
    6344              :     {
    6345              :         int32       intvalue;
    6346           52 :         ErrorSaveContext escontext = {T_ErrorSaveContext};
    6347              : 
    6348              :         /* Round and convert to int */
    6349           52 :         intvalue = numeric_int4_safe(value, (Node *) &escontext);
    6350              :         /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
    6351           52 :         if (escontext.error_occurred)
    6352            4 :             intvalue = PG_INT32_MAX;
    6353           52 :         numstr = int_to_roman(intvalue);
    6354              :     }
    6355         1149 :     else if (IS_EEEE(&Num))
    6356              :     {
    6357          156 :         orgnum = numeric_out_sci(value, Num.post);
    6358              : 
    6359              :         /*
    6360              :          * numeric_out_sci() does not emit a sign for positive numbers.  We
    6361              :          * need to add a space in this case so that positive and negative
    6362              :          * numbers are aligned.  Also must check for NaN/infinity cases, which
    6363              :          * we handle the same way as in float8_to_char.
    6364              :          */
    6365          156 :         if (strcmp(orgnum, "NaN") == 0 ||
    6366          152 :             strcmp(orgnum, "Infinity") == 0 ||
    6367          148 :             strcmp(orgnum, "-Infinity") == 0)
    6368              :         {
    6369              :             /*
    6370              :              * Allow 6 characters for the leading sign, the decimal point,
    6371              :              * "e", the exponent's sign and two exponent digits.
    6372              :              */
    6373           12 :             numstr = (char *) palloc(Num.pre + Num.post + 7);
    6374           12 :             fill_str(numstr, '#', Num.pre + Num.post + 6);
    6375           12 :             *numstr = ' ';
    6376           12 :             *(numstr + Num.pre + 1) = '.';
    6377              :         }
    6378          144 :         else if (*orgnum != '-')
    6379              :         {
    6380          128 :             numstr = (char *) palloc(strlen(orgnum) + 2);
    6381          128 :             *numstr = ' ';
    6382          128 :             strcpy(numstr + 1, orgnum);
    6383              :         }
    6384              :         else
    6385              :         {
    6386           16 :             numstr = orgnum;
    6387              :         }
    6388              :     }
    6389              :     else
    6390              :     {
    6391              :         size_t      numstr_pre_len;
    6392          993 :         Numeric     val = value;
    6393              :         Numeric     x;
    6394              : 
    6395          993 :         if (IS_MULTI(&Num))
    6396              :         {
    6397            4 :             Numeric     a = int64_to_numeric(10);
    6398            4 :             Numeric     b = int64_to_numeric(Num.multi);
    6399              : 
    6400            4 :             x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
    6401              :                                                     NumericGetDatum(a),
    6402              :                                                     NumericGetDatum(b)));
    6403            4 :             val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
    6404              :                                                       NumericGetDatum(value),
    6405              :                                                       NumericGetDatum(x)));
    6406            4 :             Num.pre += Num.multi;
    6407              :         }
    6408              : 
    6409          993 :         x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
    6410              :                                                 NumericGetDatum(val),
    6411              :                                                 Int32GetDatum(Num.post)));
    6412          993 :         orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
    6413              :                                                      NumericGetDatum(x)));
    6414              : 
    6415          993 :         if (*orgnum == '-')
    6416              :         {
    6417          281 :             sign = '-';
    6418          281 :             numstr = orgnum + 1;
    6419              :         }
    6420              :         else
    6421              :         {
    6422          712 :             sign = '+';
    6423          712 :             numstr = orgnum;
    6424              :         }
    6425              : 
    6426          993 :         if ((p = strchr(numstr, '.')))
    6427          797 :             numstr_pre_len = p - numstr;
    6428              :         else
    6429          196 :             numstr_pre_len = strlen(numstr);
    6430              : 
    6431              :         /* needs padding? */
    6432          993 :         if (numstr_pre_len < Num.pre)
    6433          920 :             out_pre_spaces = Num.pre - numstr_pre_len;
    6434              :         /* overflowed prefix digit format? */
    6435           73 :         else if (numstr_pre_len > Num.pre)
    6436              :         {
    6437           20 :             numstr = (char *) palloc(Num.pre + Num.post + 2);
    6438           20 :             fill_str(numstr, '#', Num.pre + Num.post + 1);
    6439           20 :             *(numstr + Num.pre) = '.';
    6440              :         }
    6441              :     }
    6442              : 
    6443         1201 :     NUM_TOCHAR_finish;
    6444         1201 :     PG_RETURN_TEXT_P(result);
    6445              : }
    6446              : 
    6447              : /*
    6448              :  * INT4 to_char()
    6449              :  */
    6450              : Datum
    6451       681477 : int4_to_char(PG_FUNCTION_ARGS)
    6452              : {
    6453       681477 :     int32       value = PG_GETARG_INT32(0);
    6454       681477 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    6455              :     NUMDesc     Num;
    6456              :     FormatNode *format;
    6457              :     text       *result;
    6458              :     bool        shouldFree;
    6459       681477 :     int         out_pre_spaces = 0,
    6460       681477 :                 sign = 0;
    6461              :     char       *numstr,
    6462              :                *orgnum;
    6463              : 
    6464       681477 :     NUM_TOCHAR_prepare;
    6465              : 
    6466              :     /*
    6467              :      * On DateType depend part (int32)
    6468              :      */
    6469       681477 :     if (IS_ROMAN(&Num))
    6470        15996 :         numstr = int_to_roman(value);
    6471       665481 :     else if (IS_EEEE(&Num))
    6472              :     {
    6473              :         /* we can do it easily because float8 won't lose any precision */
    6474            4 :         float8      val = (float8) value;
    6475              : 
    6476            4 :         orgnum = (char *) psprintf("%+.*e", Num.post, val);
    6477              : 
    6478              :         /*
    6479              :          * Swap a leading positive sign for a space.
    6480              :          */
    6481            4 :         if (*orgnum == '+')
    6482            4 :             *orgnum = ' ';
    6483              : 
    6484            4 :         numstr = orgnum;
    6485              :     }
    6486              :     else
    6487              :     {
    6488              :         size_t      numstr_pre_len;
    6489              : 
    6490       665477 :         if (IS_MULTI(&Num))
    6491              :         {
    6492            4 :             orgnum = DatumGetCString(DirectFunctionCall1(int4out,
    6493              :                                                          Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
    6494            4 :             Num.pre += Num.multi;
    6495              :         }
    6496              :         else
    6497              :         {
    6498       665473 :             orgnum = DatumGetCString(DirectFunctionCall1(int4out,
    6499              :                                                          Int32GetDatum(value)));
    6500              :         }
    6501              : 
    6502       665477 :         if (*orgnum == '-')
    6503              :         {
    6504            0 :             sign = '-';
    6505            0 :             orgnum++;
    6506              :         }
    6507              :         else
    6508       665477 :             sign = '+';
    6509              : 
    6510       665477 :         numstr_pre_len = strlen(orgnum);
    6511              : 
    6512              :         /* post-decimal digits?  Pad out with zeros. */
    6513       665477 :         if (Num.post)
    6514              :         {
    6515            0 :             numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
    6516            0 :             strcpy(numstr, orgnum);
    6517            0 :             *(numstr + numstr_pre_len) = '.';
    6518            0 :             memset(numstr + numstr_pre_len + 1, '0', Num.post);
    6519            0 :             *(numstr + numstr_pre_len + Num.post + 1) = '\0';
    6520              :         }
    6521              :         else
    6522       665477 :             numstr = orgnum;
    6523              : 
    6524              :         /* needs padding? */
    6525       665477 :         if (numstr_pre_len < Num.pre)
    6526       655941 :             out_pre_spaces = Num.pre - numstr_pre_len;
    6527              :         /* overflowed prefix digit format? */
    6528         9536 :         else if (numstr_pre_len > Num.pre)
    6529              :         {
    6530            0 :             numstr = (char *) palloc(Num.pre + Num.post + 2);
    6531            0 :             fill_str(numstr, '#', Num.pre + Num.post + 1);
    6532            0 :             *(numstr + Num.pre) = '.';
    6533              :         }
    6534              :     }
    6535              : 
    6536       681477 :     NUM_TOCHAR_finish;
    6537       681477 :     PG_RETURN_TEXT_P(result);
    6538              : }
    6539              : 
    6540              : /*
    6541              :  * INT8 to_char()
    6542              :  */
    6543              : Datum
    6544          473 : int8_to_char(PG_FUNCTION_ARGS)
    6545              : {
    6546          473 :     int64       value = PG_GETARG_INT64(0);
    6547          473 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    6548              :     NUMDesc     Num;
    6549              :     FormatNode *format;
    6550              :     text       *result;
    6551              :     bool        shouldFree;
    6552          473 :     int         out_pre_spaces = 0,
    6553          473 :                 sign = 0;
    6554              :     char       *numstr,
    6555              :                *orgnum;
    6556              : 
    6557          473 :     NUM_TOCHAR_prepare;
    6558              : 
    6559              :     /*
    6560              :      * On DateType depend part (int64)
    6561              :      */
    6562          473 :     if (IS_ROMAN(&Num))
    6563              :     {
    6564              :         int32       intvalue;
    6565              : 
    6566              :         /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
    6567           20 :         if (value <= PG_INT32_MAX && value >= PG_INT32_MIN)
    6568            8 :             intvalue = (int32) value;
    6569              :         else
    6570           12 :             intvalue = PG_INT32_MAX;
    6571           20 :         numstr = int_to_roman(intvalue);
    6572              :     }
    6573          453 :     else if (IS_EEEE(&Num))
    6574              :     {
    6575              :         /* to avoid loss of precision, must go via numeric not float8 */
    6576            8 :         orgnum = numeric_out_sci(int64_to_numeric(value),
    6577              :                                  Num.post);
    6578              : 
    6579              :         /*
    6580              :          * numeric_out_sci() does not emit a sign for positive numbers.  We
    6581              :          * need to add a space in this case so that positive and negative
    6582              :          * numbers are aligned.  We don't have to worry about NaN/inf here.
    6583              :          */
    6584            8 :         if (*orgnum != '-')
    6585              :         {
    6586            4 :             numstr = (char *) palloc(strlen(orgnum) + 2);
    6587            4 :             *numstr = ' ';
    6588            4 :             strcpy(numstr + 1, orgnum);
    6589              :         }
    6590              :         else
    6591              :         {
    6592            4 :             numstr = orgnum;
    6593              :         }
    6594              :     }
    6595              :     else
    6596              :     {
    6597              :         size_t      numstr_pre_len;
    6598              : 
    6599          445 :         if (IS_MULTI(&Num))
    6600              :         {
    6601            4 :             double      multi = pow((double) 10, (double) Num.multi);
    6602              : 
    6603            4 :             value = DatumGetInt64(DirectFunctionCall2(int8mul,
    6604              :                                                       Int64GetDatum(value),
    6605              :                                                       DirectFunctionCall1(dtoi8,
    6606              :                                                                           Float8GetDatum(multi))));
    6607            4 :             Num.pre += Num.multi;
    6608              :         }
    6609              : 
    6610          445 :         orgnum = DatumGetCString(DirectFunctionCall1(int8out,
    6611              :                                                      Int64GetDatum(value)));
    6612              : 
    6613          445 :         if (*orgnum == '-')
    6614              :         {
    6615          136 :             sign = '-';
    6616          136 :             orgnum++;
    6617              :         }
    6618              :         else
    6619          309 :             sign = '+';
    6620              : 
    6621          445 :         numstr_pre_len = strlen(orgnum);
    6622              : 
    6623              :         /* post-decimal digits?  Pad out with zeros. */
    6624          445 :         if (Num.post)
    6625              :         {
    6626          140 :             numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
    6627          140 :             strcpy(numstr, orgnum);
    6628          140 :             *(numstr + numstr_pre_len) = '.';
    6629          140 :             memset(numstr + numstr_pre_len + 1, '0', Num.post);
    6630          140 :             *(numstr + numstr_pre_len + Num.post + 1) = '\0';
    6631              :         }
    6632              :         else
    6633          305 :             numstr = orgnum;
    6634              : 
    6635              :         /* needs padding? */
    6636          445 :         if (numstr_pre_len < Num.pre)
    6637          180 :             out_pre_spaces = Num.pre - numstr_pre_len;
    6638              :         /* overflowed prefix digit format? */
    6639          265 :         else if (numstr_pre_len > Num.pre)
    6640              :         {
    6641            0 :             numstr = (char *) palloc(Num.pre + Num.post + 2);
    6642            0 :             fill_str(numstr, '#', Num.pre + Num.post + 1);
    6643            0 :             *(numstr + Num.pre) = '.';
    6644              :         }
    6645              :     }
    6646              : 
    6647          473 :     NUM_TOCHAR_finish;
    6648          473 :     PG_RETURN_TEXT_P(result);
    6649              : }
    6650              : 
    6651              : /*
    6652              :  * FLOAT4 to_char()
    6653              :  */
    6654              : Datum
    6655           98 : float4_to_char(PG_FUNCTION_ARGS)
    6656              : {
    6657           98 :     float4      value = PG_GETARG_FLOAT4(0);
    6658           98 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    6659              :     NUMDesc     Num;
    6660              :     FormatNode *format;
    6661              :     text       *result;
    6662              :     bool        shouldFree;
    6663           98 :     int         out_pre_spaces = 0,
    6664           98 :                 sign = 0;
    6665              :     char       *numstr,
    6666              :                *p;
    6667              : 
    6668           98 :     NUM_TOCHAR_prepare;
    6669              : 
    6670           98 :     if (IS_ROMAN(&Num))
    6671              :     {
    6672              :         int32       intvalue;
    6673              : 
    6674              :         /* See notes in ftoi4() */
    6675            8 :         value = rint(value);
    6676              :         /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
    6677            8 :         if (!isnan(value) && FLOAT4_FITS_IN_INT32(value))
    6678            4 :             intvalue = (int32) value;
    6679              :         else
    6680            4 :             intvalue = PG_INT32_MAX;
    6681            8 :         numstr = int_to_roman(intvalue);
    6682              :     }
    6683           90 :     else if (IS_EEEE(&Num))
    6684              :     {
    6685           28 :         if (isnan(value) || isinf(value))
    6686              :         {
    6687              :             /*
    6688              :              * Allow 6 characters for the leading sign, the decimal point,
    6689              :              * "e", the exponent's sign and two exponent digits.
    6690              :              */
    6691           12 :             numstr = (char *) palloc(Num.pre + Num.post + 7);
    6692           12 :             fill_str(numstr, '#', Num.pre + Num.post + 6);
    6693           12 :             *numstr = ' ';
    6694           12 :             *(numstr + Num.pre + 1) = '.';
    6695              :         }
    6696              :         else
    6697              :         {
    6698           16 :             numstr = psprintf("%+.*e", Num.post, value);
    6699              : 
    6700              :             /*
    6701              :              * Swap a leading positive sign for a space.
    6702              :              */
    6703           16 :             if (*numstr == '+')
    6704           12 :                 *numstr = ' ';
    6705              :         }
    6706              :     }
    6707              :     else
    6708              :     {
    6709           62 :         float4      val = value;
    6710              :         char       *orgnum;
    6711              :         size_t      numstr_pre_len;
    6712              : 
    6713           62 :         if (IS_MULTI(&Num))
    6714              :         {
    6715            4 :             float       multi = pow((double) 10, (double) Num.multi);
    6716              : 
    6717            4 :             val = value * multi;
    6718            4 :             Num.pre += Num.multi;
    6719              :         }
    6720              : 
    6721           62 :         orgnum = psprintf("%.0f", fabs(val));
    6722           62 :         numstr_pre_len = strlen(orgnum);
    6723              : 
    6724              :         /* adjust post digits to fit max float digits */
    6725           62 :         if (numstr_pre_len >= FLT_DIG)
    6726           28 :             Num.post = 0;
    6727           34 :         else if (numstr_pre_len + Num.post > FLT_DIG)
    6728            0 :             Num.post = FLT_DIG - numstr_pre_len;
    6729           62 :         orgnum = psprintf("%.*f", Num.post, val);
    6730              : 
    6731           62 :         if (*orgnum == '-')
    6732              :         {                       /* < 0 */
    6733           16 :             sign = '-';
    6734           16 :             numstr = orgnum + 1;
    6735              :         }
    6736              :         else
    6737              :         {
    6738           46 :             sign = '+';
    6739           46 :             numstr = orgnum;
    6740              :         }
    6741              : 
    6742           62 :         if ((p = strchr(numstr, '.')))
    6743           26 :             numstr_pre_len = p - numstr;
    6744              :         else
    6745           36 :             numstr_pre_len = strlen(numstr);
    6746              : 
    6747              :         /* needs padding? */
    6748           62 :         if (numstr_pre_len < Num.pre)
    6749           40 :             out_pre_spaces = Num.pre - numstr_pre_len;
    6750              :         /* overflowed prefix digit format? */
    6751           22 :         else if (numstr_pre_len > Num.pre)
    6752              :         {
    6753           16 :             numstr = (char *) palloc(Num.pre + Num.post + 2);
    6754           16 :             fill_str(numstr, '#', Num.pre + Num.post + 1);
    6755           16 :             *(numstr + Num.pre) = '.';
    6756              :         }
    6757              :     }
    6758              : 
    6759           98 :     NUM_TOCHAR_finish;
    6760           98 :     PG_RETURN_TEXT_P(result);
    6761              : }
    6762              : 
    6763              : /*
    6764              :  * FLOAT8 to_char()
    6765              :  */
    6766              : Datum
    6767          113 : float8_to_char(PG_FUNCTION_ARGS)
    6768              : {
    6769          113 :     float8      value = PG_GETARG_FLOAT8(0);
    6770          113 :     text       *fmt = PG_GETARG_TEXT_PP(1);
    6771              :     NUMDesc     Num;
    6772              :     FormatNode *format;
    6773              :     text       *result;
    6774              :     bool        shouldFree;
    6775          113 :     int         out_pre_spaces = 0,
    6776          113 :                 sign = 0;
    6777              :     char       *numstr,
    6778              :                *p;
    6779              : 
    6780          113 :     NUM_TOCHAR_prepare;
    6781              : 
    6782          113 :     if (IS_ROMAN(&Num))
    6783              :     {
    6784              :         int32       intvalue;
    6785              : 
    6786              :         /* See notes in dtoi4() */
    6787           12 :         value = rint(value);
    6788              :         /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
    6789           12 :         if (!isnan(value) && FLOAT8_FITS_IN_INT32(value))
    6790            8 :             intvalue = (int32) value;
    6791              :         else
    6792            4 :             intvalue = PG_INT32_MAX;
    6793           12 :         numstr = int_to_roman(intvalue);
    6794              :     }
    6795          101 :     else if (IS_EEEE(&Num))
    6796              :     {
    6797           28 :         if (isnan(value) || isinf(value))
    6798              :         {
    6799              :             /*
    6800              :              * Allow 6 characters for the leading sign, the decimal point,
    6801              :              * "e", the exponent's sign and two exponent digits.
    6802              :              */
    6803           12 :             numstr = (char *) palloc(Num.pre + Num.post + 7);
    6804           12 :             fill_str(numstr, '#', Num.pre + Num.post + 6);
    6805           12 :             *numstr = ' ';
    6806           12 :             *(numstr + Num.pre + 1) = '.';
    6807              :         }
    6808              :         else
    6809              :         {
    6810           16 :             numstr = psprintf("%+.*e", Num.post, value);
    6811              : 
    6812              :             /*
    6813              :              * Swap a leading positive sign for a space.
    6814              :              */
    6815           16 :             if (*numstr == '+')
    6816           12 :                 *numstr = ' ';
    6817              :         }
    6818              :     }
    6819              :     else
    6820              :     {
    6821           73 :         float8      val = value;
    6822              :         char       *orgnum;
    6823              :         size_t      numstr_pre_len;
    6824              : 
    6825           73 :         if (IS_MULTI(&Num))
    6826              :         {
    6827            4 :             double      multi = pow((double) 10, (double) Num.multi);
    6828              : 
    6829            4 :             val = value * multi;
    6830            4 :             Num.pre += Num.multi;
    6831              :         }
    6832              : 
    6833           73 :         orgnum = psprintf("%.0f", fabs(val));
    6834           73 :         numstr_pre_len = strlen(orgnum);
    6835              : 
    6836              :         /* adjust post digits to fit max double digits */
    6837           73 :         if (numstr_pre_len >= DBL_DIG)
    6838            4 :             Num.post = 0;
    6839           69 :         else if (numstr_pre_len + Num.post > DBL_DIG)
    6840            4 :             Num.post = DBL_DIG - numstr_pre_len;
    6841           73 :         orgnum = psprintf("%.*f", Num.post, val);
    6842              : 
    6843           73 :         if (*orgnum == '-')
    6844              :         {                       /* < 0 */
    6845           16 :             sign = '-';
    6846           16 :             numstr = orgnum + 1;
    6847              :         }
    6848              :         else
    6849              :         {
    6850           57 :             sign = '+';
    6851           57 :             numstr = orgnum;
    6852              :         }
    6853              : 
    6854           73 :         if ((p = strchr(numstr, '.')))
    6855           41 :             numstr_pre_len = p - numstr;
    6856              :         else
    6857           32 :             numstr_pre_len = strlen(numstr);
    6858              : 
    6859              :         /* needs padding? */
    6860           73 :         if (numstr_pre_len < Num.pre)
    6861           44 :             out_pre_spaces = Num.pre - numstr_pre_len;
    6862              :         /* overflowed prefix digit format? */
    6863           29 :         else if (numstr_pre_len > Num.pre)
    6864              :         {
    6865           20 :             numstr = (char *) palloc(Num.pre + Num.post + 2);
    6866           20 :             fill_str(numstr, '#', Num.pre + Num.post + 1);
    6867           20 :             *(numstr + Num.pre) = '.';
    6868              :         }
    6869              :     }
    6870              : 
    6871          113 :     NUM_TOCHAR_finish;
    6872          113 :     PG_RETURN_TEXT_P(result);
    6873              : }
        

Generated by: LCOV version 2.0-1