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

Generated by: LCOV version 1.16