Header And Logo

PostgreSQL
| The world's most advanced open source database.

formatting.c

Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002  * formatting.c
00003  *
00004  * src/backend/utils/adt/formatting.c
00005  *
00006  *
00007  *   Portions Copyright (c) 1999-2013, PostgreSQL Global Development Group
00008  *
00009  *
00010  *   TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER();
00011  *
00012  *   The PostgreSQL routines for a timestamp/int/float/numeric formatting,
00013  *   inspired by the Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines.
00014  *
00015  *
00016  *   Cache & Memory:
00017  *  Routines use (itself) internal cache for format pictures.
00018  *
00019  *  The cache uses a static buffer and is persistent across transactions.  If
00020  *  the format-picture is bigger than the cache buffer, the parser is called
00021  *  always.
00022  *
00023  *   NOTE for Number version:
00024  *  All in this version is implemented as keywords ( => not used
00025  *  suffixes), because a format picture is for *one* item (number)
00026  *  only. It not is as a timestamp version, where each keyword (can)
00027  *  has suffix.
00028  *
00029  *   NOTE for Timestamp routines:
00030  *  In this module the POSIX 'struct tm' type is *not* used, but rather
00031  *  PgSQL type, which has tm_mon based on one (*non* zero) and
00032  *  year *not* based on 1900, but is used full year number.
00033  *  Module supports AD / BC / AM / PM.
00034  *
00035  *  Supported types for to_char():
00036  *
00037  *      Timestamp, Numeric, int4, int8, float4, float8
00038  *
00039  *  Supported types for reverse conversion:
00040  *
00041  *      Timestamp   - to_timestamp()
00042  *      Date        - to_date()
00043  *      Numeric     - to_number()
00044  *
00045  *
00046  *  Karel Zak
00047  *
00048  * TODO
00049  *  - better number building (formatting) / parsing, now it isn't
00050  *        ideal code
00051  *  - use Assert()
00052  *  - add support for abstime
00053  *  - add support for roman number to standard number conversion
00054  *  - add support for number spelling
00055  *  - add support for string to string formatting (we must be better
00056  *    than Oracle :-),
00057  *      to_char('Hello', 'X X X X X') -> 'H e l l o'
00058  *
00059  * -----------------------------------------------------------------------
00060  */
00061 
00062 #ifdef DEBUG_TO_FROM_CHAR
00063 #define DEBUG_elog_output   DEBUG3
00064 #endif
00065 
00066 #include "postgres.h"
00067 
00068 #include <ctype.h>
00069 #include <unistd.h>
00070 #include <math.h>
00071 #include <float.h>
00072 #include <limits.h>
00073 
00074 /*
00075  * towlower() and friends should be in <wctype.h>, but some pre-C99 systems
00076  * declare them in <wchar.h>.
00077  */
00078 #ifdef HAVE_WCHAR_H
00079 #include <wchar.h>
00080 #endif
00081 #ifdef HAVE_WCTYPE_H
00082 #include <wctype.h>
00083 #endif
00084 
00085 #include "catalog/pg_collation.h"
00086 #include "mb/pg_wchar.h"
00087 #include "utils/builtins.h"
00088 #include "utils/date.h"
00089 #include "utils/datetime.h"
00090 #include "utils/formatting.h"
00091 #include "utils/int8.h"
00092 #include "utils/numeric.h"
00093 #include "utils/pg_locale.h"
00094 
00095 /* ----------
00096  * Routines type
00097  * ----------
00098  */
00099 #define DCH_TYPE        1       /* DATE-TIME version    */
00100 #define NUM_TYPE        2       /* NUMBER version   */
00101 
00102 /* ----------
00103  * KeyWord Index (ascii from position 32 (' ') to 126 (~))
00104  * ----------
00105  */
00106 #define KeyWord_INDEX_SIZE      ('~' - ' ')
00107 #define KeyWord_INDEX_FILTER(_c)    ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
00108 
00109 /* ----------
00110  * Maximal length of one node
00111  * ----------
00112  */
00113 #define DCH_MAX_ITEM_SIZ        9       /* max julian day       */
00114 #define NUM_MAX_ITEM_SIZ        8       /* roman number (RN has 15 chars)   */
00115 
00116 /* ----------
00117  * More is in float.c
00118  * ----------
00119  */
00120 #define MAXFLOATWIDTH   60
00121 #define MAXDOUBLEWIDTH  500
00122 
00123 
00124 /* ----------
00125  * External (defined in PgSQL datetime.c (timestamp utils))
00126  * ----------
00127  */
00128 extern char *months[],          /* month abbreviation   */
00129            *days[];             /* full days        */
00130 
00131 /* ----------
00132  * Format parser structs
00133  * ----------
00134  */
00135 typedef struct
00136 {
00137     char       *name;           /* suffix string        */
00138     int         len,            /* suffix length        */
00139                 id,             /* used in node->suffix */
00140                 type;           /* prefix / postfix         */
00141 } KeySuffix;
00142 
00143 /* ----------
00144  * FromCharDateMode
00145  * ----------
00146  *
00147  * This value is used to nominate one of several distinct (and mutually
00148  * exclusive) date conventions that a keyword can belong to.
00149  */
00150 typedef enum
00151 {
00152     FROM_CHAR_DATE_NONE = 0,    /* Value does not affect date mode. */
00153     FROM_CHAR_DATE_GREGORIAN,   /* Gregorian (day, month, year) style date */
00154     FROM_CHAR_DATE_ISOWEEK      /* ISO 8601 week date */
00155 } FromCharDateMode;
00156 
00157 typedef struct FormatNode FormatNode;
00158 
00159 typedef struct
00160 {
00161     const char *name;
00162     int         len;
00163     int         id;
00164     bool        is_digit;
00165     FromCharDateMode date_mode;
00166 } KeyWord;
00167 
00168 struct FormatNode
00169 {
00170     int         type;           /* node type            */
00171     const KeyWord *key;         /* if node type is KEYWORD  */
00172     char        character;      /* if node type is CHAR     */
00173     int         suffix;         /* keyword suffix       */
00174 };
00175 
00176 #define NODE_TYPE_END       1
00177 #define NODE_TYPE_ACTION    2
00178 #define NODE_TYPE_CHAR      3
00179 
00180 #define SUFFTYPE_PREFIX     1
00181 #define SUFFTYPE_POSTFIX    2
00182 
00183 #define CLOCK_24_HOUR       0
00184 #define CLOCK_12_HOUR       1
00185 
00186 
00187 /* ----------
00188  * Full months
00189  * ----------
00190  */
00191 static char *months_full[] = {
00192     "January", "February", "March", "April", "May", "June", "July",
00193     "August", "September", "October", "November", "December", NULL
00194 };
00195 
00196 static char *days_short[] = {
00197     "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
00198 };
00199 
00200 /* ----------
00201  * AD / BC
00202  * ----------
00203  *  There is no 0 AD.  Years go from 1 BC to 1 AD, so we make it
00204  *  positive and map year == -1 to year zero, and shift all negative
00205  *  years up one.  For interval years, we just return the year.
00206  */
00207 #define ADJUST_YEAR(year, is_interval)  ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
00208 
00209 #define A_D_STR     "A.D."
00210 #define a_d_STR     "a.d."
00211 #define AD_STR      "AD"
00212 #define ad_STR      "ad"
00213 
00214 #define B_C_STR     "B.C."
00215 #define b_c_STR     "b.c."
00216 #define BC_STR      "BC"
00217 #define bc_STR      "bc"
00218 
00219 /*
00220  * AD / BC strings for seq_search.
00221  *
00222  * These are given in two variants, a long form with periods and a standard
00223  * form without.
00224  *
00225  * The array is laid out such that matches for AD have an even index, and
00226  * matches for BC have an odd index.  So the boolean value for BC is given by
00227  * taking the array index of the match, modulo 2.
00228  */
00229 static char *adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL};
00230 static char *adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL};
00231 
00232 /* ----------
00233  * AM / PM
00234  * ----------
00235  */
00236 #define A_M_STR     "A.M."
00237 #define a_m_STR     "a.m."
00238 #define AM_STR      "AM"
00239 #define am_STR      "am"
00240 
00241 #define P_M_STR     "P.M."
00242 #define p_m_STR     "p.m."
00243 #define PM_STR      "PM"
00244 #define pm_STR      "pm"
00245 
00246 /*
00247  * AM / PM strings for seq_search.
00248  *
00249  * These are given in two variants, a long form with periods and a standard
00250  * form without.
00251  *
00252  * The array is laid out such that matches for AM have an even index, and
00253  * matches for PM have an odd index.  So the boolean value for PM is given by
00254  * taking the array index of the match, modulo 2.
00255  */
00256 static char *ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL};
00257 static char *ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL};
00258 
00259 /* ----------
00260  * Months in roman-numeral
00261  * (Must be in reverse order for seq_search (in FROM_CHAR), because
00262  *  'VIII' must have higher precedence than 'V')
00263  * ----------
00264  */
00265 static char *rm_months_upper[] =
00266 {"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};
00267 
00268 static char *rm_months_lower[] =
00269 {"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};
00270 
00271 /* ----------
00272  * Roman numbers
00273  * ----------
00274  */
00275 static char *rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};
00276 static char *rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};
00277 static char *rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};
00278 
00279 /* ----------
00280  * Ordinal postfixes
00281  * ----------
00282  */
00283 static char *numTH[] = {"ST", "ND", "RD", "TH", NULL};
00284 static char *numth[] = {"st", "nd", "rd", "th", NULL};
00285 
00286 /* ----------
00287  * Flags & Options:
00288  * ----------
00289  */
00290 #define ONE_UPPER       1       /* Name */
00291 #define ALL_UPPER       2       /* NAME */
00292 #define ALL_LOWER       3       /* name */
00293 
00294 #define FULL_SIZ        0
00295 
00296 #define MAX_MONTH_LEN   9
00297 #define MAX_MON_LEN     3
00298 #define MAX_DAY_LEN     9
00299 #define MAX_DY_LEN      3
00300 #define MAX_RM_LEN      4
00301 
00302 #define TH_UPPER        1
00303 #define TH_LOWER        2
00304 
00305 /* ----------
00306  * Number description struct
00307  * ----------
00308  */
00309 typedef struct
00310 {
00311     int         pre,            /* (count) numbers before decimal */
00312                 post,           /* (count) numbers after decimal  */
00313                 lsign,          /* want locales sign          */
00314                 flag,           /* number parameters          */
00315                 pre_lsign_num,  /* tmp value for lsign        */
00316                 multi,          /* multiplier for 'V'         */
00317                 zero_start,     /* position of first zero     */
00318                 zero_end,       /* position of last zero      */
00319                 need_locale;    /* needs it locale        */
00320 } NUMDesc;
00321 
00322 /* ----------
00323  * Flags for NUMBER version
00324  * ----------
00325  */
00326 #define NUM_F_DECIMAL       (1 << 1)
00327 #define NUM_F_LDECIMAL      (1 << 2)
00328 #define NUM_F_ZERO          (1 << 3)
00329 #define NUM_F_BLANK         (1 << 4)
00330 #define NUM_F_FILLMODE      (1 << 5)
00331 #define NUM_F_LSIGN         (1 << 6)
00332 #define NUM_F_BRACKET       (1 << 7)
00333 #define NUM_F_MINUS         (1 << 8)
00334 #define NUM_F_PLUS          (1 << 9)
00335 #define NUM_F_ROMAN         (1 << 10)
00336 #define NUM_F_MULTI         (1 << 11)
00337 #define NUM_F_PLUS_POST     (1 << 12)
00338 #define NUM_F_MINUS_POST    (1 << 13)
00339 #define NUM_F_EEEE          (1 << 14)
00340 
00341 #define NUM_LSIGN_PRE   (-1)
00342 #define NUM_LSIGN_POST  1
00343 #define NUM_LSIGN_NONE  0
00344 
00345 /* ----------
00346  * Tests
00347  * ----------
00348  */
00349 #define IS_DECIMAL(_f)  ((_f)->flag & NUM_F_DECIMAL)
00350 #define IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL)
00351 #define IS_ZERO(_f) ((_f)->flag & NUM_F_ZERO)
00352 #define IS_BLANK(_f)    ((_f)->flag & NUM_F_BLANK)
00353 #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE)
00354 #define IS_BRACKET(_f)  ((_f)->flag & NUM_F_BRACKET)
00355 #define IS_MINUS(_f)    ((_f)->flag & NUM_F_MINUS)
00356 #define IS_LSIGN(_f)    ((_f)->flag & NUM_F_LSIGN)
00357 #define IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
00358 #define IS_ROMAN(_f)    ((_f)->flag & NUM_F_ROMAN)
00359 #define IS_MULTI(_f)    ((_f)->flag & NUM_F_MULTI)
00360 #define IS_EEEE(_f)     ((_f)->flag & NUM_F_EEEE)
00361 
00362 /* ----------
00363  * Format picture cache
00364  *  (cache size:
00365  *      Number part = NUM_CACHE_SIZE * NUM_CACHE_FIELDS
00366  *      Date-time part  = DCH_CACHE_SIZE * DCH_CACHE_FIELDS
00367  *  )
00368  * ----------
00369  */
00370 #define NUM_CACHE_SIZE      64
00371 #define NUM_CACHE_FIELDS    16
00372 #define DCH_CACHE_SIZE      128
00373 #define DCH_CACHE_FIELDS    16
00374 
00375 typedef struct
00376 {
00377     FormatNode  format[DCH_CACHE_SIZE + 1];
00378     char        str[DCH_CACHE_SIZE + 1];
00379     int         age;
00380 } DCHCacheEntry;
00381 
00382 typedef struct
00383 {
00384     FormatNode  format[NUM_CACHE_SIZE + 1];
00385     char        str[NUM_CACHE_SIZE + 1];
00386     int         age;
00387     NUMDesc     Num;
00388 } NUMCacheEntry;
00389 
00390 /* global cache for --- date/time part */
00391 static DCHCacheEntry DCHCache[DCH_CACHE_FIELDS + 1];
00392 
00393 static int  n_DCHCache = 0;     /* number of entries */
00394 static int  DCHCounter = 0;
00395 
00396 /* global cache for --- number part */
00397 static NUMCacheEntry NUMCache[NUM_CACHE_FIELDS + 1];
00398 
00399 static int  n_NUMCache = 0;     /* number of entries */
00400 static int  NUMCounter = 0;
00401 static NUMCacheEntry *last_NUMCacheEntry = NUMCache + 0;
00402 
00403 /* ----------
00404  * For char->date/time conversion
00405  * ----------
00406  */
00407 typedef struct
00408 {
00409     FromCharDateMode mode;
00410     int         hh,
00411                 pm,
00412                 mi,
00413                 ss,
00414                 ssss,
00415                 d,              /* stored as 1-7, Sunday = 1, 0 means missing */
00416                 dd,
00417                 ddd,
00418                 mm,
00419                 ms,
00420                 year,
00421                 bc,
00422                 ww,
00423                 w,
00424                 cc,
00425                 j,
00426                 us,
00427                 yysz,           /* is it YY or YYYY ? */
00428                 clock;          /* 12 or 24 hour clock? */
00429 } TmFromChar;
00430 
00431 #define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
00432 
00433 /* ----------
00434  * Debug
00435  * ----------
00436  */
00437 #ifdef DEBUG_TO_FROM_CHAR
00438 #define DEBUG_TMFC(_X) \
00439         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", \
00440             (_X)->mode, (_X)->hh, (_X)->pm, (_X)->mi, (_X)->ss, (_X)->ssss, \
00441             (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, (_X)->year, \
00442             (_X)->bc, (_X)->ww, (_X)->w, (_X)->cc, (_X)->j, (_X)->us, \
00443             (_X)->yysz, (_X)->clock);
00444 #define DEBUG_TM(_X) \
00445         elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
00446             (_X)->tm_sec, (_X)->tm_year,\
00447             (_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\
00448             (_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)
00449 #else
00450 #define DEBUG_TMFC(_X)
00451 #define DEBUG_TM(_X)
00452 #endif
00453 
00454 /* ----------
00455  * Datetime to char conversion
00456  * ----------
00457  */
00458 typedef struct TmToChar
00459 {
00460     struct pg_tm tm;            /* classic 'tm' struct */
00461     fsec_t      fsec;           /* fractional seconds */
00462     const char *tzn;            /* timezone */
00463 } TmToChar;
00464 
00465 #define tmtcTm(_X)  (&(_X)->tm)
00466 #define tmtcTzn(_X) ((_X)->tzn)
00467 #define tmtcFsec(_X)    ((_X)->fsec)
00468 
00469 #define ZERO_tm(_X) \
00470 do {    \
00471     (_X)->tm_sec  = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
00472     (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
00473     (_X)->tm_mday = (_X)->tm_mon  = 1; \
00474 } while(0)
00475 
00476 #define ZERO_tmtc(_X) \
00477 do { \
00478     ZERO_tm( tmtcTm(_X) ); \
00479     tmtcFsec(_X) = 0; \
00480     tmtcTzn(_X) = NULL; \
00481 } while(0)
00482 
00483 /*
00484  *  to_char(time) appears to to_char() as an interval, so this check
00485  *  is really for interval and time data types.
00486  */
00487 #define INVALID_FOR_INTERVAL  \
00488 do { \
00489     if (is_interval) \
00490         ereport(ERROR, \
00491                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
00492                  errmsg("invalid format specification for an interval value"), \
00493                  errhint("Intervals are not tied to specific calendar dates."))); \
00494 } while(0)
00495 
00496 /*****************************************************************************
00497  *          KeyWord definitions
00498  *****************************************************************************/
00499 
00500 /* ----------
00501  * Suffixes:
00502  * ----------
00503  */
00504 #define DCH_S_FM    0x01
00505 #define DCH_S_TH    0x02
00506 #define DCH_S_th    0x04
00507 #define DCH_S_SP    0x08
00508 #define DCH_S_TM    0x10
00509 
00510 /* ----------
00511  * Suffix tests
00512  * ----------
00513  */
00514 #define S_THth(_s)  ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)
00515 #define S_TH(_s)    (((_s) & DCH_S_TH) ? 1 : 0)
00516 #define S_th(_s)    (((_s) & DCH_S_th) ? 1 : 0)
00517 #define S_TH_TYPE(_s)   (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)
00518 
00519 /* Oracle toggles FM behavior, we don't; see docs. */
00520 #define S_FM(_s)    (((_s) & DCH_S_FM) ? 1 : 0)
00521 #define S_SP(_s)    (((_s) & DCH_S_SP) ? 1 : 0)
00522 #define S_TM(_s)    (((_s) & DCH_S_TM) ? 1 : 0)
00523 
00524 /* ----------
00525  * Suffixes definition for DATE-TIME TO/FROM CHAR
00526  * ----------
00527  */
00528 static KeySuffix DCH_suff[] = {
00529     {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
00530     {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
00531     {"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX},
00532     {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
00533     {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
00534     {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
00535     {"SP", 2, DCH_S_SP, SUFFTYPE_POSTFIX},
00536     /* last */
00537     {NULL, 0, 0, 0}
00538 };
00539 
00540 /* ----------
00541  * Format-pictures (KeyWord).
00542  *
00543  * The KeyWord field; alphabetic sorted, *BUT* strings alike is sorted
00544  *        complicated -to-> easy:
00545  *
00546  *  (example: "DDD","DD","Day","D" )
00547  *
00548  * (this specific sort needs the algorithm for sequential search for strings,
00549  * which not has exact end; -> How keyword is in "HH12blabla" ? - "HH"
00550  * or "HH12"? You must first try "HH12", because "HH" is in string, but
00551  * it is not good.
00552  *
00553  * (!)
00554  *   - Position for the keyword is similar as position in the enum DCH/NUM_poz.
00555  * (!)
00556  *
00557  * For fast search is used the 'int index[]', index is ascii table from position
00558  * 32 (' ') to 126 (~), in this index is DCH_ / NUM_ enums for each ASCII
00559  * position or -1 if char is not used in the KeyWord. Search example for
00560  * string "MM":
00561  *  1)  see in index to index['M' - 32],
00562  *  2)  take keywords position (enum DCH_MI) from index
00563  *  3)  run sequential search in keywords[] from this position
00564  *
00565  * ----------
00566  */
00567 
00568 typedef enum
00569 {
00570     DCH_A_D,
00571     DCH_A_M,
00572     DCH_AD,
00573     DCH_AM,
00574     DCH_B_C,
00575     DCH_BC,
00576     DCH_CC,
00577     DCH_DAY,
00578     DCH_DDD,
00579     DCH_DD,
00580     DCH_DY,
00581     DCH_Day,
00582     DCH_Dy,
00583     DCH_D,
00584     DCH_FX,                     /* global suffix */
00585     DCH_HH24,
00586     DCH_HH12,
00587     DCH_HH,
00588     DCH_IDDD,
00589     DCH_ID,
00590     DCH_IW,
00591     DCH_IYYY,
00592     DCH_IYY,
00593     DCH_IY,
00594     DCH_I,
00595     DCH_J,
00596     DCH_MI,
00597     DCH_MM,
00598     DCH_MONTH,
00599     DCH_MON,
00600     DCH_MS,
00601     DCH_Month,
00602     DCH_Mon,
00603     DCH_P_M,
00604     DCH_PM,
00605     DCH_Q,
00606     DCH_RM,
00607     DCH_SSSS,
00608     DCH_SS,
00609     DCH_TZ,
00610     DCH_US,
00611     DCH_WW,
00612     DCH_W,
00613     DCH_Y_YYY,
00614     DCH_YYYY,
00615     DCH_YYY,
00616     DCH_YY,
00617     DCH_Y,
00618     DCH_a_d,
00619     DCH_a_m,
00620     DCH_ad,
00621     DCH_am,
00622     DCH_b_c,
00623     DCH_bc,
00624     DCH_cc,
00625     DCH_day,
00626     DCH_ddd,
00627     DCH_dd,
00628     DCH_dy,
00629     DCH_d,
00630     DCH_fx,
00631     DCH_hh24,
00632     DCH_hh12,
00633     DCH_hh,
00634     DCH_iddd,
00635     DCH_id,
00636     DCH_iw,
00637     DCH_iyyy,
00638     DCH_iyy,
00639     DCH_iy,
00640     DCH_i,
00641     DCH_j,
00642     DCH_mi,
00643     DCH_mm,
00644     DCH_month,
00645     DCH_mon,
00646     DCH_ms,
00647     DCH_p_m,
00648     DCH_pm,
00649     DCH_q,
00650     DCH_rm,
00651     DCH_ssss,
00652     DCH_ss,
00653     DCH_tz,
00654     DCH_us,
00655     DCH_ww,
00656     DCH_w,
00657     DCH_y_yyy,
00658     DCH_yyyy,
00659     DCH_yyy,
00660     DCH_yy,
00661     DCH_y,
00662 
00663     /* last */
00664     _DCH_last_
00665 }   DCH_poz;
00666 
00667 typedef enum
00668 {
00669     NUM_COMMA,
00670     NUM_DEC,
00671     NUM_0,
00672     NUM_9,
00673     NUM_B,
00674     NUM_C,
00675     NUM_D,
00676     NUM_E,
00677     NUM_FM,
00678     NUM_G,
00679     NUM_L,
00680     NUM_MI,
00681     NUM_PL,
00682     NUM_PR,
00683     NUM_RN,
00684     NUM_SG,
00685     NUM_SP,
00686     NUM_S,
00687     NUM_TH,
00688     NUM_V,
00689     NUM_b,
00690     NUM_c,
00691     NUM_d,
00692     NUM_e,
00693     NUM_fm,
00694     NUM_g,
00695     NUM_l,
00696     NUM_mi,
00697     NUM_pl,
00698     NUM_pr,
00699     NUM_rn,
00700     NUM_sg,
00701     NUM_sp,
00702     NUM_s,
00703     NUM_th,
00704     NUM_v,
00705 
00706     /* last */
00707     _NUM_last_
00708 }   NUM_poz;
00709 
00710 /* ----------
00711  * KeyWords for DATE-TIME version
00712  * ----------
00713  */
00714 static const KeyWord DCH_keywords[] = {
00715 /*  name, len, id, is_digit, date_mode */
00716     {"A.D.", 4, DCH_A_D, FALSE, FROM_CHAR_DATE_NONE},   /* A */
00717     {"A.M.", 4, DCH_A_M, FALSE, FROM_CHAR_DATE_NONE},
00718     {"AD", 2, DCH_AD, FALSE, FROM_CHAR_DATE_NONE},
00719     {"AM", 2, DCH_AM, FALSE, FROM_CHAR_DATE_NONE},
00720     {"B.C.", 4, DCH_B_C, FALSE, FROM_CHAR_DATE_NONE},   /* B */
00721     {"BC", 2, DCH_BC, FALSE, FROM_CHAR_DATE_NONE},
00722     {"CC", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE},       /* C */
00723     {"DAY", 3, DCH_DAY, FALSE, FROM_CHAR_DATE_NONE},    /* D */
00724     {"DDD", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00725     {"DD", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00726     {"DY", 2, DCH_DY, FALSE, FROM_CHAR_DATE_NONE},
00727     {"Day", 3, DCH_Day, FALSE, FROM_CHAR_DATE_NONE},
00728     {"Dy", 2, DCH_Dy, FALSE, FROM_CHAR_DATE_NONE},
00729     {"D", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
00730     {"FX", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE},      /* F */
00731     {"HH24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE},   /* H */
00732     {"HH12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
00733     {"HH", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
00734     {"IDDD", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK},        /* I */
00735     {"ID", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
00736     {"IW", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
00737     {"IYYY", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00738     {"IYY", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00739     {"IY", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00740     {"I", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
00741     {"J", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE}, /* J */
00742     {"MI", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE},       /* M */
00743     {"MM", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
00744     {"MONTH", 5, DCH_MONTH, FALSE, FROM_CHAR_DATE_GREGORIAN},
00745     {"MON", 3, DCH_MON, FALSE, FROM_CHAR_DATE_GREGORIAN},
00746     {"MS", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
00747     {"Month", 5, DCH_Month, FALSE, FROM_CHAR_DATE_GREGORIAN},
00748     {"Mon", 3, DCH_Mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
00749     {"P.M.", 4, DCH_P_M, FALSE, FROM_CHAR_DATE_NONE},   /* P */
00750     {"PM", 2, DCH_PM, FALSE, FROM_CHAR_DATE_NONE},
00751     {"Q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE}, /* Q */
00752     {"RM", 2, DCH_RM, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* R */
00753     {"SSSS", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE},   /* S */
00754     {"SS", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
00755     {"TZ", 2, DCH_TZ, FALSE, FROM_CHAR_DATE_NONE},      /* T */
00756     {"US", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE},       /* U */
00757     {"WW", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN},  /* W */
00758     {"W", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
00759     {"Y,YYY", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},    /* Y */
00760     {"YYYY", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00761     {"YYY", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00762     {"YY", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00763     {"Y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
00764     {"a.d.", 4, DCH_a_d, FALSE, FROM_CHAR_DATE_NONE},   /* a */
00765     {"a.m.", 4, DCH_a_m, FALSE, FROM_CHAR_DATE_NONE},
00766     {"ad", 2, DCH_ad, FALSE, FROM_CHAR_DATE_NONE},
00767     {"am", 2, DCH_am, FALSE, FROM_CHAR_DATE_NONE},
00768     {"b.c.", 4, DCH_b_c, FALSE, FROM_CHAR_DATE_NONE},   /* b */
00769     {"bc", 2, DCH_bc, FALSE, FROM_CHAR_DATE_NONE},
00770     {"cc", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE},       /* c */
00771     {"day", 3, DCH_day, FALSE, FROM_CHAR_DATE_NONE},    /* d */
00772     {"ddd", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00773     {"dd", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00774     {"dy", 2, DCH_dy, FALSE, FROM_CHAR_DATE_NONE},
00775     {"d", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
00776     {"fx", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE},      /* f */
00777     {"hh24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE},   /* h */
00778     {"hh12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
00779     {"hh", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
00780     {"iddd", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK},        /* i */
00781     {"id", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
00782     {"iw", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
00783     {"iyyy", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00784     {"iyy", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00785     {"iy", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00786     {"i", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
00787     {"j", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE}, /* j */
00788     {"mi", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE},       /* m */
00789     {"mm", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
00790     {"month", 5, DCH_month, FALSE, FROM_CHAR_DATE_GREGORIAN},
00791     {"mon", 3, DCH_mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
00792     {"ms", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
00793     {"p.m.", 4, DCH_p_m, FALSE, FROM_CHAR_DATE_NONE},   /* p */
00794     {"pm", 2, DCH_pm, FALSE, FROM_CHAR_DATE_NONE},
00795     {"q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE}, /* q */
00796     {"rm", 2, DCH_rm, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* r */
00797     {"ssss", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE},   /* s */
00798     {"ss", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
00799     {"tz", 2, DCH_tz, FALSE, FROM_CHAR_DATE_NONE},      /* t */
00800     {"us", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE},       /* u */
00801     {"ww", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN},  /* w */
00802     {"w", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
00803     {"y,yyy", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},    /* y */
00804     {"yyyy", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00805     {"yyy", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00806     {"yy", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00807     {"y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
00808 
00809     /* last */
00810     {NULL, 0, 0, 0, 0}
00811 };
00812 
00813 /* ----------
00814  * KeyWords for NUMBER version
00815  *
00816  * The is_digit and date_mode fields are not relevant here.
00817  * ----------
00818  */
00819 static const KeyWord NUM_keywords[] = {
00820 /*  name, len, id           is in Index */
00821     {",", 1, NUM_COMMA},        /* , */
00822     {".", 1, NUM_DEC},          /* . */
00823     {"0", 1, NUM_0},            /* 0 */
00824     {"9", 1, NUM_9},            /* 9 */
00825     {"B", 1, NUM_B},            /* B */
00826     {"C", 1, NUM_C},            /* C */
00827     {"D", 1, NUM_D},            /* D */
00828     {"EEEE", 4, NUM_E},         /* E */
00829     {"FM", 2, NUM_FM},          /* F */
00830     {"G", 1, NUM_G},            /* G */
00831     {"L", 1, NUM_L},            /* L */
00832     {"MI", 2, NUM_MI},          /* M */
00833     {"PL", 2, NUM_PL},          /* P */
00834     {"PR", 2, NUM_PR},
00835     {"RN", 2, NUM_RN},          /* R */
00836     {"SG", 2, NUM_SG},          /* S */
00837     {"SP", 2, NUM_SP},
00838     {"S", 1, NUM_S},
00839     {"TH", 2, NUM_TH},          /* T */
00840     {"V", 1, NUM_V},            /* V */
00841     {"b", 1, NUM_B},            /* b */
00842     {"c", 1, NUM_C},            /* c */
00843     {"d", 1, NUM_D},            /* d */
00844     {"eeee", 4, NUM_E},         /* e */
00845     {"fm", 2, NUM_FM},          /* f */
00846     {"g", 1, NUM_G},            /* g */
00847     {"l", 1, NUM_L},            /* l */
00848     {"mi", 2, NUM_MI},          /* m */
00849     {"pl", 2, NUM_PL},          /* p */
00850     {"pr", 2, NUM_PR},
00851     {"rn", 2, NUM_rn},          /* r */
00852     {"sg", 2, NUM_SG},          /* s */
00853     {"sp", 2, NUM_SP},
00854     {"s", 1, NUM_S},
00855     {"th", 2, NUM_th},          /* t */
00856     {"v", 1, NUM_V},            /* v */
00857 
00858     /* last */
00859     {NULL, 0, 0}
00860 };
00861 
00862 
00863 /* ----------
00864  * KeyWords index for DATE-TIME version
00865  * ----------
00866  */
00867 static const int DCH_index[KeyWord_INDEX_SIZE] = {
00868 /*
00869 0   1   2   3   4   5   6   7   8   9
00870 */
00871     /*---- first 0..31 chars are skipped ----*/
00872 
00873     -1, -1, -1, -1, -1, -1, -1, -1,
00874     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00875     -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00876     -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
00877     DCH_FX, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, -1,
00878     DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY,
00879     -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
00880     DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
00881     -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww,
00882     -1, DCH_y_yyy, -1, -1, -1, -1
00883 
00884     /*---- chars over 126 are skipped ----*/
00885 };
00886 
00887 /* ----------
00888  * KeyWords index for NUMBER version
00889  * ----------
00890  */
00891 static const int NUM_index[KeyWord_INDEX_SIZE] = {
00892 /*
00893 0   1   2   3   4   5   6   7   8   9
00894 */
00895     /*---- first 0..31 chars are skipped ----*/
00896 
00897     -1, -1, -1, -1, -1, -1, -1, -1,
00898     -1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
00899     -1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
00900     -1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
00901     NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
00902     NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
00903     -1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
00904     NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
00905     -1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
00906     -1, -1, -1, -1, -1, -1
00907 
00908     /*---- chars over 126 are skipped ----*/
00909 };
00910 
00911 /* ----------
00912  * Number processor struct
00913  * ----------
00914  */
00915 typedef struct NUMProc
00916 {
00917     bool        is_to_char;
00918     NUMDesc    *Num;            /* number description       */
00919 
00920     int         sign,           /* '-' or '+'           */
00921                 sign_wrote,     /* was sign write       */
00922                 num_count,      /* number of write digits   */
00923                 num_in,         /* is inside number     */
00924                 num_curr,       /* current position in number   */
00925                 num_pre,        /* space before first number    */
00926 
00927                 read_dec,       /* to_number - was read dec. point  */
00928                 read_post,      /* to_number - number of dec. digit */
00929                 read_pre;       /* to_number - number non-dec. digit */
00930 
00931     char       *number,         /* string with number   */
00932                *number_p,       /* pointer to current number position */
00933                *inout,          /* in / out buffer  */
00934                *inout_p,        /* pointer to current inout position */
00935                *last_relevant,  /* last relevant number after decimal point */
00936 
00937                *L_negative_sign,    /* Locale */
00938                *L_positive_sign,
00939                *decimal,
00940                *L_thousands_sep,
00941                *L_currency_symbol;
00942 } NUMProc;
00943 
00944 
00945 /* ----------
00946  * Functions
00947  * ----------
00948  */
00949 static const KeyWord *index_seq_search(char *str, const KeyWord *kw,
00950                  const int *index);
00951 static KeySuffix *suff_search(char *str, KeySuffix *suf, int type);
00952 static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
00953 static void parse_format(FormatNode *node, char *str, const KeyWord *kw,
00954              KeySuffix *suf, const int *index, int ver, NUMDesc *Num);
00955 
00956 static void DCH_to_char(FormatNode *node, bool is_interval,
00957             TmToChar *in, char *out, Oid collid);
00958 static void DCH_from_char(FormatNode *node, char *in, TmFromChar *out);
00959 
00960 #ifdef DEBUG_TO_FROM_CHAR
00961 static void dump_index(const KeyWord *k, const int *index);
00962 static void dump_node(FormatNode *node, int max);
00963 #endif
00964 
00965 static char *get_th(char *num, int type);
00966 static char *str_numth(char *dest, char *num, int type);
00967 static int  adjust_partial_year_to_2020(int year);
00968 static int  strspace_len(char *str);
00969 static int  strdigits_len(char *str);
00970 static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode);
00971 static void from_char_set_int(int *dest, const int value, const FormatNode *node);
00972 static int  from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node);
00973 static int  from_char_parse_int(int *dest, char **src, FormatNode *node);
00974 static int  seq_search(char *name, char **array, int type, int max, int *len);
00975 static int  from_char_seq_search(int *dest, char **src, char **array, int type, int max, FormatNode *node);
00976 static void do_to_timestamp(text *date_txt, text *fmt,
00977                 struct pg_tm * tm, fsec_t *fsec);
00978 static char *fill_str(char *str, int c, int max);
00979 static FormatNode *NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree);
00980 static char *int_to_roman(int number);
00981 static void NUM_prepare_locale(NUMProc *Np);
00982 static char *get_last_relevant_decnum(char *num);
00983 static void NUM_numpart_from_char(NUMProc *Np, int id, int plen);
00984 static void NUM_numpart_to_char(NUMProc *Np, int id);
00985 static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
00986               int plen, int sign, bool is_to_char, Oid collid);
00987 static DCHCacheEntry *DCH_cache_search(char *str);
00988 static DCHCacheEntry *DCH_cache_getnew(char *str);
00989 
00990 static NUMCacheEntry *NUM_cache_search(char *str);
00991 static NUMCacheEntry *NUM_cache_getnew(char *str);
00992 static void NUM_cache_remove(NUMCacheEntry *ent);
00993 
00994 
00995 /* ----------
00996  * Fast sequential search, use index for data selection which
00997  * go to seq. cycle (it is very fast for unwanted strings)
00998  * (can't be used binary search in format parsing)
00999  * ----------
01000  */
01001 static const KeyWord *
01002 index_seq_search(char *str, const KeyWord *kw, const int *index)
01003 {
01004     int         poz;
01005 
01006     if (!KeyWord_INDEX_FILTER(*str))
01007         return NULL;
01008 
01009     if ((poz = *(index + (*str - ' '))) > -1)
01010     {
01011         const KeyWord *k = kw + poz;
01012 
01013         do
01014         {
01015             if (strncmp(str, k->name, k->len) == 0)
01016                 return k;
01017             k++;
01018             if (!k->name)
01019                 return NULL;
01020         } while (*str == *k->name);
01021     }
01022     return NULL;
01023 }
01024 
01025 static KeySuffix *
01026 suff_search(char *str, KeySuffix *suf, int type)
01027 {
01028     KeySuffix  *s;
01029 
01030     for (s = suf; s->name != NULL; s++)
01031     {
01032         if (s->type != type)
01033             continue;
01034 
01035         if (strncmp(str, s->name, s->len) == 0)
01036             return s;
01037     }
01038     return NULL;
01039 }
01040 
01041 /* ----------
01042  * Prepare NUMDesc (number description struct) via FormatNode struct
01043  * ----------
01044  */
01045 static void
01046 NUMDesc_prepare(NUMDesc *num, FormatNode *n)
01047 {
01048 
01049     if (n->type != NODE_TYPE_ACTION)
01050         return;
01051 
01052     /*
01053      * In case of an error, we need to remove the numeric from the cache.  Use
01054      * a PG_TRY block to ensure that this happens.
01055      */
01056     PG_TRY();
01057     {
01058         if (IS_EEEE(num) && n->key->id != NUM_E)
01059             ereport(ERROR,
01060                     (errcode(ERRCODE_SYNTAX_ERROR),
01061                      errmsg("\"EEEE\" must be the last pattern used")));
01062 
01063         switch (n->key->id)
01064         {
01065             case NUM_9:
01066                 if (IS_BRACKET(num))
01067                     ereport(ERROR,
01068                             (errcode(ERRCODE_SYNTAX_ERROR),
01069                              errmsg("\"9\" must be ahead of \"PR\"")));
01070                 if (IS_MULTI(num))
01071                 {
01072                     ++num->multi;
01073                     break;
01074                 }
01075                 if (IS_DECIMAL(num))
01076                     ++num->post;
01077                 else
01078                     ++num->pre;
01079                 break;
01080 
01081             case NUM_0:
01082                 if (IS_BRACKET(num))
01083                     ereport(ERROR,
01084                             (errcode(ERRCODE_SYNTAX_ERROR),
01085                              errmsg("\"0\" must be ahead of \"PR\"")));
01086                 if (!IS_ZERO(num) && !IS_DECIMAL(num))
01087                 {
01088                     num->flag |= NUM_F_ZERO;
01089                     num->zero_start = num->pre + 1;
01090                 }
01091                 if (!IS_DECIMAL(num))
01092                     ++num->pre;
01093                 else
01094                     ++num->post;
01095 
01096                 num->zero_end = num->pre + num->post;
01097                 break;
01098 
01099             case NUM_B:
01100                 if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num)))
01101                     num->flag |= NUM_F_BLANK;
01102                 break;
01103 
01104             case NUM_D:
01105                 num->flag |= NUM_F_LDECIMAL;
01106                 num->need_locale = TRUE;
01107                 /* FALLTHROUGH */
01108             case NUM_DEC:
01109                 if (IS_DECIMAL(num))
01110                     ereport(ERROR,
01111                             (errcode(ERRCODE_SYNTAX_ERROR),
01112                              errmsg("multiple decimal points")));
01113                 if (IS_MULTI(num))
01114                     ereport(ERROR,
01115                             (errcode(ERRCODE_SYNTAX_ERROR),
01116                      errmsg("cannot use \"V\" and decimal point together")));
01117                 num->flag |= NUM_F_DECIMAL;
01118                 break;
01119 
01120             case NUM_FM:
01121                 num->flag |= NUM_F_FILLMODE;
01122                 break;
01123 
01124             case NUM_S:
01125                 if (IS_LSIGN(num))
01126                     ereport(ERROR,
01127                             (errcode(ERRCODE_SYNTAX_ERROR),
01128                              errmsg("cannot use \"S\" twice")));
01129                 if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
01130                     ereport(ERROR,
01131                             (errcode(ERRCODE_SYNTAX_ERROR),
01132                              errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
01133                 if (!IS_DECIMAL(num))
01134                 {
01135                     num->lsign = NUM_LSIGN_PRE;
01136                     num->pre_lsign_num = num->pre;
01137                     num->need_locale = TRUE;
01138                     num->flag |= NUM_F_LSIGN;
01139                 }
01140                 else if (num->lsign == NUM_LSIGN_NONE)
01141                 {
01142                     num->lsign = NUM_LSIGN_POST;
01143                     num->need_locale = TRUE;
01144                     num->flag |= NUM_F_LSIGN;
01145                 }
01146                 break;
01147 
01148             case NUM_MI:
01149                 if (IS_LSIGN(num))
01150                     ereport(ERROR,
01151                             (errcode(ERRCODE_SYNTAX_ERROR),
01152                              errmsg("cannot use \"S\" and \"MI\" together")));
01153                 num->flag |= NUM_F_MINUS;
01154                 if (IS_DECIMAL(num))
01155                     num->flag |= NUM_F_MINUS_POST;
01156                 break;
01157 
01158             case NUM_PL:
01159                 if (IS_LSIGN(num))
01160                     ereport(ERROR,
01161                             (errcode(ERRCODE_SYNTAX_ERROR),
01162                              errmsg("cannot use \"S\" and \"PL\" together")));
01163                 num->flag |= NUM_F_PLUS;
01164                 if (IS_DECIMAL(num))
01165                     num->flag |= NUM_F_PLUS_POST;
01166                 break;
01167 
01168             case NUM_SG:
01169                 if (IS_LSIGN(num))
01170                     ereport(ERROR,
01171                             (errcode(ERRCODE_SYNTAX_ERROR),
01172                              errmsg("cannot use \"S\" and \"SG\" together")));
01173                 num->flag |= NUM_F_MINUS;
01174                 num->flag |= NUM_F_PLUS;
01175                 break;
01176 
01177             case NUM_PR:
01178                 if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
01179                     ereport(ERROR,
01180                             (errcode(ERRCODE_SYNTAX_ERROR),
01181                              errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
01182                 num->flag |= NUM_F_BRACKET;
01183                 break;
01184 
01185             case NUM_rn:
01186             case NUM_RN:
01187                 num->flag |= NUM_F_ROMAN;
01188                 break;
01189 
01190             case NUM_L:
01191             case NUM_G:
01192                 num->need_locale = TRUE;
01193                 break;
01194 
01195             case NUM_V:
01196                 if (IS_DECIMAL(num))
01197                     ereport(ERROR,
01198                             (errcode(ERRCODE_SYNTAX_ERROR),
01199                      errmsg("cannot use \"V\" and decimal point together")));
01200                 num->flag |= NUM_F_MULTI;
01201                 break;
01202 
01203             case NUM_E:
01204                 if (IS_EEEE(num))
01205                     ereport(ERROR,
01206                             (errcode(ERRCODE_SYNTAX_ERROR),
01207                              errmsg("cannot use \"EEEE\" twice")));
01208                 if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) ||
01209                     IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) ||
01210                     IS_ROMAN(num) || IS_MULTI(num))
01211                     ereport(ERROR,
01212                             (errcode(ERRCODE_SYNTAX_ERROR),
01213                        errmsg("\"EEEE\" is incompatible with other formats"),
01214                              errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
01215                 num->flag |= NUM_F_EEEE;
01216                 break;
01217         }
01218     }
01219     PG_CATCH();
01220     {
01221         NUM_cache_remove(last_NUMCacheEntry);
01222         PG_RE_THROW();
01223     }
01224     PG_END_TRY();
01225 
01226 
01227     return;
01228 }
01229 
01230 /* ----------
01231  * Format parser, search small keywords and keyword's suffixes, and make
01232  * format-node tree.
01233  *
01234  * for DATE-TIME & NUMBER version
01235  * ----------
01236  */
01237 static void
01238 parse_format(FormatNode *node, char *str, const KeyWord *kw,
01239              KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
01240 {
01241     KeySuffix  *s;
01242     FormatNode *n;
01243     int         node_set = 0,
01244                 suffix,
01245                 last = 0;
01246 
01247 #ifdef DEBUG_TO_FROM_CHAR
01248     elog(DEBUG_elog_output, "to_char/number(): run parser");
01249 #endif
01250 
01251     n = node;
01252 
01253     while (*str)
01254     {
01255         suffix = 0;
01256 
01257         /*
01258          * Prefix
01259          */
01260         if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
01261         {
01262             suffix |= s->id;
01263             if (s->len)
01264                 str += s->len;
01265         }
01266 
01267         /*
01268          * Keyword
01269          */
01270         if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
01271         {
01272             n->type = NODE_TYPE_ACTION;
01273             n->suffix = 0;
01274             node_set = 1;
01275             if (n->key->len)
01276                 str += n->key->len;
01277 
01278             /*
01279              * NUM version: Prepare global NUMDesc struct
01280              */
01281             if (ver == NUM_TYPE)
01282                 NUMDesc_prepare(Num, n);
01283 
01284             /*
01285              * Postfix
01286              */
01287             if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
01288             {
01289                 suffix |= s->id;
01290                 if (s->len)
01291                     str += s->len;
01292             }
01293         }
01294         else if (*str)
01295         {
01296             /*
01297              * Special characters '\' and '"'
01298              */
01299             if (*str == '"' && last != '\\')
01300             {
01301                 int         x = 0;
01302 
01303                 while (*(++str))
01304                 {
01305                     if (*str == '"' && x != '\\')
01306                     {
01307                         str++;
01308                         break;
01309                     }
01310                     else if (*str == '\\' && x != '\\')
01311                     {
01312                         x = '\\';
01313                         continue;
01314                     }
01315                     n->type = NODE_TYPE_CHAR;
01316                     n->character = *str;
01317                     n->key = NULL;
01318                     n->suffix = 0;
01319                     ++n;
01320                     x = *str;
01321                 }
01322                 node_set = 0;
01323                 suffix = 0;
01324                 last = 0;
01325             }
01326             else if (*str && *str == '\\' && last != '\\' && *(str + 1) == '"')
01327             {
01328                 last = *str;
01329                 str++;
01330             }
01331             else if (*str)
01332             {
01333                 n->type = NODE_TYPE_CHAR;
01334                 n->character = *str;
01335                 n->key = NULL;
01336                 node_set = 1;
01337                 last = 0;
01338                 str++;
01339             }
01340         }
01341 
01342         /* end */
01343         if (node_set)
01344         {
01345             if (n->type == NODE_TYPE_ACTION)
01346                 n->suffix = suffix;
01347             ++n;
01348 
01349             n->suffix = 0;
01350             node_set = 0;
01351         }
01352     }
01353 
01354     n->type = NODE_TYPE_END;
01355     n->suffix = 0;
01356     return;
01357 }
01358 
01359 /* ----------
01360  * DEBUG: Dump the FormatNode Tree (debug)
01361  * ----------
01362  */
01363 #ifdef DEBUG_TO_FROM_CHAR
01364 
01365 #define DUMP_THth(_suf) (S_TH(_suf) ? "TH" : (S_th(_suf) ? "th" : " "))
01366 #define DUMP_FM(_suf)   (S_FM(_suf) ? "FM" : " ")
01367 
01368 static void
01369 dump_node(FormatNode *node, int max)
01370 {
01371     FormatNode *n;
01372     int         a;
01373 
01374     elog(DEBUG_elog_output, "to_from-char(): DUMP FORMAT");
01375 
01376     for (a = 0, n = node; a <= max; n++, a++)
01377     {
01378         if (n->type == NODE_TYPE_ACTION)
01379             elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)",
01380                  a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix));
01381         else if (n->type == NODE_TYPE_CHAR)
01382             elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character);
01383         else if (n->type == NODE_TYPE_END)
01384         {
01385             elog(DEBUG_elog_output, "%d:\t NODE_TYPE_END", a);
01386             return;
01387         }
01388         else
01389             elog(DEBUG_elog_output, "%d:\t unknown NODE!", a);
01390     }
01391 }
01392 #endif   /* DEBUG */
01393 
01394 /*****************************************************************************
01395  *          Private utils
01396  *****************************************************************************/
01397 
01398 /* ----------
01399  * Return ST/ND/RD/TH for simple (1..9) numbers
01400  * type --> 0 upper, 1 lower
01401  * ----------
01402  */
01403 static char *
01404 get_th(char *num, int type)
01405 {
01406     int         len = strlen(num),
01407                 last,
01408                 seclast;
01409 
01410     last = *(num + (len - 1));
01411     if (!isdigit((unsigned char) last))
01412         ereport(ERROR,
01413                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01414                  errmsg("\"%s\" is not a number", num)));
01415 
01416     /*
01417      * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
01418      * 'ST/st', 'ND/nd', 'RD/rd', respectively
01419      */
01420     if ((len > 1) && ((seclast = num[len - 2]) == '1'))
01421         last = 0;
01422 
01423     switch (last)
01424     {
01425         case '1':
01426             if (type == TH_UPPER)
01427                 return numTH[0];
01428             return numth[0];
01429         case '2':
01430             if (type == TH_UPPER)
01431                 return numTH[1];
01432             return numth[1];
01433         case '3':
01434             if (type == TH_UPPER)
01435                 return numTH[2];
01436             return numth[2];
01437         default:
01438             if (type == TH_UPPER)
01439                 return numTH[3];
01440             return numth[3];
01441     }
01442 }
01443 
01444 /* ----------
01445  * Convert string-number to ordinal string-number
01446  * type --> 0 upper, 1 lower
01447  * ----------
01448  */
01449 static char *
01450 str_numth(char *dest, char *num, int type)
01451 {
01452     if (dest != num)
01453         strcpy(dest, num);
01454     strcat(dest, get_th(num, type));
01455     return dest;
01456 }
01457 
01458 /*****************************************************************************
01459  *          upper/lower/initcap functions
01460  *****************************************************************************/
01461 
01462 /*
01463  * If the system provides the needed functions for wide-character manipulation
01464  * (which are all standardized by C99), then we implement upper/lower/initcap
01465  * using wide-character functions, if necessary.  Otherwise we use the
01466  * traditional <ctype.h> functions, which of course will not work as desired
01467  * in multibyte character sets.  Note that in either case we are effectively
01468  * assuming that the database character encoding matches the encoding implied
01469  * by LC_CTYPE.
01470  *
01471  * If the system provides locale_t and associated functions (which are
01472  * standardized by Open Group's XBD), we can support collations that are
01473  * neither default nor C.  The code is written to handle both combinations
01474  * of have-wide-characters and have-locale_t, though it's rather unlikely
01475  * a platform would have the latter without the former.
01476  */
01477 
01478 /*
01479  * collation-aware, wide-character-aware lower function
01480  *
01481  * We pass the number of bytes so we can pass varlena and char*
01482  * to this function.  The result is a palloc'd, null-terminated string.
01483  */
01484 char *
01485 str_tolower(const char *buff, size_t nbytes, Oid collid)
01486 {
01487     char       *result;
01488 
01489     if (!buff)
01490         return NULL;
01491 
01492     /* C/POSIX collations use this path regardless of database encoding */
01493     if (lc_ctype_is_c(collid))
01494     {
01495         result = asc_tolower(buff, nbytes);
01496     }
01497 #ifdef USE_WIDE_UPPER_LOWER
01498     else if (pg_database_encoding_max_length() > 1)
01499     {
01500         pg_locale_t mylocale = 0;
01501         wchar_t    *workspace;
01502         size_t      curr_char;
01503         size_t      result_size;
01504 
01505         if (collid != DEFAULT_COLLATION_OID)
01506         {
01507             if (!OidIsValid(collid))
01508             {
01509                 /*
01510                  * This typically means that the parser could not resolve a
01511                  * conflict of implicit collations, so report it that way.
01512                  */
01513                 ereport(ERROR,
01514                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
01515                          errmsg("could not determine which collation to use for lower() function"),
01516                          errhint("Use the COLLATE clause to set the collation explicitly.")));
01517             }
01518             mylocale = pg_newlocale_from_collation(collid);
01519         }
01520 
01521         /* Overflow paranoia */
01522         if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
01523             ereport(ERROR,
01524                     (errcode(ERRCODE_OUT_OF_MEMORY),
01525                      errmsg("out of memory")));
01526 
01527         /* Output workspace cannot have more codes than input bytes */
01528         workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
01529 
01530         char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
01531 
01532         for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
01533         {
01534 #ifdef HAVE_LOCALE_T
01535             if (mylocale)
01536                 workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
01537             else
01538 #endif
01539                 workspace[curr_char] = towlower(workspace[curr_char]);
01540         }
01541 
01542         /* Make result large enough; case change might change number of bytes */
01543         result_size = curr_char * pg_database_encoding_max_length() + 1;
01544         result = palloc(result_size);
01545 
01546         wchar2char(result, workspace, result_size, mylocale);
01547         pfree(workspace);
01548     }
01549 #endif   /* USE_WIDE_UPPER_LOWER */
01550     else
01551     {
01552 #ifdef HAVE_LOCALE_T
01553         pg_locale_t mylocale = 0;
01554 #endif
01555         char       *p;
01556 
01557         if (collid != DEFAULT_COLLATION_OID)
01558         {
01559             if (!OidIsValid(collid))
01560             {
01561                 /*
01562                  * This typically means that the parser could not resolve a
01563                  * conflict of implicit collations, so report it that way.
01564                  */
01565                 ereport(ERROR,
01566                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
01567                          errmsg("could not determine which collation to use for lower() function"),
01568                          errhint("Use the COLLATE clause to set the collation explicitly.")));
01569             }
01570 #ifdef HAVE_LOCALE_T
01571             mylocale = pg_newlocale_from_collation(collid);
01572 #endif
01573         }
01574 
01575         result = pnstrdup(buff, nbytes);
01576 
01577         /*
01578          * Note: we assume that tolower_l() will not be so broken as to need
01579          * an isupper_l() guard test.  When using the default collation, we
01580          * apply the traditional Postgres behavior that forces ASCII-style
01581          * treatment of I/i, but in non-default collations you get exactly
01582          * what the collation says.
01583          */
01584         for (p = result; *p; p++)
01585         {
01586 #ifdef HAVE_LOCALE_T
01587             if (mylocale)
01588                 *p = tolower_l((unsigned char) *p, mylocale);
01589             else
01590 #endif
01591                 *p = pg_tolower((unsigned char) *p);
01592         }
01593     }
01594 
01595     return result;
01596 }
01597 
01598 /*
01599  * collation-aware, wide-character-aware upper function
01600  *
01601  * We pass the number of bytes so we can pass varlena and char*
01602  * to this function.  The result is a palloc'd, null-terminated string.
01603  */
01604 char *
01605 str_toupper(const char *buff, size_t nbytes, Oid collid)
01606 {
01607     char       *result;
01608 
01609     if (!buff)
01610         return NULL;
01611 
01612     /* C/POSIX collations use this path regardless of database encoding */
01613     if (lc_ctype_is_c(collid))
01614     {
01615         result = asc_toupper(buff, nbytes);
01616     }
01617 #ifdef USE_WIDE_UPPER_LOWER
01618     else if (pg_database_encoding_max_length() > 1)
01619     {
01620         pg_locale_t mylocale = 0;
01621         wchar_t    *workspace;
01622         size_t      curr_char;
01623         size_t      result_size;
01624 
01625         if (collid != DEFAULT_COLLATION_OID)
01626         {
01627             if (!OidIsValid(collid))
01628             {
01629                 /*
01630                  * This typically means that the parser could not resolve a
01631                  * conflict of implicit collations, so report it that way.
01632                  */
01633                 ereport(ERROR,
01634                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
01635                          errmsg("could not determine which collation to use for upper() function"),
01636                          errhint("Use the COLLATE clause to set the collation explicitly.")));
01637             }
01638             mylocale = pg_newlocale_from_collation(collid);
01639         }
01640 
01641         /* Overflow paranoia */
01642         if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
01643             ereport(ERROR,
01644                     (errcode(ERRCODE_OUT_OF_MEMORY),
01645                      errmsg("out of memory")));
01646 
01647         /* Output workspace cannot have more codes than input bytes */
01648         workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
01649 
01650         char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
01651 
01652         for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
01653         {
01654 #ifdef HAVE_LOCALE_T
01655             if (mylocale)
01656                 workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
01657             else
01658 #endif
01659                 workspace[curr_char] = towupper(workspace[curr_char]);
01660         }
01661 
01662         /* Make result large enough; case change might change number of bytes */
01663         result_size = curr_char * pg_database_encoding_max_length() + 1;
01664         result = palloc(result_size);
01665 
01666         wchar2char(result, workspace, result_size, mylocale);
01667         pfree(workspace);
01668     }
01669 #endif   /* USE_WIDE_UPPER_LOWER */
01670     else
01671     {
01672 #ifdef HAVE_LOCALE_T
01673         pg_locale_t mylocale = 0;
01674 #endif
01675         char       *p;
01676 
01677         if (collid != DEFAULT_COLLATION_OID)
01678         {
01679             if (!OidIsValid(collid))
01680             {
01681                 /*
01682                  * This typically means that the parser could not resolve a
01683                  * conflict of implicit collations, so report it that way.
01684                  */
01685                 ereport(ERROR,
01686                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
01687                          errmsg("could not determine which collation to use for upper() function"),
01688                          errhint("Use the COLLATE clause to set the collation explicitly.")));
01689             }
01690 #ifdef HAVE_LOCALE_T
01691             mylocale = pg_newlocale_from_collation(collid);
01692 #endif
01693         }
01694 
01695         result = pnstrdup(buff, nbytes);
01696 
01697         /*
01698          * Note: we assume that toupper_l() will not be so broken as to need
01699          * an islower_l() guard test.  When using the default collation, we
01700          * apply the traditional Postgres behavior that forces ASCII-style
01701          * treatment of I/i, but in non-default collations you get exactly
01702          * what the collation says.
01703          */
01704         for (p = result; *p; p++)
01705         {
01706 #ifdef HAVE_LOCALE_T
01707             if (mylocale)
01708                 *p = toupper_l((unsigned char) *p, mylocale);
01709             else
01710 #endif
01711                 *p = pg_toupper((unsigned char) *p);
01712         }
01713     }
01714 
01715     return result;
01716 }
01717 
01718 /*
01719  * collation-aware, wide-character-aware initcap function
01720  *
01721  * We pass the number of bytes so we can pass varlena and char*
01722  * to this function.  The result is a palloc'd, null-terminated string.
01723  */
01724 char *
01725 str_initcap(const char *buff, size_t nbytes, Oid collid)
01726 {
01727     char       *result;
01728     int         wasalnum = false;
01729 
01730     if (!buff)
01731         return NULL;
01732 
01733     /* C/POSIX collations use this path regardless of database encoding */
01734     if (lc_ctype_is_c(collid))
01735     {
01736         result = asc_initcap(buff, nbytes);
01737     }
01738 #ifdef USE_WIDE_UPPER_LOWER
01739     else if (pg_database_encoding_max_length() > 1)
01740     {
01741         pg_locale_t mylocale = 0;
01742         wchar_t    *workspace;
01743         size_t      curr_char;
01744         size_t      result_size;
01745 
01746         if (collid != DEFAULT_COLLATION_OID)
01747         {
01748             if (!OidIsValid(collid))
01749             {
01750                 /*
01751                  * This typically means that the parser could not resolve a
01752                  * conflict of implicit collations, so report it that way.
01753                  */
01754                 ereport(ERROR,
01755                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
01756                          errmsg("could not determine which collation to use for initcap() function"),
01757                          errhint("Use the COLLATE clause to set the collation explicitly.")));
01758             }
01759             mylocale = pg_newlocale_from_collation(collid);
01760         }
01761 
01762         /* Overflow paranoia */
01763         if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
01764             ereport(ERROR,
01765                     (errcode(ERRCODE_OUT_OF_MEMORY),
01766                      errmsg("out of memory")));
01767 
01768         /* Output workspace cannot have more codes than input bytes */
01769         workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
01770 
01771         char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
01772 
01773         for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
01774         {
01775 #ifdef HAVE_LOCALE_T
01776             if (mylocale)
01777             {
01778                 if (wasalnum)
01779                     workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
01780                 else
01781                     workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
01782                 wasalnum = iswalnum_l(workspace[curr_char], mylocale);
01783             }
01784             else
01785 #endif
01786             {
01787                 if (wasalnum)
01788                     workspace[curr_char] = towlower(workspace[curr_char]);
01789                 else
01790                     workspace[curr_char] = towupper(workspace[curr_char]);
01791                 wasalnum = iswalnum(workspace[curr_char]);
01792             }
01793         }
01794 
01795         /* Make result large enough; case change might change number of bytes */
01796         result_size = curr_char * pg_database_encoding_max_length() + 1;
01797         result = palloc(result_size);
01798 
01799         wchar2char(result, workspace, result_size, mylocale);
01800         pfree(workspace);
01801     }
01802 #endif   /* USE_WIDE_UPPER_LOWER */
01803     else
01804     {
01805 #ifdef HAVE_LOCALE_T
01806         pg_locale_t mylocale = 0;
01807 #endif
01808         char       *p;
01809 
01810         if (collid != DEFAULT_COLLATION_OID)
01811         {
01812             if (!OidIsValid(collid))
01813             {
01814                 /*
01815                  * This typically means that the parser could not resolve a
01816                  * conflict of implicit collations, so report it that way.
01817                  */
01818                 ereport(ERROR,
01819                         (errcode(ERRCODE_INDETERMINATE_COLLATION),
01820                          errmsg("could not determine which collation to use for initcap() function"),
01821                          errhint("Use the COLLATE clause to set the collation explicitly.")));
01822             }
01823 #ifdef HAVE_LOCALE_T
01824             mylocale = pg_newlocale_from_collation(collid);
01825 #endif
01826         }
01827 
01828         result = pnstrdup(buff, nbytes);
01829 
01830         /*
01831          * Note: we assume that toupper_l()/tolower_l() will not be so broken
01832          * as to need guard tests.  When using the default collation, we apply
01833          * the traditional Postgres behavior that forces ASCII-style treatment
01834          * of I/i, but in non-default collations you get exactly what the
01835          * collation says.
01836          */
01837         for (p = result; *p; p++)
01838         {
01839 #ifdef HAVE_LOCALE_T
01840             if (mylocale)
01841             {
01842                 if (wasalnum)
01843                     *p = tolower_l((unsigned char) *p, mylocale);
01844                 else
01845                     *p = toupper_l((unsigned char) *p, mylocale);
01846                 wasalnum = isalnum_l((unsigned char) *p, mylocale);
01847             }
01848             else
01849 #endif
01850             {
01851                 if (wasalnum)
01852                     *p = pg_tolower((unsigned char) *p);
01853                 else
01854                     *p = pg_toupper((unsigned char) *p);
01855                 wasalnum = isalnum((unsigned char) *p);
01856             }
01857         }
01858     }
01859 
01860     return result;
01861 }
01862 
01863 /*
01864  * ASCII-only lower function
01865  *
01866  * We pass the number of bytes so we can pass varlena and char*
01867  * to this function.  The result is a palloc'd, null-terminated string.
01868  */
01869 char *
01870 asc_tolower(const char *buff, size_t nbytes)
01871 {
01872     char       *result;
01873     char       *p;
01874 
01875     if (!buff)
01876         return NULL;
01877 
01878     result = pnstrdup(buff, nbytes);
01879 
01880     for (p = result; *p; p++)
01881         *p = pg_ascii_tolower((unsigned char) *p);
01882 
01883     return result;
01884 }
01885 
01886 /*
01887  * ASCII-only upper function
01888  *
01889  * We pass the number of bytes so we can pass varlena and char*
01890  * to this function.  The result is a palloc'd, null-terminated string.
01891  */
01892 char *
01893 asc_toupper(const char *buff, size_t nbytes)
01894 {
01895     char       *result;
01896     char       *p;
01897 
01898     if (!buff)
01899         return NULL;
01900 
01901     result = pnstrdup(buff, nbytes);
01902 
01903     for (p = result; *p; p++)
01904         *p = pg_ascii_toupper((unsigned char) *p);
01905 
01906     return result;
01907 }
01908 
01909 /*
01910  * ASCII-only initcap function
01911  *
01912  * We pass the number of bytes so we can pass varlena and char*
01913  * to this function.  The result is a palloc'd, null-terminated string.
01914  */
01915 char *
01916 asc_initcap(const char *buff, size_t nbytes)
01917 {
01918     char       *result;
01919     char       *p;
01920     int         wasalnum = false;
01921 
01922     if (!buff)
01923         return NULL;
01924 
01925     result = pnstrdup(buff, nbytes);
01926 
01927     for (p = result; *p; p++)
01928     {
01929         char        c;
01930 
01931         if (wasalnum)
01932             *p = c = pg_ascii_tolower((unsigned char) *p);
01933         else
01934             *p = c = pg_ascii_toupper((unsigned char) *p);
01935         /* we don't trust isalnum() here */
01936         wasalnum = ((c >= 'A' && c <= 'Z') ||
01937                     (c >= 'a' && c <= 'z') ||
01938                     (c >= '0' && c <= '9'));
01939     }
01940 
01941     return result;
01942 }
01943 
01944 /* convenience routines for when the input is null-terminated */
01945 
01946 static char *
01947 str_tolower_z(const char *buff, Oid collid)
01948 {
01949     return str_tolower(buff, strlen(buff), collid);
01950 }
01951 
01952 static char *
01953 str_toupper_z(const char *buff, Oid collid)
01954 {
01955     return str_toupper(buff, strlen(buff), collid);
01956 }
01957 
01958 static char *
01959 str_initcap_z(const char *buff, Oid collid)
01960 {
01961     return str_initcap(buff, strlen(buff), collid);
01962 }
01963 
01964 static char *
01965 asc_tolower_z(const char *buff)
01966 {
01967     return asc_tolower(buff, strlen(buff));
01968 }
01969 
01970 static char *
01971 asc_toupper_z(const char *buff)
01972 {
01973     return asc_toupper(buff, strlen(buff));
01974 }
01975 
01976 /* asc_initcap_z is not currently needed */
01977 
01978 
01979 /* ----------
01980  * Skip TM / th in FROM_CHAR
01981  * ----------
01982  */
01983 #define SKIP_THth(_suf)     (S_THth(_suf) ? 2 : 0)
01984 
01985 #ifdef DEBUG_TO_FROM_CHAR
01986 /* -----------
01987  * DEBUG: Call for debug and for index checking; (Show ASCII char
01988  * and defined keyword for each used position
01989  * ----------
01990  */
01991 static void
01992 dump_index(const KeyWord *k, const int *index)
01993 {
01994     int         i,
01995                 count = 0,
01996                 free_i = 0;
01997 
01998     elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:");
01999 
02000     for (i = 0; i < KeyWord_INDEX_SIZE; i++)
02001     {
02002         if (index[i] != -1)
02003         {
02004             elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name);
02005             count++;
02006         }
02007         else
02008         {
02009             free_i++;
02010             elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]);
02011         }
02012     }
02013     elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d",
02014          count, free_i);
02015 }
02016 #endif   /* DEBUG */
02017 
02018 /* ----------
02019  * Return TRUE if next format picture is not digit value
02020  * ----------
02021  */
02022 static bool
02023 is_next_separator(FormatNode *n)
02024 {
02025     if (n->type == NODE_TYPE_END)
02026         return FALSE;
02027 
02028     if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
02029         return TRUE;
02030 
02031     /*
02032      * Next node
02033      */
02034     n++;
02035 
02036     /* end of format string is treated like a non-digit separator */
02037     if (n->type == NODE_TYPE_END)
02038         return TRUE;
02039 
02040     if (n->type == NODE_TYPE_ACTION)
02041     {
02042         if (n->key->is_digit)
02043             return FALSE;
02044 
02045         return TRUE;
02046     }
02047     else if (isdigit((unsigned char) n->character))
02048         return FALSE;
02049 
02050     return TRUE;                /* some non-digit input (separator) */
02051 }
02052 
02053 
02054 static int
02055 adjust_partial_year_to_2020(int year)
02056 {
02057     /*
02058      * Adjust all dates toward 2020; this is effectively what happens when we
02059      * assume '70' is 1970 and '69' is 2069.
02060      */
02061     /* Force 0-69 into the 2000's */
02062     if (year < 70)
02063         return year + 2000;
02064     /* Force 70-99 into the 1900's */
02065     else if (year < 100)
02066         return year + 1900;
02067     /* Force 100-519 into the 2000's */
02068     else if (year < 520)
02069         return year + 2000;
02070     /* Force 520-999 into the 1000's */
02071     else if (year < 1000)
02072         return year + 1000;
02073     else
02074         return year;
02075 }
02076 
02077 
02078 static int
02079 strspace_len(char *str)
02080 {
02081     int         len = 0;
02082 
02083     while (*str && isspace((unsigned char) *str))
02084     {
02085         str++;
02086         len++;
02087     }
02088     return len;
02089 }
02090 
02091 static int
02092 strdigits_len(char *str)
02093 {
02094     char       *p = str;
02095     int         len;
02096 
02097     len = strspace_len(str);
02098     p += len;
02099 
02100     while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ)
02101     {
02102         len++;
02103         p++;
02104     }
02105     return len;
02106 }
02107 
02108 /*
02109  * Set the date mode of a from-char conversion.
02110  *
02111  * Puke if the date mode has already been set, and the caller attempts to set
02112  * it to a conflicting mode.
02113  */
02114 static void
02115 from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode)
02116 {
02117     if (mode != FROM_CHAR_DATE_NONE)
02118     {
02119         if (tmfc->mode == FROM_CHAR_DATE_NONE)
02120             tmfc->mode = mode;
02121         else if (tmfc->mode != mode)
02122             ereport(ERROR,
02123                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02124                      errmsg("invalid combination of date conventions"),
02125                      errhint("Do not mix Gregorian and ISO week date "
02126                              "conventions in a formatting template.")));
02127     }
02128 }
02129 
02130 /*
02131  * Set the integer pointed to by 'dest' to the given value.
02132  *
02133  * Puke if the destination integer has previously been set to some other
02134  * non-zero value.
02135  */
02136 static void
02137 from_char_set_int(int *dest, const int value, const FormatNode *node)
02138 {
02139     if (*dest != 0 && *dest != value)
02140         ereport(ERROR,
02141                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02142            errmsg("conflicting values for \"%s\" field in formatting string",
02143                   node->key->name),
02144                  errdetail("This value contradicts a previous setting for "
02145                            "the same field type.")));
02146     *dest = value;
02147 }
02148 
02149 /*
02150  * Read a single integer from the source string, into the int pointed to by
02151  * 'dest'. If 'dest' is NULL, the result is discarded.
02152  *
02153  * In fixed-width mode (the node does not have the FM suffix), consume at most
02154  * 'len' characters.  However, any leading whitespace isn't counted in 'len'.
02155  *
02156  * We use strtol() to recover the integer value from the source string, in
02157  * accordance with the given FormatNode.
02158  *
02159  * If the conversion completes successfully, src will have been advanced to
02160  * point at the character immediately following the last character used in the
02161  * conversion.
02162  *
02163  * Return the number of characters consumed.
02164  *
02165  * Note that from_char_parse_int() provides a more convenient wrapper where
02166  * the length of the field is the same as the length of the format keyword (as
02167  * with DD and MI).
02168  */
02169 static int
02170 from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node)
02171 {
02172     long        result;
02173     char        copy[DCH_MAX_ITEM_SIZ + 1];
02174     char       *init = *src;
02175     int         used;
02176 
02177     /*
02178      * Skip any whitespace before parsing the integer.
02179      */
02180     *src += strspace_len(*src);
02181 
02182     Assert(len <= DCH_MAX_ITEM_SIZ);
02183     used = (int) strlcpy(copy, *src, len + 1);
02184 
02185     if (S_FM(node->suffix) || is_next_separator(node))
02186     {
02187         /*
02188          * This node is in Fill Mode, or the next node is known to be a
02189          * non-digit value, so we just slurp as many characters as we can get.
02190          */
02191         errno = 0;
02192         result = strtol(init, src, 10);
02193     }
02194     else
02195     {
02196         /*
02197          * We need to pull exactly the number of characters given in 'len' out
02198          * of the string, and convert those.
02199          */
02200         char       *last;
02201 
02202         if (used < len)
02203             ereport(ERROR,
02204                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02205                 errmsg("source string too short for \"%s\" formatting field",
02206                        node->key->name),
02207                      errdetail("Field requires %d characters, but only %d "
02208                                "remain.",
02209                                len, used),
02210                      errhint("If your source string is not fixed-width, try "
02211                              "using the \"FM\" modifier.")));
02212 
02213         errno = 0;
02214         result = strtol(copy, &last, 10);
02215         used = last - copy;
02216 
02217         if (used > 0 && used < len)
02218             ereport(ERROR,
02219                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02220                      errmsg("invalid value \"%s\" for \"%s\"",
02221                             copy, node->key->name),
02222                      errdetail("Field requires %d characters, but only %d "
02223                                "could be parsed.", len, used),
02224                      errhint("If your source string is not fixed-width, try "
02225                              "using the \"FM\" modifier.")));
02226 
02227         *src += used;
02228     }
02229 
02230     if (*src == init)
02231         ereport(ERROR,
02232                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02233                  errmsg("invalid value \"%s\" for \"%s\"",
02234                         copy, node->key->name),
02235                  errdetail("Value must be an integer.")));
02236 
02237     if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
02238         ereport(ERROR,
02239                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02240                  errmsg("value for \"%s\" in source string is out of range",
02241                         node->key->name),
02242                  errdetail("Value must be in the range %d to %d.",
02243                            INT_MIN, INT_MAX)));
02244 
02245     if (dest != NULL)
02246         from_char_set_int(dest, (int) result, node);
02247     return *src - init;
02248 }
02249 
02250 /*
02251  * Call from_char_parse_int_len(), using the length of the format keyword as
02252  * the expected length of the field.
02253  *
02254  * Don't call this function if the field differs in length from the format
02255  * keyword (as with HH24; the keyword length is 4, but the field length is 2).
02256  * In such cases, call from_char_parse_int_len() instead to specify the
02257  * required length explicitly.
02258  */
02259 static int
02260 from_char_parse_int(int *dest, char **src, FormatNode *node)
02261 {
02262     return from_char_parse_int_len(dest, src, node->key->len, node);
02263 }
02264 
02265 /* ----------
02266  * Sequential search with to upper/lower conversion
02267  * ----------
02268  */
02269 static int
02270 seq_search(char *name, char **array, int type, int max, int *len)
02271 {
02272     char       *p,
02273                *n,
02274               **a;
02275     int         last,
02276                 i;
02277 
02278     *len = 0;
02279 
02280     if (!*name)
02281         return -1;
02282 
02283     /* set first char */
02284     if (type == ONE_UPPER || type == ALL_UPPER)
02285         *name = pg_toupper((unsigned char) *name);
02286     else if (type == ALL_LOWER)
02287         *name = pg_tolower((unsigned char) *name);
02288 
02289     for (last = 0, a = array; *a != NULL; a++)
02290     {
02291         /* comperate first chars */
02292         if (*name != **a)
02293             continue;
02294 
02295         for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++)
02296         {
02297             /* search fragment (max) only */
02298             if (max && i == max)
02299             {
02300                 *len = i;
02301                 return a - array;
02302             }
02303             /* full size */
02304             if (*p == '\0')
02305             {
02306                 *len = i;
02307                 return a - array;
02308             }
02309             /* Not found in array 'a' */
02310             if (*n == '\0')
02311                 break;
02312 
02313             /*
02314              * Convert (but convert new chars only)
02315              */
02316             if (i > last)
02317             {
02318                 if (type == ONE_UPPER || type == ALL_LOWER)
02319                     *n = pg_tolower((unsigned char) *n);
02320                 else if (type == ALL_UPPER)
02321                     *n = pg_toupper((unsigned char) *n);
02322                 last = i;
02323             }
02324 
02325 #ifdef DEBUG_TO_FROM_CHAR
02326             elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)",
02327                  *n, *p, *a, name);
02328 #endif
02329             if (*n != *p)
02330                 break;
02331         }
02332     }
02333 
02334     return -1;
02335 }
02336 
02337 /*
02338  * Perform a sequential search in 'array' for text matching the first 'max'
02339  * characters of the source string.
02340  *
02341  * If a match is found, copy the array index of the match into the integer
02342  * pointed to by 'dest', advance 'src' to the end of the part of the string
02343  * which matched, and return the number of characters consumed.
02344  *
02345  * If the string doesn't match, throw an error.
02346  */
02347 static int
02348 from_char_seq_search(int *dest, char **src, char **array, int type, int max,
02349                      FormatNode *node)
02350 {
02351     int         len;
02352 
02353     *dest = seq_search(*src, array, type, max, &len);
02354     if (len <= 0)
02355     {
02356         char        copy[DCH_MAX_ITEM_SIZ + 1];
02357 
02358         Assert(max <= DCH_MAX_ITEM_SIZ);
02359         strlcpy(copy, *src, max + 1);
02360 
02361         ereport(ERROR,
02362                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02363                  errmsg("invalid value \"%s\" for \"%s\"",
02364                         copy, node->key->name),
02365                  errdetail("The given value did not match any of the allowed "
02366                            "values for this field.")));
02367     }
02368     *src += len;
02369     return len;
02370 }
02371 
02372 /* ----------
02373  * Process a TmToChar struct as denoted by a list of FormatNodes.
02374  * The formatted data is written to the string pointed to by 'out'.
02375  * ----------
02376  */
02377 static void
02378 DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
02379 {
02380     FormatNode *n;
02381     char       *s;
02382     struct pg_tm *tm = &in->tm;
02383     int         i;
02384 
02385     /* cache localized days and months */
02386     cache_locale_time();
02387 
02388     s = out;
02389     for (n = node; n->type != NODE_TYPE_END; n++)
02390     {
02391         if (n->type != NODE_TYPE_ACTION)
02392         {
02393             *s = n->character;
02394             s++;
02395             continue;
02396         }
02397 
02398         switch (n->key->id)
02399         {
02400             case DCH_A_M:
02401             case DCH_P_M:
02402                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02403                        ? P_M_STR : A_M_STR);
02404                 s += strlen(s);
02405                 break;
02406             case DCH_AM:
02407             case DCH_PM:
02408                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02409                        ? PM_STR : AM_STR);
02410                 s += strlen(s);
02411                 break;
02412             case DCH_a_m:
02413             case DCH_p_m:
02414                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02415                        ? p_m_STR : a_m_STR);
02416                 s += strlen(s);
02417                 break;
02418             case DCH_am:
02419             case DCH_pm:
02420                 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02421                        ? pm_STR : am_STR);
02422                 s += strlen(s);
02423                 break;
02424             case DCH_HH:
02425             case DCH_HH12:
02426 
02427                 /*
02428                  * display time as shown on a 12-hour clock, even for
02429                  * intervals
02430                  */
02431                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
02432                  tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? HOURS_PER_DAY / 2 :
02433                         tm->tm_hour % (HOURS_PER_DAY / 2));
02434                 if (S_THth(n->suffix))
02435                     str_numth(s, s, S_TH_TYPE(n->suffix));
02436                 s += strlen(s);
02437                 break;
02438             case DCH_HH24:
02439                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_hour);
02440                 if (S_THth(n->suffix))
02441                     str_numth(s, s, S_TH_TYPE(n->suffix));
02442                 s += strlen(s);
02443                 break;
02444             case DCH_MI:
02445                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_min);
02446                 if (S_THth(n->suffix))
02447                     str_numth(s, s, S_TH_TYPE(n->suffix));
02448                 s += strlen(s);
02449                 break;
02450             case DCH_SS:
02451                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_sec);
02452                 if (S_THth(n->suffix))
02453                     str_numth(s, s, S_TH_TYPE(n->suffix));
02454                 s += strlen(s);
02455                 break;
02456             case DCH_MS:        /* millisecond */
02457 #ifdef HAVE_INT64_TIMESTAMP
02458                 sprintf(s, "%03d", (int) (in->fsec / INT64CONST(1000)));
02459 #else
02460                 /* No rint() because we can't overflow and we might print US */
02461                 sprintf(s, "%03d", (int) (in->fsec * 1000));
02462 #endif
02463                 if (S_THth(n->suffix))
02464                     str_numth(s, s, S_TH_TYPE(n->suffix));
02465                 s += strlen(s);
02466                 break;
02467             case DCH_US:        /* microsecond */
02468 #ifdef HAVE_INT64_TIMESTAMP
02469                 sprintf(s, "%06d", (int) in->fsec);
02470 #else
02471                 /* don't use rint() because we can't overflow 1000 */
02472                 sprintf(s, "%06d", (int) (in->fsec * 1000000));
02473 #endif
02474                 if (S_THth(n->suffix))
02475                     str_numth(s, s, S_TH_TYPE(n->suffix));
02476                 s += strlen(s);
02477                 break;
02478             case DCH_SSSS:
02479                 sprintf(s, "%d", tm->tm_hour * SECS_PER_HOUR +
02480                         tm->tm_min * SECS_PER_MINUTE +
02481                         tm->tm_sec);
02482                 if (S_THth(n->suffix))
02483                     str_numth(s, s, S_TH_TYPE(n->suffix));
02484                 s += strlen(s);
02485                 break;
02486             case DCH_tz:
02487                 INVALID_FOR_INTERVAL;
02488                 if (tmtcTzn(in))
02489                 {
02490                     /* We assume here that timezone names aren't localized */
02491                     char       *p = asc_tolower_z(tmtcTzn(in));
02492 
02493                     strcpy(s, p);
02494                     pfree(p);
02495                     s += strlen(s);
02496                 }
02497                 break;
02498             case DCH_TZ:
02499                 INVALID_FOR_INTERVAL;
02500                 if (tmtcTzn(in))
02501                 {
02502                     strcpy(s, tmtcTzn(in));
02503                     s += strlen(s);
02504                 }
02505                 break;
02506             case DCH_A_D:
02507             case DCH_B_C:
02508                 INVALID_FOR_INTERVAL;
02509                 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
02510                 s += strlen(s);
02511                 break;
02512             case DCH_AD:
02513             case DCH_BC:
02514                 INVALID_FOR_INTERVAL;
02515                 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
02516                 s += strlen(s);
02517                 break;
02518             case DCH_a_d:
02519             case DCH_b_c:
02520                 INVALID_FOR_INTERVAL;
02521                 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
02522                 s += strlen(s);
02523                 break;
02524             case DCH_ad:
02525             case DCH_bc:
02526                 INVALID_FOR_INTERVAL;
02527                 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
02528                 s += strlen(s);
02529                 break;
02530             case DCH_MONTH:
02531                 INVALID_FOR_INTERVAL;
02532                 if (!tm->tm_mon)
02533                     break;
02534                 if (S_TM(n->suffix))
02535                     strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1], collid));
02536                 else
02537                     sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02538                          asc_toupper_z(months_full[tm->tm_mon - 1]));
02539                 s += strlen(s);
02540                 break;
02541             case DCH_Month:
02542                 INVALID_FOR_INTERVAL;
02543                 if (!tm->tm_mon)
02544                     break;
02545                 if (S_TM(n->suffix))
02546                     strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1], collid));
02547                 else
02548                     sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02549                             months_full[tm->tm_mon - 1]);
02550                 s += strlen(s);
02551                 break;
02552             case DCH_month:
02553                 INVALID_FOR_INTERVAL;
02554                 if (!tm->tm_mon)
02555                     break;
02556                 if (S_TM(n->suffix))
02557                     strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1], collid));
02558                 else
02559                     sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02560                             asc_tolower_z(months_full[tm->tm_mon - 1]));
02561                 s += strlen(s);
02562                 break;
02563             case DCH_MON:
02564                 INVALID_FOR_INTERVAL;
02565                 if (!tm->tm_mon)
02566                     break;
02567                 if (S_TM(n->suffix))
02568                     strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid));
02569                 else
02570                     strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
02571                 s += strlen(s);
02572                 break;
02573             case DCH_Mon:
02574                 INVALID_FOR_INTERVAL;
02575                 if (!tm->tm_mon)
02576                     break;
02577                 if (S_TM(n->suffix))
02578                     strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid));
02579                 else
02580                     strcpy(s, months[tm->tm_mon - 1]);
02581                 s += strlen(s);
02582                 break;
02583             case DCH_mon:
02584                 INVALID_FOR_INTERVAL;
02585                 if (!tm->tm_mon)
02586                     break;
02587                 if (S_TM(n->suffix))
02588                     strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid));
02589                 else
02590                     strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
02591                 s += strlen(s);
02592                 break;
02593             case DCH_MM:
02594                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mon);
02595                 if (S_THth(n->suffix))
02596                     str_numth(s, s, S_TH_TYPE(n->suffix));
02597                 s += strlen(s);
02598                 break;
02599             case DCH_DAY:
02600                 INVALID_FOR_INTERVAL;
02601                 if (S_TM(n->suffix))
02602                     strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday], collid));
02603                 else
02604                     sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02605                             asc_toupper_z(days[tm->tm_wday]));
02606                 s += strlen(s);
02607                 break;
02608             case DCH_Day:
02609                 INVALID_FOR_INTERVAL;
02610                 if (S_TM(n->suffix))
02611                     strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday], collid));
02612                 else
02613                     sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02614                             days[tm->tm_wday]);
02615                 s += strlen(s);
02616                 break;
02617             case DCH_day:
02618                 INVALID_FOR_INTERVAL;
02619                 if (S_TM(n->suffix))
02620                     strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday], collid));
02621                 else
02622                     sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02623                             asc_tolower_z(days[tm->tm_wday]));
02624                 s += strlen(s);
02625                 break;
02626             case DCH_DY:
02627                 INVALID_FOR_INTERVAL;
02628                 if (S_TM(n->suffix))
02629                     strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday], collid));
02630                 else
02631                     strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
02632                 s += strlen(s);
02633                 break;
02634             case DCH_Dy:
02635                 INVALID_FOR_INTERVAL;
02636                 if (S_TM(n->suffix))
02637                     strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday], collid));
02638                 else
02639                     strcpy(s, days_short[tm->tm_wday]);
02640                 s += strlen(s);
02641                 break;
02642             case DCH_dy:
02643                 INVALID_FOR_INTERVAL;
02644                 if (S_TM(n->suffix))
02645                     strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday], collid));
02646                 else
02647                     strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
02648                 s += strlen(s);
02649                 break;
02650             case DCH_DDD:
02651             case DCH_IDDD:
02652                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
02653                         (n->key->id == DCH_DDD) ?
02654                         tm->tm_yday :
02655                       date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday));
02656                 if (S_THth(n->suffix))
02657                     str_numth(s, s, S_TH_TYPE(n->suffix));
02658                 s += strlen(s);
02659                 break;
02660             case DCH_DD:
02661                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
02662                 if (S_THth(n->suffix))
02663                     str_numth(s, s, S_TH_TYPE(n->suffix));
02664                 s += strlen(s);
02665                 break;
02666             case DCH_D:
02667                 INVALID_FOR_INTERVAL;
02668                 sprintf(s, "%d", tm->tm_wday + 1);
02669                 if (S_THth(n->suffix))
02670                     str_numth(s, s, S_TH_TYPE(n->suffix));
02671                 s += strlen(s);
02672                 break;
02673             case DCH_ID:
02674                 INVALID_FOR_INTERVAL;
02675                 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
02676                 if (S_THth(n->suffix))
02677                     str_numth(s, s, S_TH_TYPE(n->suffix));
02678                 s += strlen(s);
02679                 break;
02680             case DCH_WW:
02681                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
02682                         (tm->tm_yday - 1) / 7 + 1);
02683                 if (S_THth(n->suffix))
02684                     str_numth(s, s, S_TH_TYPE(n->suffix));
02685                 s += strlen(s);
02686                 break;
02687             case DCH_IW:
02688                 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
02689                         date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
02690                 if (S_THth(n->suffix))
02691                     str_numth(s, s, S_TH_TYPE(n->suffix));
02692                 s += strlen(s);
02693                 break;
02694             case DCH_Q:
02695                 if (!tm->tm_mon)
02696                     break;
02697                 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
02698                 if (S_THth(n->suffix))
02699                     str_numth(s, s, S_TH_TYPE(n->suffix));
02700                 s += strlen(s);
02701                 break;
02702             case DCH_CC:
02703                 if (is_interval)    /* straight calculation */
02704                     i = tm->tm_year / 100;
02705                 else
02706                 {
02707                     if (tm->tm_year > 0)
02708                         /* Century 20 == 1901 - 2000 */
02709                         i = (tm->tm_year - 1) / 100 + 1;
02710                     else
02711                         /* Century 6BC == 600BC - 501BC */
02712                         i = tm->tm_year / 100 - 1;
02713                 }
02714                 if (i <= 99 && i >= -99)
02715                     sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, i);
02716                 else
02717                     sprintf(s, "%d", i);
02718                 if (S_THth(n->suffix))
02719                     str_numth(s, s, S_TH_TYPE(n->suffix));
02720                 s += strlen(s);
02721                 break;
02722             case DCH_Y_YYY:
02723                 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
02724                 sprintf(s, "%d,%03d", i,
02725                         ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
02726                 if (S_THth(n->suffix))
02727                     str_numth(s, s, S_TH_TYPE(n->suffix));
02728                 s += strlen(s);
02729                 break;
02730             case DCH_YYYY:
02731             case DCH_IYYY:
02732                 sprintf(s, "%0*d",
02733                         S_FM(n->suffix) ? 0 : 4,
02734                         (n->key->id == DCH_YYYY ?
02735                          ADJUST_YEAR(tm->tm_year, is_interval) :
02736                          ADJUST_YEAR(date2isoyear(tm->tm_year,
02737                                                   tm->tm_mon,
02738                                                   tm->tm_mday),
02739                                      is_interval)));
02740                 if (S_THth(n->suffix))
02741                     str_numth(s, s, S_TH_TYPE(n->suffix));
02742                 s += strlen(s);
02743                 break;
02744             case DCH_YYY:
02745             case DCH_IYY:
02746                 sprintf(s, "%0*d",
02747                         S_FM(n->suffix) ? 0 : 3,
02748                         (n->key->id == DCH_YYY ?
02749                          ADJUST_YEAR(tm->tm_year, is_interval) :
02750                          ADJUST_YEAR(date2isoyear(tm->tm_year,
02751                                                   tm->tm_mon,
02752                                                   tm->tm_mday),
02753                                      is_interval)) % 1000);
02754                 if (S_THth(n->suffix))
02755                     str_numth(s, s, S_TH_TYPE(n->suffix));
02756                 s += strlen(s);
02757                 break;
02758             case DCH_YY:
02759             case DCH_IY:
02760                 sprintf(s, "%0*d",
02761                         S_FM(n->suffix) ? 0 : 2,
02762                         (n->key->id == DCH_YY ?
02763                          ADJUST_YEAR(tm->tm_year, is_interval) :
02764                          ADJUST_YEAR(date2isoyear(tm->tm_year,
02765                                                   tm->tm_mon,
02766                                                   tm->tm_mday),
02767                                      is_interval)) % 100);
02768                 if (S_THth(n->suffix))
02769                     str_numth(s, s, S_TH_TYPE(n->suffix));
02770                 s += strlen(s);
02771                 break;
02772             case DCH_Y:
02773             case DCH_I:
02774                 sprintf(s, "%1d",
02775                         (n->key->id == DCH_Y ?
02776                          ADJUST_YEAR(tm->tm_year, is_interval) :
02777                          ADJUST_YEAR(date2isoyear(tm->tm_year,
02778                                                   tm->tm_mon,
02779                                                   tm->tm_mday),
02780                                      is_interval)) % 10);
02781                 if (S_THth(n->suffix))
02782                     str_numth(s, s, S_TH_TYPE(n->suffix));
02783                 s += strlen(s);
02784                 break;
02785             case DCH_RM:
02786                 if (!tm->tm_mon)
02787                     break;
02788                 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
02789                         rm_months_upper[MONTHS_PER_YEAR - tm->tm_mon]);
02790                 s += strlen(s);
02791                 break;
02792             case DCH_rm:
02793                 if (!tm->tm_mon)
02794                     break;
02795                 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
02796                         rm_months_lower[MONTHS_PER_YEAR - tm->tm_mon]);
02797                 s += strlen(s);
02798                 break;
02799             case DCH_W:
02800                 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
02801                 if (S_THth(n->suffix))
02802                     str_numth(s, s, S_TH_TYPE(n->suffix));
02803                 s += strlen(s);
02804                 break;
02805             case DCH_J:
02806                 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
02807                 if (S_THth(n->suffix))
02808                     str_numth(s, s, S_TH_TYPE(n->suffix));
02809                 s += strlen(s);
02810                 break;
02811         }
02812     }
02813 
02814     *s = '\0';
02815 }
02816 
02817 /* ----------
02818  * Process a string as denoted by a list of FormatNodes.
02819  * The TmFromChar struct pointed to by 'out' is populated with the results.
02820  *
02821  * Note: we currently don't have any to_interval() function, so there
02822  * is no need here for INVALID_FOR_INTERVAL checks.
02823  * ----------
02824  */
02825 static void
02826 DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
02827 {
02828     FormatNode *n;
02829     char       *s;
02830     int         len,
02831                 value;
02832     bool        fx_mode = false;
02833 
02834     for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
02835     {
02836         if (n->type != NODE_TYPE_ACTION)
02837         {
02838             s++;
02839             /* Ignore spaces when not in FX (fixed width) mode */
02840             if (isspace((unsigned char) n->character) && !fx_mode)
02841             {
02842                 while (*s != '\0' && isspace((unsigned char) *s))
02843                     s++;
02844             }
02845             continue;
02846         }
02847 
02848         from_char_set_mode(out, n->key->date_mode);
02849 
02850         switch (n->key->id)
02851         {
02852             case DCH_FX:
02853                 fx_mode = true;
02854                 break;
02855             case DCH_A_M:
02856             case DCH_P_M:
02857             case DCH_a_m:
02858             case DCH_p_m:
02859                 from_char_seq_search(&value, &s, ampm_strings_long,
02860                                      ALL_UPPER, n->key->len, n);
02861                 from_char_set_int(&out->pm, value % 2, n);
02862                 out->clock = CLOCK_12_HOUR;
02863                 break;
02864             case DCH_AM:
02865             case DCH_PM:
02866             case DCH_am:
02867             case DCH_pm:
02868                 from_char_seq_search(&value, &s, ampm_strings,
02869                                      ALL_UPPER, n->key->len, n);
02870                 from_char_set_int(&out->pm, value % 2, n);
02871                 out->clock = CLOCK_12_HOUR;
02872                 break;
02873             case DCH_HH:
02874             case DCH_HH12:
02875                 from_char_parse_int_len(&out->hh, &s, 2, n);
02876                 out->clock = CLOCK_12_HOUR;
02877                 s += SKIP_THth(n->suffix);
02878                 break;
02879             case DCH_HH24:
02880                 from_char_parse_int_len(&out->hh, &s, 2, n);
02881                 s += SKIP_THth(n->suffix);
02882                 break;
02883             case DCH_MI:
02884                 from_char_parse_int(&out->mi, &s, n);
02885                 s += SKIP_THth(n->suffix);
02886                 break;
02887             case DCH_SS:
02888                 from_char_parse_int(&out->ss, &s, n);
02889                 s += SKIP_THth(n->suffix);
02890                 break;
02891             case DCH_MS:        /* millisecond */
02892                 len = from_char_parse_int_len(&out->ms, &s, 3, n);
02893 
02894                 /*
02895                  * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
02896                  */
02897                 out->ms *= len == 1 ? 100 :
02898                     len == 2 ? 10 : 1;
02899 
02900                 s += SKIP_THth(n->suffix);
02901                 break;
02902             case DCH_US:        /* microsecond */
02903                 len = from_char_parse_int_len(&out->us, &s, 6, n);
02904 
02905                 out->us *= len == 1 ? 100000 :
02906                     len == 2 ? 10000 :
02907                     len == 3 ? 1000 :
02908                     len == 4 ? 100 :
02909                     len == 5 ? 10 : 1;
02910 
02911                 s += SKIP_THth(n->suffix);
02912                 break;
02913             case DCH_SSSS:
02914                 from_char_parse_int(&out->ssss, &s, n);
02915                 s += SKIP_THth(n->suffix);
02916                 break;
02917             case DCH_tz:
02918             case DCH_TZ:
02919                 ereport(ERROR,
02920                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02921                          errmsg("\"TZ\"/\"tz\" format patterns are not supported in to_date")));
02922             case DCH_A_D:
02923             case DCH_B_C:
02924             case DCH_a_d:
02925             case DCH_b_c:
02926                 from_char_seq_search(&value, &s, adbc_strings_long,
02927                                      ALL_UPPER, n->key->len, n);
02928                 from_char_set_int(&out->bc, value % 2, n);
02929                 break;
02930             case DCH_AD:
02931             case DCH_BC:
02932             case DCH_ad:
02933             case DCH_bc:
02934                 from_char_seq_search(&value, &s, adbc_strings,
02935                                      ALL_UPPER, n->key->len, n);
02936                 from_char_set_int(&out->bc, value % 2, n);
02937                 break;
02938             case DCH_MONTH:
02939             case DCH_Month:
02940             case DCH_month:
02941                 from_char_seq_search(&value, &s, months_full, ONE_UPPER,
02942                                      MAX_MONTH_LEN, n);
02943                 from_char_set_int(&out->mm, value + 1, n);
02944                 break;
02945             case DCH_MON:
02946             case DCH_Mon:
02947             case DCH_mon:
02948                 from_char_seq_search(&value, &s, months, ONE_UPPER,
02949                                      MAX_MON_LEN, n);
02950                 from_char_set_int(&out->mm, value + 1, n);
02951                 break;
02952             case DCH_MM:
02953                 from_char_parse_int(&out->mm, &s, n);
02954                 s += SKIP_THth(n->suffix);
02955                 break;
02956             case DCH_DAY:
02957             case DCH_Day:
02958             case DCH_day:
02959                 from_char_seq_search(&value, &s, days, ONE_UPPER,
02960                                      MAX_DAY_LEN, n);
02961                 from_char_set_int(&out->d, value, n);
02962                 out->d++;
02963                 break;
02964             case DCH_DY:
02965             case DCH_Dy:
02966             case DCH_dy:
02967                 from_char_seq_search(&value, &s, days, ONE_UPPER,
02968                                      MAX_DY_LEN, n);
02969                 from_char_set_int(&out->d, value, n);
02970                 out->d++;
02971                 break;
02972             case DCH_DDD:
02973                 from_char_parse_int(&out->ddd, &s, n);
02974                 s += SKIP_THth(n->suffix);
02975                 break;
02976             case DCH_IDDD:
02977                 from_char_parse_int_len(&out->ddd, &s, 3, n);
02978                 s += SKIP_THth(n->suffix);
02979                 break;
02980             case DCH_DD:
02981                 from_char_parse_int(&out->dd, &s, n);
02982                 s += SKIP_THth(n->suffix);
02983                 break;
02984             case DCH_D:
02985                 from_char_parse_int(&out->d, &s, n);
02986                 s += SKIP_THth(n->suffix);
02987                 break;
02988             case DCH_ID:
02989                 from_char_parse_int_len(&out->d, &s, 1, n);
02990                 /* Shift numbering to match Gregorian where Sunday = 1 */
02991                 if (++out->d > 7)
02992                     out->d = 1;
02993                 s += SKIP_THth(n->suffix);
02994                 break;
02995             case DCH_WW:
02996             case DCH_IW:
02997                 from_char_parse_int(&out->ww, &s, n);
02998                 s += SKIP_THth(n->suffix);
02999                 break;
03000             case DCH_Q:
03001 
03002                 /*
03003                  * We ignore 'Q' when converting to date because it is unclear
03004                  * which date in the quarter to use, and some people specify
03005                  * both quarter and month, so if it was honored it might
03006                  * conflict with the supplied month. That is also why we don't
03007                  * throw an error.
03008                  *
03009                  * We still parse the source string for an integer, but it
03010                  * isn't stored anywhere in 'out'.
03011                  */
03012                 from_char_parse_int((int *) NULL, &s, n);
03013                 s += SKIP_THth(n->suffix);
03014                 break;
03015             case DCH_CC:
03016                 from_char_parse_int(&out->cc, &s, n);
03017                 s += SKIP_THth(n->suffix);
03018                 break;
03019             case DCH_Y_YYY:
03020                 {
03021                     int         matched,
03022                                 years,
03023                                 millenia;
03024 
03025                     matched = sscanf(s, "%d,%03d", &millenia, &years);
03026                     if (matched != 2)
03027                         ereport(ERROR,
03028                                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
03029                               errmsg("invalid input string for \"Y,YYY\"")));
03030                     years += (millenia * 1000);
03031                     from_char_set_int(&out->year, years, n);
03032                     out->yysz = 4;
03033                     s += strdigits_len(s) + 4 + SKIP_THth(n->suffix);
03034                 }
03035                 break;
03036             case DCH_YYYY:
03037             case DCH_IYYY:
03038                 from_char_parse_int(&out->year, &s, n);
03039                 out->yysz = 4;
03040                 s += SKIP_THth(n->suffix);
03041                 break;
03042             case DCH_YYY:
03043             case DCH_IYY:
03044                 if (from_char_parse_int(&out->year, &s, n) < 4)
03045                     out->year = adjust_partial_year_to_2020(out->year);
03046                 out->yysz = 3;
03047                 s += SKIP_THth(n->suffix);
03048                 break;
03049             case DCH_YY:
03050             case DCH_IY:
03051                 if (from_char_parse_int(&out->year, &s, n) < 4)
03052                     out->year = adjust_partial_year_to_2020(out->year);
03053                 out->yysz = 2;
03054                 s += SKIP_THth(n->suffix);
03055                 break;
03056             case DCH_Y:
03057             case DCH_I:
03058                 if (from_char_parse_int(&out->year, &s, n) < 4)
03059                     out->year = adjust_partial_year_to_2020(out->year);
03060                 out->yysz = 1;
03061                 s += SKIP_THth(n->suffix);
03062                 break;
03063             case DCH_RM:
03064                 from_char_seq_search(&value, &s, rm_months_upper,
03065                                      ALL_UPPER, MAX_RM_LEN, n);
03066                 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
03067                 break;
03068             case DCH_rm:
03069                 from_char_seq_search(&value, &s, rm_months_lower,
03070                                      ALL_LOWER, MAX_RM_LEN, n);
03071                 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
03072                 break;
03073             case DCH_W:
03074                 from_char_parse_int(&out->w, &s, n);
03075                 s += SKIP_THth(n->suffix);
03076                 break;
03077             case DCH_J:
03078                 from_char_parse_int(&out->j, &s, n);
03079                 s += SKIP_THth(n->suffix);
03080                 break;
03081         }
03082     }
03083 }
03084 
03085 static DCHCacheEntry *
03086 DCH_cache_getnew(char *str)
03087 {
03088     DCHCacheEntry *ent;
03089 
03090     /* counter overflow check - paranoia? */
03091     if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
03092     {
03093         DCHCounter = 0;
03094 
03095         for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
03096             ent->age = (++DCHCounter);
03097     }
03098 
03099     /*
03100      * If cache is full, remove oldest entry
03101      */
03102     if (n_DCHCache > DCH_CACHE_FIELDS)
03103     {
03104         DCHCacheEntry *old = DCHCache + 0;
03105 
03106 #ifdef DEBUG_TO_FROM_CHAR
03107         elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
03108 #endif
03109         for (ent = DCHCache + 1; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
03110         {
03111             if (ent->age < old->age)
03112                 old = ent;
03113         }
03114 #ifdef DEBUG_TO_FROM_CHAR
03115         elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
03116 #endif
03117         StrNCpy(old->str, str, DCH_CACHE_SIZE + 1);
03118         /* old->format fill parser */
03119         old->age = (++DCHCounter);
03120         return old;
03121     }
03122     else
03123     {
03124 #ifdef DEBUG_TO_FROM_CHAR
03125         elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
03126 #endif
03127         ent = DCHCache + n_DCHCache;
03128         StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1);
03129         /* ent->format fill parser */
03130         ent->age = (++DCHCounter);
03131         ++n_DCHCache;
03132         return ent;
03133     }
03134 }
03135 
03136 static DCHCacheEntry *
03137 DCH_cache_search(char *str)
03138 {
03139     int         i;
03140     DCHCacheEntry *ent;
03141 
03142     /* counter overflow check - paranoia? */
03143     if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
03144     {
03145         DCHCounter = 0;
03146 
03147         for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
03148             ent->age = (++DCHCounter);
03149     }
03150 
03151     for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++)
03152     {
03153         if (strcmp(ent->str, str) == 0)
03154         {
03155             ent->age = (++DCHCounter);
03156             return ent;
03157         }
03158     }
03159 
03160     return NULL;
03161 }
03162 
03163 /*
03164  * Format a date/time or interval into a string according to fmt.
03165  * We parse fmt into a list of FormatNodes.  This is then passed to DCH_to_char
03166  * for formatting.
03167  */
03168 static text *
03169 datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
03170 {
03171     FormatNode *format;
03172     char       *fmt_str,
03173                *result;
03174     bool        incache;
03175     int         fmt_len;
03176     text       *res;
03177 
03178     /*
03179      * Convert fmt to C string
03180      */
03181     fmt_str = text_to_cstring(fmt);
03182     fmt_len = strlen(fmt_str);
03183 
03184     /*
03185      * Allocate workspace for result as C string
03186      */
03187     result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
03188     *result = '\0';
03189 
03190     /*
03191      * Allocate new memory if format picture is bigger than static cache and
03192      * not use cache (call parser always)
03193      */
03194     if (fmt_len > DCH_CACHE_SIZE)
03195     {
03196         format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
03197         incache = FALSE;
03198 
03199         parse_format(format, fmt_str, DCH_keywords,
03200                      DCH_suff, DCH_index, DCH_TYPE, NULL);
03201 
03202         (format + fmt_len)->type = NODE_TYPE_END;       /* Paranoia? */
03203     }
03204     else
03205     {
03206         /*
03207          * Use cache buffers
03208          */
03209         DCHCacheEntry *ent;
03210 
03211         incache = TRUE;
03212 
03213         if ((ent = DCH_cache_search(fmt_str)) == NULL)
03214         {
03215             ent = DCH_cache_getnew(fmt_str);
03216 
03217             /*
03218              * Not in the cache, must run parser and save a new format-picture
03219              * to the cache.
03220              */
03221             parse_format(ent->format, fmt_str, DCH_keywords,
03222                          DCH_suff, DCH_index, DCH_TYPE, NULL);
03223 
03224             (ent->format + fmt_len)->type = NODE_TYPE_END;      /* Paranoia? */
03225 
03226 #ifdef DEBUG_TO_FROM_CHAR
03227             /* dump_node(ent->format, fmt_len); */
03228             /* dump_index(DCH_keywords, DCH_index);  */
03229 #endif
03230         }
03231         format = ent->format;
03232     }
03233 
03234     /* The real work is here */
03235     DCH_to_char(format, is_interval, tmtc, result, collid);
03236 
03237     if (!incache)
03238         pfree(format);
03239 
03240     pfree(fmt_str);
03241 
03242     /* convert C-string result to TEXT format */
03243     res = cstring_to_text(result);
03244 
03245     pfree(result);
03246     return res;
03247 }
03248 
03249 /****************************************************************************
03250  *              Public routines
03251  ***************************************************************************/
03252 
03253 /* -------------------
03254  * TIMESTAMP to_char()
03255  * -------------------
03256  */
03257 Datum
03258 timestamp_to_char(PG_FUNCTION_ARGS)
03259 {
03260     Timestamp   dt = PG_GETARG_TIMESTAMP(0);
03261     text       *fmt = PG_GETARG_TEXT_P(1),
03262                *res;
03263     TmToChar    tmtc;
03264     struct pg_tm *tm;
03265     int         thisdate;
03266 
03267     if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
03268         PG_RETURN_NULL();
03269 
03270     ZERO_tmtc(&tmtc);
03271     tm = tmtcTm(&tmtc);
03272 
03273     if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0)
03274         ereport(ERROR,
03275                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03276                  errmsg("timestamp out of range")));
03277 
03278     thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
03279     tm->tm_wday = (thisdate + 1) % 7;
03280     tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
03281 
03282     if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
03283         PG_RETURN_NULL();
03284 
03285     PG_RETURN_TEXT_P(res);
03286 }
03287 
03288 Datum
03289 timestamptz_to_char(PG_FUNCTION_ARGS)
03290 {
03291     TimestampTz dt = PG_GETARG_TIMESTAMP(0);
03292     text       *fmt = PG_GETARG_TEXT_P(1),
03293                *res;
03294     TmToChar    tmtc;
03295     int         tz;
03296     struct pg_tm *tm;
03297     int         thisdate;
03298 
03299     if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
03300         PG_RETURN_NULL();
03301 
03302     ZERO_tmtc(&tmtc);
03303     tm = tmtcTm(&tmtc);
03304 
03305     if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
03306         ereport(ERROR,
03307                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03308                  errmsg("timestamp out of range")));
03309 
03310     thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
03311     tm->tm_wday = (thisdate + 1) % 7;
03312     tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
03313 
03314     if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
03315         PG_RETURN_NULL();
03316 
03317     PG_RETURN_TEXT_P(res);
03318 }
03319 
03320 
03321 /* -------------------
03322  * INTERVAL to_char()
03323  * -------------------
03324  */
03325 Datum
03326 interval_to_char(PG_FUNCTION_ARGS)
03327 {
03328     Interval   *it = PG_GETARG_INTERVAL_P(0);
03329     text       *fmt = PG_GETARG_TEXT_P(1),
03330                *res;
03331     TmToChar    tmtc;
03332     struct pg_tm *tm;
03333 
03334     if ((VARSIZE(fmt) - VARHDRSZ) <= 0)
03335         PG_RETURN_NULL();
03336 
03337     ZERO_tmtc(&tmtc);
03338     tm = tmtcTm(&tmtc);
03339 
03340     if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0)
03341         PG_RETURN_NULL();
03342 
03343     /* wday is meaningless, yday approximates the total span in days */
03344     tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
03345 
03346     if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
03347         PG_RETURN_NULL();
03348 
03349     PG_RETURN_TEXT_P(res);
03350 }
03351 
03352 /* ---------------------
03353  * TO_TIMESTAMP()
03354  *
03355  * Make Timestamp from date_str which is formatted at argument 'fmt'
03356  * ( to_timestamp is reverse to_char() )
03357  * ---------------------
03358  */
03359 Datum
03360 to_timestamp(PG_FUNCTION_ARGS)
03361 {
03362     text       *date_txt = PG_GETARG_TEXT_P(0);
03363     text       *fmt = PG_GETARG_TEXT_P(1);
03364     Timestamp   result;
03365     int         tz;
03366     struct pg_tm tm;
03367     fsec_t      fsec;
03368 
03369     do_to_timestamp(date_txt, fmt, &tm, &fsec);
03370 
03371     tz = DetermineTimeZoneOffset(&tm, session_timezone);
03372 
03373     if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
03374         ereport(ERROR,
03375                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03376                  errmsg("timestamp out of range")));
03377 
03378     PG_RETURN_TIMESTAMP(result);
03379 }
03380 
03381 /* ----------
03382  * TO_DATE
03383  *  Make Date from date_str which is formated at argument 'fmt'
03384  * ----------
03385  */
03386 Datum
03387 to_date(PG_FUNCTION_ARGS)
03388 {
03389     text       *date_txt = PG_GETARG_TEXT_P(0);
03390     text       *fmt = PG_GETARG_TEXT_P(1);
03391     DateADT     result;
03392     struct pg_tm tm;
03393     fsec_t      fsec;
03394 
03395     do_to_timestamp(date_txt, fmt, &tm, &fsec);
03396 
03397     if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
03398         ereport(ERROR,
03399                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03400                  errmsg("date out of range: \"%s\"",
03401                         text_to_cstring(date_txt))));
03402 
03403     result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
03404 
03405     PG_RETURN_DATEADT(result);
03406 }
03407 
03408 /*
03409  * do_to_timestamp: shared code for to_timestamp and to_date
03410  *
03411  * Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm
03412  * and fractional seconds.
03413  *
03414  * We parse 'fmt' into a list of FormatNodes, which is then passed to
03415  * DCH_from_char to populate a TmFromChar with the parsed contents of
03416  * 'date_txt'.
03417  *
03418  * The TmFromChar is then analysed and converted into the final results in
03419  * struct 'tm' and 'fsec'.
03420  *
03421  * This function does very little error checking, e.g.
03422  * to_timestamp('20096040','YYYYMMDD') works
03423  */
03424 static void
03425 do_to_timestamp(text *date_txt, text *fmt,
03426                 struct pg_tm * tm, fsec_t *fsec)
03427 {
03428     FormatNode *format;
03429     TmFromChar  tmfc;
03430     int         fmt_len;
03431 
03432     ZERO_tmfc(&tmfc);
03433     ZERO_tm(tm);
03434     *fsec = 0;
03435 
03436     fmt_len = VARSIZE_ANY_EXHDR(fmt);
03437 
03438     if (fmt_len)
03439     {
03440         char       *fmt_str;
03441         char       *date_str;
03442         bool        incache;
03443 
03444         fmt_str = text_to_cstring(fmt);
03445 
03446         /*
03447          * Allocate new memory if format picture is bigger than static cache
03448          * and not use cache (call parser always)
03449          */
03450         if (fmt_len > DCH_CACHE_SIZE)
03451         {
03452             format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
03453             incache = FALSE;
03454 
03455             parse_format(format, fmt_str, DCH_keywords,
03456                          DCH_suff, DCH_index, DCH_TYPE, NULL);
03457 
03458             (format + fmt_len)->type = NODE_TYPE_END;   /* Paranoia? */
03459         }
03460         else
03461         {
03462             /*
03463              * Use cache buffers
03464              */
03465             DCHCacheEntry *ent;
03466 
03467             incache = TRUE;
03468 
03469             if ((ent = DCH_cache_search(fmt_str)) == NULL)
03470             {
03471                 ent = DCH_cache_getnew(fmt_str);
03472 
03473                 /*
03474                  * Not in the cache, must run parser and save a new
03475                  * format-picture to the cache.
03476                  */
03477                 parse_format(ent->format, fmt_str, DCH_keywords,
03478                              DCH_suff, DCH_index, DCH_TYPE, NULL);
03479 
03480                 (ent->format + fmt_len)->type = NODE_TYPE_END;  /* Paranoia? */
03481 #ifdef DEBUG_TO_FROM_CHAR
03482                 /* dump_node(ent->format, fmt_len); */
03483                 /* dump_index(DCH_keywords, DCH_index); */
03484 #endif
03485             }
03486             format = ent->format;
03487         }
03488 
03489 #ifdef DEBUG_TO_FROM_CHAR
03490         /* dump_node(format, fmt_len); */
03491 #endif
03492 
03493         date_str = text_to_cstring(date_txt);
03494 
03495         DCH_from_char(format, date_str, &tmfc);
03496 
03497         pfree(date_str);
03498         pfree(fmt_str);
03499         if (!incache)
03500             pfree(format);
03501     }
03502 
03503     DEBUG_TMFC(&tmfc);
03504 
03505     /*
03506      * Convert values that user define for FROM_CHAR (to_date/to_timestamp) to
03507      * standard 'tm'
03508      */
03509     if (tmfc.ssss)
03510     {
03511         int         x = tmfc.ssss;
03512 
03513         tm->tm_hour = x / SECS_PER_HOUR;
03514         x %= SECS_PER_HOUR;
03515         tm->tm_min = x / SECS_PER_MINUTE;
03516         x %= SECS_PER_MINUTE;
03517         tm->tm_sec = x;
03518     }
03519 
03520     if (tmfc.ss)
03521         tm->tm_sec = tmfc.ss;
03522     if (tmfc.mi)
03523         tm->tm_min = tmfc.mi;
03524     if (tmfc.hh)
03525         tm->tm_hour = tmfc.hh;
03526 
03527     if (tmfc.clock == CLOCK_12_HOUR)
03528     {
03529         if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
03530             ereport(ERROR,
03531                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
03532                      errmsg("hour \"%d\" is invalid for the 12-hour clock",
03533                             tm->tm_hour),
03534                      errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
03535 
03536         if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
03537             tm->tm_hour += HOURS_PER_DAY / 2;
03538         else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
03539             tm->tm_hour = 0;
03540     }
03541 
03542     if (tmfc.year)
03543     {
03544         /*
03545          * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
03546          * the year in the given century.  Keep in mind that the 21st century
03547          * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
03548          * 600BC to 501BC.
03549          */
03550         if (tmfc.cc && tmfc.yysz <= 2)
03551         {
03552             if (tmfc.bc)
03553                 tmfc.cc = -tmfc.cc;
03554             tm->tm_year = tmfc.year % 100;
03555             if (tm->tm_year)
03556             {
03557                 if (tmfc.cc >= 0)
03558                     tm->tm_year += (tmfc.cc - 1) * 100;
03559                 else
03560                     tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1;
03561             }
03562             else
03563                 /* find century year for dates ending in "00" */
03564                 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);         
03565         }
03566         else
03567         /* If a 4-digit year is provided, we use that and ignore CC. */
03568         {
03569             tm->tm_year = tmfc.year;
03570             if (tmfc.bc && tm->tm_year > 0)
03571                 tm->tm_year = -(tm->tm_year - 1);
03572         }
03573     }
03574     else if (tmfc.cc)   /* use first year of century */
03575     {
03576         if (tmfc.bc)
03577             tmfc.cc = -tmfc.cc;
03578         if (tmfc.cc >= 0)
03579             /* +1 becuase 21st century started in 2001 */
03580             tm->tm_year = (tmfc.cc - 1) * 100 + 1;
03581         else
03582             /* +1 because year == 599 is 600 BC */
03583             tm->tm_year = tmfc.cc * 100 + 1;
03584     }
03585 
03586     if (tmfc.j)
03587         j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03588 
03589     if (tmfc.ww)
03590     {
03591         if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
03592         {
03593             /*
03594              * If tmfc.d is not set, then the date is left at the beginning of
03595              * the ISO week (Monday).
03596              */
03597             if (tmfc.d)
03598                 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03599             else
03600                 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03601         }
03602         else
03603             tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
03604     }
03605 
03606     if (tmfc.w)
03607         tmfc.dd = (tmfc.w - 1) * 7 + 1;
03608     if (tmfc.d)
03609         tm->tm_wday = tmfc.d - 1;   /* convert to native numbering */
03610     if (tmfc.dd)
03611         tm->tm_mday = tmfc.dd;
03612     if (tmfc.ddd)
03613         tm->tm_yday = tmfc.ddd;
03614     if (tmfc.mm)
03615         tm->tm_mon = tmfc.mm;
03616 
03617     if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
03618     {
03619         /*
03620          * The month and day field have not been set, so we use the
03621          * day-of-year field to populate them.  Depending on the date mode,
03622          * this field may be interpreted as a Gregorian day-of-year, or an ISO
03623          * week date day-of-year.
03624          */
03625 
03626         if (!tm->tm_year && !tmfc.bc)
03627             ereport(ERROR,
03628                     (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
03629             errmsg("cannot calculate day of year without year information")));
03630 
03631         if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
03632         {
03633             int         j0;     /* zeroth day of the ISO year, in Julian */
03634 
03635             j0 = isoweek2j(tm->tm_year, 1) - 1;
03636 
03637             j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03638         }
03639         else
03640         {
03641             const int  *y;
03642             int         i;
03643 
03644             static const int ysum[2][13] = {
03645                 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
03646             {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
03647 
03648             y = ysum[isleap(tm->tm_year)];
03649 
03650             for (i = 1; i <= MONTHS_PER_YEAR; i++)
03651             {
03652                 if (tmfc.ddd < y[i])
03653                     break;
03654             }
03655             if (tm->tm_mon <= 1)
03656                 tm->tm_mon = i;
03657 
03658             if (tm->tm_mday <= 1)
03659                 tm->tm_mday = tmfc.ddd - y[i - 1];
03660         }
03661     }
03662 
03663 #ifdef HAVE_INT64_TIMESTAMP
03664     if (tmfc.ms)
03665         *fsec += tmfc.ms * 1000;
03666     if (tmfc.us)
03667         *fsec += tmfc.us;
03668 #else
03669     if (tmfc.ms)
03670         *fsec += (double) tmfc.ms / 1000;
03671     if (tmfc.us)
03672         *fsec += (double) tmfc.us / 1000000;
03673 #endif
03674 
03675     DEBUG_TM(tm);
03676 }
03677 
03678 
03679 /**********************************************************************
03680  *  the NUMBER version part
03681  *********************************************************************/
03682 
03683 
03684 static char *
03685 fill_str(char *str, int c, int max)
03686 {
03687     memset(str, c, max);
03688     *(str + max) = '\0';
03689     return str;
03690 }
03691 
03692 #define zeroize_NUM(_n) \
03693 do { \
03694     (_n)->flag      = 0;    \
03695     (_n)->lsign     = 0;    \
03696     (_n)->pre       = 0;    \
03697     (_n)->post      = 0;    \
03698     (_n)->pre_lsign_num = 0;    \
03699     (_n)->need_locale   = 0;    \
03700     (_n)->multi     = 0;    \
03701     (_n)->zero_start    = 0;    \
03702     (_n)->zero_end      = 0;    \
03703 } while(0)
03704 
03705 static NUMCacheEntry *
03706 NUM_cache_getnew(char *str)
03707 {
03708     NUMCacheEntry *ent;
03709 
03710     /* counter overflow check - paranoia? */
03711     if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
03712     {
03713         NUMCounter = 0;
03714 
03715         for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
03716             ent->age = (++NUMCounter);
03717     }
03718 
03719     /*
03720      * If cache is full, remove oldest entry
03721      */
03722     if (n_NUMCache > NUM_CACHE_FIELDS)
03723     {
03724         NUMCacheEntry *old = NUMCache + 0;
03725 
03726 #ifdef DEBUG_TO_FROM_CHAR
03727         elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
03728 #endif
03729         for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
03730         {
03731             /*
03732              * entry removed via NUM_cache_remove() can be used here, which is
03733              * why it's worth scanning first entry again
03734              */
03735             if (ent->str[0] == '\0')
03736             {
03737                 old = ent;
03738                 break;
03739             }
03740             if (ent->age < old->age)
03741                 old = ent;
03742         }
03743 #ifdef DEBUG_TO_FROM_CHAR
03744         elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
03745 #endif
03746         StrNCpy(old->str, str, NUM_CACHE_SIZE + 1);
03747         /* old->format fill parser */
03748         old->age = (++NUMCounter);
03749         ent = old;
03750     }
03751     else
03752     {
03753 #ifdef DEBUG_TO_FROM_CHAR
03754         elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
03755 #endif
03756         ent = NUMCache + n_NUMCache;
03757         StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1);
03758         /* ent->format fill parser */
03759         ent->age = (++NUMCounter);
03760         ++n_NUMCache;
03761     }
03762 
03763     zeroize_NUM(&ent->Num);
03764 
03765     last_NUMCacheEntry = ent;
03766     return ent;
03767 }
03768 
03769 static NUMCacheEntry *
03770 NUM_cache_search(char *str)
03771 {
03772     int         i;
03773     NUMCacheEntry *ent;
03774 
03775     /* counter overflow check - paranoia? */
03776     if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
03777     {
03778         NUMCounter = 0;
03779 
03780         for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
03781             ent->age = (++NUMCounter);
03782     }
03783 
03784     for (i = 0, ent = NUMCache; i < n_NUMCache; i++, ent++)
03785     {
03786         if (strcmp(ent->str, str) == 0)
03787         {
03788             ent->age = (++NUMCounter);
03789             last_NUMCacheEntry = ent;
03790             return ent;
03791         }
03792     }
03793 
03794     return NULL;
03795 }
03796 
03797 static void
03798 NUM_cache_remove(NUMCacheEntry *ent)
03799 {
03800 #ifdef DEBUG_TO_FROM_CHAR
03801     elog(DEBUG_elog_output, "REMOVING ENTRY (%s)", ent->str);
03802 #endif
03803     ent->str[0] = '\0';
03804     ent->age = 0;
03805 }
03806 
03807 /* ----------
03808  * Cache routine for NUM to_char version
03809  * ----------
03810  */
03811 static FormatNode *
03812 NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
03813 {
03814     FormatNode *format = NULL;
03815     char       *str;
03816 
03817     str = text_to_cstring(pars_str);
03818 
03819     /*
03820      * Allocate new memory if format picture is bigger than static cache and
03821      * not use cache (call parser always). This branches sets shouldFree to
03822      * true, accordingly.
03823      */
03824     if (len > NUM_CACHE_SIZE)
03825     {
03826         format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
03827 
03828         *shouldFree = true;
03829 
03830         zeroize_NUM(Num);
03831 
03832         parse_format(format, str, NUM_keywords,
03833                      NULL, NUM_index, NUM_TYPE, Num);
03834 
03835         (format + len)->type = NODE_TYPE_END;   /* Paranoia? */
03836     }
03837     else
03838     {
03839         /*
03840          * Use cache buffers
03841          */
03842         NUMCacheEntry *ent;
03843 
03844         *shouldFree = false;
03845 
03846         if ((ent = NUM_cache_search(str)) == NULL)
03847         {
03848             ent = NUM_cache_getnew(str);
03849 
03850             /*
03851              * Not in the cache, must run parser and save a new format-picture
03852              * to the cache.
03853              */
03854             parse_format(ent->format, str, NUM_keywords,
03855                          NULL, NUM_index, NUM_TYPE, &ent->Num);
03856 
03857             (ent->format + len)->type = NODE_TYPE_END;  /* Paranoia? */
03858         }
03859 
03860         format = ent->format;
03861 
03862         /*
03863          * Copy cache to used struct
03864          */
03865         Num->flag = ent->Num.flag;
03866         Num->lsign = ent->Num.lsign;
03867         Num->pre = ent->Num.pre;
03868         Num->post = ent->Num.post;
03869         Num->pre_lsign_num = ent->Num.pre_lsign_num;
03870         Num->need_locale = ent->Num.need_locale;
03871         Num->multi = ent->Num.multi;
03872         Num->zero_start = ent->Num.zero_start;
03873         Num->zero_end = ent->Num.zero_end;
03874     }
03875 
03876 #ifdef DEBUG_TO_FROM_CHAR
03877     /* dump_node(format, len); */
03878     dump_index(NUM_keywords, NUM_index);
03879 #endif
03880 
03881     pfree(str);
03882     return format;
03883 }
03884 
03885 
03886 static char *
03887 int_to_roman(int number)
03888 {
03889     int         len = 0,
03890                 num = 0;
03891     char       *p = NULL,
03892                *result,
03893                 numstr[5];
03894 
03895     result = (char *) palloc(16);
03896     *result = '\0';
03897 
03898     if (number > 3999 || number < 1)
03899     {
03900         fill_str(result, '#', 15);
03901         return result;
03902     }
03903     len = snprintf(numstr, sizeof(numstr), "%d", number);
03904 
03905     for (p = numstr; *p != '\0'; p++, --len)
03906     {
03907         num = *p - 49;          /* 48 ascii + 1 */
03908         if (num < 0)
03909             continue;
03910 
03911         if (len > 3)
03912         {
03913             while (num-- != -1)
03914                 strcat(result, "M");
03915         }
03916         else
03917         {
03918             if (len == 3)
03919                 strcat(result, rm100[num]);
03920             else if (len == 2)
03921                 strcat(result, rm10[num]);
03922             else if (len == 1)
03923                 strcat(result, rm1[num]);
03924         }
03925     }
03926     return result;
03927 }
03928 
03929 
03930 
03931 /* ----------
03932  * Locale
03933  * ----------
03934  */
03935 static void
03936 NUM_prepare_locale(NUMProc *Np)
03937 {
03938     if (Np->Num->need_locale)
03939     {
03940         struct lconv *lconv;
03941 
03942         /*
03943          * Get locales
03944          */
03945         lconv = PGLC_localeconv();
03946 
03947         /*
03948          * Positive / Negative number sign
03949          */
03950         if (lconv->negative_sign && *lconv->negative_sign)
03951             Np->L_negative_sign = lconv->negative_sign;
03952         else
03953             Np->L_negative_sign = "-";
03954 
03955         if (lconv->positive_sign && *lconv->positive_sign)
03956             Np->L_positive_sign = lconv->positive_sign;
03957         else
03958             Np->L_positive_sign = "+";
03959 
03960         /*
03961          * Number decimal point
03962          */
03963         if (lconv->decimal_point && *lconv->decimal_point)
03964             Np->decimal = lconv->decimal_point;
03965 
03966         else
03967             Np->decimal = ".";
03968 
03969         if (!IS_LDECIMAL(Np->Num))
03970             Np->decimal = ".";
03971 
03972         /*
03973          * Number thousands separator
03974          *
03975          * Some locales (e.g. broken glibc pt_BR), have a comma for decimal,
03976          * but "" for thousands_sep, so we set the thousands_sep too.
03977          * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php
03978          */
03979         if (lconv->thousands_sep && *lconv->thousands_sep)
03980             Np->L_thousands_sep = lconv->thousands_sep;
03981         /* Make sure thousands separator doesn't match decimal point symbol. */
03982         else if (strcmp(Np->decimal, ",") !=0)
03983             Np->L_thousands_sep = ",";
03984         else
03985             Np->L_thousands_sep = ".";
03986 
03987         /*
03988          * Currency symbol
03989          */
03990         if (lconv->currency_symbol && *lconv->currency_symbol)
03991             Np->L_currency_symbol = lconv->currency_symbol;
03992         else
03993             Np->L_currency_symbol = " ";
03994     }
03995     else
03996     {
03997         /*
03998          * Default values
03999          */
04000         Np->L_negative_sign = "-";
04001         Np->L_positive_sign = "+";
04002         Np->decimal = ".";
04003 
04004         Np->L_thousands_sep = ",";
04005         Np->L_currency_symbol = " ";
04006     }
04007 }
04008 
04009 /* ----------
04010  * Return pointer of last relevant number after decimal point
04011  *  12.0500 --> last relevant is '5'
04012  *  12.0000 --> last relevant is '.'
04013  * If there is no decimal point, return NULL (which will result in same
04014  * behavior as if FM hadn't been specified).
04015  * ----------
04016  */
04017 static char *
04018 get_last_relevant_decnum(char *num)
04019 {
04020     char       *result,
04021                *p = strchr(num, '.');
04022 
04023 #ifdef DEBUG_TO_FROM_CHAR
04024     elog(DEBUG_elog_output, "get_last_relevant_decnum()");
04025 #endif
04026 
04027     if (!p)
04028         return NULL;
04029 
04030     result = p;
04031 
04032     while (*(++p))
04033     {
04034         if (*p != '0')
04035             result = p;
04036     }
04037 
04038     return result;
04039 }
04040 
04041 /* ----------
04042  * Number extraction for TO_NUMBER()
04043  * ----------
04044  */
04045 static void
04046 NUM_numpart_from_char(NUMProc *Np, int id, int plen)
04047 {
04048     bool        isread = FALSE;
04049 
04050 #ifdef DEBUG_TO_FROM_CHAR
04051     elog(DEBUG_elog_output, " --- scan start --- id=%s",
04052          (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
04053 #endif
04054 
04055     if (*Np->inout_p == ' ')
04056         Np->inout_p++;
04057 
04058 #define OVERLOAD_TEST   (Np->inout_p >= Np->inout + plen)
04059 #define AMOUNT_TEST(_s) (plen-(Np->inout_p-Np->inout) >= _s)
04060 
04061     if (*Np->inout_p == ' ')
04062         Np->inout_p++;
04063 
04064     if (OVERLOAD_TEST)
04065         return;
04066 
04067     /*
04068      * read sign before number
04069      */
04070     if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
04071         (Np->read_pre + Np->read_post) == 0)
04072     {
04073 #ifdef DEBUG_TO_FROM_CHAR
04074         elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
04075              *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
04076 #endif
04077 
04078         /*
04079          * locale sign
04080          */
04081         if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
04082         {
04083             int         x = 0;
04084 
04085 #ifdef DEBUG_TO_FROM_CHAR
04086             elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
04087 #endif
04088             if ((x = strlen(Np->L_negative_sign)) &&
04089                 AMOUNT_TEST(x) &&
04090                 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
04091             {
04092                 Np->inout_p += x;
04093                 *Np->number = '-';
04094             }
04095             else if ((x = strlen(Np->L_positive_sign)) &&
04096                      AMOUNT_TEST(x) &&
04097                      strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
04098             {
04099                 Np->inout_p += x;
04100                 *Np->number = '+';
04101             }
04102         }
04103         else
04104         {
04105 #ifdef DEBUG_TO_FROM_CHAR
04106             elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
04107 #endif
04108 
04109             /*
04110              * simple + - < >
04111              */
04112             if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
04113                                         *Np->inout_p == '<'))
04114             {
04115                 *Np->number = '-';      /* set - */
04116                 Np->inout_p++;
04117             }
04118             else if (*Np->inout_p == '+')
04119             {
04120                 *Np->number = '+';      /* set + */
04121                 Np->inout_p++;
04122             }
04123         }
04124     }
04125 
04126     if (OVERLOAD_TEST)
04127         return;
04128 
04129 #ifdef DEBUG_TO_FROM_CHAR
04130     elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
04131 #endif
04132 
04133     /*
04134      * read digit
04135      */
04136     if (isdigit((unsigned char) *Np->inout_p))
04137     {
04138         if (Np->read_dec && Np->read_post == Np->Num->post)
04139             return;
04140 
04141         *Np->number_p = *Np->inout_p;
04142         Np->number_p++;
04143 
04144         if (Np->read_dec)
04145             Np->read_post++;
04146         else
04147             Np->read_pre++;
04148 
04149         isread = TRUE;
04150 
04151 #ifdef DEBUG_TO_FROM_CHAR
04152         elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
04153 #endif
04154 
04155         /*
04156          * read decimal point
04157          */
04158     }
04159     else if (IS_DECIMAL(Np->Num) && Np->read_dec == FALSE)
04160     {
04161 #ifdef DEBUG_TO_FROM_CHAR
04162         elog(DEBUG_elog_output, "Try read decimal point (%c)", *Np->inout_p);
04163 #endif
04164         if (*Np->inout_p == '.')
04165         {
04166             *Np->number_p = '.';
04167             Np->number_p++;
04168             Np->read_dec = TRUE;
04169             isread = TRUE;
04170         }
04171         else
04172         {
04173             int         x = strlen(Np->decimal);
04174 
04175 #ifdef DEBUG_TO_FROM_CHAR
04176             elog(DEBUG_elog_output, "Try read locale point (%c)",
04177                  *Np->inout_p);
04178 #endif
04179             if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
04180             {
04181                 Np->inout_p += x - 1;
04182                 *Np->number_p = '.';
04183                 Np->number_p++;
04184                 Np->read_dec = TRUE;
04185                 isread = TRUE;
04186             }
04187         }
04188     }
04189 
04190     if (OVERLOAD_TEST)
04191         return;
04192 
04193     /*
04194      * Read sign behind "last" number
04195      *
04196      * We need sign detection because determine exact position of post-sign is
04197      * difficult:
04198      *
04199      * FM9999.9999999S     -> 123.001- 9.9S            -> .5- FM9.999999MI ->
04200      * 5.01-
04201      */
04202     if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
04203     {
04204         /*
04205          * locale sign (NUM_S) is always anchored behind a last number, if: -
04206          * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
04207          * next char is not digit
04208          */
04209         if (IS_LSIGN(Np->Num) && isread &&
04210             (Np->inout_p + 1) <= Np->inout + plen &&
04211             !isdigit((unsigned char) *(Np->inout_p + 1)))
04212         {
04213             int         x;
04214             char       *tmp = Np->inout_p++;
04215 
04216 #ifdef DEBUG_TO_FROM_CHAR
04217             elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
04218 #endif
04219             if ((x = strlen(Np->L_negative_sign)) &&
04220                 AMOUNT_TEST(x) &&
04221                 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
04222             {
04223                 Np->inout_p += x - 1;   /* -1 .. NUM_processor() do inout_p++ */
04224                 *Np->number = '-';
04225             }
04226             else if ((x = strlen(Np->L_positive_sign)) &&
04227                      AMOUNT_TEST(x) &&
04228                      strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
04229             {
04230                 Np->inout_p += x - 1;   /* -1 .. NUM_processor() do inout_p++ */
04231                 *Np->number = '+';
04232             }
04233             if (*Np->number == ' ')
04234                 /* no sign read */
04235                 Np->inout_p = tmp;
04236         }
04237 
04238         /*
04239          * try read non-locale sign, it's happen only if format is not exact
04240          * and we cannot determine sign position of MI/PL/SG, an example:
04241          *
04242          * FM9.999999MI            -> 5.01-
04243          *
04244          * if (.... && IS_LSIGN(Np->Num)==FALSE) prevents read wrong formats
04245          * like to_number('1 -', '9S') where sign is not anchored to last
04246          * number.
04247          */
04248         else if (isread == FALSE && IS_LSIGN(Np->Num) == FALSE &&
04249                  (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
04250         {
04251 #ifdef DEBUG_TO_FROM_CHAR
04252             elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
04253 #endif
04254 
04255             /*
04256              * simple + -
04257              */
04258             if (*Np->inout_p == '-' || *Np->inout_p == '+')
04259                 /* NUM_processor() do inout_p++ */
04260                 *Np->number = *Np->inout_p;
04261         }
04262     }
04263 }
04264 
04265 #define IS_PREDEC_SPACE(_n) \
04266         (IS_ZERO((_n)->Num)==FALSE && \
04267          (_n)->number == (_n)->number_p && \
04268          *(_n)->number == '0' && \
04269                  (_n)->Num->post != 0)
04270 
04271 /* ----------
04272  * Add digit or sign to number-string
04273  * ----------
04274  */
04275 static void
04276 NUM_numpart_to_char(NUMProc *Np, int id)
04277 {
04278     int         end;
04279 
04280     if (IS_ROMAN(Np->Num))
04281         return;
04282 
04283     /* Note: in this elog() output not set '\0' in 'inout' */
04284 
04285 #ifdef DEBUG_TO_FROM_CHAR
04286 
04287     /*
04288      * Np->num_curr is number of current item in format-picture, it is not
04289      * current position in inout!
04290      */
04291     elog(DEBUG_elog_output,
04292          "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
04293          Np->sign_wrote,
04294          Np->num_curr,
04295          Np->number_p,
04296          Np->inout);
04297 #endif
04298     Np->num_in = FALSE;
04299 
04300     /*
04301      * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
04302      * handle "9.9" --> " .1"
04303      */
04304     if (Np->sign_wrote == FALSE &&
04305         (Np->num_curr >= Np->num_pre || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
04306         (IS_PREDEC_SPACE(Np) == FALSE || (Np->last_relevant && *Np->last_relevant == '.')))
04307     {
04308         if (IS_LSIGN(Np->Num))
04309         {
04310             if (Np->Num->lsign == NUM_LSIGN_PRE)
04311             {
04312                 if (Np->sign == '-')
04313                     strcpy(Np->inout_p, Np->L_negative_sign);
04314                 else
04315                     strcpy(Np->inout_p, Np->L_positive_sign);
04316                 Np->inout_p += strlen(Np->inout_p);
04317                 Np->sign_wrote = TRUE;
04318             }
04319         }
04320         else if (IS_BRACKET(Np->Num))
04321         {
04322             *Np->inout_p = Np->sign == '+' ? ' ' : '<';
04323             ++Np->inout_p;
04324             Np->sign_wrote = TRUE;
04325         }
04326         else if (Np->sign == '+')
04327         {
04328             if (!IS_FILLMODE(Np->Num))
04329             {
04330                 *Np->inout_p = ' ';     /* Write + */
04331                 ++Np->inout_p;
04332             }
04333             Np->sign_wrote = TRUE;
04334         }
04335         else if (Np->sign == '-')
04336         {                       /* Write - */
04337             *Np->inout_p = '-';
04338             ++Np->inout_p;
04339             Np->sign_wrote = TRUE;
04340         }
04341     }
04342 
04343 
04344     /*
04345      * digits / FM / Zero / Dec. point
04346      */
04347     if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
04348     {
04349         if (Np->num_curr < Np->num_pre &&
04350             (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
04351         {
04352             /*
04353              * Write blank space
04354              */
04355             if (!IS_FILLMODE(Np->Num))
04356             {
04357                 *Np->inout_p = ' ';     /* Write ' ' */
04358                 ++Np->inout_p;
04359             }
04360         }
04361         else if (IS_ZERO(Np->Num) &&
04362                  Np->num_curr < Np->num_pre &&
04363                  Np->Num->zero_start <= Np->num_curr)
04364         {
04365             /*
04366              * Write ZERO
04367              */
04368             *Np->inout_p = '0'; /* Write '0' */
04369             ++Np->inout_p;
04370             Np->num_in = TRUE;
04371         }
04372         else
04373         {
04374             /*
04375              * Write Decimal point
04376              */
04377             if (*Np->number_p == '.')
04378             {
04379                 if (!Np->last_relevant || *Np->last_relevant != '.')
04380                 {
04381                     strcpy(Np->inout_p, Np->decimal);   /* Write DEC/D */
04382                     Np->inout_p += strlen(Np->inout_p);
04383                 }
04384 
04385                 /*
04386                  * Ora 'n' -- FM9.9 --> 'n.'
04387                  */
04388                 else if (IS_FILLMODE(Np->Num) &&
04389                          Np->last_relevant && *Np->last_relevant == '.')
04390                 {
04391                     strcpy(Np->inout_p, Np->decimal);   /* Write DEC/D */
04392                     Np->inout_p += strlen(Np->inout_p);
04393                 }
04394             }
04395             else
04396             {
04397                 /*
04398                  * Write Digits
04399                  */
04400                 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
04401                     id != NUM_0)
04402                     ;
04403 
04404                 /*
04405                  * '0.1' -- 9.9 --> '  .1'
04406                  */
04407                 else if (IS_PREDEC_SPACE(Np))
04408                 {
04409                     if (!IS_FILLMODE(Np->Num))
04410                     {
04411                         *Np->inout_p = ' ';
04412                         ++Np->inout_p;
04413                     }
04414 
04415                     /*
04416                      * '0' -- FM9.9 --> '0.'
04417                      */
04418                     else if (Np->last_relevant && *Np->last_relevant == '.')
04419                     {
04420                         *Np->inout_p = '0';
04421                         ++Np->inout_p;
04422                     }
04423                 }
04424                 else
04425                 {
04426                     *Np->inout_p = *Np->number_p;       /* Write DIGIT */
04427                     ++Np->inout_p;
04428                     Np->num_in = TRUE;
04429                 }
04430             }
04431             ++Np->number_p;
04432         }
04433 
04434         end = Np->num_count + (Np->num_pre ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
04435 
04436         if (Np->last_relevant && Np->last_relevant == Np->number_p)
04437             end = Np->num_curr;
04438 
04439         if (Np->num_curr + 1 == end)
04440         {
04441             if (Np->sign_wrote == TRUE && IS_BRACKET(Np->Num))
04442             {
04443                 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
04444                 ++Np->inout_p;
04445             }
04446             else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
04447             {
04448                 if (Np->sign == '-')
04449                     strcpy(Np->inout_p, Np->L_negative_sign);
04450                 else
04451                     strcpy(Np->inout_p, Np->L_positive_sign);
04452                 Np->inout_p += strlen(Np->inout_p);
04453             }
04454         }
04455     }
04456 
04457     ++Np->num_curr;
04458 }
04459 
04460 /*
04461  * Note: 'plen' is used in FROM_CHAR conversion and it's length of
04462  * input (inout). In TO_CHAR conversion it's space before first number.
04463  */
04464 static char *
04465 NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
04466               int plen, int sign, bool is_to_char, Oid collid)
04467 {
04468     FormatNode *n;
04469     NUMProc     _Np,
04470                *Np = &_Np;
04471 
04472     MemSet(Np, 0, sizeof(NUMProc));
04473 
04474     Np->Num = Num;
04475     Np->is_to_char = is_to_char;
04476     Np->number = number;
04477     Np->inout = inout;
04478     Np->last_relevant = NULL;
04479     Np->read_post = 0;
04480     Np->read_pre = 0;
04481     Np->read_dec = FALSE;
04482 
04483     if (Np->Num->zero_start)
04484         --Np->Num->zero_start;
04485 
04486     if (IS_EEEE(Np->Num))
04487     {
04488         if (!Np->is_to_char)
04489             ereport(ERROR,
04490                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04491                      errmsg("\"EEEE\" not supported for input")));
04492         return strcpy(inout, number);
04493     }
04494 
04495     /*
04496      * Roman correction
04497      */
04498     if (IS_ROMAN(Np->Num))
04499     {
04500         if (!Np->is_to_char)
04501             ereport(ERROR,
04502                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04503                      errmsg("\"RN\" not supported for input")));
04504 
04505         Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->post =
04506             Np->Num->pre = Np->num_pre = Np->sign = 0;
04507 
04508         if (IS_FILLMODE(Np->Num))
04509         {
04510             Np->Num->flag = 0;
04511             Np->Num->flag |= NUM_F_FILLMODE;
04512         }
04513         else
04514             Np->Num->flag = 0;
04515         Np->Num->flag |= NUM_F_ROMAN;
04516     }
04517 
04518     /*
04519      * Sign
04520      */
04521     if (is_to_char)
04522     {
04523         Np->sign = sign;
04524 
04525         /* MI/PL/SG - write sign itself and not in number */
04526         if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
04527         {
04528             if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == FALSE)
04529                 Np->sign_wrote = FALSE; /* need sign */
04530             else
04531                 Np->sign_wrote = TRUE;  /* needn't sign */
04532         }
04533         else
04534         {
04535             if (Np->sign != '-')
04536             {
04537                 if (IS_BRACKET(Np->Num) && IS_FILLMODE(Np->Num))
04538                     Np->Num->flag &= ~NUM_F_BRACKET;
04539                 if (IS_MINUS(Np->Num))
04540                     Np->Num->flag &= ~NUM_F_MINUS;
04541             }
04542             else if (Np->sign != '+' && IS_PLUS(Np->Num))
04543                 Np->Num->flag &= ~NUM_F_PLUS;
04544 
04545             if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == FALSE)
04546                 Np->sign_wrote = TRUE;  /* needn't sign */
04547             else
04548                 Np->sign_wrote = FALSE; /* need sign */
04549 
04550             if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
04551                 Np->Num->lsign = NUM_LSIGN_POST;
04552         }
04553     }
04554     else
04555         Np->sign = FALSE;
04556 
04557     /*
04558      * Count
04559      */
04560     Np->num_count = Np->Num->post + Np->Num->pre - 1;
04561 
04562     if (is_to_char)
04563     {
04564         Np->num_pre = plen;
04565 
04566         if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
04567         {
04568             Np->last_relevant = get_last_relevant_decnum(Np->number);
04569 
04570             /*
04571              * If any '0' specifiers are present, make sure we don't strip
04572              * those digits.
04573              */
04574             if (Np->last_relevant && Np->Num->zero_end > Np->num_pre)
04575             {
04576                 char       *last_zero;
04577 
04578                 last_zero = Np->number + (Np->Num->zero_end - Np->num_pre);
04579                 if (Np->last_relevant < last_zero)
04580                     Np->last_relevant = last_zero;
04581             }
04582         }
04583 
04584         if (Np->sign_wrote == FALSE && Np->num_pre == 0)
04585             ++Np->num_count;
04586     }
04587     else
04588     {
04589         Np->num_pre = 0;
04590         *Np->number = ' ';      /* sign space */
04591         *(Np->number + 1) = '\0';
04592     }
04593 
04594     Np->num_in = 0;
04595     Np->num_curr = 0;
04596 
04597 #ifdef DEBUG_TO_FROM_CHAR
04598     elog(DEBUG_elog_output,
04599          "\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",
04600          Np->sign,
04601          Np->number,
04602          Np->Num->pre,
04603          Np->Num->post,
04604          Np->num_count,
04605          Np->num_pre,
04606          Np->sign_wrote ? "Yes" : "No",
04607          IS_ZERO(Np->Num) ? "Yes" : "No",
04608          Np->Num->zero_start,
04609          Np->Num->zero_end,
04610          Np->last_relevant ? Np->last_relevant : "<not set>",
04611          IS_BRACKET(Np->Num) ? "Yes" : "No",
04612          IS_PLUS(Np->Num) ? "Yes" : "No",
04613          IS_MINUS(Np->Num) ? "Yes" : "No",
04614          IS_FILLMODE(Np->Num) ? "Yes" : "No",
04615          IS_ROMAN(Np->Num) ? "Yes" : "No",
04616          IS_EEEE(Np->Num) ? "Yes" : "No"
04617         );
04618 #endif
04619 
04620     /*
04621      * Locale
04622      */
04623     NUM_prepare_locale(Np);
04624 
04625     /*
04626      * Processor direct cycle
04627      */
04628     if (Np->is_to_char)
04629         Np->number_p = Np->number;
04630     else
04631         Np->number_p = Np->number + 1;  /* first char is space for sign */
04632 
04633     for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
04634     {
04635         if (!Np->is_to_char)
04636         {
04637             /*
04638              * Check non-string inout end
04639              */
04640             if (Np->inout_p >= Np->inout + plen)
04641                 break;
04642         }
04643 
04644         /*
04645          * Format pictures actions
04646          */
04647         if (n->type == NODE_TYPE_ACTION)
04648         {
04649             /*
04650              * Create/reading digit/zero/blank/sing
04651              *
04652              * 'NUM_S' note: The locale sign is anchored to number and we
04653              * read/write it when we work with first or last number
04654              * (NUM_0/NUM_9). This is reason why NUM_S missing in follow
04655              * switch().
04656              */
04657             switch (n->key->id)
04658             {
04659                 case NUM_9:
04660                 case NUM_0:
04661                 case NUM_DEC:
04662                 case NUM_D:
04663                     if (Np->is_to_char)
04664                     {
04665                         NUM_numpart_to_char(Np, n->key->id);
04666                         continue;       /* for() */
04667                     }
04668                     else
04669                     {
04670                         NUM_numpart_from_char(Np, n->key->id, plen);
04671                         break;  /* switch() case: */
04672                     }
04673 
04674                 case NUM_COMMA:
04675                     if (Np->is_to_char)
04676                     {
04677                         if (!Np->num_in)
04678                         {
04679                             if (IS_FILLMODE(Np->Num))
04680                                 continue;
04681                             else
04682                                 *Np->inout_p = ' ';
04683                         }
04684                         else
04685                             *Np->inout_p = ',';
04686                     }
04687                     else
04688                     {
04689                         if (!Np->num_in)
04690                         {
04691                             if (IS_FILLMODE(Np->Num))
04692                                 continue;
04693                         }
04694                     }
04695                     break;
04696 
04697                 case NUM_G:
04698                     if (Np->is_to_char)
04699                     {
04700                         if (!Np->num_in)
04701                         {
04702                             if (IS_FILLMODE(Np->Num))
04703                                 continue;
04704                             else
04705                             {
04706                                 int         x = strlen(Np->L_thousands_sep);
04707 
04708                                 memset(Np->inout_p, ' ', x);
04709                                 Np->inout_p += x - 1;
04710                             }
04711                         }
04712                         else
04713                         {
04714                             strcpy(Np->inout_p, Np->L_thousands_sep);
04715                             Np->inout_p += strlen(Np->inout_p) - 1;
04716                         }
04717                     }
04718                     else
04719                     {
04720                         if (!Np->num_in)
04721                         {
04722                             if (IS_FILLMODE(Np->Num))
04723                                 continue;
04724                         }
04725                         Np->inout_p += strlen(Np->L_thousands_sep) - 1;
04726                     }
04727                     break;
04728 
04729                 case NUM_L:
04730                     if (Np->is_to_char)
04731                     {
04732                         strcpy(Np->inout_p, Np->L_currency_symbol);
04733                         Np->inout_p += strlen(Np->inout_p) - 1;
04734                     }
04735                     else
04736                         Np->inout_p += strlen(Np->L_currency_symbol) - 1;
04737                     break;
04738 
04739                 case NUM_RN:
04740                     if (IS_FILLMODE(Np->Num))
04741                     {
04742                         strcpy(Np->inout_p, Np->number_p);
04743                         Np->inout_p += strlen(Np->inout_p) - 1;
04744                     }
04745                     else
04746                     {
04747                         sprintf(Np->inout_p, "%15s", Np->number_p);
04748                         Np->inout_p += strlen(Np->inout_p) - 1;
04749                     }
04750                     break;
04751 
04752                 case NUM_rn:
04753                     if (IS_FILLMODE(Np->Num))
04754                     {
04755                         strcpy(Np->inout_p, asc_tolower_z(Np->number_p));
04756                         Np->inout_p += strlen(Np->inout_p) - 1;
04757                     }
04758                     else
04759                     {
04760                         sprintf(Np->inout_p, "%15s", asc_tolower_z(Np->number_p));
04761                         Np->inout_p += strlen(Np->inout_p) - 1;
04762                     }
04763                     break;
04764 
04765                 case NUM_th:
04766                     if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
04767                         Np->sign == '-' || IS_DECIMAL(Np->Num))
04768                         continue;
04769 
04770                     if (Np->is_to_char)
04771                         strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
04772                     Np->inout_p += 1;
04773                     break;
04774 
04775                 case NUM_TH:
04776                     if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
04777                         Np->sign == '-' || IS_DECIMAL(Np->Num))
04778                         continue;
04779 
04780                     if (Np->is_to_char)
04781                         strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
04782                     Np->inout_p += 1;
04783                     break;
04784 
04785                 case NUM_MI:
04786                     if (Np->is_to_char)
04787                     {
04788                         if (Np->sign == '-')
04789                             *Np->inout_p = '-';
04790                         else if (IS_FILLMODE(Np->Num))
04791                             continue;
04792                         else
04793                             *Np->inout_p = ' ';
04794                     }
04795                     else
04796                     {
04797                         if (*Np->inout_p == '-')
04798                             *Np->number = '-';
04799                     }
04800                     break;
04801 
04802                 case NUM_PL:
04803                     if (Np->is_to_char)
04804                     {
04805                         if (Np->sign == '+')
04806                             *Np->inout_p = '+';
04807                         else if (IS_FILLMODE(Np->Num))
04808                             continue;
04809                         else
04810                             *Np->inout_p = ' ';
04811                     }
04812                     else
04813                     {
04814                         if (*Np->inout_p == '+')
04815                             *Np->number = '+';
04816                     }
04817                     break;
04818 
04819                 case NUM_SG:
04820                     if (Np->is_to_char)
04821                         *Np->inout_p = Np->sign;
04822 
04823                     else
04824                     {
04825                         if (*Np->inout_p == '-')
04826                             *Np->number = '-';
04827                         else if (*Np->inout_p == '+')
04828                             *Np->number = '+';
04829                     }
04830                     break;
04831 
04832 
04833                 default:
04834                     continue;
04835                     break;
04836             }
04837         }
04838         else
04839         {
04840             /*
04841              * Remove to output char from input in TO_CHAR
04842              */
04843             if (Np->is_to_char)
04844                 *Np->inout_p = n->character;
04845         }
04846         Np->inout_p++;
04847     }
04848 
04849     if (Np->is_to_char)
04850     {
04851         *Np->inout_p = '\0';
04852         return Np->inout;
04853     }
04854     else
04855     {
04856         if (*(Np->number_p - 1) == '.')
04857             *(Np->number_p - 1) = '\0';
04858         else
04859             *Np->number_p = '\0';
04860 
04861         /*
04862          * Correction - precision of dec. number
04863          */
04864         Np->Num->post = Np->read_post;
04865 
04866 #ifdef DEBUG_TO_FROM_CHAR
04867         elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
04868 #endif
04869         return Np->number;
04870     }
04871 }
04872 
04873 /* ----------
04874  * MACRO: Start part of NUM - for all NUM's to_char variants
04875  *  (sorry, but I hate copy same code - macro is better..)
04876  * ----------
04877  */
04878 #define NUM_TOCHAR_prepare \
04879 do { \
04880     len = VARSIZE_ANY_EXHDR(fmt); \
04881     if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ)     \
04882         PG_RETURN_TEXT_P(cstring_to_text("")); \
04883     result  = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ);    \
04884     format  = NUM_cache(len, &Num, fmt, &shouldFree);       \
04885 } while (0)
04886 
04887 /* ----------
04888  * MACRO: Finish part of NUM
04889  * ----------
04890  */
04891 #define NUM_TOCHAR_finish \
04892 do { \
04893     NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true, PG_GET_COLLATION()); \
04894                                     \
04895     if (shouldFree)                 \
04896         pfree(format);              \
04897                                     \
04898     /*                              \
04899      * Convert null-terminated representation of result to standard text. \
04900      * The result is usually much bigger than it needs to be, but there \
04901      * seems little point in realloc'ing it smaller. \
04902      */                             \
04903     len = strlen(VARDATA(result));  \
04904     SET_VARSIZE(result, len + VARHDRSZ); \
04905 } while (0)
04906 
04907 /* -------------------
04908  * NUMERIC to_number() (convert string to numeric)
04909  * -------------------
04910  */
04911 Datum
04912 numeric_to_number(PG_FUNCTION_ARGS)
04913 {
04914     text       *value = PG_GETARG_TEXT_P(0);
04915     text       *fmt = PG_GETARG_TEXT_P(1);
04916     NUMDesc     Num;
04917     Datum       result;
04918     FormatNode *format;
04919     char       *numstr;
04920     bool        shouldFree;
04921     int         len = 0;
04922     int         scale,
04923                 precision;
04924 
04925     len = VARSIZE(fmt) - VARHDRSZ;
04926 
04927     if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
04928         PG_RETURN_NULL();
04929 
04930     format = NUM_cache(len, &Num, fmt, &shouldFree);
04931 
04932     numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
04933 
04934     NUM_processor(format, &Num, VARDATA(value), numstr,
04935                   VARSIZE(value) - VARHDRSZ, 0, false, PG_GET_COLLATION());
04936 
04937     scale = Num.post;
04938     precision = Max(0, Num.pre) + scale;
04939 
04940     if (shouldFree)
04941         pfree(format);
04942 
04943     result = DirectFunctionCall3(numeric_in,
04944                                  CStringGetDatum(numstr),
04945                                  ObjectIdGetDatum(InvalidOid),
04946                       Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
04947     pfree(numstr);
04948     return result;
04949 }
04950 
04951 /* ------------------
04952  * NUMERIC to_char()
04953  * ------------------
04954  */
04955 Datum
04956 numeric_to_char(PG_FUNCTION_ARGS)
04957 {
04958     Numeric     value = PG_GETARG_NUMERIC(0);
04959     text       *fmt = PG_GETARG_TEXT_P(1);
04960     NUMDesc     Num;
04961     FormatNode *format;
04962     text       *result;
04963     bool        shouldFree;
04964     int         len = 0,
04965                 plen = 0,
04966                 sign = 0;
04967     char       *numstr,
04968                *orgnum,
04969                *p;
04970     Numeric     x;
04971 
04972     NUM_TOCHAR_prepare;
04973 
04974     /*
04975      * On DateType depend part (numeric)
04976      */
04977     if (IS_ROMAN(&Num))
04978     {
04979         x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
04980                                                 NumericGetDatum(value),
04981                                                 Int32GetDatum(0)));
04982         numstr = orgnum =
04983             int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
04984                                                        NumericGetDatum(x))));
04985     }
04986     else if (IS_EEEE(&Num))
04987     {
04988         orgnum = numeric_out_sci(value, Num.post);
04989 
04990         /*
04991          * numeric_out_sci() does not emit a sign for positive numbers.  We
04992          * need to add a space in this case so that positive and negative
04993          * numbers are aligned.  We also have to do the right thing for NaN.
04994          */
04995         if (strcmp(orgnum, "NaN") == 0)
04996         {
04997             /*
04998              * Allow 6 characters for the leading sign, the decimal point,
04999              * "e", the exponent's sign and two exponent digits.
05000              */
05001             numstr = (char *) palloc(Num.pre + Num.post + 7);
05002             fill_str(numstr, '#', Num.pre + Num.post + 6);
05003             *numstr = ' ';
05004             *(numstr + Num.pre + 1) = '.';
05005         }
05006         else if (*orgnum != '-')
05007         {
05008             numstr = (char *) palloc(strlen(orgnum) + 2);
05009             *numstr = ' ';
05010             strcpy(numstr + 1, orgnum);
05011             len = strlen(numstr);
05012         }
05013         else
05014         {
05015             numstr = orgnum;
05016             len = strlen(orgnum);
05017         }
05018     }
05019     else
05020     {
05021         Numeric     val = value;
05022 
05023         if (IS_MULTI(&Num))
05024         {
05025             Numeric     a = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
05026                                                          Int32GetDatum(10)));
05027             Numeric     b = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
05028                                                   Int32GetDatum(Num.multi)));
05029 
05030             x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
05031                                                     NumericGetDatum(a),
05032                                                     NumericGetDatum(b)));
05033             val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
05034                                                       NumericGetDatum(value),
05035                                                       NumericGetDatum(x)));
05036             Num.pre += Num.multi;
05037         }
05038 
05039         x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
05040                                                 NumericGetDatum(val),
05041                                                 Int32GetDatum(Num.post)));
05042         orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
05043                                                      NumericGetDatum(x)));
05044 
05045         if (*orgnum == '-')
05046         {
05047             sign = '-';
05048             numstr = orgnum + 1;
05049         }
05050         else
05051         {
05052             sign = '+';
05053             numstr = orgnum;
05054         }
05055         if ((p = strchr(numstr, '.')))
05056             len = p - numstr;
05057         else
05058             len = strlen(numstr);
05059 
05060         if (Num.pre > len)
05061             plen = Num.pre - len;
05062         else if (len > Num.pre)
05063         {
05064             numstr = (char *) palloc(Num.pre + Num.post + 2);
05065             fill_str(numstr, '#', Num.pre + Num.post + 1);
05066             *(numstr + Num.pre) = '.';
05067         }
05068     }
05069 
05070     NUM_TOCHAR_finish;
05071     PG_RETURN_TEXT_P(result);
05072 }
05073 
05074 /* ---------------
05075  * INT4 to_char()
05076  * ---------------
05077  */
05078 Datum
05079 int4_to_char(PG_FUNCTION_ARGS)
05080 {
05081     int32       value = PG_GETARG_INT32(0);
05082     text       *fmt = PG_GETARG_TEXT_P(1);
05083     NUMDesc     Num;
05084     FormatNode *format;
05085     text       *result;
05086     bool        shouldFree;
05087     int         len = 0,
05088                 plen = 0,
05089                 sign = 0;
05090     char       *numstr,
05091                *orgnum;
05092 
05093     NUM_TOCHAR_prepare;
05094 
05095     /*
05096      * On DateType depend part (int32)
05097      */
05098     if (IS_ROMAN(&Num))
05099         numstr = orgnum = int_to_roman(value);
05100     else if (IS_EEEE(&Num))
05101     {
05102         /* we can do it easily because float8 won't lose any precision */
05103         float8      val = (float8) value;
05104 
05105         orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05106         snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val);
05107 
05108         /*
05109          * Swap a leading positive sign for a space.
05110          */
05111         if (*orgnum == '+')
05112             *orgnum = ' ';
05113 
05114         len = strlen(orgnum);
05115         numstr = orgnum;
05116     }
05117     else
05118     {
05119         if (IS_MULTI(&Num))
05120         {
05121             orgnum = DatumGetCString(DirectFunctionCall1(int4out,
05122                                                          Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
05123             Num.pre += Num.multi;
05124         }
05125         else
05126         {
05127             orgnum = DatumGetCString(DirectFunctionCall1(int4out,
05128                                                       Int32GetDatum(value)));
05129         }
05130 
05131         if (*orgnum == '-')
05132         {
05133             sign = '-';
05134             orgnum++;
05135         }
05136         else
05137             sign = '+';
05138         len = strlen(orgnum);
05139 
05140         if (Num.post)
05141         {
05142             numstr = (char *) palloc(len + Num.post + 2);
05143             strcpy(numstr, orgnum);
05144             *(numstr + len) = '.';
05145             memset(numstr + len + 1, '0', Num.post);
05146             *(numstr + len + Num.post + 1) = '\0';
05147         }
05148         else
05149             numstr = orgnum;
05150 
05151         if (Num.pre > len)
05152             plen = Num.pre - len;
05153         else if (len > Num.pre)
05154         {
05155             numstr = (char *) palloc(Num.pre + Num.post + 2);
05156             fill_str(numstr, '#', Num.pre + Num.post + 1);
05157             *(numstr + Num.pre) = '.';
05158         }
05159     }
05160 
05161     NUM_TOCHAR_finish;
05162     PG_RETURN_TEXT_P(result);
05163 }
05164 
05165 /* ---------------
05166  * INT8 to_char()
05167  * ---------------
05168  */
05169 Datum
05170 int8_to_char(PG_FUNCTION_ARGS)
05171 {
05172     int64       value = PG_GETARG_INT64(0);
05173     text       *fmt = PG_GETARG_TEXT_P(1);
05174     NUMDesc     Num;
05175     FormatNode *format;
05176     text       *result;
05177     bool        shouldFree;
05178     int         len = 0,
05179                 plen = 0,
05180                 sign = 0;
05181     char       *numstr,
05182                *orgnum;
05183 
05184     NUM_TOCHAR_prepare;
05185 
05186     /*
05187      * On DateType depend part (int32)
05188      */
05189     if (IS_ROMAN(&Num))
05190     {
05191         /* Currently don't support int8 conversion to roman... */
05192         numstr = orgnum = int_to_roman(DatumGetInt32(
05193                           DirectFunctionCall1(int84, Int64GetDatum(value))));
05194     }
05195     else if (IS_EEEE(&Num))
05196     {
05197         /* to avoid loss of precision, must go via numeric not float8 */
05198         Numeric     val;
05199 
05200         val = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
05201                                                   Int64GetDatum(value)));
05202         orgnum = numeric_out_sci(val, Num.post);
05203 
05204         /*
05205          * numeric_out_sci() does not emit a sign for positive numbers.  We
05206          * need to add a space in this case so that positive and negative
05207          * numbers are aligned.  We don't have to worry about NaN here.
05208          */
05209         if (*orgnum != '-')
05210         {
05211             numstr = (char *) palloc(strlen(orgnum) + 2);
05212             *numstr = ' ';
05213             strcpy(numstr + 1, orgnum);
05214             len = strlen(numstr);
05215         }
05216         else
05217         {
05218             numstr = orgnum;
05219             len = strlen(orgnum);
05220         }
05221     }
05222     else
05223     {
05224         if (IS_MULTI(&Num))
05225         {
05226             double      multi = pow((double) 10, (double) Num.multi);
05227 
05228             value = DatumGetInt64(DirectFunctionCall2(int8mul,
05229                                                       Int64GetDatum(value),
05230                                                    DirectFunctionCall1(dtoi8,
05231                                                     Float8GetDatum(multi))));
05232             Num.pre += Num.multi;
05233         }
05234 
05235         orgnum = DatumGetCString(DirectFunctionCall1(int8out,
05236                                                      Int64GetDatum(value)));
05237 
05238         if (*orgnum == '-')
05239         {
05240             sign = '-';
05241             orgnum++;
05242         }
05243         else
05244             sign = '+';
05245         len = strlen(orgnum);
05246 
05247         if (Num.post)
05248         {
05249             numstr = (char *) palloc(len + Num.post + 2);
05250             strcpy(numstr, orgnum);
05251             *(numstr + len) = '.';
05252             memset(numstr + len + 1, '0', Num.post);
05253             *(numstr + len + Num.post + 1) = '\0';
05254         }
05255         else
05256             numstr = orgnum;
05257 
05258         if (Num.pre > len)
05259             plen = Num.pre - len;
05260         else if (len > Num.pre)
05261         {
05262             numstr = (char *) palloc(Num.pre + Num.post + 2);
05263             fill_str(numstr, '#', Num.pre + Num.post + 1);
05264             *(numstr + Num.pre) = '.';
05265         }
05266     }
05267 
05268     NUM_TOCHAR_finish;
05269     PG_RETURN_TEXT_P(result);
05270 }
05271 
05272 /* -----------------
05273  * FLOAT4 to_char()
05274  * -----------------
05275  */
05276 Datum
05277 float4_to_char(PG_FUNCTION_ARGS)
05278 {
05279     float4      value = PG_GETARG_FLOAT4(0);
05280     text       *fmt = PG_GETARG_TEXT_P(1);
05281     NUMDesc     Num;
05282     FormatNode *format;
05283     text       *result;
05284     bool        shouldFree;
05285     int         len = 0,
05286                 plen = 0,
05287                 sign = 0;
05288     char       *numstr,
05289                *orgnum,
05290                *p;
05291 
05292     NUM_TOCHAR_prepare;
05293 
05294     if (IS_ROMAN(&Num))
05295         numstr = orgnum = int_to_roman((int) rint(value));
05296     else if (IS_EEEE(&Num))
05297     {
05298         numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05299         if (isnan(value) || is_infinite(value))
05300         {
05301             /*
05302              * Allow 6 characters for the leading sign, the decimal point,
05303              * "e", the exponent's sign and two exponent digits.
05304              */
05305             numstr = (char *) palloc(Num.pre + Num.post + 7);
05306             fill_str(numstr, '#', Num.pre + Num.post + 6);
05307             *numstr = ' ';
05308             *(numstr + Num.pre + 1) = '.';
05309         }
05310         else
05311         {
05312             snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
05313 
05314             /*
05315              * Swap a leading positive sign for a space.
05316              */
05317             if (*orgnum == '+')
05318                 *orgnum = ' ';
05319 
05320             len = strlen(orgnum);
05321             numstr = orgnum;
05322         }
05323     }
05324     else
05325     {
05326         float4      val = value;
05327 
05328         if (IS_MULTI(&Num))
05329         {
05330             float       multi = pow((double) 10, (double) Num.multi);
05331 
05332             val = value * multi;
05333             Num.pre += Num.multi;
05334         }
05335 
05336         orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
05337         snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
05338         len = strlen(orgnum);
05339         if (Num.pre > len)
05340             plen = Num.pre - len;
05341         if (len >= FLT_DIG)
05342             Num.post = 0;
05343         else if (Num.post + len > FLT_DIG)
05344             Num.post = FLT_DIG - len;
05345         snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
05346 
05347         if (*orgnum == '-')
05348         {                       /* < 0 */
05349             sign = '-';
05350             numstr = orgnum + 1;
05351         }
05352         else
05353         {
05354             sign = '+';
05355             numstr = orgnum;
05356         }
05357         if ((p = strchr(numstr, '.')))
05358             len = p - numstr;
05359         else
05360             len = strlen(numstr);
05361 
05362         if (Num.pre > len)
05363             plen = Num.pre - len;
05364         else if (len > Num.pre)
05365         {
05366             numstr = (char *) palloc(Num.pre + Num.post + 2);
05367             fill_str(numstr, '#', Num.pre + Num.post + 1);
05368             *(numstr + Num.pre) = '.';
05369         }
05370     }
05371 
05372     NUM_TOCHAR_finish;
05373     PG_RETURN_TEXT_P(result);
05374 }
05375 
05376 /* -----------------
05377  * FLOAT8 to_char()
05378  * -----------------
05379  */
05380 Datum
05381 float8_to_char(PG_FUNCTION_ARGS)
05382 {
05383     float8      value = PG_GETARG_FLOAT8(0);
05384     text       *fmt = PG_GETARG_TEXT_P(1);
05385     NUMDesc     Num;
05386     FormatNode *format;
05387     text       *result;
05388     bool        shouldFree;
05389     int         len = 0,
05390                 plen = 0,
05391                 sign = 0;
05392     char       *numstr,
05393                *orgnum,
05394                *p;
05395 
05396     NUM_TOCHAR_prepare;
05397 
05398     if (IS_ROMAN(&Num))
05399         numstr = orgnum = int_to_roman((int) rint(value));
05400     else if (IS_EEEE(&Num))
05401     {
05402         numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05403         if (isnan(value) || is_infinite(value))
05404         {
05405             /*
05406              * Allow 6 characters for the leading sign, the decimal point,
05407              * "e", the exponent's sign and two exponent digits.
05408              */
05409             numstr = (char *) palloc(Num.pre + Num.post + 7);
05410             fill_str(numstr, '#', Num.pre + Num.post + 6);
05411             *numstr = ' ';
05412             *(numstr + Num.pre + 1) = '.';
05413         }
05414         else
05415         {
05416             snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
05417 
05418             /*
05419              * Swap a leading positive sign for a space.
05420              */
05421             if (*orgnum == '+')
05422                 *orgnum = ' ';
05423 
05424             len = strlen(orgnum);
05425             numstr = orgnum;
05426         }
05427     }
05428     else
05429     {
05430         float8      val = value;
05431 
05432         if (IS_MULTI(&Num))
05433         {
05434             double      multi = pow((double) 10, (double) Num.multi);
05435 
05436             val = value * multi;
05437             Num.pre += Num.multi;
05438         }
05439         orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05440         len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val));
05441         if (Num.pre > len)
05442             plen = Num.pre - len;
05443         if (len >= DBL_DIG)
05444             Num.post = 0;
05445         else if (Num.post + len > DBL_DIG)
05446             Num.post = DBL_DIG - len;
05447         snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
05448 
05449         if (*orgnum == '-')
05450         {                       /* < 0 */
05451             sign = '-';
05452             numstr = orgnum + 1;
05453         }
05454         else
05455         {
05456             sign = '+';
05457             numstr = orgnum;
05458         }
05459         if ((p = strchr(numstr, '.')))
05460             len = p - numstr;
05461         else
05462             len = strlen(numstr);
05463 
05464         if (Num.pre > len)
05465             plen = Num.pre - len;
05466         else if (len > Num.pre)
05467         {
05468             numstr = (char *) palloc(Num.pre + Num.post + 2);
05469             fill_str(numstr, '#', Num.pre + Num.post + 1);
05470             *(numstr + Num.pre) = '.';
05471         }
05472     }
05473 
05474     NUM_TOCHAR_finish;
05475     PG_RETURN_TEXT_P(result);
05476 }