LCOV - code coverage report
Current view: top level - src/backend/utils/adt - formatting.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 86.5 % 2782 2407
Test Date: 2026-01-26 10:56:24 Functions: 94.4 % 71 67
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 63.6 % 2478 1575

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

Generated by: LCOV version 2.3.2-1