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

Generated by: LCOV version 1.13