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

Generated by: LCOV version 1.14