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

Generated by: LCOV version 1.14