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

Generated by: LCOV version 1.13