]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/formatting.c
Allow to_char() to print localized month and day names.
[postgresql] / src / backend / utils / adt / formatting.c
1 /* -----------------------------------------------------------------------
2  * formatting.c
3  *
4  * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.104 2006/02/12 04:44:15 momjian Exp $
5  *
6  *
7  *       Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group
8  *
9  *
10  *       TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER();
11  *
12  *       The PostgreSQL routines for a timestamp/int/float/numeric formatting,
13  *       inspired by the Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines.
14  *
15  *
16  *       Cache & Memory:
17  *      Routines use (itself) internal cache for format pictures.
18  *
19  *      The cache uses a static buffers and is persistent across transactions.
20  *      If format-picture is bigger than cache buffer, parser is called always.
21  *
22  *       NOTE for Number version:
23  *      All in this version is implemented as keywords ( => not used
24  *      suffixes), because a format picture is for *one* item (number)
25  *      only. It not is as a timestamp version, where each keyword (can)
26  *      has suffix.
27  *
28  *       NOTE for Timestamp routines:
29  *      In this module the POSIX 'struct tm' type is *not* used, but rather
30  *      PgSQL type, which has tm_mon based on one (*non* zero) and
31  *      year *not* based on 1900, but is used full year number.
32  *      Module supports AD / BC / AM / PM.
33  *
34  *      Supported types for to_char():
35  *
36  *              Timestamp, Numeric, int4, int8, float4, float8
37  *
38  *      Supported types for reverse conversion:
39  *
40  *              Timestamp       - to_timestamp()
41  *              Date            - to_date()
42  *              Numeric         - to_number()
43  *
44  *
45  *      Karel Zak
46  *
47  * TODO
48  *      - better number building (formatting) / parsing, now it isn't
49  *                ideal code
50  *      - use Assert()
51  *      - add support for abstime
52  *      - add support for roman number to standard number conversion
53  *      - add support for number spelling
54  *      - add support for string to string formatting (we must be better
55  *        than Oracle :-),
56  *              to_char('Hello', 'X X X X X') -> 'H e l l o'
57  *
58  * -----------------------------------------------------------------------
59  */
60
61 /* ----------
62  * UnComment me for DEBUG
63  * ----------
64  */
65 /***
66 #define DEBUG_TO_FROM_CHAR
67 #define DEBUG_elog_output       DEBUG3
68 ***/
69
70 #include "postgres.h"
71
72 #include <ctype.h>
73 #include <unistd.h>
74 #include <math.h>
75 #include <float.h>
76 #include <locale.h>
77
78 #include "utils/builtins.h"
79 #include "utils/date.h"
80 #include "utils/datetime.h"
81 #include "utils/formatting.h"
82 #include "utils/int8.h"
83 #include "utils/numeric.h"
84 #include "utils/pg_locale.h"
85
86 #define _(x)    gettext((x))
87
88 /* ----------
89  * Routines type
90  * ----------
91  */
92 #define DCH_TYPE                1               /* DATE-TIME version    */
93 #define NUM_TYPE                2               /* NUMBER version       */
94
95 /* ----------
96  * KeyWord Index (ascii from position 32 (' ') to 126 (~))
97  * ----------
98  */
99 #define KeyWord_INDEX_SIZE              ('~' - ' ')
100 #define KeyWord_INDEX_FILTER(_c)        ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
101
102 /* ----------
103  * Maximal length of one node
104  * ----------
105  */
106 #define DCH_MAX_ITEM_SIZ                9               /* max julian day               */
107 #define NUM_MAX_ITEM_SIZ                8               /* roman number (RN has 15 chars)       */
108
109 /* ----------
110  * More is in float.c
111  * ----------
112  */
113 #define MAXFLOATWIDTH   64
114 #define MAXDOUBLEWIDTH  128
115
116 /* ----------
117  * External (defined in PgSQL datetime.c (timestamp utils))
118  * ----------
119  */
120 extern char *months[],                  /* month abbreviation   */
121                    *days[];                             /* full days            */
122
123 /* ----------
124  * Format parser structs
125  * ----------
126  */
127 typedef struct
128 {
129         char       *name;                       /* suffix string                */
130         int                     len,                    /* suffix length                */
131                                 id,                             /* used in node->suffix */
132                                 type;                   /* prefix / postfix                     */
133 } KeySuffix;
134
135 typedef struct FormatNode FormatNode;
136
137 typedef struct
138 {
139         const char *name;                       /* keyword                      */
140         int                     len;                    /* keyword length               */
141         int                     (*action) (int arg, char *inout,                /* action for keyword */
142                                                                   int suf, bool is_to_char, bool is_interval,
143                                                                            FormatNode *node, void *data);
144         int                     id;                             /* keyword id                   */
145         bool            isitdigit;              /* is expected output/input digit */
146 } KeyWord;
147
148 struct FormatNode
149 {
150         int                     type;                   /* node type                    */
151         const KeyWord *key;                     /* if node type is KEYWORD      */
152         int                     character,              /* if node type is CHAR         */
153                                 suffix;                 /* keyword suffix               */
154 };
155
156 #define NODE_TYPE_END           1
157 #define NODE_TYPE_ACTION        2
158 #define NODE_TYPE_CHAR          3
159
160 #define SUFFTYPE_PREFIX         1
161 #define SUFFTYPE_POSTFIX        2
162
163
164 /* ----------
165  * Full months
166  * ----------
167  */
168 static char *months_full[] = {
169         "January", "February", "March", "April", "May", "June", "July",
170         "August", "September", "October", "November", "December", NULL
171 };
172
173 static char *days_short[] = {
174         "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
175 };
176
177 /* ----------
178  * AC / DC
179  * ----------
180  */
181 /*
182  *      There is no 0 AD.  Years go from 1 BC to 1 AD, so we make it
183  *      positive and map year == -1 to year zero, and shift all negative
184  *      years up one.  For interval years, we just return the year.
185  */
186 #define ADJUST_YEAR(year, is_interval)  ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
187 #define BC_STR_ORIG " BC"
188
189 #define A_D_STR         "A.D."
190 #define a_d_STR         "a.d."
191 #define AD_STR          "AD"
192 #define ad_STR          "ad"
193
194 #define B_C_STR         "B.C."
195 #define b_c_STR         "b.c."
196 #define BC_STR          "BC"
197 #define bc_STR          "bc"
198
199
200 /* ----------
201  * AM / PM
202  * ----------
203  */
204 #define A_M_STR         "A.M."
205 #define a_m_STR         "a.m."
206 #define AM_STR          "AM"
207 #define am_STR          "am"
208
209 #define P_M_STR         "P.M."
210 #define p_m_STR         "p.m."
211 #define PM_STR          "PM"
212 #define pm_STR          "pm"
213
214
215 /* ----------
216  * Months in roman-numeral
217  * (Must be conversely for seq_search (in FROM_CHAR), because
218  *      'VIII' must be over 'V')
219  * ----------
220  */
221 static char *rm_months_upper[] =
222 {"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};
223
224 static char *rm_months_lower[] =
225 {"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};
226
227 /* ----------
228  * Roman numbers
229  * ----------
230  */
231 static char *rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};
232 static char *rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};
233 static char *rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};
234
235 /* ----------
236  * Ordinal postfixes
237  * ----------
238  */
239 static char *numTH[] = {"ST", "ND", "RD", "TH", NULL};
240 static char *numth[] = {"st", "nd", "rd", "th", NULL};
241
242 /* ----------
243  * Flags & Options:
244  * ----------
245  */
246 #define ONE_UPPER       1                       /* Name */
247 #define ALL_UPPER       2                       /* NAME */
248 #define ALL_LOWER       3                       /* name */
249
250 #define FULL_SIZ        0
251
252 #define MAX_MON_LEN 3
253 #define MAX_DY_LEN      3
254
255 #define TH_UPPER        1
256 #define TH_LOWER        2
257
258 /* ----------
259  * Flags for DCH version
260  * ----------
261  */
262 static bool DCH_global_fx = false;
263
264
265 /* ----------
266  * Number description struct
267  * ----------
268  */
269 typedef struct
270 {
271         int                     pre,                    /* (count) numbers before decimal */
272                                 post,                   /* (count) numbers after decimal  */
273                                 lsign,                  /* want locales sign              */
274                                 flag,                   /* number parameters              */
275                                 pre_lsign_num,  /* tmp value for lsign            */
276                                 multi,                  /* multiplier for 'V'             */
277                                 zero_start,             /* position of first zero         */
278                                 zero_end,               /* position of last zero          */
279                                 need_locale;    /* needs it locale                */
280 } NUMDesc;
281
282 /* ----------
283  * Flags for NUMBER version
284  * ----------
285  */
286 #define NUM_F_DECIMAL           (1 << 1)
287 #define NUM_F_LDECIMAL          (1 << 2)
288 #define NUM_F_ZERO                      (1 << 3)
289 #define NUM_F_BLANK                     (1 << 4)
290 #define NUM_F_FILLMODE          (1 << 5)
291 #define NUM_F_LSIGN                     (1 << 6)
292 #define NUM_F_BRACKET           (1 << 7)
293 #define NUM_F_MINUS                     (1 << 8)
294 #define NUM_F_PLUS                      (1 << 9)
295 #define NUM_F_ROMAN                     (1 << 10)
296 #define NUM_F_MULTI                     (1 << 11)
297 #define NUM_F_PLUS_POST         (1 << 12)
298 #define NUM_F_MINUS_POST        (1 << 13)
299
300 #define NUM_LSIGN_PRE   (-1)
301 #define NUM_LSIGN_POST  1
302 #define NUM_LSIGN_NONE  0
303
304 /* ----------
305  * Tests
306  * ----------
307  */
308 #define IS_DECIMAL(_f)  ((_f)->flag & NUM_F_DECIMAL)
309 #define IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL)
310 #define IS_ZERO(_f) ((_f)->flag & NUM_F_ZERO)
311 #define IS_BLANK(_f)    ((_f)->flag & NUM_F_BLANK)
312 #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE)
313 #define IS_BRACKET(_f)  ((_f)->flag & NUM_F_BRACKET)
314 #define IS_MINUS(_f)    ((_f)->flag & NUM_F_MINUS)
315 #define IS_LSIGN(_f)    ((_f)->flag & NUM_F_LSIGN)
316 #define IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
317 #define IS_ROMAN(_f)    ((_f)->flag & NUM_F_ROMAN)
318 #define IS_MULTI(_f)    ((_f)->flag & NUM_F_MULTI)
319
320 /* ----------
321  * Format picture cache
322  *      (cache size:
323  *              Number part = NUM_CACHE_SIZE * NUM_CACHE_FIELDS
324  *              Date-time part  = DCH_CACHE_SIZE * DCH_CACHE_FIELDS
325  *      )
326  * ----------
327  */
328 #define NUM_CACHE_SIZE          64
329 #define NUM_CACHE_FIELDS        16
330 #define DCH_CACHE_SIZE          128
331 #define DCH_CACHE_FIELDS        16
332
333 typedef struct
334 {
335         FormatNode      format[DCH_CACHE_SIZE + 1];
336         char            str[DCH_CACHE_SIZE + 1];
337         int                     age;
338 } DCHCacheEntry;
339
340 typedef struct
341 {
342         FormatNode      format[NUM_CACHE_SIZE + 1];
343         char            str[NUM_CACHE_SIZE + 1];
344         int                     age;
345         NUMDesc         Num;
346 } NUMCacheEntry;
347
348 /* global cache for --- date/time part */
349 static DCHCacheEntry DCHCache[DCH_CACHE_FIELDS + 1];
350
351 static int      n_DCHCache = 0;         /* number of entries */
352 static int      DCHCounter = 0;
353
354 /* global cache for --- number part */
355 static NUMCacheEntry NUMCache[NUM_CACHE_FIELDS + 1];
356 static NUMCacheEntry *last_NUMCacheEntry;
357
358 static int      n_NUMCache = 0;         /* number of entries */
359 static int      NUMCounter = 0;
360
361 #define MAX_INT32       (2147483600)
362
363 /* ----------
364  * For char->date/time conversion
365  * ----------
366  */
367 typedef struct
368 {
369         int                     hh,
370                                 am,
371                                 pm,
372                                 mi,
373                                 ss,
374                                 ssss,
375                                 d,
376                                 dd,
377                                 ddd,
378                                 mm,
379                                 ms,
380                                 year,
381                                 bc,
382                                 iw,
383                                 ww,
384                                 w,
385                                 cc,
386                                 q,
387                                 j,
388                                 us,
389                                 yysz;                   /* is it YY or YYYY ? */
390 } TmFromChar;
391
392 #define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
393
394 /* ----------
395  * Debug
396  * ----------
397  */
398 #ifdef DEBUG_TO_FROM_CHAR
399 #define DEBUG_TMFC(_X) \
400                 elog(DEBUG_elog_output, "TMFC:\nhh %d\nam %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nms: %d\nyear %d\nbc %d\niw %d\nww %d\nw %d\ncc %d\nq %d\nj %d\nus: %d\nyysz: %d", \
401                         (_X)->hh, (_X)->am, (_X)->pm, (_X)->mi, (_X)->ss, \
402                         (_X)->ssss, (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, \
403                         (_X)->year, (_X)->bc, (_X)->iw, (_X)->ww, (_X)->w, \
404                         (_X)->cc, (_X)->q, (_X)->j, (_X)->us, (_X)->yysz);
405 #define DEBUG_TM(_X) \
406                 elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
407                         (_X)->tm_sec, (_X)->tm_year,\
408                         (_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\
409                         (_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)
410 #else
411 #define DEBUG_TMFC(_X)
412 #define DEBUG_TM(_X)
413 #endif
414
415 /* ----------
416  * Datetime to char conversion
417  * ----------
418  */
419 typedef struct TmToChar
420 {
421         struct pg_tm tm;                        /* classic 'tm' struct */
422         fsec_t          fsec;                   /* fractional seconds */
423         char       *tzn;                        /* timezone */
424 } TmToChar;
425
426 #define tmtcTm(_X)      (&(_X)->tm)
427 #define tmtcTzn(_X) ((_X)->tzn)
428 #define tmtcFsec(_X)    ((_X)->fsec)
429
430 #define ZERO_tm(_X) \
431 do {    \
432         (_X)->tm_sec  = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
433         (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
434         (_X)->tm_mday = (_X)->tm_mon  = 1; \
435 } while(0)
436
437 #define ZERO_tmtc(_X) \
438 do { \
439         ZERO_tm( tmtcTm(_X) ); \
440         tmtcFsec(_X) = 0; \
441         tmtcTzn(_X) = NULL; \
442 } while(0)
443
444 /*
445  *      to_char(time) appears to to_char() as an interval, so this check
446  *      is really for interval and time data types.
447  */
448 #define INVALID_FOR_INTERVAL  \
449 do { \
450         if (is_interval) \
451                 ereport(ERROR, \
452                                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
453                                  errmsg("invalid format specification for an interval value"), \
454                                  errhint("Intervals are not tied to specific calendar dates."))); \
455 } while(0)
456
457 /*****************************************************************************
458  *                      KeyWords definition & action
459  *****************************************************************************/
460
461 static int dch_global(int arg, char *inout, int suf, bool is_to_char,
462                    bool is_interval, FormatNode *node, void *data);
463 static int dch_time(int arg, char *inout, int suf, bool is_to_char,
464                  bool is_interval, FormatNode *node, void *data);
465 static int dch_date(int arg, char *inout, int suf, bool is_to_char,
466                  bool is_interval, FormatNode *node, void *data);
467
468 /* ----------
469  * Suffixes:
470  * ----------
471  */
472 #define DCH_S_FM        0x01
473 #define DCH_S_TH        0x02
474 #define DCH_S_th        0x04
475 #define DCH_S_SP        0x08
476 #define DCH_S_TM        0x10
477
478 /* ----------
479  * Suffix tests
480  * ----------
481  */
482 #define S_THth(_s)      ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)
483 #define S_TH(_s)        (((_s) & DCH_S_TH) ? 1 : 0)
484 #define S_th(_s)        (((_s) & DCH_S_th) ? 1 : 0)
485 #define S_TH_TYPE(_s)   (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)
486
487 #define S_FM(_s)        (((_s) & DCH_S_FM) ? 1 : 0)
488 #define S_SP(_s)        (((_s) & DCH_S_SP) ? 1 : 0)
489 #define S_TM(_s)        (((_s) & DCH_S_TM) ? 1 : 0)
490
491 /* ----------
492  * Suffixes definition for DATE-TIME TO/FROM CHAR
493  * ----------
494  */
495 static KeySuffix DCH_suff[] = {
496         {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
497         {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
498         {"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX},
499         {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
500         {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
501         {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
502         {"SP", 2, DCH_S_SP, SUFFTYPE_POSTFIX},
503         /* last */
504         {NULL, 0, 0, 0}
505 };
506
507 /* ----------
508  * Format-pictures (KeyWord).
509  *
510  * The KeyWord field; alphabetic sorted, *BUT* strings alike is sorted
511  *                complicated -to-> easy:
512  *
513  *      (example: "DDD","DD","Day","D" )
514  *
515  * (this specific sort needs the algorithm for sequential search for strings,
516  * which not has exact end; -> How keyword is in "HH12blabla" ? - "HH"
517  * or "HH12"? You must first try "HH12", because "HH" is in string, but
518  * it is not good.
519  *
520  * (!)
521  *       - Position for the keyword is similar as position in the enum DCH/NUM_poz.
522  * (!)
523  *
524  * For fast search is used the 'int index[]', index is ascii table from position
525  * 32 (' ') to 126 (~), in this index is DCH_ / NUM_ enums for each ASCII
526  * position or -1 if char is not used in the KeyWord. Search example for
527  * string "MM":
528  *      1)      see in index to index['M' - 32],
529  *      2)      take keywords position (enum DCH_MM) from index
530  *      3)      run sequential search in keywords[] from this position
531  *
532  * ----------
533  */
534
535 typedef enum
536 {
537         DCH_A_D,
538         DCH_A_M,
539         DCH_AD,
540         DCH_AM,
541         DCH_B_C,
542         DCH_BC,
543         DCH_CC,
544         DCH_DAY,
545         DCH_DDD,
546         DCH_DD,
547         DCH_DY,
548         DCH_Day,
549         DCH_Dy,
550         DCH_D,
551         DCH_FX,                                         /* global suffix */
552         DCH_HH24,
553         DCH_HH12,
554         DCH_HH,
555         DCH_IW,
556         DCH_IYYY,
557         DCH_IYY,
558         DCH_IY,
559         DCH_I,
560         DCH_J,
561         DCH_MI,
562         DCH_MM,
563         DCH_MONTH,
564         DCH_MON,
565         DCH_MS,
566         DCH_Month,
567         DCH_Mon,
568         DCH_P_M,
569         DCH_PM,
570         DCH_Q,
571         DCH_RM,
572         DCH_SSSS,
573         DCH_SS,
574         DCH_TZ,
575         DCH_US,
576         DCH_WW,
577         DCH_W,
578         DCH_Y_YYY,
579         DCH_YYYY,
580         DCH_YYY,
581         DCH_YY,
582         DCH_Y,
583         DCH_a_d,
584         DCH_a_m,
585         DCH_ad,
586         DCH_am,
587         DCH_b_c,
588         DCH_bc,
589         DCH_cc,
590         DCH_day,
591         DCH_ddd,
592         DCH_dd,
593         DCH_dy,
594         DCH_d,
595         DCH_fx,
596         DCH_hh24,
597         DCH_hh12,
598         DCH_hh,
599         DCH_iw,
600         DCH_iyyy,
601         DCH_iyy,
602         DCH_iy,
603         DCH_i,
604         DCH_j,
605         DCH_mi,
606         DCH_mm,
607         DCH_month,
608         DCH_mon,
609         DCH_ms,
610         DCH_p_m,
611         DCH_pm,
612         DCH_q,
613         DCH_rm,
614         DCH_ssss,
615         DCH_ss,
616         DCH_tz,
617         DCH_us,
618         DCH_ww,
619         DCH_w,
620         DCH_y_yyy,
621         DCH_yyyy,
622         DCH_yyy,
623         DCH_yy,
624         DCH_y,
625
626         /* last */
627         _DCH_last_
628 } DCH_poz;
629
630 typedef enum
631 {
632         NUM_COMMA,
633         NUM_DEC,
634         NUM_0,
635         NUM_9,
636         NUM_B,
637         NUM_C,
638         NUM_D,
639         NUM_E,
640         NUM_FM,
641         NUM_G,
642         NUM_L,
643         NUM_MI,
644         NUM_PL,
645         NUM_PR,
646         NUM_RN,
647         NUM_SG,
648         NUM_SP,
649         NUM_S,
650         NUM_TH,
651         NUM_V,
652         NUM_b,
653         NUM_c,
654         NUM_d,
655         NUM_e,
656         NUM_fm,
657         NUM_g,
658         NUM_l,
659         NUM_mi,
660         NUM_pl,
661         NUM_pr,
662         NUM_rn,
663         NUM_sg,
664         NUM_sp,
665         NUM_s,
666         NUM_th,
667         NUM_v,
668
669         /* last */
670         _NUM_last_
671 } NUM_poz;
672
673 /* ----------
674  * KeyWords for DATE-TIME version
675  * ----------
676  */
677 static const KeyWord DCH_keywords[] = {
678 /*      keyword, len, func, type, isitdigit                      is in Index */
679         {"A.D.", 4, dch_date, DCH_A_D, FALSE},          /* A */
680         {"A.M.", 4, dch_time, DCH_A_M, FALSE},
681         {"AD", 2, dch_date, DCH_AD, FALSE},
682         {"AM", 2, dch_time, DCH_AM, FALSE},
683         {"B.C.", 4, dch_date, DCH_B_C, FALSE},          /* B */
684         {"BC", 2, dch_date, DCH_BC, FALSE},
685         {"CC", 2, dch_date, DCH_CC, TRUE},      /* C */
686         {"DAY", 3, dch_date, DCH_DAY, FALSE},           /* D */
687         {"DDD", 3, dch_date, DCH_DDD, TRUE},
688         {"DD", 2, dch_date, DCH_DD, TRUE},
689         {"DY", 2, dch_date, DCH_DY, FALSE},
690         {"Day", 3, dch_date, DCH_Day, FALSE},
691         {"Dy", 2, dch_date, DCH_Dy, FALSE},
692         {"D", 1, dch_date, DCH_D, TRUE},
693         {"FX", 2, dch_global, DCH_FX, FALSE},           /* F */
694         {"HH24", 4, dch_time, DCH_HH24, TRUE},          /* H */
695         {"HH12", 4, dch_time, DCH_HH12, TRUE},
696         {"HH", 2, dch_time, DCH_HH, TRUE},
697         {"IW", 2, dch_date, DCH_IW, TRUE},      /* I */
698         {"IYYY", 4, dch_date, DCH_IYYY, TRUE},
699         {"IYY", 3, dch_date, DCH_IYY, TRUE},
700         {"IY", 2, dch_date, DCH_IY, TRUE},
701         {"I", 1, dch_date, DCH_I, TRUE},
702         {"J", 1, dch_date, DCH_J, TRUE},        /* J */
703         {"MI", 2, dch_time, DCH_MI, TRUE},
704         {"MM", 2, dch_date, DCH_MM, TRUE},
705         {"MONTH", 5, dch_date, DCH_MONTH, FALSE},
706         {"MON", 3, dch_date, DCH_MON, FALSE},
707         {"MS", 2, dch_time, DCH_MS, TRUE},
708         {"Month", 5, dch_date, DCH_Month, FALSE},
709         {"Mon", 3, dch_date, DCH_Mon, FALSE},
710         {"P.M.", 4, dch_time, DCH_P_M, FALSE},          /* P */
711         {"PM", 2, dch_time, DCH_PM, FALSE},
712         {"Q", 1, dch_date, DCH_Q, TRUE},        /* Q */
713         {"RM", 2, dch_date, DCH_RM, FALSE}, /* R */
714         {"SSSS", 4, dch_time, DCH_SSSS, TRUE},          /* S */
715         {"SS", 2, dch_time, DCH_SS, TRUE},
716         {"TZ", 2, dch_time, DCH_TZ, FALSE}, /* T */
717         {"US", 2, dch_time, DCH_US, TRUE},      /* U */
718         {"WW", 2, dch_date, DCH_WW, TRUE},      /* W */
719         {"W", 1, dch_date, DCH_W, TRUE},
720         {"Y,YYY", 5, dch_date, DCH_Y_YYY, TRUE},        /* Y */
721         {"YYYY", 4, dch_date, DCH_YYYY, TRUE},
722         {"YYY", 3, dch_date, DCH_YYY, TRUE},
723         {"YY", 2, dch_date, DCH_YY, TRUE},
724         {"Y", 1, dch_date, DCH_Y, TRUE},
725         {"a.d.", 4, dch_date, DCH_a_d, FALSE},          /* a */
726         {"a.m.", 4, dch_time, DCH_a_m, FALSE},
727         {"ad", 2, dch_date, DCH_ad, FALSE},
728         {"am", 2, dch_time, DCH_am, FALSE},
729         {"b.c.", 4, dch_date, DCH_b_c, FALSE},          /* b */
730         {"bc", 2, dch_date, DCH_bc, FALSE},
731         {"cc", 2, dch_date, DCH_CC, TRUE},      /* c */
732         {"day", 3, dch_date, DCH_day, FALSE},           /* d */
733         {"ddd", 3, dch_date, DCH_DDD, TRUE},
734         {"dd", 2, dch_date, DCH_DD, TRUE},
735         {"dy", 2, dch_date, DCH_dy, FALSE},
736         {"d", 1, dch_date, DCH_D, TRUE},
737         {"fx", 2, dch_global, DCH_FX, FALSE},           /* f */
738         {"hh24", 4, dch_time, DCH_HH24, TRUE},          /* h */
739         {"hh12", 4, dch_time, DCH_HH12, TRUE},
740         {"hh", 2, dch_time, DCH_HH, TRUE},
741         {"iw", 2, dch_date, DCH_IW, TRUE},      /* i */
742         {"iyyy", 4, dch_date, DCH_IYYY, TRUE},
743         {"iyy", 3, dch_date, DCH_IYY, TRUE},
744         {"iy", 2, dch_date, DCH_IY, TRUE},
745         {"i", 1, dch_date, DCH_I, TRUE},
746         {"j", 1, dch_time, DCH_J, TRUE},        /* j */
747         {"mi", 2, dch_time, DCH_MI, TRUE},      /* m */
748         {"mm", 2, dch_date, DCH_MM, TRUE},
749         {"month", 5, dch_date, DCH_month, FALSE},
750         {"mon", 3, dch_date, DCH_mon, FALSE},
751         {"ms", 2, dch_time, DCH_MS, TRUE},
752         {"p.m.", 4, dch_time, DCH_p_m, FALSE},          /* p */
753         {"pm", 2, dch_time, DCH_pm, FALSE},
754         {"q", 1, dch_date, DCH_Q, TRUE},        /* q */
755         {"rm", 2, dch_date, DCH_rm, FALSE}, /* r */
756         {"ssss", 4, dch_time, DCH_SSSS, TRUE},          /* s */
757         {"ss", 2, dch_time, DCH_SS, TRUE},
758         {"tz", 2, dch_time, DCH_tz, FALSE}, /* t */
759         {"us", 2, dch_time, DCH_US, TRUE},      /* u */
760         {"ww", 2, dch_date, DCH_WW, TRUE},      /* w */
761         {"w", 1, dch_date, DCH_W, TRUE},
762         {"y,yyy", 5, dch_date, DCH_Y_YYY, TRUE},        /* y */
763         {"yyyy", 4, dch_date, DCH_YYYY, TRUE},
764         {"yyy", 3, dch_date, DCH_YYY, TRUE},
765         {"yy", 2, dch_date, DCH_YY, TRUE},
766         {"y", 1, dch_date, DCH_Y, TRUE},
767 /* last */
768 {NULL, 0, NULL, 0}};
769
770 /* ----------
771  * KeyWords for NUMBER version (now, isitdigit info is not needful here..)
772  * ----------
773  */
774 static const KeyWord NUM_keywords[] = {
775 /*      keyword,        len, func.      type                       is in Index */
776         {",", 1, NULL, NUM_COMMA},      /* , */
777         {".", 1, NULL, NUM_DEC},        /* . */
778         {"0", 1, NULL, NUM_0},          /* 0 */
779         {"9", 1, NULL, NUM_9},          /* 9 */
780         {"B", 1, NULL, NUM_B},          /* B */
781         {"C", 1, NULL, NUM_C},          /* C */
782         {"D", 1, NULL, NUM_D},          /* D */
783         {"E", 1, NULL, NUM_E},          /* E */
784         {"FM", 2, NULL, NUM_FM},        /* F */
785         {"G", 1, NULL, NUM_G},          /* G */
786         {"L", 1, NULL, NUM_L},          /* L */
787         {"MI", 2, NULL, NUM_MI},        /* M */
788         {"PL", 2, NULL, NUM_PL},        /* P */
789         {"PR", 2, NULL, NUM_PR},
790         {"RN", 2, NULL, NUM_RN},        /* R */
791         {"SG", 2, NULL, NUM_SG},        /* S */
792         {"SP", 2, NULL, NUM_SP},
793         {"S", 1, NULL, NUM_S},
794         {"TH", 2, NULL, NUM_TH},        /* T */
795         {"V", 1, NULL, NUM_V},          /* V */
796         {"b", 1, NULL, NUM_B},          /* b */
797         {"c", 1, NULL, NUM_C},          /* c */
798         {"d", 1, NULL, NUM_D},          /* d */
799         {"e", 1, NULL, NUM_E},          /* e */
800         {"fm", 2, NULL, NUM_FM},        /* f */
801         {"g", 1, NULL, NUM_G},          /* g */
802         {"l", 1, NULL, NUM_L},          /* l */
803         {"mi", 2, NULL, NUM_MI},        /* m */
804         {"pl", 2, NULL, NUM_PL},        /* p */
805         {"pr", 2, NULL, NUM_PR},
806         {"rn", 2, NULL, NUM_rn},        /* r */
807         {"sg", 2, NULL, NUM_SG},        /* s */
808         {"sp", 2, NULL, NUM_SP},
809         {"s", 1, NULL, NUM_S},
810         {"th", 2, NULL, NUM_th},        /* t */
811         {"v", 1, NULL, NUM_V},          /* v */
812
813 /* last */
814 {NULL, 0, NULL, 0}};
815
816
817 /* ----------
818  * KeyWords index for DATE-TIME version
819  * ----------
820  */
821 static const int DCH_index[KeyWord_INDEX_SIZE] = {
822 /*
823 0       1       2       3       4       5       6       7       8       9
824 */
825         /*---- first 0..31 chars are skipped ----*/
826
827         -1, -1, -1, -1, -1, -1, -1, -1,
828         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
829         -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
830         -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
831         DCH_FX, -1, DCH_HH24, DCH_IW, DCH_J, -1, -1, DCH_MI, -1, -1,
832         DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY,
833         -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
834         DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iw, DCH_j, -1, -1, DCH_mi,
835         -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww,
836         -1, DCH_y_yyy, -1, -1, -1, -1
837
838         /*---- chars over 126 are skiped ----*/
839 };
840
841 /* ----------
842  * KeyWords index for NUMBER version
843  * ----------
844  */
845 static const int NUM_index[KeyWord_INDEX_SIZE] = {
846 /*
847 0       1       2       3       4       5       6       7       8       9
848 */
849         /*---- first 0..31 chars are skiped ----*/
850
851         -1, -1, -1, -1, -1, -1, -1, -1,
852         -1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
853         -1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
854         -1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
855         NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
856         NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
857         -1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
858         NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
859         -1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
860         -1, -1, -1, -1, -1, -1
861
862         /*---- chars over 126 are skiped ----*/
863 };
864
865 /* ----------
866  * Number processor struct
867  * ----------
868  */
869 typedef struct NUMProc
870 {
871         bool            is_to_char;
872         NUMDesc    *Num;                        /* number description           */
873
874         int                     sign,                   /* '-' or '+'                   */
875                                 sign_wrote,             /* was sign write               */
876                                 num_count,              /* number of write digits       */
877                                 num_in,                 /* is inside number             */
878                                 num_curr,               /* current position in number   */
879                                 num_pre,                /* space before first number    */
880
881                                 read_dec,               /* to_number - was read dec. point      */
882                                 read_post,              /* to_number - number of dec. digit */
883                                 read_pre;               /* to_number - number non-dec. digit */
884
885         char       *number,                     /* string with number   */
886                            *number_p,           /* pointer to current number position */
887                            *inout,                      /* in / out buffer      */
888                            *inout_p,            /* pointer to current inout position */
889                            *last_relevant,      /* last relevant number after decimal point */
890
891                            *L_negative_sign,    /* Locale */
892                            *L_positive_sign,
893                            *decimal,
894                            *L_thousands_sep,
895                            *L_currency_symbol;
896 } NUMProc;
897
898
899 /* ----------
900  * Functions
901  * ----------
902  */
903 static const KeyWord *index_seq_search(char *str, const KeyWord *kw,
904                                  const int *index);
905 static KeySuffix *suff_search(char *str, KeySuffix *suf, int type);
906 static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
907 static void parse_format(FormatNode *node, char *str, const KeyWord *kw,
908                          KeySuffix *suf, const int *index, int ver, NUMDesc *Num);
909 static char *DCH_processor(FormatNode *node, char *inout, bool is_to_char,
910                           bool is_interval, void *data);
911
912 #ifdef DEBUG_TO_FROM_CHAR
913 static void dump_index(const KeyWord *k, const int *index);
914 static void dump_node(FormatNode *node, int max);
915 #endif
916
917 static char *get_th(char *num, int type);
918 static char *str_numth(char *dest, char *num, int type);
919 static int      strdigits_len(char *str);
920 static char *str_toupper(char *buff);
921 static char *str_tolower(char *buff);
922
923 /* static int is_acdc(char *str, int *len); */
924 static int      seq_search(char *name, char **array, int type, int max, int *len);
925 static void do_to_timestamp(text *date_txt, text *fmt,
926                                 struct pg_tm * tm, fsec_t *fsec);
927 static char *fill_str(char *str, int c, int max);
928 static FormatNode *NUM_cache(int len, NUMDesc *Num, char *pars_str, bool *shouldFree);
929 static char *int_to_roman(int number);
930 static void NUM_prepare_locale(NUMProc *Np);
931 static char *get_last_relevant_decnum(char *num);
932 static void NUM_numpart_from_char(NUMProc *Np, int id, int plen);
933 static void NUM_numpart_to_char(NUMProc *Np, int id);
934 static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
935                           int plen, int sign, bool is_to_char);
936 static DCHCacheEntry *DCH_cache_search(char *str);
937 static DCHCacheEntry *DCH_cache_getnew(char *str);
938
939 static NUMCacheEntry *NUM_cache_search(char *str);
940 static NUMCacheEntry *NUM_cache_getnew(char *str);
941 static void NUM_cache_remove(NUMCacheEntry *ent);
942
943 static char *localize_month_full(int index);
944 static char *localize_month(int index);
945 static char *localize_day_full(int index);
946 static char *localize_day(int index);
947
948 /* ----------
949  * Fast sequential search, use index for data selection which
950  * go to seq. cycle (it is very fast for unwanted strings)
951  * (can't be used binary search in format parsing)
952  * ----------
953  */
954 static const KeyWord *
955 index_seq_search(char *str, const KeyWord *kw, const int *index)
956 {
957         int                     poz;
958
959         if (!KeyWord_INDEX_FILTER(*str))
960                 return NULL;
961
962         if ((poz = *(index + (*str - ' '))) > -1)
963         {
964                 const KeyWord *k = kw + poz;
965
966                 do
967                 {
968                         if (!strncmp(str, k->name, k->len))
969                                 return k;
970                         k++;
971                         if (!k->name)
972                                 return NULL;
973                 } while (*str == *k->name);
974         }
975         return NULL;
976 }
977
978 static KeySuffix *
979 suff_search(char *str, KeySuffix *suf, int type)
980 {
981         KeySuffix  *s;
982
983         for (s = suf; s->name != NULL; s++)
984         {
985                 if (s->type != type)
986                         continue;
987
988                 if (!strncmp(str, s->name, s->len))
989                         return s;
990         }
991         return NULL;
992 }
993
994 /* ----------
995  * Prepare NUMDesc (number description struct) via FormatNode struct
996  * ----------
997  */
998 static void
999 NUMDesc_prepare(NUMDesc *num, FormatNode *n)
1000 {
1001
1002         if (n->type != NODE_TYPE_ACTION)
1003                 return;
1004
1005         switch (n->key->id)
1006         {
1007                 case NUM_9:
1008                         if (IS_BRACKET(num))
1009                         {
1010                                 NUM_cache_remove(last_NUMCacheEntry);
1011                                 ereport(ERROR,
1012                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1013                                                  errmsg("\"9\" must be ahead of \"PR\"")));
1014                         }
1015                         if (IS_MULTI(num))
1016                         {
1017                                 ++num->multi;
1018                                 break;
1019                         }
1020                         if (IS_DECIMAL(num))
1021                                 ++num->post;
1022                         else
1023                                 ++num->pre;
1024                         break;
1025
1026                 case NUM_0:
1027                         if (IS_BRACKET(num))
1028                         {
1029                                 NUM_cache_remove(last_NUMCacheEntry);
1030                                 ereport(ERROR,
1031                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1032                                                  errmsg("\"0\" must be ahead of \"PR\"")));
1033                         }
1034                         if (!IS_ZERO(num) && !IS_DECIMAL(num))
1035                         {
1036                                 num->flag |= NUM_F_ZERO;
1037                                 num->zero_start = num->pre + 1;
1038                         }
1039                         if (!IS_DECIMAL(num))
1040                                 ++num->pre;
1041                         else
1042                                 ++num->post;
1043
1044                         num->zero_end = num->pre + num->post;
1045                         break;
1046
1047                 case NUM_B:
1048                         if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num)))
1049                                 num->flag |= NUM_F_BLANK;
1050                         break;
1051
1052                 case NUM_D:
1053                         num->flag |= NUM_F_LDECIMAL;
1054                         num->need_locale = TRUE;
1055                 case NUM_DEC:
1056                         if (IS_DECIMAL(num))
1057                         {
1058                                 NUM_cache_remove(last_NUMCacheEntry);
1059                                 ereport(ERROR,
1060                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1061                                                  errmsg("multiple decimal points")));
1062                         }
1063                         if (IS_MULTI(num))
1064                         {
1065                                 NUM_cache_remove(last_NUMCacheEntry);
1066                                 ereport(ERROR,
1067                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1068                                          errmsg("cannot use \"V\" and decimal point together")));
1069                         }
1070                         num->flag |= NUM_F_DECIMAL;
1071                         break;
1072
1073                 case NUM_FM:
1074                         num->flag |= NUM_F_FILLMODE;
1075                         break;
1076
1077                 case NUM_S:
1078                         if (IS_LSIGN(num))
1079                         {
1080                                 NUM_cache_remove(last_NUMCacheEntry);
1081                                 ereport(ERROR,
1082                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1083                                                  errmsg("not unique \"S\"")));
1084                         }
1085                         if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
1086                         {
1087                                 NUM_cache_remove(last_NUMCacheEntry);
1088                                 ereport(ERROR,
1089                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1090                                                  errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
1091                         }
1092                         if (!IS_DECIMAL(num))
1093                         {
1094                                 num->lsign = NUM_LSIGN_PRE;
1095                                 num->pre_lsign_num = num->pre;
1096                                 num->need_locale = TRUE;
1097                                 num->flag |= NUM_F_LSIGN;
1098
1099                         }
1100                         else if (num->lsign == NUM_LSIGN_NONE)
1101                         {
1102                                 num->lsign = NUM_LSIGN_POST;
1103                                 num->need_locale = TRUE;
1104                                 num->flag |= NUM_F_LSIGN;
1105                         }
1106                         break;
1107
1108                 case NUM_MI:
1109                         if (IS_LSIGN(num))
1110                         {
1111                                 NUM_cache_remove(last_NUMCacheEntry);
1112                                 ereport(ERROR,
1113                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1114                                                  errmsg("cannot use \"S\" and \"MI\" together")));
1115                         }
1116                         num->flag |= NUM_F_MINUS;
1117                         if (IS_DECIMAL(num))
1118                                 num->flag |= NUM_F_MINUS_POST;
1119                         break;
1120
1121                 case NUM_PL:
1122                         if (IS_LSIGN(num))
1123                         {
1124                                 NUM_cache_remove(last_NUMCacheEntry);
1125                                 ereport(ERROR,
1126                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1127                                                  errmsg("cannot use \"S\" and \"PL\" together")));
1128                         }
1129                         num->flag |= NUM_F_PLUS;
1130                         if (IS_DECIMAL(num))
1131                                 num->flag |= NUM_F_PLUS_POST;
1132                         break;
1133
1134                 case NUM_SG:
1135                         if (IS_LSIGN(num))
1136                         {
1137                                 NUM_cache_remove(last_NUMCacheEntry);
1138                                 ereport(ERROR,
1139                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1140                                                  errmsg("cannot use \"S\" and \"SG\" together")));
1141                         }
1142                         num->flag |= NUM_F_MINUS;
1143                         num->flag |= NUM_F_PLUS;
1144                         break;
1145
1146                 case NUM_PR:
1147                         if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
1148                         {
1149                                 NUM_cache_remove(last_NUMCacheEntry);
1150                                 ereport(ERROR,
1151                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1152                                                  errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
1153                         }
1154                         num->flag |= NUM_F_BRACKET;
1155                         break;
1156
1157                 case NUM_rn:
1158                 case NUM_RN:
1159                         num->flag |= NUM_F_ROMAN;
1160                         break;
1161
1162                 case NUM_L:
1163                 case NUM_G:
1164                         num->need_locale = TRUE;
1165                         break;
1166
1167                 case NUM_V:
1168                         if (IS_DECIMAL(num))
1169                         {
1170                                 NUM_cache_remove(last_NUMCacheEntry);
1171                                 ereport(ERROR,
1172                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1173                                          errmsg("cannot use \"V\" and decimal point together")));
1174                         }
1175                         num->flag |= NUM_F_MULTI;
1176                         break;
1177
1178                 case NUM_E:
1179                         NUM_cache_remove(last_NUMCacheEntry);
1180                         ereport(ERROR,
1181                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1182                                          errmsg("\"E\" is not supported")));
1183         }
1184
1185         return;
1186 }
1187
1188 /* ----------
1189  * Format parser, search small keywords and keyword's suffixes, and make
1190  * format-node tree.
1191  *
1192  * for DATE-TIME & NUMBER version
1193  * ----------
1194  */
1195 static void
1196 parse_format(FormatNode *node, char *str, const KeyWord *kw,
1197                          KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
1198 {
1199         KeySuffix  *s;
1200         FormatNode *n;
1201         int                     node_set = 0,
1202                                 suffix,
1203                                 last = 0;
1204
1205 #ifdef DEBUG_TO_FROM_CHAR
1206         elog(DEBUG_elog_output, "to_char/number(): run parser");
1207 #endif
1208
1209         n = node;
1210
1211         while (*str)
1212         {
1213                 suffix = 0;
1214
1215                 /*
1216                  * Prefix
1217                  */
1218                 if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
1219                 {
1220                         suffix |= s->id;
1221                         if (s->len)
1222                                 str += s->len;
1223                 }
1224
1225                 /*
1226                  * Keyword
1227                  */
1228                 if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
1229                 {
1230
1231                         n->type = NODE_TYPE_ACTION;
1232                         n->suffix = 0;
1233                         node_set = 1;
1234                         if (n->key->len)
1235                                 str += n->key->len;
1236
1237                         /*
1238                          * NUM version: Prepare global NUMDesc struct
1239                          */
1240                         if (ver == NUM_TYPE)
1241                                 NUMDesc_prepare(Num, n);
1242
1243                         /*
1244                          * Postfix
1245                          */
1246                         if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
1247                         {
1248                                 suffix |= s->id;
1249                                 if (s->len)
1250                                         str += s->len;
1251                         }
1252
1253                 }
1254                 else if (*str)
1255                 {
1256                         /*
1257                          * Special characters '\' and '"'
1258                          */
1259                         if (*str == '"' && last != '\\')
1260                         {
1261
1262                                 int                     x = 0;
1263
1264                                 while (*(++str))
1265                                 {
1266                                         if (*str == '"' && x != '\\')
1267                                         {
1268                                                 str++;
1269                                                 break;
1270                                         }
1271                                         else if (*str == '\\' && x != '\\')
1272                                         {
1273                                                 x = '\\';
1274                                                 continue;
1275                                         }
1276                                         n->type = NODE_TYPE_CHAR;
1277                                         n->character = *str;
1278                                         n->key = NULL;
1279                                         n->suffix = 0;
1280                                         ++n;
1281                                         x = *str;
1282                                 }
1283                                 node_set = 0;
1284                                 suffix = 0;
1285                                 last = 0;
1286
1287                         }
1288                         else if (*str && *str == '\\' && last != '\\' && *(str + 1) == '"')
1289                         {
1290                                 last = *str;
1291                                 str++;
1292
1293                         }
1294                         else if (*str)
1295                         {
1296                                 n->type = NODE_TYPE_CHAR;
1297                                 n->character = *str;
1298                                 n->key = NULL;
1299                                 node_set = 1;
1300                                 last = 0;
1301                                 str++;
1302                         }
1303
1304                 }
1305
1306                 /* end */
1307                 if (node_set)
1308                 {
1309                         if (n->type == NODE_TYPE_ACTION)
1310                                 n->suffix = suffix;
1311                         ++n;
1312
1313                         n->suffix = 0;
1314                         node_set = 0;
1315                 }
1316
1317         }
1318
1319         n->type = NODE_TYPE_END;
1320         n->suffix = 0;
1321         return;
1322 }
1323
1324 /* ----------
1325  * Call keyword's function for each of (action) node in format-node tree
1326  * ----------
1327  */
1328 static char *
1329 DCH_processor(FormatNode *node, char *inout, bool is_to_char,
1330                           bool is_interval, void *data)
1331 {
1332         FormatNode *n;
1333         char       *s;
1334
1335         /*
1336          * Zeroing global flags
1337          */
1338         DCH_global_fx = false;
1339
1340         for (n = node, s = inout; n->type != NODE_TYPE_END; n++)
1341         {
1342                 if (!is_to_char && *s == '\0')
1343
1344                         /*
1345                          * The input string is shorter than format picture, so it's good
1346                          * time to break this loop...
1347                          *
1348                          * Note: this isn't relevant for TO_CHAR mode, because it uses
1349                          * 'inout' allocated by format picture length.
1350                          */
1351                         break;
1352
1353                 if (n->type == NODE_TYPE_ACTION)
1354                 {
1355                         int                     len;
1356
1357                         /*
1358                          * Call node action function
1359                          */
1360                         len = n->key->action(n->key->id, s, n->suffix, is_to_char,
1361                                                                  is_interval, n, data);
1362                         if (len > 0)
1363                                 s += len - 1;   /* s++ is at the end of the loop */
1364                         else if (len == -1)
1365                                 continue;
1366                 }
1367                 else
1368                 {
1369                         /*
1370                          * Remove to output char from input in TO_CHAR
1371                          */
1372                         if (is_to_char)
1373                                 *s = n->character;
1374                         else
1375                         {
1376                                 /*
1377                                  * Skip blank space in FROM_CHAR's input
1378                                  */
1379                                 if (isspace((unsigned char) n->character) && !DCH_global_fx)
1380                                         while (*s != '\0' && isspace((unsigned char) *(s + 1)))
1381                                                 ++s;
1382                         }
1383                 }
1384                 ++s;
1385         }
1386
1387         if (is_to_char)
1388                 *s = '\0';
1389         return inout;
1390 }
1391
1392
1393 /* ----------
1394  * DEBUG: Dump the FormatNode Tree (debug)
1395  * ----------
1396  */
1397 #ifdef DEBUG_TO_FROM_CHAR
1398
1399 #define DUMP_THth(_suf) (S_TH(_suf) ? "TH" : (S_th(_suf) ? "th" : " "))
1400 #define DUMP_FM(_suf)   (S_FM(_suf) ? "FM" : " ")
1401
1402 static void
1403 dump_node(FormatNode *node, int max)
1404 {
1405         FormatNode *n;
1406         int                     a;
1407
1408         elog(DEBUG_elog_output, "to_from-char(): DUMP FORMAT");
1409
1410         for (a = 0, n = node; a <= max; n++, a++)
1411         {
1412                 if (n->type == NODE_TYPE_ACTION)
1413                         elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)",
1414                                  a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix));
1415                 else if (n->type == NODE_TYPE_CHAR)
1416                         elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character);
1417                 else if (n->type == NODE_TYPE_END)
1418                 {
1419                         elog(DEBUG_elog_output, "%d:\t NODE_TYPE_END", a);
1420                         return;
1421                 }
1422                 else
1423                         elog(DEBUG_elog_output, "%d:\t unknown NODE!", a);
1424
1425         }
1426 }
1427 #endif   /* DEBUG */
1428
1429 /*****************************************************************************
1430  *                      Private utils
1431  *****************************************************************************/
1432
1433 /* ----------
1434  * Return ST/ND/RD/TH for simple (1..9) numbers
1435  * type --> 0 upper, 1 lower
1436  * ----------
1437  */
1438 static char *
1439 get_th(char *num, int type)
1440 {
1441         int                     len = strlen(num),
1442                                 last,
1443                                 seclast;
1444
1445         last = *(num + (len - 1));
1446         if (!isdigit((unsigned char) last))
1447                 ereport(ERROR,
1448                                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1449                                  errmsg("\"%s\" is not a number", num)));
1450
1451         /*
1452          * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1453          * 'ST/st', 'ND/nd', 'RD/rd', respectively
1454          */
1455         if ((len > 1) && ((seclast = num[len - 2]) == '1'))
1456                 last = 0;
1457
1458         switch (last)
1459         {
1460                 case '1':
1461                         if (type == TH_UPPER)
1462                                 return numTH[0];
1463                         return numth[0];
1464                 case '2':
1465                         if (type == TH_UPPER)
1466                                 return numTH[1];
1467                         return numth[1];
1468                 case '3':
1469                         if (type == TH_UPPER)
1470                                 return numTH[2];
1471                         return numth[2];
1472                 default:
1473                         if (type == TH_UPPER)
1474                                 return numTH[3];
1475                         return numth[3];
1476         }
1477         return NULL;
1478 }
1479
1480 /* ----------
1481  * Convert string-number to ordinal string-number
1482  * type --> 0 upper, 1 lower
1483  * ----------
1484  */
1485 static char *
1486 str_numth(char *dest, char *num, int type)
1487 {
1488         if (dest != num)
1489                 strcpy(dest, num);
1490         strcat(dest, get_th(num, type));
1491         return dest;
1492 }
1493
1494 /* ----------
1495  * Convert string to upper-string. Input string is modified in place.
1496  * ----------
1497  */
1498 static char *
1499 str_toupper(char *buff)
1500 {
1501         char       *p_buff = buff;
1502
1503         if (!buff)
1504                 return NULL;
1505
1506         while (*p_buff)
1507         {
1508                 *p_buff = pg_toupper((unsigned char) *p_buff);
1509                 ++p_buff;
1510         }
1511         return buff;
1512 }
1513
1514 /* ----------
1515  * Convert string to lower-string. Input string is modified in place.
1516  * ----------
1517  */
1518 static char *
1519 str_tolower(char *buff)
1520 {
1521         char       *p_buff = buff;
1522
1523         if (!buff)
1524                 return NULL;
1525
1526         while (*p_buff)
1527         {
1528                 *p_buff = pg_tolower((unsigned char) *p_buff);
1529                 ++p_buff;
1530         }
1531         return buff;
1532 }
1533
1534 /* ----------
1535  * Sequential search with to upper/lower conversion
1536  * ----------
1537  */
1538 static int
1539 seq_search(char *name, char **array, int type, int max, int *len)
1540 {
1541         char       *p,
1542                            *n,
1543                           **a;
1544         int                     last,
1545                                 i;
1546
1547         *len = 0;
1548
1549         if (!*name)
1550                 return -1;
1551
1552         /* set first char */
1553         if (type == ONE_UPPER || type == ALL_UPPER)
1554                 *name = pg_toupper((unsigned char) *name);
1555         else if (type == ALL_LOWER)
1556                 *name = pg_tolower((unsigned char) *name);
1557
1558         for (last = 0, a = array; *a != NULL; a++)
1559         {
1560
1561                 /* comperate first chars */
1562                 if (*name != **a)
1563                         continue;
1564
1565                 for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++)
1566                 {
1567
1568                         /* search fragment (max) only */
1569                         if (max && i == max)
1570                         {
1571                                 *len = i;
1572                                 return a - array;
1573                         }
1574                         /* full size */
1575                         if (*p == '\0')
1576                         {
1577                                 *len = i;
1578                                 return a - array;
1579                         }
1580                         /* Not found in array 'a' */
1581                         if (*n == '\0')
1582                                 break;
1583
1584                         /*
1585                          * Convert (but convert new chars only)
1586                          */
1587                         if (i > last)
1588                         {
1589                                 if (type == ONE_UPPER || type == ALL_LOWER)
1590                                         *n = pg_tolower((unsigned char) *n);
1591                                 else if (type == ALL_UPPER)
1592                                         *n = pg_toupper((unsigned char) *n);
1593                                 last = i;
1594                         }
1595
1596 #ifdef DEBUG_TO_FROM_CHAR
1597
1598                         /*
1599                          * elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)", *n, *p, *a,
1600                          * name);
1601                          */
1602 #endif
1603                         if (*n != *p)
1604                                 break;
1605                 }
1606         }
1607
1608         return -1;
1609 }
1610
1611
1612 #ifdef DEBUG_TO_FROM_CHAR
1613 /* -----------
1614  * DEBUG: Call for debug and for index checking; (Show ASCII char
1615  * and defined keyword for each used position
1616  * ----------
1617  */
1618 static void
1619 dump_index(const KeyWord *k, const int *index)
1620 {
1621         int                     i,
1622                                 count = 0,
1623                                 free_i = 0;
1624
1625         elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:");
1626
1627         for (i = 0; i < KeyWord_INDEX_SIZE; i++)
1628         {
1629                 if (index[i] != -1)
1630                 {
1631                         elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name);
1632                         count++;
1633                 }
1634                 else
1635                 {
1636                         free_i++;
1637                         elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]);
1638                 }
1639         }
1640         elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d",
1641                  count, free_i);
1642 }
1643 #endif   /* DEBUG */
1644
1645 /* ----------
1646  * Skip TM / th in FROM_CHAR
1647  * ----------
1648  */
1649 #define SKIP_THth(_suf)         (S_THth(_suf) ? 2 : 0)
1650
1651
1652 /* ----------
1653  * Global format option for DCH version
1654  * ----------
1655  */
1656 static int
1657 dch_global(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
1658                    FormatNode *node, void *data)
1659 {
1660         if (arg == DCH_FX)
1661                 DCH_global_fx = true;
1662         return -1;
1663 }
1664
1665 /* ----------
1666  * Return TRUE if next format picture is not digit value
1667  * ----------
1668  */
1669 static bool
1670 is_next_separator(FormatNode *n)
1671 {
1672         if (n->type == NODE_TYPE_END)
1673                 return FALSE;
1674
1675         if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
1676                 return TRUE;
1677
1678         /*
1679          * Next node
1680          */
1681         n++;
1682
1683         if (n->type == NODE_TYPE_END)
1684                 return FALSE;
1685
1686         if (n->type == NODE_TYPE_ACTION)
1687         {
1688                 if (n->key->isitdigit)
1689                         return FALSE;
1690
1691                 return TRUE;
1692         }
1693         else if (isdigit((unsigned char) n->character))
1694                 return FALSE;
1695
1696         return TRUE;                            /* some non-digit input (separator) */
1697 }
1698
1699 static int
1700 strdigits_len(char *str)
1701 {
1702         char       *p = str;
1703         int                     len = 0;
1704
1705         while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ)
1706         {
1707                 len++;
1708                 p++;
1709         }
1710         return len;
1711 }
1712
1713 #define AMPM_ERROR      ereport(ERROR, \
1714                                                         (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
1715                                                          errmsg("invalid AM/PM string")));
1716
1717 /* ----------
1718  * Master function of TIME for:
1719  *                        TO_CHAR       - write (inout) formated string
1720  *                        FROM_CHAR - scan (inout) string by course of FormatNode
1721  * ----------
1722  */
1723 static int
1724 dch_time(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
1725                  FormatNode *node, void *data)
1726 {
1727         char       *p_inout = inout;
1728         struct pg_tm *tm = NULL;
1729         TmFromChar *tmfc = NULL;
1730         TmToChar   *tmtc = NULL;
1731
1732         if (is_to_char)
1733         {
1734                 tmtc = (TmToChar *) data;
1735                 tm = tmtcTm(tmtc);
1736         }
1737         else
1738                 tmfc = (TmFromChar *) data;
1739
1740         switch (arg)
1741         {
1742                 case DCH_A_M:
1743                 case DCH_P_M:
1744                         if (is_to_char)
1745                         {
1746                                 strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
1747                                            ? P_M_STR : A_M_STR);
1748                                 return strlen(p_inout);
1749                         }
1750                         else
1751                         {
1752                                 if (strncmp(inout, P_M_STR, 4) == 0)
1753                                         tmfc->pm = TRUE;
1754                                 else if (strncmp(inout, A_M_STR, 4) == 0)
1755                                         tmfc->am = TRUE;
1756                                 else
1757                                         AMPM_ERROR;
1758                                 return strlen(p_inout);
1759                         }
1760                         break;
1761                 case DCH_AM:
1762                 case DCH_PM:
1763                         if (is_to_char)
1764                         {
1765                                 strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
1766                                            ? PM_STR : AM_STR);
1767                                 return strlen(p_inout);
1768                         }
1769                         else
1770                         {
1771                                 if (strncmp(inout, PM_STR, 2) == 0)
1772                                         tmfc->pm = TRUE;
1773                                 else if (strncmp(inout, AM_STR, 2) == 0)
1774                                         tmfc->am = TRUE;
1775                                 else
1776                                         AMPM_ERROR;
1777                                 return strlen(p_inout);
1778                         }
1779                         break;
1780                 case DCH_a_m:
1781                 case DCH_p_m:
1782                         if (is_to_char)
1783                         {
1784                                 strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
1785                                            ? p_m_STR : a_m_STR);
1786                                 return strlen(p_inout);
1787                         }
1788                         else
1789                         {
1790                                 if (strncmp(inout, p_m_STR, 4) == 0)
1791                                         tmfc->pm = TRUE;
1792                                 else if (strncmp(inout, a_m_STR, 4) == 0)
1793                                         tmfc->am = TRUE;
1794                                 else
1795                                         AMPM_ERROR;
1796                                 return strlen(p_inout);
1797                         }
1798                         break;
1799                 case DCH_am:
1800                 case DCH_pm:
1801                         if (is_to_char)
1802                         {
1803                                 strcpy(inout, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
1804                                            ? pm_STR : am_STR);
1805                                 return strlen(p_inout);
1806                         }
1807                         else
1808                         {
1809                                 if (strncmp(inout, pm_STR, 2) == 0)
1810                                         tmfc->pm = TRUE;
1811                                 else if (strncmp(inout, am_STR, 2) == 0)
1812                                         tmfc->am = TRUE;
1813                                 else
1814                                         AMPM_ERROR;
1815                                 return strlen(p_inout);
1816                         }
1817                         break;
1818                 case DCH_HH:
1819                 case DCH_HH12:
1820                         if (is_to_char)
1821                         {
1822                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2,
1823                                                 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? 12 :
1824                                             tm->tm_hour % (HOURS_PER_DAY / 2));
1825                                 if (S_THth(suf))
1826                                         str_numth(p_inout, inout, 0);
1827                                 return strlen(p_inout);
1828                         }
1829                         else
1830                         {
1831                                 if (S_FM(suf) || is_next_separator(node))
1832                                 {
1833                                         sscanf(inout, "%d", &tmfc->hh);
1834                                         return strdigits_len(inout) + SKIP_THth(suf);
1835                                 }
1836                                 else
1837                                 {
1838                                         sscanf(inout, "%02d", &tmfc->hh);
1839                                         return 2 + SKIP_THth(suf);
1840                                 }
1841                         }
1842                         break;
1843                 case DCH_HH24:
1844                         if (is_to_char)
1845                         {
1846                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_hour);
1847                                 if (S_THth(suf))
1848                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
1849                                 return strlen(p_inout);
1850                         }
1851                         else
1852                         {
1853                                 if (S_FM(suf) || is_next_separator(node))
1854                                 {
1855                                         sscanf(inout, "%d", &tmfc->hh);
1856                                         return strdigits_len(inout) + SKIP_THth(suf);
1857                                 }
1858                                 else
1859                                 {
1860                                         sscanf(inout, "%02d", &tmfc->hh);
1861                                         return 2 + SKIP_THth(suf);
1862                                 }
1863                         }
1864                         break;
1865                 case DCH_MI:
1866                         if (is_to_char)
1867                         {
1868                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_min);
1869                                 if (S_THth(suf))
1870                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
1871                                 return strlen(p_inout);
1872                         }
1873                         else
1874                         {
1875                                 if (S_FM(suf) || is_next_separator(node))
1876                                 {
1877                                         sscanf(inout, "%d", &tmfc->mi);
1878                                         return strdigits_len(inout) + SKIP_THth(suf);
1879                                 }
1880                                 else
1881                                 {
1882                                         sscanf(inout, "%02d", &tmfc->mi);
1883                                         return 2 + SKIP_THth(suf);
1884                                 }
1885                         }
1886                         break;
1887                 case DCH_SS:
1888                         if (is_to_char)
1889                         {
1890                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_sec);
1891                                 if (S_THth(suf))
1892                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
1893                                 return strlen(p_inout);
1894                         }
1895                         else
1896                         {
1897                                 if (S_FM(suf) || is_next_separator(node))
1898                                 {
1899                                         sscanf(inout, "%d", &tmfc->ss);
1900                                         return strdigits_len(inout) + SKIP_THth(suf);
1901                                 }
1902                                 else
1903                                 {
1904                                         sscanf(inout, "%02d", &tmfc->ss);
1905                                         return 2 + SKIP_THth(suf);
1906                                 }
1907                         }
1908                         break;
1909                 case DCH_MS:                    /* millisecond */
1910                         if (is_to_char)
1911                         {
1912 #ifdef HAVE_INT64_TIMESTAMP
1913                                 sprintf(inout, "%03d", (int) (tmtc->fsec / INT64CONST(1000)));
1914 #else
1915                                 sprintf(inout, "%03d", (int) rint(tmtc->fsec * 1000));
1916 #endif
1917                                 if (S_THth(suf))
1918                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
1919                                 return strlen(p_inout);
1920                         }
1921                         else
1922                         {
1923                                 int                     len,
1924                                                         x;
1925
1926                                 if (is_next_separator(node))
1927                                 {
1928                                         sscanf(inout, "%d", &tmfc->ms);
1929                                         len = x = strdigits_len(inout);
1930                                 }
1931                                 else
1932                                 {
1933                                         sscanf(inout, "%03d", &tmfc->ms);
1934                                         x = strdigits_len(inout);
1935                                         len = x = x > 3 ? 3 : x;
1936                                 }
1937
1938                                 /*
1939                                  * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
1940                                  */
1941                                 tmfc->ms *= x == 1 ? 100 :
1942                                         x == 2 ? 10 : 1;
1943
1944                                 /*
1945                                  * elog(DEBUG3, "X: %d, MS: %d, LEN: %d", x, tmfc->ms, len);
1946                                  */
1947                                 return len + SKIP_THth(suf);
1948                         }
1949                         break;
1950                 case DCH_US:                    /* microsecond */
1951                         if (is_to_char)
1952                         {
1953 #ifdef HAVE_INT64_TIMESTAMP
1954                                 sprintf(inout, "%06d", (int) tmtc->fsec);
1955 #else
1956                                 sprintf(inout, "%06d", (int) rint(tmtc->fsec * 1000000));
1957 #endif
1958                                 if (S_THth(suf))
1959                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
1960                                 return strlen(p_inout);
1961                         }
1962                         else
1963                         {
1964                                 int                     len,
1965                                                         x;
1966
1967                                 if (is_next_separator(node))
1968                                 {
1969                                         sscanf(inout, "%d", &tmfc->us);
1970                                         len = x = strdigits_len(inout);
1971                                 }
1972                                 else
1973                                 {
1974                                         sscanf(inout, "%06d", &tmfc->us);
1975                                         x = strdigits_len(inout);
1976                                         len = x = x > 6 ? 6 : x;
1977                                 }
1978
1979                                 tmfc->us *= x == 1 ? 100000 :
1980                                         x == 2 ? 10000 :
1981                                         x == 3 ? 1000 :
1982                                         x == 4 ? 100 :
1983                                         x == 5 ? 10 : 1;
1984
1985                                 /*
1986                                  * elog(DEBUG3, "X: %d, US: %d, LEN: %d", x, tmfc->us, len);
1987                                  */
1988                                 return len + SKIP_THth(suf);
1989                         }
1990                         break;
1991                 case DCH_SSSS:
1992                         if (is_to_char)
1993                         {
1994                                 sprintf(inout, "%d", tm->tm_hour * SECS_PER_HOUR +
1995                                                 tm->tm_min * SECS_PER_MINUTE +
1996                                                 tm->tm_sec);
1997                                 if (S_THth(suf))
1998                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
1999                                 return strlen(p_inout);
2000                         }
2001                         else
2002                         {
2003                                 if (S_FM(suf) || is_next_separator(node))
2004                                 {
2005                                         sscanf(inout, "%d", &tmfc->ssss);
2006                                         return strdigits_len(inout) + SKIP_THth(suf);
2007                                 }
2008                                 else
2009                                 {
2010                                         sscanf(inout, "%05d", &tmfc->ssss);
2011                                         return 5 + SKIP_THth(suf);
2012                                 }
2013                         }
2014                         break;
2015                 case DCH_tz:
2016                 case DCH_TZ:
2017                         INVALID_FOR_INTERVAL;
2018                         if (is_to_char && tmtcTzn(tmtc))
2019                         {
2020                                 int                     siz = strlen(tmtcTzn(tmtc));
2021
2022                                 if (arg == DCH_TZ)
2023                                         strcpy(inout, tmtcTzn(tmtc));
2024                                 else
2025                                 {
2026                                         char       *p = palloc(siz);
2027
2028                                         strcpy(p, tmtcTzn(tmtc));
2029                                         strcpy(inout, str_tolower(p));
2030                                         pfree(p);
2031                                 }
2032                                 return siz;
2033                         }
2034                         else if (!is_to_char)
2035                                 ereport(ERROR,
2036                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2037                                                  errmsg("\"TZ\"/\"tz\" not supported")));
2038         }
2039         return -1;
2040 }
2041
2042 #define CHECK_SEQ_SEARCH(_l, _s) \
2043 do { \
2044         if ((_l) <= 0) {                                                        \
2045                 ereport(ERROR,  \
2046                                 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),      \
2047                                  errmsg("invalid value for %s", (_s))));        \
2048         }                                                               \
2049 } while (0)
2050
2051
2052 /* ----------
2053  * Master of DATE for:
2054  *                TO_CHAR - write (inout) formated string
2055  *                FROM_CHAR - scan (inout) string by course of FormatNode
2056  * ----------
2057  */
2058 static int
2059 dch_date(int arg, char *inout, int suf, bool is_to_char, bool is_interval,
2060                  FormatNode *node, void *data)
2061 {
2062         char            buff[DCH_CACHE_SIZE],
2063                                 workbuff[32],
2064                            *p_inout = inout;
2065         int                     i,
2066                                 len;
2067         struct pg_tm *tm = NULL;
2068         TmFromChar *tmfc = NULL;
2069         TmToChar   *tmtc = NULL;
2070
2071         if (is_to_char)
2072         {
2073                 tmtc = (TmToChar *) data;
2074                 tm = tmtcTm(tmtc);
2075         }
2076         else
2077                 tmfc = (TmFromChar *) data;
2078
2079         /*
2080          * In the FROM-char there is no difference between "January" or "JANUARY" or
2081          * "january", all is before search convert to "first-upper". This
2082          * convention is used for MONTH, MON, DAY, DY
2083          */
2084         if (!is_to_char)
2085         {
2086                 if (arg == DCH_MONTH || arg == DCH_Month || arg == DCH_month)
2087                 {
2088                         tmfc->mm = seq_search(inout, months_full, ONE_UPPER, FULL_SIZ, &len) + 1;
2089                         CHECK_SEQ_SEARCH(len, "MONTH/Month/month");
2090                         if (S_FM(suf))
2091                                 return len;
2092                         else
2093                                 return 9;
2094                 }
2095                 else if (arg == DCH_MON || arg == DCH_Mon || arg == DCH_mon)
2096                 {
2097                         tmfc->mm = seq_search(inout, months, ONE_UPPER, MAX_MON_LEN, &len) + 1;
2098                         CHECK_SEQ_SEARCH(len, "MON/Mon/mon");
2099                         return 3;
2100                 }
2101                 else if (arg == DCH_DAY || arg == DCH_Day || arg == DCH_day)
2102                 {
2103                         tmfc->d = seq_search(inout, days, ONE_UPPER, FULL_SIZ, &len);
2104                         CHECK_SEQ_SEARCH(len, "DAY/Day/day");
2105                         if (S_FM(suf))
2106                                 return len;
2107                         else
2108                                 return 9;
2109                 }
2110                 else if (arg == DCH_DY || arg == DCH_Dy || arg == DCH_dy)
2111                 {
2112                         tmfc->d = seq_search(inout, days, ONE_UPPER, MAX_DY_LEN, &len);
2113                         CHECK_SEQ_SEARCH(len, "DY/Dy/dy");
2114                         return 3;
2115                 }
2116         }
2117
2118         switch (arg)
2119         {
2120                 case DCH_A_D:
2121                 case DCH_B_C:
2122                         INVALID_FOR_INTERVAL;
2123                         if (is_to_char)
2124                         {
2125                                 strcpy(inout, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2126                                 return strlen(p_inout);
2127                         }
2128                         else
2129                         {
2130                                 if (strncmp(inout, B_C_STR, 4) == 0)
2131                                         tmfc->bc = TRUE;
2132                                 return 4;
2133                         }
2134                         break;
2135                 case DCH_AD:
2136                 case DCH_BC:
2137                         INVALID_FOR_INTERVAL;
2138                         if (is_to_char)
2139                         {
2140                                 strcpy(inout, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2141                                 return strlen(p_inout);
2142                         }
2143                         else
2144                         {
2145                                 if (strncmp(inout, BC_STR, 2) == 0)
2146                                         tmfc->bc = TRUE;
2147                                 return 2;
2148                         }
2149                         break;
2150                 case DCH_a_d:
2151                 case DCH_b_c:
2152                         INVALID_FOR_INTERVAL;
2153                         if (is_to_char)
2154                         {
2155                                 strcpy(inout, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2156                                 return strlen(p_inout);
2157                         }
2158                         else
2159                         {
2160                                 if (strncmp(inout, b_c_STR, 4) == 0)
2161                                         tmfc->bc = TRUE;
2162                                 return 4;
2163                         }
2164                         break;
2165                 case DCH_ad:
2166                 case DCH_bc:
2167                         INVALID_FOR_INTERVAL;
2168                         if (is_to_char)
2169                         {
2170                                 strcpy(inout, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2171                                 return strlen(p_inout);
2172                         }
2173                         else
2174                         {
2175                                 if (strncmp(inout, bc_STR, 2) == 0)
2176                                         tmfc->bc = TRUE;
2177                                 return 2;
2178                         }
2179                         break;
2180                 case DCH_MONTH:
2181                         INVALID_FOR_INTERVAL;
2182                         if (!tm->tm_mon)
2183                                 return -1;
2184                         if (S_TM(suf))
2185                                 strcpy(workbuff, localize_month_full(tm->tm_mon - 1));
2186                         else
2187                                 strcpy(workbuff, months_full[tm->tm_mon - 1]);
2188                         sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
2189                         return strlen(p_inout);
2190
2191                 case DCH_Month:
2192                         INVALID_FOR_INTERVAL;
2193                         if (!tm->tm_mon)
2194                                 return -1;
2195                         if (S_TM(suf))
2196                                 sprintf(inout, "%*s", 0, localize_month_full(tm->tm_mon - 1));
2197                         else
2198                                 sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
2199                         return strlen(p_inout);
2200
2201                 case DCH_month:
2202                         INVALID_FOR_INTERVAL;
2203                         if (!tm->tm_mon)
2204                                 return -1;
2205                         if (S_TM(suf))
2206                                 sprintf(inout, "%*s", 0, localize_month_full(tm->tm_mon - 1));
2207                         else
2208                                 sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, months_full[tm->tm_mon - 1]);
2209                         *inout = pg_tolower((unsigned char) *inout);
2210                         return strlen(p_inout);
2211
2212                 case DCH_MON:
2213                         INVALID_FOR_INTERVAL;
2214                         if (!tm->tm_mon)
2215                                 return -1;
2216                         if (S_TM(suf))
2217                                 strcpy(inout, localize_month(tm->tm_mon - 1));
2218                         else
2219                                 strcpy(inout, months[tm->tm_mon - 1]);
2220                         str_toupper(inout);
2221                         return strlen(p_inout);
2222
2223                 case DCH_Mon:
2224                         INVALID_FOR_INTERVAL;
2225                         if (!tm->tm_mon)
2226                                 return -1;
2227                         if (S_TM(suf))
2228                                 strcpy(inout, localize_month(tm->tm_mon - 1));
2229                         else
2230                                 strcpy(inout, months[tm->tm_mon - 1]);
2231                         return strlen(p_inout);
2232
2233                 case DCH_mon:
2234                         INVALID_FOR_INTERVAL;
2235                         if (!tm->tm_mon)
2236                                 return -1;
2237                         if (S_TM(suf))
2238                                 strcpy(inout, localize_month(tm->tm_mon - 1));
2239                         else
2240                                 strcpy(inout, months[tm->tm_mon - 1]);
2241                         *inout = pg_tolower((unsigned char) *inout);
2242                         return strlen(p_inout);
2243
2244                 case DCH_MM:
2245                         if (is_to_char)
2246                         {
2247                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mon);
2248                                 if (S_THth(suf))
2249                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2250                                 return strlen(p_inout);
2251                         }
2252                         else
2253                         {
2254                                 if (S_FM(suf) || is_next_separator(node))
2255                                 {
2256                                         sscanf(inout, "%d", &tmfc->mm);
2257                                         return strdigits_len(inout) + SKIP_THth(suf);
2258                                 }
2259                                 else
2260                                 {
2261                                         sscanf(inout, "%02d", &tmfc->mm);
2262                                         return 2 + SKIP_THth(suf);
2263                                 }
2264                         }
2265                         break;
2266                 case DCH_DAY:
2267                         INVALID_FOR_INTERVAL;
2268                         if (S_TM(suf))
2269                                 strcpy(workbuff, localize_day_full(tm->tm_wday));
2270                         else
2271                                 strcpy(workbuff, days[tm->tm_wday]);
2272                         sprintf(inout, "%*s", (S_FM(suf) || S_TM(suf)) ? 0 : -9, str_toupper(workbuff));
2273                         return strlen(p_inout);
2274
2275                 case DCH_Day:
2276                         INVALID_FOR_INTERVAL;
2277                         if (S_TM(suf))
2278                                 sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
2279                         else
2280                                 sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
2281                         return strlen(p_inout);
2282
2283                 case DCH_day:
2284                         INVALID_FOR_INTERVAL;
2285                         if (S_TM(suf))
2286                                 sprintf(inout, "%*s", 0, localize_day_full(tm->tm_wday));
2287                         else
2288                                 sprintf(inout, "%*s", S_FM(suf) ? 0 : -9, days[tm->tm_wday]);
2289                         *inout = pg_tolower((unsigned char) *inout);
2290                         return strlen(p_inout);
2291
2292                 case DCH_DY:
2293                         INVALID_FOR_INTERVAL;
2294                         if (S_TM(suf))
2295                                 strcpy(inout, localize_day(tm->tm_wday));
2296                         else
2297                                 strcpy(inout, days_short[tm->tm_wday]);
2298                         str_toupper(inout);
2299                         return strlen(p_inout);
2300
2301                 case DCH_Dy:
2302                         INVALID_FOR_INTERVAL;
2303                         if (S_TM(suf))
2304                                 strcpy(inout, localize_day(tm->tm_wday));
2305                         else
2306                                 strcpy(inout, days_short[tm->tm_wday]);
2307                         return strlen(p_inout);
2308
2309                 case DCH_dy:
2310                         INVALID_FOR_INTERVAL;
2311                         if (S_TM(suf))
2312                                 strcpy(inout, localize_day(tm->tm_wday));
2313                         else
2314                                 strcpy(inout, days_short[tm->tm_wday]);
2315                         *inout = pg_tolower((unsigned char) *inout);
2316                         return strlen(p_inout);
2317
2318                 case DCH_DDD:
2319                         if (is_to_char)
2320                         {
2321                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 3, tm->tm_yday);
2322                                 if (S_THth(suf))
2323                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2324                                 return strlen(p_inout);
2325                         }
2326                         else
2327                         {
2328                                 if (S_FM(suf) || is_next_separator(node))
2329                                 {
2330                                         sscanf(inout, "%d", &tmfc->ddd);
2331                                         return strdigits_len(inout) + SKIP_THth(suf);
2332                                 }
2333                                 else
2334                                 {
2335                                         sscanf(inout, "%03d", &tmfc->ddd);
2336                                         return 3 + SKIP_THth(suf);
2337                                 }
2338                         }
2339                         break;
2340                 case DCH_DD:
2341                         if (is_to_char)
2342                         {
2343                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, tm->tm_mday);
2344                                 if (S_THth(suf))
2345                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2346                                 return strlen(p_inout);
2347                         }
2348                         else
2349                         {
2350                                 if (S_FM(suf) || is_next_separator(node))
2351                                 {
2352                                         sscanf(inout, "%d", &tmfc->dd);
2353                                         return strdigits_len(inout) + SKIP_THth(suf);
2354                                 }
2355                                 else
2356                                 {
2357                                         sscanf(inout, "%02d", &tmfc->dd);
2358                                         return 2 + SKIP_THth(suf);
2359                                 }
2360                         }
2361                         break;
2362                 case DCH_D:
2363                         if (is_to_char)
2364                         {
2365                                 sprintf(inout, "%d", tm->tm_wday + 1);
2366                                 if (S_THth(suf))
2367                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2368                                 return strlen(p_inout);
2369                         }
2370                         else
2371                         {
2372                                 sscanf(inout, "%1d", &tmfc->d);
2373                                 return 1 + SKIP_THth(suf);
2374                         }
2375                         break;
2376                 case DCH_WW:
2377                         if (is_to_char)
2378                         {
2379                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2,
2380                                                 (tm->tm_yday - 1) / 7 + 1);
2381                                 if (S_THth(suf))
2382                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2383                                 return strlen(p_inout);
2384                         }
2385                         else
2386                         {
2387                                 if (S_FM(suf) || is_next_separator(node))
2388                                 {
2389                                         sscanf(inout, "%d", &tmfc->ww);
2390                                         return strdigits_len(inout) + SKIP_THth(suf);
2391                                 }
2392                                 else
2393                                 {
2394                                         sscanf(inout, "%02d", &tmfc->ww);
2395                                         return 2 + SKIP_THth(suf);
2396                                 }
2397                         }
2398                         break;
2399                 case DCH_IW:
2400                         if (is_to_char)
2401                         {
2402                                 sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2,
2403                                                 date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
2404                                 if (S_THth(suf))
2405                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2406                                 return strlen(p_inout);
2407                         }
2408                         else
2409                         {
2410                                 if (S_FM(suf) || is_next_separator(node))
2411                                 {
2412                                         sscanf(inout, "%d", &tmfc->iw);
2413                                         return strdigits_len(inout) + SKIP_THth(suf);
2414                                 }
2415                                 else
2416                                 {
2417                                         sscanf(inout, "%02d", &tmfc->iw);
2418                                         return 2 + SKIP_THth(suf);
2419                                 }
2420                         }
2421                         break;
2422                 case DCH_Q:
2423                         if (is_to_char)
2424                         {
2425                                 if (!tm->tm_mon)
2426                                         return -1;
2427                                 sprintf(inout, "%d", (tm->tm_mon - 1) / 3 + 1);
2428                                 if (S_THth(suf))
2429                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2430                                 return strlen(p_inout);
2431                         }
2432                         else
2433                         {
2434                                 sscanf(inout, "%1d", &tmfc->q);
2435                                 return 1 + SKIP_THth(suf);
2436                         }
2437                         break;
2438                 case DCH_CC:
2439                         if (is_to_char)
2440                         {
2441                                 i = tm->tm_year / 100 + ((is_interval) ? 0 : 1);
2442                                 if (i <= 99 && i >= -99)
2443                                         sprintf(inout, "%0*d", S_FM(suf) ? 0 : 2, i);
2444                                 else
2445                                         sprintf(inout, "%d", i);
2446                                 if (S_THth(suf))
2447                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2448                                 return strlen(p_inout);
2449                         }
2450                         else
2451                         {
2452                                 if (S_FM(suf) || is_next_separator(node))
2453                                 {
2454                                         sscanf(inout, "%d", &tmfc->cc);
2455                                         return strdigits_len(inout) + SKIP_THth(suf);
2456                                 }
2457                                 else
2458                                 {
2459                                         sscanf(inout, "%02d", &tmfc->cc);
2460                                         return 2 + SKIP_THth(suf);
2461                                 }
2462                         }
2463                         break;
2464                 case DCH_Y_YYY:
2465                         if (is_to_char)
2466                         {
2467                                 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
2468                                 sprintf(inout, "%d,%03d", i, ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
2469                                 if (S_THth(suf))
2470                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2471                                 return strlen(p_inout);
2472                         }
2473                         else
2474                         {
2475                                 int                     cc;
2476
2477                                 sscanf(inout, "%d,%03d", &cc, &tmfc->year);
2478                                 tmfc->year += (cc * 1000);
2479                                 tmfc->yysz = 4;
2480                                 return strdigits_len(inout) + 4 + SKIP_THth(suf);
2481                         }
2482                         break;
2483                 case DCH_YYYY:
2484                 case DCH_IYYY:
2485                         if (is_to_char)
2486                         {
2487                                 if (tm->tm_year <= 9999 && tm->tm_year >= -9998)
2488                                         sprintf(inout, "%0*d",
2489                                                         S_FM(suf) ? 0 : 4,
2490                                                         arg == DCH_YYYY ?
2491                                                         ADJUST_YEAR(tm->tm_year, is_interval) :
2492                                                         ADJUST_YEAR(date2isoyear(
2493                                                                                                          tm->tm_year,
2494                                                                                                          tm->tm_mon,
2495                                                                                                  tm->tm_mday), is_interval));
2496                                 else
2497                                         sprintf(inout, "%d",
2498                                                         arg == DCH_YYYY ?
2499                                                         ADJUST_YEAR(tm->tm_year, is_interval) :
2500                                                         ADJUST_YEAR(date2isoyear(
2501                                                                                                          tm->tm_year,
2502                                                                                                          tm->tm_mon,
2503                                                                                                  tm->tm_mday), is_interval));
2504                                 if (S_THth(suf))
2505                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2506                                 return strlen(p_inout);
2507                         }
2508                         else
2509                         {
2510                                 if (S_FM(suf) || is_next_separator(node))
2511                                 {
2512                                         sscanf(inout, "%d", &tmfc->year);
2513                                         tmfc->yysz = 4;
2514                                         return strdigits_len(inout) + SKIP_THth(suf);
2515                                 }
2516                                 else
2517                                 {
2518                                         sscanf(inout, "%04d", &tmfc->year);
2519                                         tmfc->yysz = 4;
2520                                         return 4 + SKIP_THth(suf);
2521                                 }
2522                         }
2523                         break;
2524                 case DCH_YYY:
2525                 case DCH_IYY:
2526                         if (is_to_char)
2527                         {
2528                                 snprintf(buff, sizeof(buff), "%03d",
2529                                                  arg == DCH_YYY ?
2530                                                  ADJUST_YEAR(tm->tm_year, is_interval) :
2531                                                  ADJUST_YEAR(date2isoyear(tm->tm_year,
2532                                                                                                   tm->tm_mon, tm->tm_mday),
2533                                                                          is_interval));
2534                                 i = strlen(buff);
2535                                 strcpy(inout, buff + (i - 3));
2536                                 if (S_THth(suf))
2537                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2538                                 return strlen(p_inout);
2539                         }
2540                         else
2541                         {
2542                                 sscanf(inout, "%03d", &tmfc->year);
2543
2544                                 /*
2545                                  * 3-digit year: '100' ... '999' = 1100 ... 1999 '000' ...
2546                                  * '099' = 2000 ... 2099
2547                                  */
2548                                 if (tmfc->year >= 100)
2549                                         tmfc->year += 1000;
2550                                 else
2551                                         tmfc->year += 2000;
2552                                 tmfc->yysz = 3;
2553                                 return 3 + SKIP_THth(suf);
2554                         }
2555                         break;
2556                 case DCH_YY:
2557                 case DCH_IY:
2558                         if (is_to_char)
2559                         {
2560                                 snprintf(buff, sizeof(buff), "%02d",
2561                                                  arg == DCH_YY ?
2562                                                  ADJUST_YEAR(tm->tm_year, is_interval) :
2563                                                  ADJUST_YEAR(date2isoyear(tm->tm_year,
2564                                                                                                   tm->tm_mon, tm->tm_mday),
2565                                                                          is_interval));
2566                                 i = strlen(buff);
2567                                 strcpy(inout, buff + (i - 2));
2568                                 if (S_THth(suf))
2569                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2570                                 return strlen(p_inout);
2571                         }
2572                         else
2573                         {
2574                                 sscanf(inout, "%02d", &tmfc->year);
2575
2576                                 /*
2577                                  * 2-digit year: '00' ... '69'  = 2000 ... 2069 '70' ... '99'
2578                                  * = 1970 ... 1999
2579                                  */
2580                                 if (tmfc->year < 70)
2581                                         tmfc->year += 2000;
2582                                 else
2583                                         tmfc->year += 1900;
2584                                 tmfc->yysz = 2;
2585                                 return 2 + SKIP_THth(suf);
2586                         }
2587                         break;
2588                 case DCH_Y:
2589                 case DCH_I:
2590                         if (is_to_char)
2591                         {
2592                                 snprintf(buff, sizeof(buff), "%1d",
2593                                                  arg == DCH_Y ?
2594                                                  ADJUST_YEAR(tm->tm_year, is_interval) :
2595                                                  ADJUST_YEAR(date2isoyear(tm->tm_year,
2596                                                                                                   tm->tm_mon, tm->tm_mday),
2597                                                                          is_interval));
2598                                 i = strlen(buff);
2599                                 strcpy(inout, buff + (i - 1));
2600                                 if (S_THth(suf))
2601                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2602                                 return strlen(p_inout);
2603                         }
2604                         else
2605                         {
2606                                 sscanf(inout, "%1d", &tmfc->year);
2607
2608                                 /*
2609                                  * 1-digit year: always +2000
2610                                  */
2611                                 tmfc->year += 2000;
2612                                 tmfc->yysz = 1;
2613                                 return 1 + SKIP_THth(suf);
2614                         }
2615                         break;
2616                 case DCH_RM:
2617                         if (is_to_char)
2618                         {
2619                                 if (!tm->tm_mon)
2620                                         return -1;
2621                                 sprintf(inout, "%*s", S_FM(suf) ? 0 : -4,
2622                                                 rm_months_upper[12 - tm->tm_mon]);
2623                                 return strlen(p_inout);
2624                         }
2625                         else
2626                         {
2627                                 tmfc->mm = 12 - seq_search(inout, rm_months_upper, ALL_UPPER, FULL_SIZ, &len);
2628                                 CHECK_SEQ_SEARCH(len, "RM");
2629                                 if (S_FM(suf))
2630                                         return len;
2631                                 else
2632                                         return 4;
2633                         }
2634                         break;
2635                 case DCH_rm:
2636                         if (is_to_char)
2637                         {
2638                                 if (!tm->tm_mon)
2639                                         return -1;
2640                                 sprintf(inout, "%*s", S_FM(suf) ? 0 : -4,
2641                                                 rm_months_lower[12 - tm->tm_mon]);
2642                                 return strlen(p_inout);
2643                         }
2644                         else
2645                         {
2646                                 tmfc->mm = 12 - seq_search(inout, rm_months_lower, ALL_LOWER, FULL_SIZ, &len);
2647                                 CHECK_SEQ_SEARCH(len, "rm");
2648                                 if (S_FM(suf))
2649                                         return len;
2650                                 else
2651                                         return 4;
2652                         }
2653                         break;
2654                 case DCH_W:
2655                         if (is_to_char)
2656                         {
2657                                 sprintf(inout, "%d", (tm->tm_mday - 1) / 7 + 1);
2658                                 if (S_THth(suf))
2659                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2660                                 return strlen(p_inout);
2661                         }
2662                         else
2663                         {
2664                                 sscanf(inout, "%1d", &tmfc->w);
2665                                 return 1 + SKIP_THth(suf);
2666                         }
2667                         break;
2668                 case DCH_J:
2669                         if (is_to_char)
2670                         {
2671                                 sprintf(inout, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
2672                                 if (S_THth(suf))
2673                                         str_numth(p_inout, inout, S_TH_TYPE(suf));
2674                                 return strlen(p_inout);
2675                         }
2676                         else
2677                         {
2678                                 sscanf(inout, "%d", &tmfc->j);
2679                                 return strdigits_len(inout) + SKIP_THth(suf);
2680                         }
2681                         break;
2682         }
2683         return -1;
2684 }
2685
2686 static DCHCacheEntry *
2687 DCH_cache_getnew(char *str)
2688 {
2689         DCHCacheEntry *ent = NULL;
2690
2691         /* counter overload check  - paranoia? */
2692         if (DCHCounter + DCH_CACHE_FIELDS >= MAX_INT32)
2693         {
2694                 DCHCounter = 0;
2695
2696                 for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
2697                         ent->age = (++DCHCounter);
2698         }
2699
2700         /*
2701          * Cache is full - needs remove any older entry
2702          */
2703         if (n_DCHCache > DCH_CACHE_FIELDS)
2704         {
2705
2706                 DCHCacheEntry *old = DCHCache + 0;
2707
2708 #ifdef DEBUG_TO_FROM_CHAR
2709                 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
2710 #endif
2711                 for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
2712                 {
2713                         if (ent->age < old->age)
2714                                 old = ent;
2715                 }
2716 #ifdef DEBUG_TO_FROM_CHAR
2717                 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
2718 #endif
2719                 StrNCpy(old->str, str, DCH_CACHE_SIZE + 1);
2720                 /* old->format fill parser */
2721                 old->age = (++DCHCounter);
2722                 return old;
2723         }
2724         else
2725         {
2726 #ifdef DEBUG_TO_FROM_CHAR
2727                 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
2728 #endif
2729                 ent = DCHCache + n_DCHCache;
2730                 StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1);
2731                 /* ent->format fill parser */
2732                 ent->age = (++DCHCounter);
2733                 ++n_DCHCache;
2734                 return ent;
2735         }
2736
2737         return NULL;                            /* never */
2738 }
2739
2740 static DCHCacheEntry *
2741 DCH_cache_search(char *str)
2742 {
2743         int                     i = 0;
2744         DCHCacheEntry *ent;
2745
2746         /* counter overload check  - paranoia? */
2747         if (DCHCounter + DCH_CACHE_FIELDS >= MAX_INT32)
2748         {
2749                 DCHCounter = 0;
2750
2751                 for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
2752                         ent->age = (++DCHCounter);
2753         }
2754
2755         for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
2756         {
2757                 if (i == n_DCHCache)
2758                         break;
2759                 if (strcmp(ent->str, str) == 0)
2760                 {
2761                         ent->age = (++DCHCounter);
2762                         return ent;
2763                 }
2764                 i++;
2765         }
2766
2767         return NULL;
2768 }
2769
2770 static text *
2771 datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval)
2772 {
2773         FormatNode *format;
2774         char       *fmt_str,
2775                            *result;
2776         bool            incache;
2777         int                     fmt_len = VARSIZE(fmt) - VARHDRSZ;
2778         int                     reslen;
2779         text       *res;
2780
2781         /*
2782          * Convert fmt to C string
2783          */
2784         fmt_str = (char *) palloc(fmt_len + 1);
2785         memcpy(fmt_str, VARDATA(fmt), fmt_len);
2786         *(fmt_str + fmt_len) = '\0';
2787
2788         /*
2789          * Allocate workspace for result as C string
2790          */
2791         result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
2792         *result = '\0';
2793
2794         /*
2795          * Allocate new memory if format picture is bigger than static cache and
2796          * not use cache (call parser always)
2797          */
2798         if (fmt_len > DCH_CACHE_SIZE)
2799         {
2800                 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
2801                 incache = FALSE;
2802
2803                 parse_format(format, fmt_str, DCH_keywords,
2804                                          DCH_suff, DCH_index, DCH_TYPE, NULL);
2805
2806                 (format + fmt_len)->type = NODE_TYPE_END;               /* Paranoia? */
2807         }
2808         else
2809         {
2810                 /*
2811                  * Use cache buffers
2812                  */
2813                 DCHCacheEntry *ent;
2814
2815                 incache = TRUE;
2816
2817                 if ((ent = DCH_cache_search(fmt_str)) == NULL)
2818                 {
2819                         ent = DCH_cache_getnew(fmt_str);
2820
2821                         /*
2822                          * Not in the cache, must run parser and save a new format-picture
2823                          * to the cache.
2824                          */
2825                         parse_format(ent->format, fmt_str, DCH_keywords,
2826                                                  DCH_suff, DCH_index, DCH_TYPE, NULL);
2827
2828                         (ent->format + fmt_len)->type = NODE_TYPE_END;          /* Paranoia? */
2829
2830 #ifdef DEBUG_TO_FROM_CHAR
2831                         /* dump_node(ent->format, fmt_len); */
2832                         /* dump_index(DCH_keywords, DCH_index);  */
2833 #endif
2834                 }
2835                 format = ent->format;
2836         }
2837
2838         /* The real work is here */
2839         DCH_processor(format, result, true, is_interval, (void *) tmtc);
2840
2841         if (!incache)
2842                 pfree(format);
2843
2844         pfree(fmt_str);
2845
2846         /* convert C-string result to TEXT format */
2847         reslen = strlen(result);
2848         res = (text *) palloc(reslen + VARHDRSZ);
2849         memcpy(VARDATA(res), result, reslen);
2850         VARATT_SIZEP(res) = reslen + VARHDRSZ;
2851
2852         pfree(result);
2853         return res;
2854 }
2855
2856 static char *
2857 localize_month_full(int index)
2858 {
2859         char    *m      = NULL;
2860
2861         switch (index)
2862         {
2863                 case 0:
2864                         m = _("January");
2865                         break;
2866                 case 1:
2867                         m = _("February");
2868                         break;
2869                 case 2:
2870                         m = _("March");
2871                         break;
2872                 case 3:
2873                         m = _("April");
2874                         break;
2875                 case 4:
2876                         m = _("May");
2877                         break;
2878                 case 5:
2879                         m = _("June");
2880                         break;
2881                 case 6:
2882                         m = _("July");
2883                         break;
2884                 case 7:
2885                         m = _("August");
2886                         break;
2887                 case 8:
2888                         m = _("September");
2889                         break;
2890                 case 9:
2891                         m = _("October");
2892                         break;
2893                 case 10:
2894                         m = _("November");
2895                         break;
2896                 case 11:
2897                         m = _("December");
2898                         break;
2899         }
2900
2901         return m;
2902 }
2903
2904 static char *
2905 localize_month(int index)
2906 {
2907         char    *m      = NULL;
2908
2909         switch (index)
2910         {
2911                 case 0:
2912                         m = _("Jan");
2913                         break;
2914                 case 1:
2915                         m = _("Feb");
2916                         break;
2917                 case 2:
2918                         m = _("Mar");
2919                         break;
2920                 case 3:
2921                         m = _("Apr");
2922                         break;
2923                 case 4:
2924                         m = _("May");
2925                         break;
2926                 case 5:
2927                         m = _("Jun");
2928                         break;
2929                 case 6:
2930                         m = _("Jul");
2931                         break;
2932                 case 7:
2933                         m = _("Aug");
2934                         break;
2935                 case 8:
2936                         m = _("Sep");
2937                         break;
2938                 case 9:
2939                         m = _("Oct");
2940                         break;
2941                 case 10:
2942                         m = _("Nov");
2943                         break;
2944                 case 11:
2945                         m = _("Dec");
2946                         break;
2947         }
2948
2949         return m;
2950 }
2951
2952 static char *
2953 localize_day_full(int index)
2954 {
2955         char    *d      = NULL;
2956
2957         switch (index)
2958         {
2959                 case 0:
2960                         d = _("Sunday");
2961                         break;
2962                 case 1:
2963                         d = _("Monday");
2964                         break;
2965                 case 2:
2966                         d = _("Tuesday");
2967                         break;
2968                 case 3:
2969                         d = _("Wednesday");
2970                         break;
2971                 case 4:
2972                         d = _("Thursday");
2973                         break;
2974                 case 5:
2975                         d = _("Friday");
2976                         break;
2977                 case 6:
2978                         d = _("Saturday");
2979                         break;
2980         }
2981
2982         return d;
2983 }
2984
2985 static char *
2986 localize_day(int index)
2987 {
2988         char    *d      = NULL;
2989
2990         switch (index)
2991         {
2992                 case 0:
2993                         d = _("Sun");
2994                         break;
2995                 case 1:
2996                         d = _("Mon");
2997                         break;
2998                 case 2:
2999                         d = _("Tue");
3000                         break;
3001                 case 3:
3002                         d = _("Wed");
3003                         break;
3004                 case 4:
3005                         d = _("Thu");
3006                         break;
3007                 case 5:
3008                         d = _("Fri");
3009                         break;
3010                 case 6:
3011                         d = _("Sat");
3012                         break;
3013         }
3014
3015         return d;
3016 }
3017
3018 /****************************************************************************
3019  *                              Public routines
3020  ***************************************************************************/
3021
3022 /* -------------------
3023  * TIMESTAMP to_char()
3024  * -------------------
3025  */
3026 Datum
3027 timestamp_to_char(PG_FUNCTION_ARGS)
3028 {
3029         Timestamp       dt = PG_GETARG_TIMESTAMP(0);
3030         text       *fmt = PG_GETARG_TEXT_P(1),
3031                            *res;
3032         TmToChar        tmtc;
3033         struct pg_tm *tm;
3034         int                     thisdate;
3035
3036         if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
3037                 PG_RETURN_NULL();
3038
3039         ZERO_tmtc(&tmtc);
3040         tm = tmtcTm(&tmtc);
3041
3042         if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0)
3043                 ereport(ERROR,
3044                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3045                                  errmsg("timestamp out of range")));
3046
3047         thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3048         tm->tm_wday = (thisdate + 1) % 7;
3049         tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
3050
3051         if (!(res = datetime_to_char_body(&tmtc, fmt, false)))
3052                 PG_RETURN_NULL();
3053
3054         PG_RETURN_TEXT_P(res);
3055 }
3056
3057 Datum
3058 timestamptz_to_char(PG_FUNCTION_ARGS)
3059 {
3060         TimestampTz dt = PG_GETARG_TIMESTAMP(0);
3061         text       *fmt = PG_GETARG_TEXT_P(1),
3062                            *res;
3063         TmToChar        tmtc;
3064         int                     tz;
3065         struct pg_tm *tm;
3066         int                     thisdate;
3067
3068         if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
3069                 PG_RETURN_NULL();
3070
3071         ZERO_tmtc(&tmtc);
3072         tm = tmtcTm(&tmtc);
3073
3074         if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
3075                 ereport(ERROR,
3076                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3077                                  errmsg("timestamp out of range")));
3078
3079         thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3080         tm->tm_wday = (thisdate + 1) % 7;
3081         tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
3082
3083         if (!(res = datetime_to_char_body(&tmtc, fmt, false)))
3084                 PG_RETURN_NULL();
3085
3086         PG_RETURN_TEXT_P(res);
3087 }
3088
3089
3090 /* -------------------
3091  * INTERVAL to_char()
3092  * -------------------
3093  */
3094 Datum
3095 interval_to_char(PG_FUNCTION_ARGS)
3096 {
3097         Interval   *it = PG_GETARG_INTERVAL_P(0);
3098         text       *fmt = PG_GETARG_TEXT_P(1),
3099                            *res;
3100         TmToChar        tmtc;
3101         struct pg_tm *tm;
3102
3103         if ((VARSIZE(fmt) - VARHDRSZ) <= 0)
3104                 PG_RETURN_NULL();
3105
3106         ZERO_tmtc(&tmtc);
3107         tm = tmtcTm(&tmtc);
3108
3109         if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0)
3110                 PG_RETURN_NULL();
3111
3112         /* wday is meaningless, yday approximates the total span in days */
3113         tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
3114
3115         if (!(res = datetime_to_char_body(&tmtc, fmt, true)))
3116                 PG_RETURN_NULL();
3117
3118         PG_RETURN_TEXT_P(res);
3119 }
3120
3121 /* ---------------------
3122  * TO_TIMESTAMP()
3123  *
3124  * Make Timestamp from date_str which is formatted at argument 'fmt'
3125  * ( to_timestamp is reverse to_char() )
3126  * ---------------------
3127  */
3128 Datum
3129 to_timestamp(PG_FUNCTION_ARGS)
3130 {
3131         text       *date_txt = PG_GETARG_TEXT_P(0);
3132         text       *fmt = PG_GETARG_TEXT_P(1);
3133         Timestamp       result;
3134         int                     tz;
3135         struct pg_tm tm;
3136         fsec_t          fsec;
3137
3138         do_to_timestamp(date_txt, fmt, &tm, &fsec);
3139
3140         tz = DetermineTimeZoneOffset(&tm, global_timezone);
3141
3142         if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
3143                 ereport(ERROR,
3144                                 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3145                                  errmsg("timestamp out of range")));
3146
3147         PG_RETURN_TIMESTAMP(result);
3148 }
3149
3150 /* ----------
3151  * TO_DATE
3152  *      Make Date from date_str which is formated at argument 'fmt'
3153  * ----------
3154  */
3155 Datum
3156 to_date(PG_FUNCTION_ARGS)
3157 {
3158         text       *date_txt = PG_GETARG_TEXT_P(0);
3159         text       *fmt = PG_GETARG_TEXT_P(1);
3160         DateADT         result;
3161         struct pg_tm tm;
3162         fsec_t          fsec;
3163
3164         do_to_timestamp(date_txt, fmt, &tm, &fsec);
3165
3166         result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
3167
3168         PG_RETURN_DATEADT(result);
3169 }
3170
3171 /*
3172  * do_to_timestamp: shared code for to_timestamp and to_date
3173  *
3174  * Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm
3175  * and fractional seconds.
3176  */
3177 static void
3178 do_to_timestamp(text *date_txt, text *fmt,
3179                                 struct pg_tm * tm, fsec_t *fsec)
3180 {
3181         FormatNode *format;
3182         TmFromChar      tmfc;
3183         int                     fmt_len;
3184
3185         ZERO_tm(tm);
3186         *fsec = 0;
3187
3188         ZERO_tmfc(&tmfc);
3189
3190         fmt_len = VARSIZE(fmt) - VARHDRSZ;
3191
3192         if (fmt_len)
3193         {
3194                 int                     date_len;
3195                 char       *fmt_str;
3196                 char       *date_str;
3197                 bool            incache;
3198
3199                 fmt_str = (char *) palloc(fmt_len + 1);
3200                 memcpy(fmt_str, VARDATA(fmt), fmt_len);
3201                 *(fmt_str + fmt_len) = '\0';
3202
3203                 /*
3204                  * Allocate new memory if format picture is bigger than static cache
3205                  * and not use cache (call parser always)
3206                  */
3207                 if (fmt_len > DCH_CACHE_SIZE)
3208                 {
3209                         format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3210                         incache = FALSE;
3211
3212                         parse_format(format, fmt_str, DCH_keywords,
3213                                                  DCH_suff, DCH_index, DCH_TYPE, NULL);
3214
3215                         (format + fmt_len)->type = NODE_TYPE_END;       /* Paranoia? */
3216                 }
3217                 else
3218                 {
3219                         /*
3220                          * Use cache buffers
3221                          */
3222                         DCHCacheEntry *ent;
3223
3224                         incache = TRUE;
3225
3226                         if ((ent = DCH_cache_search(fmt_str)) == NULL)
3227                         {
3228
3229                                 ent = DCH_cache_getnew(fmt_str);
3230
3231                                 /*
3232                                  * Not in the cache, must run parser and save a new
3233                                  * format-picture to the cache.
3234                                  */
3235                                 parse_format(ent->format, fmt_str, DCH_keywords,
3236                                                          DCH_suff, DCH_index, DCH_TYPE, NULL);
3237
3238                                 (ent->format + fmt_len)->type = NODE_TYPE_END;  /* Paranoia? */
3239 #ifdef DEBUG_TO_FROM_CHAR
3240                                 /* dump_node(ent->format, fmt_len); */
3241                                 /* dump_index(DCH_keywords, DCH_index); */
3242 #endif
3243                         }
3244                         format = ent->format;
3245                 }
3246
3247                 /*
3248                  * Call action for each node in FormatNode tree
3249                  */
3250 #ifdef DEBUG_TO_FROM_CHAR
3251                 /* dump_node(format, fmt_len); */
3252 #endif
3253
3254                 /*
3255                  * Convert date to C string
3256                  */
3257                 date_len = VARSIZE(date_txt) - VARHDRSZ;
3258                 date_str = (char *) palloc(date_len + 1);
3259                 memcpy(date_str, VARDATA(date_txt), date_len);
3260                 *(date_str + date_len) = '\0';
3261
3262                 DCH_processor(format, date_str, false, false, (void *) &tmfc);
3263
3264                 pfree(date_str);
3265                 pfree(fmt_str);
3266                 if (!incache)
3267                         pfree(format);
3268         }
3269
3270         DEBUG_TMFC(&tmfc);
3271
3272         /*
3273          * Convert values that user define for FROM_CHAR (to_date/to_timestamp) to
3274          * standard 'tm'
3275          */
3276         if (tmfc.ssss)
3277         {
3278                 int                     x = tmfc.ssss;
3279
3280                 tm->tm_hour = x / SECS_PER_HOUR;
3281                 x %= SECS_PER_HOUR;
3282                 tm->tm_min = x / SECS_PER_MINUTE;
3283                 x %= SECS_PER_MINUTE;
3284                 tm->tm_sec = x;
3285         }
3286
3287         if (tmfc.cc)
3288                 tm->tm_year = (tmfc.cc - 1) * 100;
3289
3290         if (tmfc.ww)
3291                 tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
3292
3293         if (tmfc.w)
3294                 tmfc.dd = (tmfc.w - 1) * 7 + 1;
3295
3296         if (tmfc.ss)
3297                 tm->tm_sec = tmfc.ss;
3298         if (tmfc.mi)
3299                 tm->tm_min = tmfc.mi;
3300         if (tmfc.hh)
3301                 tm->tm_hour = tmfc.hh;
3302
3303         if (tmfc.pm || tmfc.am)
3304         {
3305                 if (tm->tm_hour < 1 || tm->tm_hour > 12)
3306                         ereport(ERROR,
3307                                         (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3308                                          errmsg("AM/PM hour must be between 1 and 12")));
3309
3310                 if (tmfc.pm && tm->tm_hour < 12)
3311                         tm->tm_hour += 12;
3312
3313                 else if (tmfc.am && tm->tm_hour == 12)
3314                         tm->tm_hour = 0;
3315         }
3316
3317         switch (tmfc.q)
3318         {
3319                 case 1:
3320                         tm->tm_mday = 1;
3321                         tm->tm_mon = 1;
3322                         break;
3323                 case 2:
3324                         tm->tm_mday = 1;
3325                         tm->tm_mon = 4;
3326                         break;
3327                 case 3:
3328                         tm->tm_mday = 1;
3329                         tm->tm_mon = 7;
3330                         break;
3331                 case 4:
3332                         tm->tm_mday = 1;
3333                         tm->tm_mon = 10;
3334                         break;
3335         }
3336
3337         if (tmfc.year)
3338         {
3339                 if (tmfc.yysz == 2 && tmfc.cc)
3340                 {
3341                         /*
3342                          * CC and YY defined why -[2000|1900]? See dch_date() DCH_YY code.
3343                          */
3344                         tm->tm_year = (tmfc.cc - 1) * 100 + (tmfc.year >= 2000 ? tmfc.year - 2000 : tmfc.year - 1900);
3345                 }
3346                 else if (tmfc.yysz == 1 && tmfc.cc)
3347                 {
3348                         /*
3349                          * CC and Y defined
3350                          */
3351                         tm->tm_year = (tmfc.cc - 1) * 100 + tmfc.year - 2000;
3352                 }
3353                 else
3354                         /* set year (and ignore CC if defined) */
3355                         tm->tm_year = tmfc.year;
3356         }
3357         if (tmfc.bc)
3358         {
3359                 if (tm->tm_year > 0)
3360                         tm->tm_year = -(tm->tm_year - 1);
3361                 else
3362                         ereport(ERROR,
3363                                         (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3364                                          errmsg("inconsistent use of year %04d and \"BC\"",
3365                                                         tm->tm_year)));
3366         }
3367
3368         if (tmfc.j)
3369                 j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3370
3371         if (tmfc.iw)
3372                 isoweek2date(tmfc.iw, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3373
3374         if (tmfc.d)
3375                 tm->tm_wday = tmfc.d;
3376         if (tmfc.dd)
3377                 tm->tm_mday = tmfc.dd;
3378         if (tmfc.ddd)
3379                 tm->tm_yday = tmfc.ddd;
3380         if (tmfc.mm)
3381                 tm->tm_mon = tmfc.mm;
3382
3383         /*
3384          * we don't ignore DDD
3385          */
3386         if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
3387         {
3388                 /* count mday and mon from yday */
3389                 int                *y,
3390                                         i;
3391
3392                 int                     ysum[2][13] = {
3393                         {31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0},
3394                 {31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366, 0}};
3395
3396                 if (!tm->tm_year)
3397                         ereport(ERROR,
3398                                         (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3399                         errmsg("cannot calculate day of year without year information")));
3400
3401                 y = ysum[isleap(tm->tm_year)];
3402
3403                 for (i = 0; i <= 11; i++)
3404                 {
3405                         if (tm->tm_yday < y[i])
3406                                 break;
3407                 }
3408                 if (tm->tm_mon <= 1)
3409                         tm->tm_mon = i + 1;
3410
3411                 if (tm->tm_mday <= 1)
3412                         tm->tm_mday = i == 0 ? tm->tm_yday :
3413                                 tm->tm_yday - y[i - 1];
3414         }
3415
3416 #ifdef HAVE_INT64_TIMESTAMP
3417         if (tmfc.ms)
3418                 *fsec += tmfc.ms * 1000;
3419         if (tmfc.us)
3420                 *fsec += tmfc.us;
3421 #else
3422         if (tmfc.ms)
3423                 *fsec += (double) tmfc.ms / 1000;
3424         if (tmfc.us)
3425                 *fsec += (double) tmfc.us / 1000000;
3426 #endif
3427
3428         DEBUG_TM(tm);
3429 }
3430
3431
3432 /**********************************************************************
3433  *      the NUMBER version part
3434  *********************************************************************/
3435
3436
3437 static char *
3438 fill_str(char *str, int c, int max)
3439 {
3440         memset(str, c, max);
3441         *(str + max + 1) = '\0';
3442         return str;
3443 }
3444
3445 #define zeroize_NUM(_n) \
3446 do { \
3447         (_n)->flag              = 0;    \
3448         (_n)->lsign             = 0;    \
3449         (_n)->pre               = 0;    \
3450         (_n)->post              = 0;    \
3451         (_n)->pre_lsign_num = 0;        \
3452         (_n)->need_locale       = 0;    \
3453         (_n)->multi             = 0;    \
3454         (_n)->zero_start        = 0;    \
3455         (_n)->zero_end          = 0;    \
3456 } while(0)
3457
3458 static NUMCacheEntry *
3459 NUM_cache_getnew(char *str)
3460 {
3461         NUMCacheEntry *ent = NULL;
3462
3463         /* counter overload check  - paranoia? */
3464         if (NUMCounter + NUM_CACHE_FIELDS >= MAX_INT32)
3465         {
3466                 NUMCounter = 0;
3467
3468                 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3469                         ent->age = (++NUMCounter);
3470         }
3471
3472         /*
3473          * Cache is full - needs remove any older entry
3474          */
3475         if (n_NUMCache > NUM_CACHE_FIELDS)
3476         {
3477
3478                 NUMCacheEntry *old = NUMCache + 0;
3479
3480 #ifdef DEBUG_TO_FROM_CHAR
3481                 elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
3482 #endif
3483
3484                 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3485                 {
3486                         /*
3487                          * entry removed via NUM_cache_remove() can be used here
3488                          */
3489                         if (*ent->str == '\0')
3490                         {
3491                                 old = ent;
3492                                 break;
3493                         }
3494                         if (ent->age < old->age)
3495                                 old = ent;
3496                 }
3497 #ifdef DEBUG_TO_FROM_CHAR
3498                 elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
3499 #endif
3500                 StrNCpy(old->str, str, NUM_CACHE_SIZE + 1);
3501                 /* old->format fill parser */
3502                 old->age = (++NUMCounter);
3503
3504                 ent = old;
3505
3506         }
3507         else
3508         {
3509 #ifdef DEBUG_TO_FROM_CHAR
3510                 elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
3511 #endif
3512                 ent = NUMCache + n_NUMCache;
3513                 StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1);
3514                 /* ent->format fill parser */
3515                 ent->age = (++NUMCounter);
3516                 ++n_NUMCache;
3517         }
3518
3519         zeroize_NUM(&ent->Num);
3520
3521         last_NUMCacheEntry = ent;
3522         return ent;                                     /* never */
3523 }
3524
3525 static NUMCacheEntry *
3526 NUM_cache_search(char *str)
3527 {
3528         int                     i = 0;
3529         NUMCacheEntry *ent;
3530
3531         /* counter overload check - paranoia? */
3532         if (NUMCounter + NUM_CACHE_FIELDS >= MAX_INT32)
3533         {
3534                 NUMCounter = 0;
3535
3536                 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3537                         ent->age = (++NUMCounter);
3538         }
3539
3540         for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3541         {
3542                 if (i == n_NUMCache)
3543                         break;
3544                 if (strcmp(ent->str, str) == 0)
3545                 {
3546                         ent->age = (++NUMCounter);
3547                         last_NUMCacheEntry = ent;
3548                         return ent;
3549                 }
3550                 i++;
3551         }
3552
3553         return NULL;
3554 }
3555
3556 static void
3557 NUM_cache_remove(NUMCacheEntry *ent)
3558 {
3559 #ifdef DEBUG_TO_FROM_CHAR
3560         elog(DEBUG_elog_output, "REMOVING ENTRY (%s)", ent->str);
3561 #endif
3562         *ent->str = '\0';
3563         ent->age = 0;
3564 }
3565
3566 /* ----------
3567  * Cache routine for NUM to_char version
3568  * ----------
3569  */
3570 static FormatNode *
3571 NUM_cache(int len, NUMDesc *Num, char *pars_str, bool *shouldFree)
3572 {
3573         FormatNode *format = NULL;
3574         char       *str;
3575
3576         /*
3577          * Convert VARDATA() to string
3578          */
3579         str = (char *) palloc(len + 1);
3580         memcpy(str, pars_str, len);
3581         *(str + len) = '\0';
3582
3583         /*
3584          * Allocate new memory if format picture is bigger than static cache and
3585          * not use cache (call parser always). This branches sets shouldFree to
3586          * true, accordingly.
3587          */
3588         if (len > NUM_CACHE_SIZE)
3589         {
3590                 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
3591
3592                 *shouldFree = true;
3593
3594                 zeroize_NUM(Num);
3595
3596                 parse_format(format, str, NUM_keywords,
3597                                          NULL, NUM_index, NUM_TYPE, Num);
3598
3599                 (format + len)->type = NODE_TYPE_END;   /* Paranoia? */
3600
3601         }
3602         else
3603         {
3604                 /*
3605                  * Use cache buffers
3606                  */
3607                 NUMCacheEntry *ent;
3608
3609                 *shouldFree = false;
3610
3611                 if ((ent = NUM_cache_search(str)) == NULL)
3612                 {
3613
3614                         ent = NUM_cache_getnew(str);
3615
3616                         /*
3617                          * Not in the cache, must run parser and save a new format-picture
3618                          * to the cache.
3619                          */
3620                         parse_format(ent->format, str, NUM_keywords,
3621                                                  NULL, NUM_index, NUM_TYPE, &ent->Num);
3622
3623                         (ent->format + len)->type = NODE_TYPE_END;      /* Paranoia? */
3624
3625                 }
3626
3627                 format = ent->format;
3628
3629                 /*
3630                  * Copy cache to used struct
3631                  */
3632                 Num->flag = ent->Num.flag;
3633                 Num->lsign = ent->Num.lsign;
3634                 Num->pre = ent->Num.pre;
3635                 Num->post = ent->Num.post;
3636                 Num->pre_lsign_num = ent->Num.pre_lsign_num;
3637                 Num->need_locale = ent->Num.need_locale;
3638                 Num->multi = ent->Num.multi;
3639                 Num->zero_start = ent->Num.zero_start;
3640                 Num->zero_end = ent->Num.zero_end;
3641         }
3642
3643 #ifdef DEBUG_TO_FROM_CHAR
3644         /* dump_node(format, len); */
3645         dump_index(NUM_keywords, NUM_index);
3646 #endif
3647
3648         pfree(str);
3649         return format;
3650 }
3651
3652
3653 static char *
3654 int_to_roman(int number)
3655 {
3656         int                     len = 0,
3657                                 num = 0;
3658         char       *p = NULL,
3659                            *result,
3660                                 numstr[5];
3661
3662         result = (char *) palloc(16);
3663         *result = '\0';
3664
3665         if (number > 3999 || number < 1)
3666         {
3667                 fill_str(result, '#', 15);
3668                 return result;
3669         }
3670         len = snprintf(numstr, sizeof(numstr), "%d", number);
3671
3672         for (p = numstr; *p != '\0'; p++, --len)
3673         {
3674                 num = *p - 49;                  /* 48 ascii + 1 */
3675                 if (num < 0)
3676                         continue;
3677
3678                 if (len > 3)
3679                 {
3680                         while (num-- != -1)
3681                                 strcat(result, "M");
3682                 }
3683                 else
3684                 {
3685                         if (len == 3)
3686                                 strcat(result, rm100[num]);
3687                         else if (len == 2)
3688                                 strcat(result, rm10[num]);
3689                         else if (len == 1)
3690                                 strcat(result, rm1[num]);
3691                 }
3692         }
3693         return result;
3694 }
3695
3696
3697
3698 /* ----------
3699  * Locale
3700  * ----------
3701  */
3702 static void
3703 NUM_prepare_locale(NUMProc *Np)
3704 {
3705         if (Np->Num->need_locale)
3706         {
3707
3708                 struct lconv *lconv;
3709
3710                 /*
3711                  * Get locales
3712                  */
3713                 lconv = PGLC_localeconv();
3714
3715                 /*
3716                  * Positive / Negative number sign
3717                  */
3718                 if (lconv->negative_sign && *lconv->negative_sign)
3719                         Np->L_negative_sign = lconv->negative_sign;
3720                 else
3721                         Np->L_negative_sign = "-";
3722
3723                 if (lconv->positive_sign && *lconv->positive_sign)
3724                         Np->L_positive_sign = lconv->positive_sign;
3725                 else
3726                         Np->L_positive_sign = "+";
3727
3728                 /*
3729                  * Number thousands separator
3730                  */
3731                 if (lconv->thousands_sep && *lconv->thousands_sep)
3732                         Np->L_thousands_sep = lconv->thousands_sep;
3733                 else
3734                         Np->L_thousands_sep = ",";
3735
3736                 /*
3737                  * Number decimal point
3738                  */
3739                 if (lconv->decimal_point && *lconv->decimal_point)
3740                         Np->decimal = lconv->decimal_point;
3741
3742                 else
3743                         Np->decimal = ".";
3744
3745                 /*
3746                  * Currency symbol
3747                  */
3748                 if (lconv->currency_symbol && *lconv->currency_symbol)
3749                         Np->L_currency_symbol = lconv->currency_symbol;
3750                 else
3751                         Np->L_currency_symbol = " ";
3752
3753
3754                 if (!IS_LDECIMAL(Np->Num))
3755                         Np->decimal = ".";
3756         }
3757         else
3758         {
3759                 /*
3760                  * Default values
3761                  */
3762                 Np->L_negative_sign = "-";
3763                 Np->L_positive_sign = "+";
3764                 Np->decimal = ".";
3765
3766                 Np->L_thousands_sep = ",";
3767                 Np->L_currency_symbol = " ";
3768         }
3769 }
3770
3771 /* ----------
3772  * Return pointer of last relevant number after decimal point
3773  *      12.0500 --> last relevant is '5'
3774  * ----------
3775  */
3776 static char *
3777 get_last_relevant_decnum(char *num)
3778 {
3779         char       *result,
3780                            *p = strchr(num, '.');
3781
3782 #ifdef DEBUG_TO_FROM_CHAR
3783         elog(DEBUG_elog_output, "get_last_relevant_decnum()");
3784 #endif
3785
3786         if (!p)
3787                 p = num;
3788         result = p;
3789
3790         while (*(++p))
3791         {
3792                 if (*p != '0')
3793                         result = p;
3794         }
3795
3796         return result;
3797 }
3798
3799 /* ----------
3800  * Number extraction for TO_NUMBER()
3801  * ----------
3802  */
3803 static void
3804 NUM_numpart_from_char(NUMProc *Np, int id, int plen)
3805 {
3806         bool            isread = FALSE;
3807
3808 #ifdef DEBUG_TO_FROM_CHAR
3809         elog(DEBUG_elog_output, " --- scan start --- id=%s",
3810                  (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
3811 #endif
3812
3813         if (*Np->inout_p == ' ')
3814                 Np->inout_p++;
3815
3816 #define OVERLOAD_TEST   (Np->inout_p >= Np->inout + plen)
3817 #define AMOUNT_TEST(_s) (plen-(Np->inout_p-Np->inout) >= _s)
3818
3819         if (*Np->inout_p == ' ')
3820                 Np->inout_p++;
3821
3822         if (OVERLOAD_TEST)
3823                 return;
3824
3825         /*
3826          * read sign before number
3827          */
3828         if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
3829                 (Np->read_pre + Np->read_post) == 0)
3830         {
3831
3832 #ifdef DEBUG_TO_FROM_CHAR
3833                 elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
3834                          *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
3835 #endif
3836
3837                 /*
3838                  * locale sign
3839                  */
3840                 if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
3841                 {
3842                         int                     x = 0;
3843
3844 #ifdef DEBUG_TO_FROM_CHAR
3845                         elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
3846 #endif
3847                         if ((x = strlen(Np->L_negative_sign)) &&
3848                                 AMOUNT_TEST(x) &&
3849                                 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
3850                         {
3851                                 Np->inout_p += x;
3852                                 *Np->number = '-';
3853                         }
3854                         else if ((x = strlen(Np->L_positive_sign)) &&
3855                                          AMOUNT_TEST(x) &&
3856                                          strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
3857                         {
3858                                 Np->inout_p += x;
3859                                 *Np->number = '+';
3860                         }
3861                 }
3862                 else
3863                 {
3864 #ifdef DEBUG_TO_FROM_CHAR
3865                         elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
3866 #endif
3867
3868                         /*
3869                          * simple + - < >
3870                          */
3871                         if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
3872                                                                                 *Np->inout_p == '<'))
3873                         {
3874
3875                                 *Np->number = '-';              /* set - */
3876                                 Np->inout_p++;
3877
3878                         }
3879                         else if (*Np->inout_p == '+')
3880                         {
3881
3882                                 *Np->number = '+';              /* set + */
3883                                 Np->inout_p++;
3884                         }
3885                 }
3886         }
3887
3888         if (OVERLOAD_TEST)
3889                 return;
3890
3891 #ifdef DEBUG_TO_FROM_CHAR
3892         elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
3893 #endif
3894
3895         /*
3896          * read digit
3897          */
3898         if (isdigit((unsigned char) *Np->inout_p))
3899         {
3900
3901                 if (Np->read_dec && Np->read_post == Np->Num->post)
3902                         return;
3903
3904                 *Np->number_p = *Np->inout_p;
3905                 Np->number_p++;
3906
3907                 if (Np->read_dec)
3908                         Np->read_post++;
3909                 else
3910                         Np->read_pre++;
3911
3912                 isread = TRUE;
3913
3914 #ifdef DEBUG_TO_FROM_CHAR
3915                 elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
3916 #endif
3917
3918                 /*
3919                  * read decimal point
3920                  */
3921         }
3922         else if (IS_DECIMAL(Np->Num) && Np->read_dec == FALSE)
3923         {
3924
3925 #ifdef DEBUG_TO_FROM_CHAR
3926                 elog(DEBUG_elog_output, "Try read decimal point (%c)", *Np->inout_p);
3927 #endif
3928                 if (*Np->inout_p == '.')
3929                 {
3930
3931                         *Np->number_p = '.';
3932                         Np->number_p++;
3933                         Np->read_dec = TRUE;
3934                         isread = TRUE;
3935                 }
3936                 else
3937                 {
3938                         int                     x = strlen(Np->decimal);
3939
3940 #ifdef DEBUG_TO_FROM_CHAR
3941                         elog(DEBUG_elog_output, "Try read locale point (%c)",
3942                                  *Np->inout_p);
3943 #endif
3944                         if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
3945                         {
3946                                 Np->inout_p += x - 1;
3947                                 *Np->number_p = '.';
3948                                 Np->number_p++;
3949                                 Np->read_dec = TRUE;
3950                                 isread = TRUE;
3951                         }
3952                 }
3953         }
3954
3955         if (OVERLOAD_TEST)
3956                 return;
3957
3958         /*
3959          * Read sign behind "last" number
3960          *
3961          * We need sign detection because determine exact position of post-sign is
3962          * difficult:
3963          *
3964          * FM9999.9999999S         -> 123.001- 9.9S                        -> .5- FM9.999999MI ->
3965          * 5.01-
3966          */
3967         if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
3968         {
3969                 /*
3970                  * locale sign (NUM_S) is always anchored behind a last number, if: -
3971                  * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
3972                  * next char is not digit
3973                  */
3974                 if (IS_LSIGN(Np->Num) && isread &&
3975                         (Np->inout_p + 1) <= Np->inout + plen &&
3976                         !isdigit((unsigned char) *(Np->inout_p + 1)))
3977                 {
3978                         int                     x;
3979                         char       *tmp = Np->inout_p++;
3980
3981 #ifdef DEBUG_TO_FROM_CHAR
3982                         elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
3983 #endif
3984                         if ((x = strlen(Np->L_negative_sign)) &&
3985                                 AMOUNT_TEST(x) &&
3986                                 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
3987                         {
3988                                 Np->inout_p += x - 1;   /* -1 .. NUM_processor() do inout_p++ */
3989                                 *Np->number = '-';
3990                         }
3991                         else if ((x = strlen(Np->L_positive_sign)) &&
3992                                          AMOUNT_TEST(x) &&
3993                                          strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
3994                         {
3995                                 Np->inout_p += x - 1;   /* -1 .. NUM_processor() do inout_p++ */
3996                                 *Np->number = '+';
3997                         }
3998                         if (*Np->number == ' ')
3999                                 /* no sign read */
4000                                 Np->inout_p = tmp;
4001                 }
4002
4003                 /*
4004                  * try read non-locale sign, it's happen only if format is not exact
4005                  * and we cannot determine sign position of MI/PL/SG, an example:
4006                  *
4007                  * FM9.999999MI                    -> 5.01-
4008                  *
4009                  * if (.... && IS_LSIGN(Np->Num)==FALSE) prevents read wrong formats
4010                  * like to_number('1 -', '9S') where sign is not anchored to last
4011                  * number.
4012                  */
4013                 else if (isread == FALSE && IS_LSIGN(Np->Num) == FALSE &&
4014                                  (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
4015                 {
4016 #ifdef DEBUG_TO_FROM_CHAR
4017                         elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
4018 #endif
4019
4020                         /*
4021                          * simple + -
4022                          */
4023                         if (*Np->inout_p == '-' || *Np->inout_p == '+')
4024                                 /* NUM_processor() do inout_p++ */
4025                                 *Np->number = *Np->inout_p;
4026                 }
4027         }
4028 }
4029
4030 #define IS_PREDEC_SPACE(_n) \
4031                 (IS_ZERO((_n)->Num)==FALSE && \
4032                  (_n)->number == (_n)->number_p && \
4033                  *(_n)->number == '0' && \
4034                                  (_n)->Num->post != 0)
4035
4036 /* ----------
4037  * Add digit or sign to number-string
4038  * ----------
4039  */
4040 static void
4041 NUM_numpart_to_char(NUMProc *Np, int id)
4042 {
4043         int                     end;
4044
4045         if (IS_ROMAN(Np->Num))
4046                 return;
4047
4048         /* Note: in this elog() output not set '\0' in 'inout' */
4049
4050 #ifdef DEBUG_TO_FROM_CHAR
4051
4052         /*
4053          * Np->num_curr is number of current item in format-picture, it is not
4054          * current position in inout!
4055          */
4056         elog(DEBUG_elog_output,
4057                  "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
4058                  Np->sign_wrote,
4059                  Np->num_curr,
4060                  Np->number_p,
4061                  Np->inout);
4062 #endif
4063         Np->num_in = FALSE;
4064
4065         /*
4066          * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
4067          * handle "9.9" --> " .1"
4068          */
4069         if (Np->sign_wrote == FALSE &&
4070                 (Np->num_curr >= Np->num_pre || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
4071                 (IS_PREDEC_SPACE(Np) == FALSE || (Np->last_relevant && *Np->last_relevant == '.')))
4072         {
4073                 if (IS_LSIGN(Np->Num))
4074                 {
4075                         if (Np->Num->lsign == NUM_LSIGN_PRE)
4076                         {
4077                                 if (Np->sign == '-')
4078                                         strcpy(Np->inout_p, Np->L_negative_sign);
4079                                 else
4080                                         strcpy(Np->inout_p, Np->L_positive_sign);
4081                                 Np->inout_p += strlen(Np->inout_p);
4082                                 Np->sign_wrote = TRUE;
4083                         }
4084                 }
4085                 else if (IS_BRACKET(Np->Num))
4086                 {
4087                         *Np->inout_p = Np->sign == '+' ? ' ' : '<';
4088                         ++Np->inout_p;
4089                         Np->sign_wrote = TRUE;
4090                 }
4091                 else if (Np->sign == '+')
4092                 {
4093                         if (!IS_FILLMODE(Np->Num))
4094                         {
4095                                 *Np->inout_p = ' ';             /* Write + */
4096                                 ++Np->inout_p;
4097                         }
4098                         Np->sign_wrote = TRUE;
4099                 }
4100                 else if (Np->sign == '-')
4101                 {                                               /* Write - */
4102                         *Np->inout_p = '-';
4103                         ++Np->inout_p;
4104                         Np->sign_wrote = TRUE;
4105                 }
4106         }
4107
4108
4109         /*
4110          * digits / FM / Zero / Dec. point
4111          */
4112         if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
4113         {
4114                 if (Np->num_curr < Np->num_pre &&
4115                         (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
4116                 {
4117                         /*
4118                          * Write blank space
4119                          */
4120                         if (!IS_FILLMODE(Np->Num))
4121                         {
4122                                 *Np->inout_p = ' ';             /* Write ' ' */
4123                                 ++Np->inout_p;
4124                         }
4125
4126                 }
4127                 else if (IS_ZERO(Np->Num) &&
4128                                  Np->num_curr < Np->num_pre &&
4129                                  Np->Num->zero_start <= Np->num_curr)
4130                 {
4131                         /*
4132                          * Write ZERO
4133                          */
4134                         *Np->inout_p = '0'; /* Write '0' */
4135                         ++Np->inout_p;
4136                         Np->num_in = TRUE;
4137
4138                 }
4139                 else
4140                 {
4141                         /*
4142                          * Write Decimal point
4143                          */
4144                         if (*Np->number_p == '.')
4145                         {
4146
4147                                 if (!Np->last_relevant || *Np->last_relevant != '.')
4148                                 {
4149                                         strcpy(Np->inout_p, Np->decimal);       /* Write DEC/D */
4150                                         Np->inout_p += strlen(Np->inout_p);
4151                                 }
4152
4153                                 /*
4154                                  * Ora 'n' -- FM9.9 --> 'n.'
4155                                  */
4156                                 else if (IS_FILLMODE(Np->Num) &&
4157                                                  Np->last_relevant && *Np->last_relevant == '.')
4158                                 {
4159
4160                                         strcpy(Np->inout_p, Np->decimal);       /* Write DEC/D */
4161                                         Np->inout_p += strlen(Np->inout_p);
4162                                 }
4163
4164                         }
4165                         else
4166                         {
4167                                 /*
4168                                  * Write Digits
4169                                  */
4170                                 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
4171                                         id != NUM_0)
4172                                         ;
4173
4174                                 /*
4175                                  * '0.1' -- 9.9 --> '  .1'
4176                                  */
4177                                 else if (IS_PREDEC_SPACE(Np))
4178                                 {
4179                                         if (!IS_FILLMODE(Np->Num))
4180                                         {
4181                                                 *Np->inout_p = ' ';
4182                                                 ++Np->inout_p;
4183                                         }
4184
4185                                         /*
4186                                          * '0' -- FM9.9 --> '0.'
4187                                          */
4188                                         else if (Np->last_relevant && *Np->last_relevant == '.')
4189                                         {
4190                                                 *Np->inout_p = '0';
4191                                                 ++Np->inout_p;
4192                                         }
4193                                 }
4194                                 else
4195                                 {
4196                                         *Np->inout_p = *Np->number_p;           /* Write DIGIT */
4197                                         ++Np->inout_p;
4198                                         Np->num_in = TRUE;
4199                                 }
4200                         }
4201                         ++Np->number_p;
4202                 }
4203
4204                 end = Np->num_count + (Np->num_pre ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
4205
4206                 if (Np->last_relevant && Np->last_relevant == Np->number_p)
4207                         end = Np->num_curr;
4208
4209                 if (Np->num_curr + 1 == end)
4210                 {
4211                         if (Np->sign_wrote == TRUE && IS_BRACKET(Np->Num))
4212                         {
4213                                 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
4214                                 ++Np->inout_p;
4215                         }
4216                         else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
4217                         {
4218                                 if (Np->sign == '-')
4219                                         strcpy(Np->inout_p, Np->L_negative_sign);
4220                                 else
4221                                         strcpy(Np->inout_p, Np->L_positive_sign);
4222                                 Np->inout_p += strlen(Np->inout_p);
4223                         }
4224                 }
4225         }
4226
4227         ++Np->num_curr;
4228 }
4229
4230 /*
4231  * Note: 'plen' is used in FROM_CHAR conversion and it's length of
4232  * input (inout). In TO_CHAR conversion it's space before first number.
4233  */
4234 static char *
4235 NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
4236                           int plen, int sign, bool is_to_char)
4237 {
4238         FormatNode *n;
4239         NUMProc         _Np,
4240                            *Np = &_Np;
4241
4242         MemSet(Np, 0, sizeof(NUMProc));
4243
4244         Np->Num = Num;
4245         Np->is_to_char = is_to_char;
4246         Np->number = number;
4247         Np->inout = inout;
4248         Np->last_relevant = NULL;
4249         Np->read_post = 0;
4250         Np->read_pre = 0;
4251         Np->read_dec = FALSE;
4252
4253         if (Np->Num->zero_start)
4254                 --Np->Num->zero_start;
4255
4256         /*
4257          * Roman correction
4258          */
4259         if (IS_ROMAN(Np->Num))
4260         {
4261                 if (!Np->is_to_char)
4262                         ereport(ERROR,
4263                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4264                                          errmsg("\"RN\" not supported")));
4265
4266                 Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->post =
4267                         Np->Num->pre = Np->num_pre = Np->sign = 0;
4268
4269                 if (IS_FILLMODE(Np->Num))
4270                 {
4271                         Np->Num->flag = 0;
4272                         Np->Num->flag |= NUM_F_FILLMODE;
4273                 }
4274                 else
4275                         Np->Num->flag = 0;
4276                 Np->Num->flag |= NUM_F_ROMAN;
4277         }
4278
4279         /*
4280          * Sign
4281          */
4282         if (is_to_char)
4283         {
4284                 Np->sign = sign;
4285
4286                 /* MI/PL/SG - write sign itself and not in number */
4287                 if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
4288                 {
4289                         if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == FALSE)
4290                                 Np->sign_wrote = FALSE; /* need sign */
4291                         else
4292                                 Np->sign_wrote = TRUE;  /* needn't sign */
4293                 }
4294                 else
4295                 {
4296                         if (Np->sign != '-')
4297                         {
4298                                 if (IS_BRACKET(Np->Num) && IS_FILLMODE(Np->Num))
4299                                         Np->Num->flag &= ~NUM_F_BRACKET;
4300                                 if (IS_MINUS(Np->Num))
4301                                         Np->Num->flag &= ~NUM_F_MINUS;
4302                         }
4303                         else if (Np->sign != '+' && IS_PLUS(Np->Num))
4304                                 Np->Num->flag &= ~NUM_F_PLUS;
4305
4306                         if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == FALSE)
4307                                 Np->sign_wrote = TRUE;  /* needn't sign */
4308                         else
4309                                 Np->sign_wrote = FALSE; /* need sign */
4310
4311                         if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
4312                                 Np->Num->lsign = NUM_LSIGN_POST;
4313                 }
4314         }
4315         else
4316                 Np->sign = FALSE;
4317
4318         /*
4319          * Count
4320          */
4321         Np->num_count = Np->Num->post + Np->Num->pre - 1;
4322
4323         if (is_to_char)
4324         {
4325                 Np->num_pre = plen;
4326
4327                 if (IS_FILLMODE(Np->Num))
4328                 {
4329                         if (IS_DECIMAL(Np->Num))
4330                                 Np->last_relevant = get_last_relevant_decnum(
4331                                                                                                                          Np->number +
4332                                                                          ((Np->Num->zero_end - Np->num_pre > 0) ?
4333                                                                           Np->Num->zero_end - Np->num_pre : 0));
4334                 }
4335
4336                 if (Np->sign_wrote == FALSE && Np->num_pre == 0)
4337                         ++Np->num_count;
4338         }
4339         else
4340         {
4341                 Np->num_pre = 0;
4342                 *Np->number = ' ';              /* sign space */
4343                 *(Np->number + 1) = '\0';
4344         }
4345
4346         Np->num_in = 0;
4347         Np->num_curr = 0;
4348
4349 #ifdef DEBUG_TO_FROM_CHAR
4350         elog(DEBUG_elog_output,
4351                  "\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",
4352                  Np->sign,
4353                  Np->number,
4354                  Np->Num->pre,
4355                  Np->Num->post,
4356                  Np->num_count,
4357                  Np->num_pre,
4358                  Np->sign_wrote ? "Yes" : "No",
4359                  IS_ZERO(Np->Num) ? "Yes" : "No",
4360                  Np->Num->zero_start,
4361                  Np->Num->zero_end,
4362                  Np->last_relevant ? Np->last_relevant : "<not set>",
4363                  IS_BRACKET(Np->Num) ? "Yes" : "No",
4364                  IS_PLUS(Np->Num) ? "Yes" : "No",
4365                  IS_MINUS(Np->Num) ? "Yes" : "No",
4366                  IS_FILLMODE(Np->Num) ? "Yes" : "No",
4367                  IS_ROMAN(Np->Num) ? "Yes" : "No"
4368                 );
4369 #endif
4370
4371         /*
4372          * Locale
4373          */
4374         NUM_prepare_locale(Np);
4375
4376         /*
4377          * Processor direct cycle
4378          */
4379         if (Np->is_to_char)
4380                 Np->number_p = Np->number;
4381         else
4382                 Np->number_p = Np->number + 1;  /* first char is space for sign */
4383
4384         for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
4385         {
4386                 if (!Np->is_to_char)
4387                 {
4388                         /*
4389                          * Check non-string inout end
4390                          */
4391                         if (Np->inout_p >= Np->inout + plen)
4392                                 break;
4393                 }
4394
4395                 /*
4396                  * Format pictures actions
4397                  */
4398                 if (n->type == NODE_TYPE_ACTION)
4399                 {
4400                         /*
4401                          * Create/reading digit/zero/blank/sing
4402                          *
4403                          * 'NUM_S' note: The locale sign is anchored to number and we
4404                          * read/write it when we work with first or last number
4405                          * (NUM_0/NUM_9). This is reason why NUM_S missing in follow
4406                          * switch().
4407                          */
4408                         switch (n->key->id)
4409                         {
4410
4411                                 case NUM_9:
4412                                 case NUM_0:
4413                                 case NUM_DEC:
4414                                 case NUM_D:
4415                                         if (Np->is_to_char)
4416                                         {
4417                                                 NUM_numpart_to_char(Np, n->key->id);
4418                                                 continue;               /* for() */
4419                                         }
4420                                         else
4421                                         {
4422                                                 NUM_numpart_from_char(Np, n->key->id, plen);
4423                                                 break;  /* switch() case: */
4424                                         }
4425
4426                                 case NUM_COMMA:
4427                                         if (Np->is_to_char)
4428                                         {
4429                                                 if (!Np->num_in)
4430                                                 {
4431                                                         if (IS_FILLMODE(Np->Num))
4432                                                                 continue;
4433                                                         else
4434                                                                 *Np->inout_p = ' ';
4435                                                 }
4436                                                 else
4437                                                         *Np->inout_p = ',';
4438                                         }
4439                                         else
4440                                         {
4441                                                 if (!Np->num_in)
4442                                                 {
4443                                                         if (IS_FILLMODE(Np->Num))
4444                                                                 continue;
4445                                                 }
4446                                         }
4447                                         break;
4448
4449                                 case NUM_G:
4450                                         if (Np->is_to_char)
4451                                         {
4452                                                 if (!Np->num_in)
4453                                                 {
4454                                                         if (IS_FILLMODE(Np->Num))
4455                                                                 continue;
4456                                                         else
4457                                                         {
4458                                                                 int                     x = strlen(Np->L_thousands_sep);
4459
4460                                                                 memset(Np->inout_p, ' ', x);
4461                                                                 Np->inout_p += x - 1;
4462                                                         }
4463                                                 }
4464                                                 else
4465                                                 {
4466                                                         strcpy(Np->inout_p, Np->L_thousands_sep);
4467                                                         Np->inout_p += strlen(Np->inout_p) - 1;
4468                                                 }
4469
4470                                         }
4471                                         else
4472                                         {
4473                                                 if (!Np->num_in)
4474                                                 {
4475                                                         if (IS_FILLMODE(Np->Num))
4476                                                                 continue;
4477                                                 }
4478                                                 Np->inout_p += strlen(Np->L_thousands_sep) - 1;
4479                                         }
4480                                         break;
4481
4482                                 case NUM_L:
4483                                         if (Np->is_to_char)
4484                                         {
4485                                                 strcpy(Np->inout_p, Np->L_currency_symbol);
4486                                                 Np->inout_p += strlen(Np->inout_p) - 1;
4487
4488                                         }
4489                                         else
4490                                                 Np->inout_p += strlen(Np->L_currency_symbol) - 1;
4491                                         break;
4492
4493                                 case NUM_RN:
4494                                         if (IS_FILLMODE(Np->Num))
4495                                         {
4496                                                 strcpy(Np->inout_p, Np->number_p);
4497                                                 Np->inout_p += strlen(Np->inout_p) - 1;
4498                                         }
4499                                         else
4500                                         {
4501                                                 sprintf(Np->inout_p, "%15s", Np->number_p);
4502                                                 Np->inout_p += strlen(Np->inout_p) - 1;
4503                                         }
4504                                         break;
4505
4506                                 case NUM_rn:
4507                                         if (IS_FILLMODE(Np->Num))
4508                                         {
4509                                                 strcpy(Np->inout_p, str_tolower(Np->number_p));
4510                                                 Np->inout_p += strlen(Np->inout_p) - 1;
4511                                         }
4512                                         else
4513                                         {
4514                                                 sprintf(Np->inout_p, "%15s", str_tolower(Np->number_p));
4515                                                 Np->inout_p += strlen(Np->inout_p) - 1;
4516                                         }
4517                                         break;
4518
4519                                 case NUM_th:
4520                                         if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
4521                                                 Np->sign == '-' || IS_DECIMAL(Np->Num))
4522                                                 continue;
4523
4524                                         if (Np->is_to_char)
4525                                                 strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
4526                                         Np->inout_p += 1;
4527                                         break;
4528
4529                                 case NUM_TH:
4530                                         if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
4531                                                 Np->sign == '-' || IS_DECIMAL(Np->Num))
4532                                                 continue;
4533
4534                                         if (Np->is_to_char)
4535                                                 strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
4536                                         Np->inout_p += 1;
4537                                         break;
4538
4539                                 case NUM_MI:
4540                                         if (Np->is_to_char)
4541                                         {
4542                                                 if (Np->sign == '-')
4543                                                         *Np->inout_p = '-';
4544                                                 else if (IS_FILLMODE(Np->Num))
4545                                                         continue;
4546                                                 else
4547                                                         *Np->inout_p = ' ';
4548
4549                                         }
4550                                         else
4551                                         {
4552                                                 if (*Np->inout_p == '-')
4553                                                         *Np->number = '-';
4554                                         }
4555                                         break;
4556
4557                                 case NUM_PL:
4558                                         if (Np->is_to_char)
4559                                         {
4560                                                 if (Np->sign == '+')
4561                                                         *Np->inout_p = '+';
4562                                                 else if (IS_FILLMODE(Np->Num))
4563                                                         continue;
4564                                                 else
4565                                                         *Np->inout_p = ' ';
4566
4567                                         }
4568                                         else
4569                                         {
4570                                                 if (*Np->inout_p == '+')
4571                                                         *Np->number = '+';
4572                                         }
4573                                         break;
4574
4575                                 case NUM_SG:
4576                                         if (Np->is_to_char)
4577                                                 *Np->inout_p = Np->sign;
4578
4579                                         else
4580                                         {
4581                                                 if (*Np->inout_p == '-')
4582                                                         *Np->number = '-';
4583                                                 else if (*Np->inout_p == '+')
4584                                                         *Np->number = '+';
4585                                         }
4586                                         break;
4587
4588
4589                                 default:
4590                                         continue;
4591                                         break;
4592                         }
4593
4594                 }
4595                 else
4596                 {
4597                         /*
4598                          * Remove to output char from input in TO_CHAR
4599                          */
4600                         if (Np->is_to_char)
4601                                 *Np->inout_p = n->character;
4602                 }
4603                 Np->inout_p++;
4604         }
4605
4606         if (Np->is_to_char)
4607         {
4608                 *Np->inout_p = '\0';
4609                 return Np->inout;
4610         }
4611         else
4612         {
4613                 if (*(Np->number_p - 1) == '.')
4614                         *(Np->number_p - 1) = '\0';
4615                 else
4616                         *Np->number_p = '\0';
4617
4618                 /*
4619                  * Correction - precision of dec. number
4620                  */
4621                 Np->Num->post = Np->read_post;
4622
4623 #ifdef DEBUG_TO_FROM_CHAR
4624                 elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
4625 #endif
4626                 return Np->number;
4627         }
4628 }
4629
4630 /* ----------
4631  * MACRO: Start part of NUM - for all NUM's to_char variants
4632  *      (sorry, but I hate copy same code - macro is better..)
4633  * ----------
4634  */
4635 #define NUM_TOCHAR_prepare \
4636 do { \
4637         len = VARSIZE(fmt) - VARHDRSZ;                                  \
4638         if (len <= 0)                                                   \
4639                 return DirectFunctionCall1(textin, CStringGetDatum(""));        \
4640         result  = (text *) palloc( (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
4641         memset(result, 0,  (len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ ); \
4642         format  = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);              \
4643 } while (0)
4644
4645 /* ----------
4646  * MACRO: Finish part of NUM
4647  * ----------
4648  */
4649 #define NUM_TOCHAR_finish \
4650 do { \
4651         NUM_processor(format, &Num, VARDATA(result),                    \
4652                 numstr, plen, sign, true);                              \
4653         pfree(orgnum);                                                  \
4654                                                                         \
4655         if (shouldFree)                                                 \
4656                 pfree(format);                                          \
4657                                                                         \
4658         /*
4659          * for result is allocated max memory, which current format-picture\
4660          * needs, now it must be re-allocate to result real size        \
4661          */                                                             \
4662         if (!(len = strlen(VARDATA(result))))                           \
4663         {                                                               \
4664                 pfree(result);                                          \
4665                 PG_RETURN_NULL();                                       \
4666         }                                                               \
4667                                                                         \
4668         result_tmp      = result;                                       \
4669         result          = (text *) palloc( len + 1 + VARHDRSZ);         \
4670                                                                         \
4671         strcpy( VARDATA(result), VARDATA(result_tmp));                  \
4672         VARATT_SIZEP(result) = len + VARHDRSZ;                          \
4673         pfree(result_tmp);                                              \
4674 } while(0)
4675
4676 /* -------------------
4677  * NUMERIC to_number() (convert string to numeric)
4678  * -------------------
4679  */
4680 Datum
4681 numeric_to_number(PG_FUNCTION_ARGS)
4682 {
4683         text       *value = PG_GETARG_TEXT_P(0);
4684         text       *fmt = PG_GETARG_TEXT_P(1);
4685         NUMDesc         Num;
4686         Datum           result;
4687         FormatNode *format;
4688         char       *numstr;
4689         bool            shouldFree;
4690         int                     len = 0;
4691         int                     scale,
4692                                 precision;
4693
4694         len = VARSIZE(fmt) - VARHDRSZ;
4695
4696         if (len <= 0)
4697                 PG_RETURN_NULL();
4698
4699         format = NUM_cache(len, &Num, VARDATA(fmt), &shouldFree);
4700
4701         numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
4702
4703         NUM_processor(format, &Num, VARDATA(value), numstr,
4704                                   VARSIZE(value) - VARHDRSZ, 0, false);
4705
4706         scale = Num.post;
4707         precision = Max(0, Num.pre) + scale;
4708
4709         if (shouldFree)
4710                 pfree(format);
4711
4712         result = DirectFunctionCall3(numeric_in,
4713                                                                  CStringGetDatum(numstr),
4714                                                                  ObjectIdGetDatum(InvalidOid),
4715                                           Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
4716         pfree(numstr);
4717         return result;
4718 }
4719
4720 /* ------------------
4721  * NUMERIC to_char()
4722  * ------------------
4723  */
4724 Datum
4725 numeric_to_char(PG_FUNCTION_ARGS)
4726 {
4727         Numeric         value = PG_GETARG_NUMERIC(0);
4728         text       *fmt = PG_GETARG_TEXT_P(1);
4729         NUMDesc         Num;
4730         FormatNode *format;
4731         text       *result,
4732                            *result_tmp;
4733         bool            shouldFree;
4734         int                     len = 0,
4735                                 plen = 0,
4736                                 sign = 0;
4737         char       *numstr,
4738                            *orgnum,
4739                            *p;
4740         Numeric         x;
4741
4742         NUM_TOCHAR_prepare;
4743
4744         /*
4745          * On DateType depend part (numeric)
4746          */
4747         if (IS_ROMAN(&Num))
4748         {
4749                 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
4750                                                                                                 NumericGetDatum(value),
4751                                                                                                 Int32GetDatum(0)));
4752                 numstr = orgnum =
4753                         int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
4754                                                                                                            NumericGetDatum(x))));
4755                 pfree(x);
4756         }
4757         else
4758         {
4759                 Numeric         val = value;
4760
4761                 if (IS_MULTI(&Num))
4762                 {
4763                         Numeric         a = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
4764                                                                                                                  Int32GetDatum(10)));
4765                         Numeric         b = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
4766                                                                                                   Int32GetDatum(Num.multi)));
4767
4768                         x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
4769                                                                                                         NumericGetDatum(a),
4770                                                                                                         NumericGetDatum(b)));
4771                         val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
4772                                                                                                           NumericGetDatum(value),
4773                                                                                                           NumericGetDatum(x)));
4774                         pfree(x);
4775                         pfree(a);
4776                         pfree(b);
4777                         Num.pre += Num.multi;
4778                 }
4779
4780                 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
4781                                                                                                 NumericGetDatum(val),
4782                                                                                                 Int32GetDatum(Num.post)));
4783                 orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
4784                                                                                                          NumericGetDatum(x)));
4785                 pfree(x);
4786
4787                 if (*orgnum == '-')
4788                 {                                               /* < 0 */
4789                         sign = '-';
4790                         numstr = orgnum + 1;
4791                 }
4792                 else
4793                 {
4794                         sign = '+';
4795                         numstr = orgnum;
4796                 }
4797                 if ((p = strchr(numstr, '.')))
4798                         len = p - numstr;
4799                 else
4800                         len = strlen(numstr);
4801
4802                 if (Num.pre > len)
4803                         plen = Num.pre - len;
4804                 else if (len > Num.pre)
4805                 {
4806                         fill_str(numstr, '#', Num.pre);
4807                         *(numstr + Num.pre) = '.';
4808                         fill_str(numstr + 1 + Num.pre, '#', Num.post);
4809                 }
4810
4811                 if (IS_MULTI(&Num))
4812                         pfree(val);
4813         }
4814
4815         NUM_TOCHAR_finish;
4816         PG_RETURN_TEXT_P(result);
4817 }
4818
4819 /* ---------------
4820  * INT4 to_char()
4821  * ---------------
4822  */
4823 Datum
4824 int4_to_char(PG_FUNCTION_ARGS)
4825 {
4826         int32           value = PG_GETARG_INT32(0);
4827         text       *fmt = PG_GETARG_TEXT_P(1);
4828         NUMDesc         Num;
4829         FormatNode *format;
4830         text       *result,
4831                            *result_tmp;
4832         bool            shouldFree;
4833         int                     len = 0,
4834                                 plen = 0,
4835                                 sign = 0;
4836         char       *numstr,
4837                            *orgnum;
4838
4839         NUM_TOCHAR_prepare;
4840
4841         /*
4842          * On DateType depend part (int32)
4843          */
4844         if (IS_ROMAN(&Num))
4845                 numstr = orgnum = int_to_roman(value);
4846         else
4847         {
4848                 if (IS_MULTI(&Num))
4849                 {
4850                         orgnum = DatumGetCString(DirectFunctionCall1(int4out,
4851                                                                                                                  Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
4852                         Num.pre += Num.multi;
4853                 }
4854                 else
4855                 {
4856                         orgnum = DatumGetCString(DirectFunctionCall1(int4out,
4857                                                                                                           Int32GetDatum(value)));
4858                 }
4859                 len = strlen(orgnum);
4860
4861                 if (*orgnum == '-')
4862                 {                                               /* < 0 */
4863                         sign = '-';
4864                         --len;
4865                 }
4866                 else
4867                         sign = '+';
4868
4869                 if (Num.post)
4870                 {
4871                         int                     i;
4872
4873                         numstr = (char *) palloc(len + Num.post + 2);
4874                         strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
4875                         *(numstr + len) = '.';
4876
4877                         for (i = len + 1; i <= len + Num.post; i++)
4878                                 *(numstr + i) = '0';
4879                         *(numstr + len + Num.post + 1) = '\0';
4880                         pfree(orgnum);
4881                         orgnum = numstr;
4882                 }
4883                 else
4884                         numstr = orgnum + (*orgnum == '-' ? 1 : 0);
4885
4886                 if (Num.pre > len)
4887                         plen = Num.pre - len;
4888                 else if (len > Num.pre)
4889                 {
4890                         fill_str(numstr, '#', Num.pre);
4891                         *(numstr + Num.pre) = '.';
4892                         fill_str(numstr + 1 + Num.pre, '#', Num.post);
4893                 }
4894         }
4895
4896         NUM_TOCHAR_finish;
4897         PG_RETURN_TEXT_P(result);
4898 }
4899
4900 /* ---------------
4901  * INT8 to_char()
4902  * ---------------
4903  */
4904 Datum
4905 int8_to_char(PG_FUNCTION_ARGS)
4906 {
4907         int64           value = PG_GETARG_INT64(0);
4908         text       *fmt = PG_GETARG_TEXT_P(1);
4909         NUMDesc         Num;
4910         FormatNode *format;
4911         text       *result,
4912                            *result_tmp;
4913         bool            shouldFree;
4914         int                     len = 0,
4915                                 plen = 0,
4916                                 sign = 0;
4917         char       *numstr,
4918                            *orgnum;
4919
4920         NUM_TOCHAR_prepare;
4921
4922         /*
4923          * On DateType depend part (int32)
4924          */
4925         if (IS_ROMAN(&Num))
4926         {
4927                 /* Currently don't support int8 conversion to roman... */
4928                 numstr = orgnum = int_to_roman(DatumGetInt32(
4929                                                   DirectFunctionCall1(int84, Int64GetDatum(value))));
4930         }
4931         else
4932         {
4933                 if (IS_MULTI(&Num))
4934                 {
4935                         double          multi = pow((double) 10, (double) Num.multi);
4936
4937                         value = DatumGetInt64(DirectFunctionCall2(int8mul,
4938                                                                                                           Int64GetDatum(value),
4939                                                                                                    DirectFunctionCall1(dtoi8,
4940                                                                                                         Float8GetDatum(multi))));
4941                         Num.pre += Num.multi;
4942                 }
4943
4944                 orgnum = DatumGetCString(DirectFunctionCall1(int8out,
4945                                                                                                          Int64GetDatum(value)));
4946                 len = strlen(orgnum);
4947
4948                 if (*orgnum == '-')
4949                 {                                               /* < 0 */
4950                         sign = '-';
4951                         --len;
4952                 }
4953                 else
4954                         sign = '+';
4955
4956                 if (Num.post)
4957                 {
4958                         int                     i;
4959
4960                         numstr = (char *) palloc(len + Num.post + 2);
4961                         strcpy(numstr, orgnum + (*orgnum == '-' ? 1 : 0));
4962                         *(numstr + len) = '.';
4963
4964                         for (i = len + 1; i <= len + Num.post; i++)
4965                                 *(numstr + i) = '0';
4966                         *(numstr + len + Num.post + 1) = '\0';
4967                         pfree(orgnum);
4968                         orgnum = numstr;
4969                 }
4970                 else
4971                         numstr = orgnum + (*orgnum == '-' ? 1 : 0);
4972
4973                 if (Num.pre > len)
4974                         plen = Num.pre - len;
4975                 else if (len > Num.pre)
4976                 {
4977                         fill_str(numstr, '#', Num.pre);
4978                         *(numstr + Num.pre) = '.';
4979                         fill_str(numstr + 1 + Num.pre, '#', Num.post);
4980                 }
4981         }
4982
4983         NUM_TOCHAR_finish;
4984         PG_RETURN_TEXT_P(result);
4985 }
4986
4987 /* -----------------
4988  * FLOAT4 to_char()
4989  * -----------------
4990  */
4991 Datum
4992 float4_to_char(PG_FUNCTION_ARGS)
4993 {
4994         float4          value = PG_GETARG_FLOAT4(0);
4995         text       *fmt = PG_GETARG_TEXT_P(1);
4996         NUMDesc         Num;
4997         FormatNode *format;
4998         text       *result,
4999                            *result_tmp;
5000         bool            shouldFree;
5001         int                     len = 0,
5002                                 plen = 0,
5003                                 sign = 0;
5004         char       *numstr,
5005                            *orgnum,
5006                            *p;
5007
5008         NUM_TOCHAR_prepare;
5009
5010         if (IS_ROMAN(&Num))
5011                 numstr = orgnum = int_to_roman((int) rint(value));
5012         else
5013         {
5014                 float4          val = value;
5015
5016                 if (IS_MULTI(&Num))
5017                 {
5018                         float           multi = pow((double) 10, (double) Num.multi);
5019
5020                         val = value * multi;
5021                         Num.pre += Num.multi;
5022                 }
5023
5024                 orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
5025                 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
5026                 len = strlen(orgnum);
5027                 if (Num.pre > len)
5028                         plen = Num.pre - len;
5029                 if (len >= FLT_DIG)
5030                         Num.post = 0;
5031                 else if (Num.post + len > FLT_DIG)
5032                         Num.post = FLT_DIG - len;
5033                 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
5034
5035                 if (*orgnum == '-')
5036                 {                                               /* < 0 */
5037                         sign = '-';
5038                         numstr = orgnum + 1;
5039                 }
5040                 else
5041                 {
5042                         sign = '+';
5043                         numstr = orgnum;
5044                 }
5045                 if ((p = strchr(numstr, '.')))
5046                         len = p - numstr;
5047                 else
5048                         len = strlen(numstr);
5049
5050                 if (Num.pre > len)
5051                         plen = Num.pre - len;
5052                 else if (len > Num.pre)
5053                 {
5054                         fill_str(numstr, '#', Num.pre);
5055                         *(numstr + Num.pre) = '.';
5056                         fill_str(numstr + 1 + Num.pre, '#', Num.post);
5057                 }
5058         }
5059
5060         NUM_TOCHAR_finish;
5061         PG_RETURN_TEXT_P(result);
5062 }
5063
5064 /* -----------------
5065  * FLOAT8 to_char()
5066  * -----------------
5067  */
5068 Datum
5069 float8_to_char(PG_FUNCTION_ARGS)
5070 {
5071         float8          value = PG_GETARG_FLOAT8(0);
5072         text       *fmt = PG_GETARG_TEXT_P(1);
5073         NUMDesc         Num;
5074         FormatNode *format;
5075         text       *result,
5076                            *result_tmp;
5077         bool            shouldFree;
5078         int                     len = 0,
5079                                 plen = 0,
5080                                 sign = 0;
5081         char       *numstr,
5082                            *orgnum,
5083                            *p;
5084
5085         NUM_TOCHAR_prepare;
5086
5087         if (IS_ROMAN(&Num))
5088                 numstr = orgnum = int_to_roman((int) rint(value));
5089         else
5090         {
5091                 float8          val = value;
5092
5093                 if (IS_MULTI(&Num))
5094                 {
5095                         double          multi = pow((double) 10, (double) Num.multi);
5096
5097                         val = value * multi;
5098                         Num.pre += Num.multi;
5099                 }
5100                 orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5101                 len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val));
5102                 if (Num.pre > len)
5103                         plen = Num.pre - len;
5104                 if (len >= DBL_DIG)
5105                         Num.post = 0;
5106                 else if (Num.post + len > DBL_DIG)
5107                         Num.post = DBL_DIG - len;
5108                 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
5109
5110                 if (*orgnum == '-')
5111                 {                                               /* < 0 */
5112                         sign = '-';
5113                         numstr = orgnum + 1;
5114                 }
5115                 else
5116                 {
5117                         sign = '+';
5118                         numstr = orgnum;
5119                 }
5120                 if ((p = strchr(numstr, '.')))
5121                         len = p - numstr;
5122                 else
5123                         len = strlen(numstr);
5124
5125                 if (Num.pre > len)
5126                         plen = Num.pre - len;
5127                 else if (len > Num.pre)
5128                 {
5129                         fill_str(numstr, '#', Num.pre);
5130                         *(numstr + Num.pre) = '.';
5131                         fill_str(numstr + 1 + Num.pre, '#', Num.post);
5132                 }
5133         }
5134
5135         NUM_TOCHAR_finish;
5136         PG_RETURN_TEXT_P(result);
5137 }