LCOV - code coverage report
Current view: top level - src/backend/utils/adt - formatting.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 85.8 % 2419 2075
Test Date: 2026-07-03 19:57:34 Functions: 94.4 % 72 68
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 66.6 % 2384 1587

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

Generated by: LCOV version 2.0-1