LCOV - code coverage report
Current view: top level - src/backend/utils/adt - formatting.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 1979 2317 85.4 %
Date: 2025-01-18 04:15:08 Functions: 59 63 93.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14