1 /* -----------------------------------------------------------------------
4 * src/backend/utils/adt/formatting.c
7 * Portions Copyright (c) 1999-2017, PostgreSQL Global Development Group
10 * TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER();
12 * The PostgreSQL routines for a timestamp/int/float/numeric formatting,
13 * inspired by the Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines.
17 * Routines use (itself) internal cache for format pictures.
19 * The cache uses a static buffer and is persistent across transactions. If
20 * the format-picture is bigger than the cache buffer, the parser is called
23 * NOTE for Number version:
24 * All in this version is implemented as keywords ( => not used
25 * suffixes), because a format picture is for *one* item (number)
26 * only. It not is as a timestamp version, where each keyword (can)
29 * NOTE for Timestamp routines:
30 * In this module the POSIX 'struct tm' type is *not* used, but rather
31 * PgSQL type, which has tm_mon based on one (*non* zero) and
32 * year *not* based on 1900, but is used full year number.
33 * Module supports AD / BC / AM / PM.
35 * Supported types for to_char():
37 * Timestamp, Numeric, int4, int8, float4, float8
39 * Supported types for reverse conversion:
41 * Timestamp - to_timestamp()
43 * Numeric - to_number()
49 * - better number building (formatting) / parsing, now it isn't
52 * - add support for abstime
53 * - add support for roman number to standard number conversion
54 * - add support for number spelling
55 * - add support for string to string formatting (we must be better
57 * to_char('Hello', 'X X X X X') -> 'H e l l o'
59 * -----------------------------------------------------------------------
62 #ifdef DEBUG_TO_FROM_CHAR
63 #define DEBUG_elog_output DEBUG3
75 * towlower() and friends should be in <wctype.h>, but some pre-C99 systems
76 * declare them in <wchar.h>.
85 #include "catalog/pg_collation.h"
86 #include "mb/pg_wchar.h"
87 #include "utils/builtins.h"
88 #include "utils/date.h"
89 #include "utils/datetime.h"
90 #include "utils/formatting.h"
91 #include "utils/int8.h"
92 #include "utils/numeric.h"
93 #include "utils/pg_locale.h"
99 #define DCH_TYPE 1 /* DATE-TIME version */
100 #define NUM_TYPE 2 /* NUMBER version */
103 * KeyWord Index (ascii from position 32 (' ') to 126 (~))
106 #define KeyWord_INDEX_SIZE ('~' - ' ')
107 #define KeyWord_INDEX_FILTER(_c) ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
110 * Maximal length of one node
113 #define DCH_MAX_ITEM_SIZ 12 /* max localized day name */
114 #define NUM_MAX_ITEM_SIZ 8 /* roman number (RN has 15 chars) */
120 #define MAXFLOATWIDTH 60
121 #define MAXDOUBLEWIDTH 500
125 * Format parser structs
130 char *name; /* suffix string */
131 int len, /* suffix length */
132 id, /* used in node->suffix */
133 type; /* prefix / postfix */
140 * This value is used to nominate one of several distinct (and mutually
141 * exclusive) date conventions that a keyword can belong to.
145 FROM_CHAR_DATE_NONE = 0, /* Value does not affect date mode. */
146 FROM_CHAR_DATE_GREGORIAN, /* Gregorian (day, month, year) style date */
147 FROM_CHAR_DATE_ISOWEEK /* ISO 8601 week date */
150 typedef struct FormatNode FormatNode;
158 FromCharDateMode date_mode;
163 int type; /* node type */
164 const KeyWord *key; /* if node type is KEYWORD */
165 char character; /* if node type is CHAR */
166 int suffix; /* keyword suffix */
169 #define NODE_TYPE_END 1
170 #define NODE_TYPE_ACTION 2
171 #define NODE_TYPE_CHAR 3
173 #define SUFFTYPE_PREFIX 1
174 #define SUFFTYPE_POSTFIX 2
176 #define CLOCK_24_HOUR 0
177 #define CLOCK_12_HOUR 1
184 static const char *const months_full[] = {
185 "January", "February", "March", "April", "May", "June", "July",
186 "August", "September", "October", "November", "December", NULL
189 static const char *const days_short[] = {
190 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
196 * There is no 0 AD. Years go from 1 BC to 1 AD, so we make it
197 * positive and map year == -1 to year zero, and shift all negative
198 * years up one. For interval years, we just return the year.
200 #define ADJUST_YEAR(year, is_interval) ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
202 #define A_D_STR "A.D."
203 #define a_d_STR "a.d."
207 #define B_C_STR "B.C."
208 #define b_c_STR "b.c."
213 * AD / BC strings for seq_search.
215 * These are given in two variants, a long form with periods and a standard
218 * The array is laid out such that matches for AD have an even index, and
219 * matches for BC have an odd index. So the boolean value for BC is given by
220 * taking the array index of the match, modulo 2.
222 static const char *const adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL};
223 static const char *const adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL};
229 #define A_M_STR "A.M."
230 #define a_m_STR "a.m."
234 #define P_M_STR "P.M."
235 #define p_m_STR "p.m."
240 * AM / PM strings for seq_search.
242 * These are given in two variants, a long form with periods and a standard
245 * The array is laid out such that matches for AM have an even index, and
246 * matches for PM have an odd index. So the boolean value for PM is given by
247 * taking the array index of the match, modulo 2.
249 static const char *const ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL};
250 static const char *const ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL};
253 * Months in roman-numeral
254 * (Must be in reverse order for seq_search (in FROM_CHAR), because
255 * 'VIII' must have higher precedence than 'V')
258 static const char *const rm_months_upper[] =
259 {"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};
261 static const char *const rm_months_lower[] =
262 {"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};
268 static const char *const rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};
269 static const char *const rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};
270 static const char *const rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};
276 static const char *const numTH[] = {"ST", "ND", "RD", "TH", NULL};
277 static const char *const numth[] = {"st", "nd", "rd", "th", NULL};
283 #define ONE_UPPER 1 /* Name */
284 #define ALL_UPPER 2 /* NAME */
285 #define ALL_LOWER 3 /* name */
289 #define MAX_MONTH_LEN 9
290 #define MAX_MON_LEN 3
291 #define MAX_DAY_LEN 9
299 * Number description struct
304 int pre, /* (count) numbers before decimal */
305 post, /* (count) numbers after decimal */
306 lsign, /* want locales sign */
307 flag, /* number parameters */
308 pre_lsign_num, /* tmp value for lsign */
309 multi, /* multiplier for 'V' */
310 zero_start, /* position of first zero */
311 zero_end, /* position of last zero */
312 need_locale; /* needs it locale */
316 * Flags for NUMBER version
319 #define NUM_F_DECIMAL (1 << 1)
320 #define NUM_F_LDECIMAL (1 << 2)
321 #define NUM_F_ZERO (1 << 3)
322 #define NUM_F_BLANK (1 << 4)
323 #define NUM_F_FILLMODE (1 << 5)
324 #define NUM_F_LSIGN (1 << 6)
325 #define NUM_F_BRACKET (1 << 7)
326 #define NUM_F_MINUS (1 << 8)
327 #define NUM_F_PLUS (1 << 9)
328 #define NUM_F_ROMAN (1 << 10)
329 #define NUM_F_MULTI (1 << 11)
330 #define NUM_F_PLUS_POST (1 << 12)
331 #define NUM_F_MINUS_POST (1 << 13)
332 #define NUM_F_EEEE (1 << 14)
334 #define NUM_LSIGN_PRE (-1)
335 #define NUM_LSIGN_POST 1
336 #define NUM_LSIGN_NONE 0
342 #define IS_DECIMAL(_f) ((_f)->flag & NUM_F_DECIMAL)
343 #define IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL)
344 #define IS_ZERO(_f) ((_f)->flag & NUM_F_ZERO)
345 #define IS_BLANK(_f) ((_f)->flag & NUM_F_BLANK)
346 #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE)
347 #define IS_BRACKET(_f) ((_f)->flag & NUM_F_BRACKET)
348 #define IS_MINUS(_f) ((_f)->flag & NUM_F_MINUS)
349 #define IS_LSIGN(_f) ((_f)->flag & NUM_F_LSIGN)
350 #define IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
351 #define IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN)
352 #define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI)
353 #define IS_EEEE(_f) ((_f)->flag & NUM_F_EEEE)
356 * Format picture cache
358 * We will cache datetime format pictures up to DCH_CACHE_SIZE bytes long;
359 * likewise number format pictures up to NUM_CACHE_SIZE bytes long.
361 * For simplicity, the cache entries are fixed-size, so they allow for the
362 * worst case of a FormatNode for each byte in the picture string.
364 * The max number of entries in the caches is DCH_CACHE_ENTRIES
365 * resp. NUM_CACHE_ENTRIES.
368 #define NUM_CACHE_SIZE 64
369 #define NUM_CACHE_ENTRIES 20
370 #define DCH_CACHE_SIZE 128
371 #define DCH_CACHE_ENTRIES 20
375 FormatNode format[DCH_CACHE_SIZE + 1];
376 char str[DCH_CACHE_SIZE + 1];
383 FormatNode format[NUM_CACHE_SIZE + 1];
384 char str[NUM_CACHE_SIZE + 1];
390 /* global cache for date/time format pictures */
391 static DCHCacheEntry DCHCache[DCH_CACHE_ENTRIES];
392 static int n_DCHCache = 0; /* current number of entries */
393 static int DCHCounter = 0; /* aging-event counter */
395 /* global cache for number format pictures */
396 static NUMCacheEntry NUMCache[NUM_CACHE_ENTRIES];
397 static int n_NUMCache = 0; /* current number of entries */
398 static int NUMCounter = 0; /* aging-event counter */
401 * For char->date/time conversion
406 FromCharDateMode mode;
412 d, /* stored as 1-7, Sunday = 1, 0 means missing */
424 yysz, /* is it YY or YYYY ? */
425 clock; /* 12 or 24 hour clock? */
428 #define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
434 #ifdef DEBUG_TO_FROM_CHAR
435 #define DEBUG_TMFC(_X) \
436 elog(DEBUG_elog_output, "TMFC:\nmode %d\nhh %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nms: %d\nyear %d\nbc %d\nww %d\nw %d\ncc %d\nj %d\nus: %d\nyysz: %d\nclock: %d", \
437 (_X)->mode, (_X)->hh, (_X)->pm, (_X)->mi, (_X)->ss, (_X)->ssss, \
438 (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, (_X)->year, \
439 (_X)->bc, (_X)->ww, (_X)->w, (_X)->cc, (_X)->j, (_X)->us, \
440 (_X)->yysz, (_X)->clock);
441 #define DEBUG_TM(_X) \
442 elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
443 (_X)->tm_sec, (_X)->tm_year,\
444 (_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\
445 (_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)
447 #define DEBUG_TMFC(_X)
452 * Datetime to char conversion
455 typedef struct TmToChar
457 struct pg_tm tm; /* classic 'tm' struct */
458 fsec_t fsec; /* fractional seconds */
459 const char *tzn; /* timezone */
462 #define tmtcTm(_X) (&(_X)->tm)
463 #define tmtcTzn(_X) ((_X)->tzn)
464 #define tmtcFsec(_X) ((_X)->fsec)
466 #define ZERO_tm(_X) \
468 (_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
469 (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
470 (_X)->tm_mday = (_X)->tm_mon = 1; \
473 #define ZERO_tmtc(_X) \
475 ZERO_tm( tmtcTm(_X) ); \
477 tmtcTzn(_X) = NULL; \
481 * to_char(time) appears to to_char() as an interval, so this check
482 * is really for interval and time data types.
484 #define INVALID_FOR_INTERVAL \
488 (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
489 errmsg("invalid format specification for an interval value"), \
490 errhint("Intervals are not tied to specific calendar dates."))); \
493 /*****************************************************************************
494 * KeyWord definitions
495 *****************************************************************************/
501 #define DCH_S_FM 0x01
502 #define DCH_S_TH 0x02
503 #define DCH_S_th 0x04
504 #define DCH_S_SP 0x08
505 #define DCH_S_TM 0x10
511 #define S_THth(_s) ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)
512 #define S_TH(_s) (((_s) & DCH_S_TH) ? 1 : 0)
513 #define S_th(_s) (((_s) & DCH_S_th) ? 1 : 0)
514 #define S_TH_TYPE(_s) (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)
516 /* Oracle toggles FM behavior, we don't; see docs. */
517 #define S_FM(_s) (((_s) & DCH_S_FM) ? 1 : 0)
518 #define S_SP(_s) (((_s) & DCH_S_SP) ? 1 : 0)
519 #define S_TM(_s) (((_s) & DCH_S_TM) ? 1 : 0)
522 * Suffixes definition for DATE-TIME TO/FROM CHAR
525 #define TM_SUFFIX_LEN 2
527 static const KeySuffix DCH_suff[] = {
528 {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
529 {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
530 {"TM", TM_SUFFIX_LEN, DCH_S_TM, SUFFTYPE_PREFIX},
531 {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
532 {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
533 {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
534 {"SP", 2, DCH_S_SP, SUFFTYPE_POSTFIX},
541 * Format-pictures (KeyWord).
543 * The KeyWord field; alphabetic sorted, *BUT* strings alike is sorted
544 * complicated -to-> easy:
546 * (example: "DDD","DD","Day","D" )
548 * (this specific sort needs the algorithm for sequential search for strings,
549 * which not has exact end; -> How keyword is in "HH12blabla" ? - "HH"
550 * or "HH12"? You must first try "HH12", because "HH" is in string, but
554 * - Position for the keyword is similar as position in the enum DCH/NUM_poz.
557 * For fast search is used the 'int index[]', index is ascii table from position
558 * 32 (' ') to 126 (~), in this index is DCH_ / NUM_ enums for each ASCII
559 * position or -1 if char is not used in the KeyWord. Search example for
561 * 1) see in index to index['M' - 32],
562 * 2) take keywords position (enum DCH_MI) from index
563 * 3) run sequential search in keywords[] from this position
584 DCH_FX, /* global suffix */
712 * KeyWords for DATE-TIME version
715 static const KeyWord DCH_keywords[] = {
716 /* name, len, id, is_digit, date_mode */
717 {"A.D.", 4, DCH_A_D, FALSE, FROM_CHAR_DATE_NONE}, /* A */
718 {"A.M.", 4, DCH_A_M, FALSE, FROM_CHAR_DATE_NONE},
719 {"AD", 2, DCH_AD, FALSE, FROM_CHAR_DATE_NONE},
720 {"AM", 2, DCH_AM, FALSE, FROM_CHAR_DATE_NONE},
721 {"B.C.", 4, DCH_B_C, FALSE, FROM_CHAR_DATE_NONE}, /* B */
722 {"BC", 2, DCH_BC, FALSE, FROM_CHAR_DATE_NONE},
723 {"CC", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE}, /* C */
724 {"DAY", 3, DCH_DAY, FALSE, FROM_CHAR_DATE_NONE}, /* D */
725 {"DDD", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
726 {"DD", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
727 {"DY", 2, DCH_DY, FALSE, FROM_CHAR_DATE_NONE},
728 {"Day", 3, DCH_Day, FALSE, FROM_CHAR_DATE_NONE},
729 {"Dy", 2, DCH_Dy, FALSE, FROM_CHAR_DATE_NONE},
730 {"D", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
731 {"FX", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE}, /* F */
732 {"HH24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE}, /* H */
733 {"HH12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
734 {"HH", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
735 {"IDDD", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK}, /* I */
736 {"ID", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
737 {"IW", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
738 {"IYYY", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
739 {"IYY", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
740 {"IY", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
741 {"I", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
742 {"J", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE}, /* J */
743 {"MI", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE}, /* M */
744 {"MM", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
745 {"MONTH", 5, DCH_MONTH, FALSE, FROM_CHAR_DATE_GREGORIAN},
746 {"MON", 3, DCH_MON, FALSE, FROM_CHAR_DATE_GREGORIAN},
747 {"MS", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
748 {"Month", 5, DCH_Month, FALSE, FROM_CHAR_DATE_GREGORIAN},
749 {"Mon", 3, DCH_Mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
750 {"OF", 2, DCH_OF, FALSE, FROM_CHAR_DATE_NONE}, /* O */
751 {"P.M.", 4, DCH_P_M, FALSE, FROM_CHAR_DATE_NONE}, /* P */
752 {"PM", 2, DCH_PM, FALSE, FROM_CHAR_DATE_NONE},
753 {"Q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE}, /* Q */
754 {"RM", 2, DCH_RM, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* R */
755 {"SSSS", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE}, /* S */
756 {"SS", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
757 {"TZ", 2, DCH_TZ, FALSE, FROM_CHAR_DATE_NONE}, /* T */
758 {"US", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE}, /* U */
759 {"WW", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* W */
760 {"W", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
761 {"Y,YYY", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* Y */
762 {"YYYY", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
763 {"YYY", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
764 {"YY", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
765 {"Y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
766 {"a.d.", 4, DCH_a_d, FALSE, FROM_CHAR_DATE_NONE}, /* a */
767 {"a.m.", 4, DCH_a_m, FALSE, FROM_CHAR_DATE_NONE},
768 {"ad", 2, DCH_ad, FALSE, FROM_CHAR_DATE_NONE},
769 {"am", 2, DCH_am, FALSE, FROM_CHAR_DATE_NONE},
770 {"b.c.", 4, DCH_b_c, FALSE, FROM_CHAR_DATE_NONE}, /* b */
771 {"bc", 2, DCH_bc, FALSE, FROM_CHAR_DATE_NONE},
772 {"cc", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE}, /* c */
773 {"day", 3, DCH_day, FALSE, FROM_CHAR_DATE_NONE}, /* d */
774 {"ddd", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
775 {"dd", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
776 {"dy", 2, DCH_dy, FALSE, FROM_CHAR_DATE_NONE},
777 {"d", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
778 {"fx", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE}, /* f */
779 {"hh24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE}, /* h */
780 {"hh12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
781 {"hh", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
782 {"iddd", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK}, /* i */
783 {"id", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
784 {"iw", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
785 {"iyyy", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
786 {"iyy", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
787 {"iy", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
788 {"i", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
789 {"j", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE}, /* j */
790 {"mi", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE}, /* m */
791 {"mm", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
792 {"month", 5, DCH_month, FALSE, FROM_CHAR_DATE_GREGORIAN},
793 {"mon", 3, DCH_mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
794 {"ms", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
795 {"p.m.", 4, DCH_p_m, FALSE, FROM_CHAR_DATE_NONE}, /* p */
796 {"pm", 2, DCH_pm, FALSE, FROM_CHAR_DATE_NONE},
797 {"q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE}, /* q */
798 {"rm", 2, DCH_rm, FALSE, FROM_CHAR_DATE_GREGORIAN}, /* r */
799 {"ssss", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE}, /* s */
800 {"ss", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
801 {"tz", 2, DCH_tz, FALSE, FROM_CHAR_DATE_NONE}, /* t */
802 {"us", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE}, /* u */
803 {"ww", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* w */
804 {"w", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
805 {"y,yyy", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN}, /* y */
806 {"yyyy", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
807 {"yyy", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
808 {"yy", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
809 {"y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
816 * KeyWords for NUMBER version
818 * The is_digit and date_mode fields are not relevant here.
821 static const KeyWord NUM_keywords[] = {
822 /* name, len, id is in Index */
823 {",", 1, NUM_COMMA}, /* , */
824 {".", 1, NUM_DEC}, /* . */
825 {"0", 1, NUM_0}, /* 0 */
826 {"9", 1, NUM_9}, /* 9 */
827 {"B", 1, NUM_B}, /* B */
828 {"C", 1, NUM_C}, /* C */
829 {"D", 1, NUM_D}, /* D */
830 {"EEEE", 4, NUM_E}, /* E */
831 {"FM", 2, NUM_FM}, /* F */
832 {"G", 1, NUM_G}, /* G */
833 {"L", 1, NUM_L}, /* L */
834 {"MI", 2, NUM_MI}, /* M */
835 {"PL", 2, NUM_PL}, /* P */
837 {"RN", 2, NUM_RN}, /* R */
838 {"SG", 2, NUM_SG}, /* S */
841 {"TH", 2, NUM_TH}, /* T */
842 {"V", 1, NUM_V}, /* V */
843 {"b", 1, NUM_B}, /* b */
844 {"c", 1, NUM_C}, /* c */
845 {"d", 1, NUM_D}, /* d */
846 {"eeee", 4, NUM_E}, /* e */
847 {"fm", 2, NUM_FM}, /* f */
848 {"g", 1, NUM_G}, /* g */
849 {"l", 1, NUM_L}, /* l */
850 {"mi", 2, NUM_MI}, /* m */
851 {"pl", 2, NUM_PL}, /* p */
853 {"rn", 2, NUM_rn}, /* r */
854 {"sg", 2, NUM_SG}, /* s */
857 {"th", 2, NUM_th}, /* t */
858 {"v", 1, NUM_V}, /* v */
866 * KeyWords index for DATE-TIME version
869 static const int DCH_index[KeyWord_INDEX_SIZE] = {
873 /*---- first 0..31 chars are skipped ----*/
875 -1, -1, -1, -1, -1, -1, -1, -1,
876 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
877 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
878 -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
879 DCH_FX, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, DCH_OF,
880 DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY,
881 -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
882 DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
883 -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww,
884 -1, DCH_y_yyy, -1, -1, -1, -1
886 /*---- chars over 126 are skipped ----*/
890 * KeyWords index for NUMBER version
893 static const int NUM_index[KeyWord_INDEX_SIZE] = {
897 /*---- first 0..31 chars are skipped ----*/
899 -1, -1, -1, -1, -1, -1, -1, -1,
900 -1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
901 -1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
902 -1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
903 NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
904 NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
905 -1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
906 NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
907 -1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
908 -1, -1, -1, -1, -1, -1
910 /*---- chars over 126 are skipped ----*/
914 * Number processor struct
917 typedef struct NUMProc
920 NUMDesc *Num; /* number description */
922 int sign, /* '-' or '+' */
923 sign_wrote, /* was sign write */
924 num_count, /* number of write digits */
925 num_in, /* is inside number */
926 num_curr, /* current position in number */
927 out_pre_spaces, /* spaces before first digit */
929 read_dec, /* to_number - was read dec. point */
930 read_post, /* to_number - number of dec. digit */
931 read_pre; /* to_number - number non-dec. digit */
933 char *number, /* string with number */
934 *number_p, /* pointer to current number position */
935 *inout, /* in / out buffer */
936 *inout_p, /* pointer to current inout position */
937 *last_relevant, /* last relevant number after decimal point */
939 *L_negative_sign, /* Locale */
951 static const KeyWord *index_seq_search(const char *str, const KeyWord *kw,
953 static const KeySuffix *suff_search(const char *str, const KeySuffix *suf, int type);
954 static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
955 static void parse_format(FormatNode *node, const char *str, const KeyWord *kw,
956 const KeySuffix *suf, const int *index, int ver, NUMDesc *Num);
958 static void DCH_to_char(FormatNode *node, bool is_interval,
959 TmToChar *in, char *out, Oid collid);
960 static void DCH_from_char(FormatNode *node, char *in, TmFromChar *out);
962 #ifdef DEBUG_TO_FROM_CHAR
963 static void dump_index(const KeyWord *k, const int *index);
964 static void dump_node(FormatNode *node, int max);
967 static const char *get_th(char *num, int type);
968 static char *str_numth(char *dest, char *num, int type);
969 static int adjust_partial_year_to_2020(int year);
970 static int strspace_len(char *str);
971 static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode);
972 static void from_char_set_int(int *dest, const int value, const FormatNode *node);
973 static int from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node);
974 static int from_char_parse_int(int *dest, char **src, FormatNode *node);
975 static int seq_search(char *name, const char *const * array, int type, int max, int *len);
976 static int from_char_seq_search(int *dest, char **src, const char *const * array, int type, int max, FormatNode *node);
977 static void do_to_timestamp(text *date_txt, text *fmt,
978 struct pg_tm * tm, fsec_t *fsec);
979 static char *fill_str(char *str, int c, int max);
980 static FormatNode *NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree);
981 static char *int_to_roman(int number);
982 static void NUM_prepare_locale(NUMProc *Np);
983 static char *get_last_relevant_decnum(char *num);
984 static void NUM_numpart_from_char(NUMProc *Np, int id, int input_len);
985 static void NUM_numpart_to_char(NUMProc *Np, int id);
986 static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout,
987 char *number, int from_char_input_len, int to_char_out_pre_spaces,
988 int sign, bool is_to_char, Oid collid);
989 static DCHCacheEntry *DCH_cache_getnew(const char *str);
990 static DCHCacheEntry *DCH_cache_search(const char *str);
991 static DCHCacheEntry *DCH_cache_fetch(const char *str);
992 static NUMCacheEntry *NUM_cache_getnew(const char *str);
993 static NUMCacheEntry *NUM_cache_search(const char *str);
994 static NUMCacheEntry *NUM_cache_fetch(const char *str);
998 * Fast sequential search, use index for data selection which
999 * go to seq. cycle (it is very fast for unwanted strings)
1000 * (can't be used binary search in format parsing)
1003 static const KeyWord *
1004 index_seq_search(const char *str, const KeyWord *kw, const int *index)
1008 if (!KeyWord_INDEX_FILTER(*str))
1011 if ((poz = *(index + (*str - ' '))) > -1)
1013 const KeyWord *k = kw + poz;
1017 if (strncmp(str, k->name, k->len) == 0)
1022 } while (*str == *k->name);
1027 static const KeySuffix *
1028 suff_search(const char *str, const KeySuffix *suf, int type)
1032 for (s = suf; s->name != NULL; s++)
1034 if (s->type != type)
1037 if (strncmp(str, s->name, s->len) == 0)
1044 * Prepare NUMDesc (number description struct) via FormatNode struct
1048 NUMDesc_prepare(NUMDesc *num, FormatNode *n)
1050 if (n->type != NODE_TYPE_ACTION)
1053 if (IS_EEEE(num) && n->key->id != NUM_E)
1055 (errcode(ERRCODE_SYNTAX_ERROR),
1056 errmsg("\"EEEE\" must be the last pattern used")));
1061 if (IS_BRACKET(num))
1063 (errcode(ERRCODE_SYNTAX_ERROR),
1064 errmsg("\"9\" must be ahead of \"PR\"")));
1070 if (IS_DECIMAL(num))
1077 if (IS_BRACKET(num))
1079 (errcode(ERRCODE_SYNTAX_ERROR),
1080 errmsg("\"0\" must be ahead of \"PR\"")));
1081 if (!IS_ZERO(num) && !IS_DECIMAL(num))
1083 num->flag |= NUM_F_ZERO;
1084 num->zero_start = num->pre + 1;
1086 if (!IS_DECIMAL(num))
1091 num->zero_end = num->pre + num->post;
1095 if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num)))
1096 num->flag |= NUM_F_BLANK;
1100 num->flag |= NUM_F_LDECIMAL;
1101 num->need_locale = TRUE;
1104 if (IS_DECIMAL(num))
1106 (errcode(ERRCODE_SYNTAX_ERROR),
1107 errmsg("multiple decimal points")));
1110 (errcode(ERRCODE_SYNTAX_ERROR),
1111 errmsg("cannot use \"V\" and decimal point together")));
1112 num->flag |= NUM_F_DECIMAL;
1116 num->flag |= NUM_F_FILLMODE;
1122 (errcode(ERRCODE_SYNTAX_ERROR),
1123 errmsg("cannot use \"S\" twice")));
1124 if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
1126 (errcode(ERRCODE_SYNTAX_ERROR),
1127 errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
1128 if (!IS_DECIMAL(num))
1130 num->lsign = NUM_LSIGN_PRE;
1131 num->pre_lsign_num = num->pre;
1132 num->need_locale = TRUE;
1133 num->flag |= NUM_F_LSIGN;
1135 else if (num->lsign == NUM_LSIGN_NONE)
1137 num->lsign = NUM_LSIGN_POST;
1138 num->need_locale = TRUE;
1139 num->flag |= NUM_F_LSIGN;
1146 (errcode(ERRCODE_SYNTAX_ERROR),
1147 errmsg("cannot use \"S\" and \"MI\" together")));
1148 num->flag |= NUM_F_MINUS;
1149 if (IS_DECIMAL(num))
1150 num->flag |= NUM_F_MINUS_POST;
1156 (errcode(ERRCODE_SYNTAX_ERROR),
1157 errmsg("cannot use \"S\" and \"PL\" together")));
1158 num->flag |= NUM_F_PLUS;
1159 if (IS_DECIMAL(num))
1160 num->flag |= NUM_F_PLUS_POST;
1166 (errcode(ERRCODE_SYNTAX_ERROR),
1167 errmsg("cannot use \"S\" and \"SG\" together")));
1168 num->flag |= NUM_F_MINUS;
1169 num->flag |= NUM_F_PLUS;
1173 if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
1175 (errcode(ERRCODE_SYNTAX_ERROR),
1176 errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
1177 num->flag |= NUM_F_BRACKET;
1182 num->flag |= NUM_F_ROMAN;
1187 num->need_locale = TRUE;
1191 if (IS_DECIMAL(num))
1193 (errcode(ERRCODE_SYNTAX_ERROR),
1194 errmsg("cannot use \"V\" and decimal point together")));
1195 num->flag |= NUM_F_MULTI;
1201 (errcode(ERRCODE_SYNTAX_ERROR),
1202 errmsg("cannot use \"EEEE\" twice")));
1203 if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) ||
1204 IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) ||
1205 IS_ROMAN(num) || IS_MULTI(num))
1207 (errcode(ERRCODE_SYNTAX_ERROR),
1208 errmsg("\"EEEE\" is incompatible with other formats"),
1209 errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
1210 num->flag |= NUM_F_EEEE;
1216 * Format parser, search small keywords and keyword's suffixes, and make
1219 * for DATE-TIME & NUMBER version
1223 parse_format(FormatNode *node, const char *str, const KeyWord *kw,
1224 const KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
1232 #ifdef DEBUG_TO_FROM_CHAR
1233 elog(DEBUG_elog_output, "to_char/number(): run parser");
1245 if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
1255 if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
1257 n->type = NODE_TYPE_ACTION;
1264 * NUM version: Prepare global NUMDesc struct
1266 if (ver == NUM_TYPE)
1267 NUMDesc_prepare(Num, n);
1272 if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
1282 * Special characters '\' and '"'
1284 if (*str == '"' && last != '\\')
1290 if (*str == '"' && x != '\\')
1295 else if (*str == '\\' && x != '\\')
1300 n->type = NODE_TYPE_CHAR;
1301 n->character = *str;
1311 else if (*str && *str == '\\' && last != '\\' && *(str + 1) == '"')
1318 n->type = NODE_TYPE_CHAR;
1319 n->character = *str;
1330 if (n->type == NODE_TYPE_ACTION)
1339 n->type = NODE_TYPE_END;
1344 * DEBUG: Dump the FormatNode Tree (debug)
1347 #ifdef DEBUG_TO_FROM_CHAR
1349 #define DUMP_THth(_suf) (S_TH(_suf) ? "TH" : (S_th(_suf) ? "th" : " "))
1350 #define DUMP_FM(_suf) (S_FM(_suf) ? "FM" : " ")
1353 dump_node(FormatNode *node, int max)
1358 elog(DEBUG_elog_output, "to_from-char(): DUMP FORMAT");
1360 for (a = 0, n = node; a <= max; n++, a++)
1362 if (n->type == NODE_TYPE_ACTION)
1363 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)",
1364 a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix));
1365 else if (n->type == NODE_TYPE_CHAR)
1366 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character);
1367 else if (n->type == NODE_TYPE_END)
1369 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_END", a);
1373 elog(DEBUG_elog_output, "%d:\t unknown NODE!", a);
1378 /*****************************************************************************
1380 *****************************************************************************/
1383 * Return ST/ND/RD/TH for simple (1..9) numbers
1384 * type --> 0 upper, 1 lower
1388 get_th(char *num, int type)
1390 int len = strlen(num),
1394 last = *(num + (len - 1));
1395 if (!isdigit((unsigned char) last))
1397 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1398 errmsg("\"%s\" is not a number", num)));
1401 * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1402 * 'ST/st', 'ND/nd', 'RD/rd', respectively
1404 if ((len > 1) && ((seclast = num[len - 2]) == '1'))
1410 if (type == TH_UPPER)
1414 if (type == TH_UPPER)
1418 if (type == TH_UPPER)
1422 if (type == TH_UPPER)
1429 * Convert string-number to ordinal string-number
1430 * type --> 0 upper, 1 lower
1434 str_numth(char *dest, char *num, int type)
1438 strcat(dest, get_th(num, type));
1442 /*****************************************************************************
1443 * upper/lower/initcap functions
1444 *****************************************************************************/
1447 * If the system provides the needed functions for wide-character manipulation
1448 * (which are all standardized by C99), then we implement upper/lower/initcap
1449 * using wide-character functions, if necessary. Otherwise we use the
1450 * traditional <ctype.h> functions, which of course will not work as desired
1451 * in multibyte character sets. Note that in either case we are effectively
1452 * assuming that the database character encoding matches the encoding implied
1455 * If the system provides locale_t and associated functions (which are
1456 * standardized by Open Group's XBD), we can support collations that are
1457 * neither default nor C. The code is written to handle both combinations
1458 * of have-wide-characters and have-locale_t, though it's rather unlikely
1459 * a platform would have the latter without the former.
1463 * collation-aware, wide-character-aware lower function
1465 * We pass the number of bytes so we can pass varlena and char*
1466 * to this function. The result is a palloc'd, null-terminated string.
1469 str_tolower(const char *buff, size_t nbytes, Oid collid)
1476 /* C/POSIX collations use this path regardless of database encoding */
1477 if (lc_ctype_is_c(collid))
1479 result = asc_tolower(buff, nbytes);
1481 #ifdef USE_WIDE_UPPER_LOWER
1482 else if (pg_database_encoding_max_length() > 1)
1484 pg_locale_t mylocale = 0;
1489 if (collid != DEFAULT_COLLATION_OID)
1491 if (!OidIsValid(collid))
1494 * This typically means that the parser could not resolve a
1495 * conflict of implicit collations, so report it that way.
1498 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1499 errmsg("could not determine which collation to use for lower() function"),
1500 errhint("Use the COLLATE clause to set the collation explicitly.")));
1502 mylocale = pg_newlocale_from_collation(collid);
1505 /* Overflow paranoia */
1506 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1508 (errcode(ERRCODE_OUT_OF_MEMORY),
1509 errmsg("out of memory")));
1511 /* Output workspace cannot have more codes than input bytes */
1512 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1514 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1516 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1518 #ifdef HAVE_LOCALE_T
1520 workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
1523 workspace[curr_char] = towlower(workspace[curr_char]);
1526 /* Make result large enough; case change might change number of bytes */
1527 result_size = curr_char * pg_database_encoding_max_length() + 1;
1528 result = palloc(result_size);
1530 wchar2char(result, workspace, result_size, mylocale);
1533 #endif /* USE_WIDE_UPPER_LOWER */
1536 #ifdef HAVE_LOCALE_T
1537 pg_locale_t mylocale = 0;
1541 if (collid != DEFAULT_COLLATION_OID)
1543 if (!OidIsValid(collid))
1546 * This typically means that the parser could not resolve a
1547 * conflict of implicit collations, so report it that way.
1550 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1551 errmsg("could not determine which collation to use for lower() function"),
1552 errhint("Use the COLLATE clause to set the collation explicitly.")));
1554 #ifdef HAVE_LOCALE_T
1555 mylocale = pg_newlocale_from_collation(collid);
1559 result = pnstrdup(buff, nbytes);
1562 * Note: we assume that tolower_l() will not be so broken as to need
1563 * an isupper_l() guard test. When using the default collation, we
1564 * apply the traditional Postgres behavior that forces ASCII-style
1565 * treatment of I/i, but in non-default collations you get exactly
1566 * what the collation says.
1568 for (p = result; *p; p++)
1570 #ifdef HAVE_LOCALE_T
1572 *p = tolower_l((unsigned char) *p, mylocale);
1575 *p = pg_tolower((unsigned char) *p);
1583 * collation-aware, wide-character-aware upper function
1585 * We pass the number of bytes so we can pass varlena and char*
1586 * to this function. The result is a palloc'd, null-terminated string.
1589 str_toupper(const char *buff, size_t nbytes, Oid collid)
1596 /* C/POSIX collations use this path regardless of database encoding */
1597 if (lc_ctype_is_c(collid))
1599 result = asc_toupper(buff, nbytes);
1601 #ifdef USE_WIDE_UPPER_LOWER
1602 else if (pg_database_encoding_max_length() > 1)
1604 pg_locale_t mylocale = 0;
1609 if (collid != DEFAULT_COLLATION_OID)
1611 if (!OidIsValid(collid))
1614 * This typically means that the parser could not resolve a
1615 * conflict of implicit collations, so report it that way.
1618 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1619 errmsg("could not determine which collation to use for upper() function"),
1620 errhint("Use the COLLATE clause to set the collation explicitly.")));
1622 mylocale = pg_newlocale_from_collation(collid);
1625 /* Overflow paranoia */
1626 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1628 (errcode(ERRCODE_OUT_OF_MEMORY),
1629 errmsg("out of memory")));
1631 /* Output workspace cannot have more codes than input bytes */
1632 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1634 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1636 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1638 #ifdef HAVE_LOCALE_T
1640 workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
1643 workspace[curr_char] = towupper(workspace[curr_char]);
1646 /* Make result large enough; case change might change number of bytes */
1647 result_size = curr_char * pg_database_encoding_max_length() + 1;
1648 result = palloc(result_size);
1650 wchar2char(result, workspace, result_size, mylocale);
1653 #endif /* USE_WIDE_UPPER_LOWER */
1656 #ifdef HAVE_LOCALE_T
1657 pg_locale_t mylocale = 0;
1661 if (collid != DEFAULT_COLLATION_OID)
1663 if (!OidIsValid(collid))
1666 * This typically means that the parser could not resolve a
1667 * conflict of implicit collations, so report it that way.
1670 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1671 errmsg("could not determine which collation to use for upper() function"),
1672 errhint("Use the COLLATE clause to set the collation explicitly.")));
1674 #ifdef HAVE_LOCALE_T
1675 mylocale = pg_newlocale_from_collation(collid);
1679 result = pnstrdup(buff, nbytes);
1682 * Note: we assume that toupper_l() will not be so broken as to need
1683 * an islower_l() guard test. When using the default collation, we
1684 * apply the traditional Postgres behavior that forces ASCII-style
1685 * treatment of I/i, but in non-default collations you get exactly
1686 * what the collation says.
1688 for (p = result; *p; p++)
1690 #ifdef HAVE_LOCALE_T
1692 *p = toupper_l((unsigned char) *p, mylocale);
1695 *p = pg_toupper((unsigned char) *p);
1703 * collation-aware, wide-character-aware initcap function
1705 * We pass the number of bytes so we can pass varlena and char*
1706 * to this function. The result is a palloc'd, null-terminated string.
1709 str_initcap(const char *buff, size_t nbytes, Oid collid)
1712 int wasalnum = false;
1717 /* C/POSIX collations use this path regardless of database encoding */
1718 if (lc_ctype_is_c(collid))
1720 result = asc_initcap(buff, nbytes);
1722 #ifdef USE_WIDE_UPPER_LOWER
1723 else if (pg_database_encoding_max_length() > 1)
1725 pg_locale_t mylocale = 0;
1730 if (collid != DEFAULT_COLLATION_OID)
1732 if (!OidIsValid(collid))
1735 * This typically means that the parser could not resolve a
1736 * conflict of implicit collations, so report it that way.
1739 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1740 errmsg("could not determine which collation to use for initcap() function"),
1741 errhint("Use the COLLATE clause to set the collation explicitly.")));
1743 mylocale = pg_newlocale_from_collation(collid);
1746 /* Overflow paranoia */
1747 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1749 (errcode(ERRCODE_OUT_OF_MEMORY),
1750 errmsg("out of memory")));
1752 /* Output workspace cannot have more codes than input bytes */
1753 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1755 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1757 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1759 #ifdef HAVE_LOCALE_T
1763 workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
1765 workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
1766 wasalnum = iswalnum_l(workspace[curr_char], mylocale);
1772 workspace[curr_char] = towlower(workspace[curr_char]);
1774 workspace[curr_char] = towupper(workspace[curr_char]);
1775 wasalnum = iswalnum(workspace[curr_char]);
1779 /* Make result large enough; case change might change number of bytes */
1780 result_size = curr_char * pg_database_encoding_max_length() + 1;
1781 result = palloc(result_size);
1783 wchar2char(result, workspace, result_size, mylocale);
1786 #endif /* USE_WIDE_UPPER_LOWER */
1789 #ifdef HAVE_LOCALE_T
1790 pg_locale_t mylocale = 0;
1794 if (collid != DEFAULT_COLLATION_OID)
1796 if (!OidIsValid(collid))
1799 * This typically means that the parser could not resolve a
1800 * conflict of implicit collations, so report it that way.
1803 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1804 errmsg("could not determine which collation to use for initcap() function"),
1805 errhint("Use the COLLATE clause to set the collation explicitly.")));
1807 #ifdef HAVE_LOCALE_T
1808 mylocale = pg_newlocale_from_collation(collid);
1812 result = pnstrdup(buff, nbytes);
1815 * Note: we assume that toupper_l()/tolower_l() will not be so broken
1816 * as to need guard tests. When using the default collation, we apply
1817 * the traditional Postgres behavior that forces ASCII-style treatment
1818 * of I/i, but in non-default collations you get exactly what the
1821 for (p = result; *p; p++)
1823 #ifdef HAVE_LOCALE_T
1827 *p = tolower_l((unsigned char) *p, mylocale);
1829 *p = toupper_l((unsigned char) *p, mylocale);
1830 wasalnum = isalnum_l((unsigned char) *p, mylocale);
1836 *p = pg_tolower((unsigned char) *p);
1838 *p = pg_toupper((unsigned char) *p);
1839 wasalnum = isalnum((unsigned char) *p);
1848 * ASCII-only lower function
1850 * We pass the number of bytes so we can pass varlena and char*
1851 * to this function. The result is a palloc'd, null-terminated string.
1854 asc_tolower(const char *buff, size_t nbytes)
1862 result = pnstrdup(buff, nbytes);
1864 for (p = result; *p; p++)
1865 *p = pg_ascii_tolower((unsigned char) *p);
1871 * ASCII-only upper function
1873 * We pass the number of bytes so we can pass varlena and char*
1874 * to this function. The result is a palloc'd, null-terminated string.
1877 asc_toupper(const char *buff, size_t nbytes)
1885 result = pnstrdup(buff, nbytes);
1887 for (p = result; *p; p++)
1888 *p = pg_ascii_toupper((unsigned char) *p);
1894 * ASCII-only initcap function
1896 * We pass the number of bytes so we can pass varlena and char*
1897 * to this function. The result is a palloc'd, null-terminated string.
1900 asc_initcap(const char *buff, size_t nbytes)
1904 int wasalnum = false;
1909 result = pnstrdup(buff, nbytes);
1911 for (p = result; *p; p++)
1916 *p = c = pg_ascii_tolower((unsigned char) *p);
1918 *p = c = pg_ascii_toupper((unsigned char) *p);
1919 /* we don't trust isalnum() here */
1920 wasalnum = ((c >= 'A' && c <= 'Z') ||
1921 (c >= 'a' && c <= 'z') ||
1922 (c >= '0' && c <= '9'));
1928 /* convenience routines for when the input is null-terminated */
1931 str_tolower_z(const char *buff, Oid collid)
1933 return str_tolower(buff, strlen(buff), collid);
1937 str_toupper_z(const char *buff, Oid collid)
1939 return str_toupper(buff, strlen(buff), collid);
1943 str_initcap_z(const char *buff, Oid collid)
1945 return str_initcap(buff, strlen(buff), collid);
1949 asc_tolower_z(const char *buff)
1951 return asc_tolower(buff, strlen(buff));
1955 asc_toupper_z(const char *buff)
1957 return asc_toupper(buff, strlen(buff));
1960 /* asc_initcap_z is not currently needed */
1964 * Skip TM / th in FROM_CHAR
1966 * If S_THth is on, skip two chars, assuming there are two available
1969 #define SKIP_THth(ptr, _suf) \
1973 if (*(ptr)) (ptr)++; \
1974 if (*(ptr)) (ptr)++; \
1979 #ifdef DEBUG_TO_FROM_CHAR
1981 * DEBUG: Call for debug and for index checking; (Show ASCII char
1982 * and defined keyword for each used position
1986 dump_index(const KeyWord *k, const int *index)
1992 elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:");
1994 for (i = 0; i < KeyWord_INDEX_SIZE; i++)
1998 elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name);
2004 elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]);
2007 elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d",
2013 * Return TRUE if next format picture is not digit value
2017 is_next_separator(FormatNode *n)
2019 if (n->type == NODE_TYPE_END)
2022 if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
2030 /* end of format string is treated like a non-digit separator */
2031 if (n->type == NODE_TYPE_END)
2034 if (n->type == NODE_TYPE_ACTION)
2036 if (n->key->is_digit)
2041 else if (isdigit((unsigned char) n->character))
2044 return TRUE; /* some non-digit input (separator) */
2049 adjust_partial_year_to_2020(int year)
2052 * Adjust all dates toward 2020; this is effectively what happens when we
2053 * assume '70' is 1970 and '69' is 2069.
2055 /* Force 0-69 into the 2000's */
2058 /* Force 70-99 into the 1900's */
2059 else if (year < 100)
2061 /* Force 100-519 into the 2000's */
2062 else if (year < 520)
2064 /* Force 520-999 into the 1000's */
2065 else if (year < 1000)
2073 strspace_len(char *str)
2077 while (*str && isspace((unsigned char) *str))
2086 * Set the date mode of a from-char conversion.
2088 * Puke if the date mode has already been set, and the caller attempts to set
2089 * it to a conflicting mode.
2092 from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode)
2094 if (mode != FROM_CHAR_DATE_NONE)
2096 if (tmfc->mode == FROM_CHAR_DATE_NONE)
2098 else if (tmfc->mode != mode)
2100 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2101 errmsg("invalid combination of date conventions"),
2102 errhint("Do not mix Gregorian and ISO week date "
2103 "conventions in a formatting template.")));
2108 * Set the integer pointed to by 'dest' to the given value.
2110 * Puke if the destination integer has previously been set to some other
2114 from_char_set_int(int *dest, const int value, const FormatNode *node)
2116 if (*dest != 0 && *dest != value)
2118 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2119 errmsg("conflicting values for \"%s\" field in formatting string",
2121 errdetail("This value contradicts a previous setting for "
2122 "the same field type.")));
2127 * Read a single integer from the source string, into the int pointed to by
2128 * 'dest'. If 'dest' is NULL, the result is discarded.
2130 * In fixed-width mode (the node does not have the FM suffix), consume at most
2131 * 'len' characters. However, any leading whitespace isn't counted in 'len'.
2133 * We use strtol() to recover the integer value from the source string, in
2134 * accordance with the given FormatNode.
2136 * If the conversion completes successfully, src will have been advanced to
2137 * point at the character immediately following the last character used in the
2140 * Return the number of characters consumed.
2142 * Note that from_char_parse_int() provides a more convenient wrapper where
2143 * the length of the field is the same as the length of the format keyword (as
2147 from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node)
2150 char copy[DCH_MAX_ITEM_SIZ + 1];
2155 * Skip any whitespace before parsing the integer.
2157 *src += strspace_len(*src);
2159 Assert(len <= DCH_MAX_ITEM_SIZ);
2160 used = (int) strlcpy(copy, *src, len + 1);
2162 if (S_FM(node->suffix) || is_next_separator(node))
2165 * This node is in Fill Mode, or the next node is known to be a
2166 * non-digit value, so we just slurp as many characters as we can get.
2169 result = strtol(init, src, 10);
2174 * We need to pull exactly the number of characters given in 'len' out
2175 * of the string, and convert those.
2181 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2182 errmsg("source string too short for \"%s\" formatting field",
2184 errdetail("Field requires %d characters, but only %d "
2187 errhint("If your source string is not fixed-width, try "
2188 "using the \"FM\" modifier.")));
2191 result = strtol(copy, &last, 10);
2194 if (used > 0 && used < len)
2196 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2197 errmsg("invalid value \"%s\" for \"%s\"",
2198 copy, node->key->name),
2199 errdetail("Field requires %d characters, but only %d "
2200 "could be parsed.", len, used),
2201 errhint("If your source string is not fixed-width, try "
2202 "using the \"FM\" modifier.")));
2209 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2210 errmsg("invalid value \"%s\" for \"%s\"",
2211 copy, node->key->name),
2212 errdetail("Value must be an integer.")));
2214 if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
2216 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2217 errmsg("value for \"%s\" in source string is out of range",
2219 errdetail("Value must be in the range %d to %d.",
2220 INT_MIN, INT_MAX)));
2223 from_char_set_int(dest, (int) result, node);
2228 * Call from_char_parse_int_len(), using the length of the format keyword as
2229 * the expected length of the field.
2231 * Don't call this function if the field differs in length from the format
2232 * keyword (as with HH24; the keyword length is 4, but the field length is 2).
2233 * In such cases, call from_char_parse_int_len() instead to specify the
2234 * required length explicitly.
2237 from_char_parse_int(int *dest, char **src, FormatNode *node)
2239 return from_char_parse_int_len(dest, src, node->key->len, node);
2243 * Sequential search with to upper/lower conversion
2247 seq_search(char *name, const char *const * array, int type, int max, int *len)
2250 const char *const * a;
2260 /* set first char */
2261 if (type == ONE_UPPER || type == ALL_UPPER)
2262 *name = pg_toupper((unsigned char) *name);
2263 else if (type == ALL_LOWER)
2264 *name = pg_tolower((unsigned char) *name);
2266 for (last = 0, a = array; *a != NULL; a++)
2268 /* compare first chars */
2272 for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++)
2274 /* search fragment (max) only */
2275 if (max && i == max)
2286 /* Not found in array 'a' */
2291 * Convert (but convert new chars only)
2295 if (type == ONE_UPPER || type == ALL_LOWER)
2296 *n = pg_tolower((unsigned char) *n);
2297 else if (type == ALL_UPPER)
2298 *n = pg_toupper((unsigned char) *n);
2302 #ifdef DEBUG_TO_FROM_CHAR
2303 elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)",
2315 * Perform a sequential search in 'array' for text matching the first 'max'
2316 * characters of the source string.
2318 * If a match is found, copy the array index of the match into the integer
2319 * pointed to by 'dest', advance 'src' to the end of the part of the string
2320 * which matched, and return the number of characters consumed.
2322 * If the string doesn't match, throw an error.
2325 from_char_seq_search(int *dest, char **src, const char *const * array, int type, int max,
2330 *dest = seq_search(*src, array, type, max, &len);
2333 char copy[DCH_MAX_ITEM_SIZ + 1];
2335 Assert(max <= DCH_MAX_ITEM_SIZ);
2336 strlcpy(copy, *src, max + 1);
2339 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2340 errmsg("invalid value \"%s\" for \"%s\"",
2341 copy, node->key->name),
2342 errdetail("The given value did not match any of the allowed "
2343 "values for this field.")));
2350 * Process a TmToChar struct as denoted by a list of FormatNodes.
2351 * The formatted data is written to the string pointed to by 'out'.
2355 DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
2359 struct pg_tm *tm = &in->tm;
2362 /* cache localized days and months */
2363 cache_locale_time();
2366 for (n = node; n->type != NODE_TYPE_END; n++)
2368 if (n->type != NODE_TYPE_ACTION)
2379 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2380 ? P_M_STR : A_M_STR);
2385 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2391 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2392 ? p_m_STR : a_m_STR);
2397 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2405 * display time as shown on a 12-hour clock, even for
2408 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2409 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? HOURS_PER_DAY / 2 :
2410 tm->tm_hour % (HOURS_PER_DAY / 2));
2411 if (S_THth(n->suffix))
2412 str_numth(s, s, S_TH_TYPE(n->suffix));
2416 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2418 if (S_THth(n->suffix))
2419 str_numth(s, s, S_TH_TYPE(n->suffix));
2423 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2425 if (S_THth(n->suffix))
2426 str_numth(s, s, S_TH_TYPE(n->suffix));
2430 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2432 if (S_THth(n->suffix))
2433 str_numth(s, s, S_TH_TYPE(n->suffix));
2436 case DCH_MS: /* millisecond */
2437 #ifdef HAVE_INT64_TIMESTAMP
2438 sprintf(s, "%03d", (int) (in->fsec / INT64CONST(1000)));
2440 /* No rint() because we can't overflow and we might print US */
2441 sprintf(s, "%03d", (int) (in->fsec * 1000));
2443 if (S_THth(n->suffix))
2444 str_numth(s, s, S_TH_TYPE(n->suffix));
2447 case DCH_US: /* microsecond */
2448 #ifdef HAVE_INT64_TIMESTAMP
2449 sprintf(s, "%06d", (int) in->fsec);
2451 /* don't use rint() because we can't overflow 1000 */
2452 sprintf(s, "%06d", (int) (in->fsec * 1000000));
2454 if (S_THth(n->suffix))
2455 str_numth(s, s, S_TH_TYPE(n->suffix));
2459 sprintf(s, "%d", tm->tm_hour * SECS_PER_HOUR +
2460 tm->tm_min * SECS_PER_MINUTE +
2462 if (S_THth(n->suffix))
2463 str_numth(s, s, S_TH_TYPE(n->suffix));
2467 INVALID_FOR_INTERVAL;
2470 /* We assume here that timezone names aren't localized */
2471 char *p = asc_tolower_z(tmtcTzn(in));
2479 INVALID_FOR_INTERVAL;
2482 strcpy(s, tmtcTzn(in));
2487 INVALID_FOR_INTERVAL;
2488 sprintf(s, "%c%0*d",
2489 (tm->tm_gmtoff >= 0) ? '+' : '-',
2490 S_FM(n->suffix) ? 0 : 2,
2491 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2493 if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2496 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2502 INVALID_FOR_INTERVAL;
2503 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2508 INVALID_FOR_INTERVAL;
2509 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2514 INVALID_FOR_INTERVAL;
2515 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2520 INVALID_FOR_INTERVAL;
2521 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2525 INVALID_FOR_INTERVAL;
2528 if (S_TM(n->suffix))
2530 char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid);
2532 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2536 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2537 errmsg("localized string format value too long")));
2540 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2541 asc_toupper_z(months_full[tm->tm_mon - 1]));
2545 INVALID_FOR_INTERVAL;
2548 if (S_TM(n->suffix))
2550 char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid);
2552 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2556 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2557 errmsg("localized string format value too long")));
2560 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2561 months_full[tm->tm_mon - 1]);
2565 INVALID_FOR_INTERVAL;
2568 if (S_TM(n->suffix))
2570 char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid);
2572 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2576 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2577 errmsg("localized string format value too long")));
2580 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2581 asc_tolower_z(months_full[tm->tm_mon - 1]));
2585 INVALID_FOR_INTERVAL;
2588 if (S_TM(n->suffix))
2590 char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2592 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2596 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2597 errmsg("localized string format value too long")));
2600 strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2604 INVALID_FOR_INTERVAL;
2607 if (S_TM(n->suffix))
2609 char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2611 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2615 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2616 errmsg("localized string format value too long")));
2619 strcpy(s, months[tm->tm_mon - 1]);
2623 INVALID_FOR_INTERVAL;
2626 if (S_TM(n->suffix))
2628 char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2630 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2634 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2635 errmsg("localized string format value too long")));
2638 strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
2642 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
2644 if (S_THth(n->suffix))
2645 str_numth(s, s, S_TH_TYPE(n->suffix));
2649 INVALID_FOR_INTERVAL;
2650 if (S_TM(n->suffix))
2652 char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid);
2654 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2658 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2659 errmsg("localized string format value too long")));
2662 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2663 asc_toupper_z(days[tm->tm_wday]));
2667 INVALID_FOR_INTERVAL;
2668 if (S_TM(n->suffix))
2670 char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid);
2672 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2676 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2677 errmsg("localized string format value too long")));
2680 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2685 INVALID_FOR_INTERVAL;
2686 if (S_TM(n->suffix))
2688 char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid);
2690 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2694 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2695 errmsg("localized string format value too long")));
2698 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2699 asc_tolower_z(days[tm->tm_wday]));
2703 INVALID_FOR_INTERVAL;
2704 if (S_TM(n->suffix))
2706 char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid);
2708 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2712 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2713 errmsg("localized string format value too long")));
2716 strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
2720 INVALID_FOR_INTERVAL;
2721 if (S_TM(n->suffix))
2723 char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid);
2725 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2729 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2730 errmsg("localized string format value too long")));
2733 strcpy(s, days_short[tm->tm_wday]);
2737 INVALID_FOR_INTERVAL;
2738 if (S_TM(n->suffix))
2740 char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid);
2742 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2746 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2747 errmsg("localized string format value too long")));
2750 strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
2755 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
2756 (n->key->id == DCH_DDD) ?
2758 date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday));
2759 if (S_THth(n->suffix))
2760 str_numth(s, s, S_TH_TYPE(n->suffix));
2764 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
2765 if (S_THth(n->suffix))
2766 str_numth(s, s, S_TH_TYPE(n->suffix));
2770 INVALID_FOR_INTERVAL;
2771 sprintf(s, "%d", tm->tm_wday + 1);
2772 if (S_THth(n->suffix))
2773 str_numth(s, s, S_TH_TYPE(n->suffix));
2777 INVALID_FOR_INTERVAL;
2778 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
2779 if (S_THth(n->suffix))
2780 str_numth(s, s, S_TH_TYPE(n->suffix));
2784 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2785 (tm->tm_yday - 1) / 7 + 1);
2786 if (S_THth(n->suffix))
2787 str_numth(s, s, S_TH_TYPE(n->suffix));
2791 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2792 date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
2793 if (S_THth(n->suffix))
2794 str_numth(s, s, S_TH_TYPE(n->suffix));
2800 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
2801 if (S_THth(n->suffix))
2802 str_numth(s, s, S_TH_TYPE(n->suffix));
2806 if (is_interval) /* straight calculation */
2807 i = tm->tm_year / 100;
2810 if (tm->tm_year > 0)
2811 /* Century 20 == 1901 - 2000 */
2812 i = (tm->tm_year - 1) / 100 + 1;
2814 /* Century 6BC == 600BC - 501BC */
2815 i = tm->tm_year / 100 - 1;
2817 if (i <= 99 && i >= -99)
2818 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
2820 sprintf(s, "%d", i);
2821 if (S_THth(n->suffix))
2822 str_numth(s, s, S_TH_TYPE(n->suffix));
2826 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
2827 sprintf(s, "%d,%03d", i,
2828 ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
2829 if (S_THth(n->suffix))
2830 str_numth(s, s, S_TH_TYPE(n->suffix));
2836 S_FM(n->suffix) ? 0 :
2837 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
2838 (n->key->id == DCH_YYYY ?
2839 ADJUST_YEAR(tm->tm_year, is_interval) :
2840 ADJUST_YEAR(date2isoyear(tm->tm_year,
2844 if (S_THth(n->suffix))
2845 str_numth(s, s, S_TH_TYPE(n->suffix));
2851 S_FM(n->suffix) ? 0 :
2852 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
2853 (n->key->id == DCH_YYY ?
2854 ADJUST_YEAR(tm->tm_year, is_interval) :
2855 ADJUST_YEAR(date2isoyear(tm->tm_year,
2858 is_interval)) % 1000);
2859 if (S_THth(n->suffix))
2860 str_numth(s, s, S_TH_TYPE(n->suffix));
2866 S_FM(n->suffix) ? 0 :
2867 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
2868 (n->key->id == DCH_YY ?
2869 ADJUST_YEAR(tm->tm_year, is_interval) :
2870 ADJUST_YEAR(date2isoyear(tm->tm_year,
2873 is_interval)) % 100);
2874 if (S_THth(n->suffix))
2875 str_numth(s, s, S_TH_TYPE(n->suffix));
2881 (n->key->id == DCH_Y ?
2882 ADJUST_YEAR(tm->tm_year, is_interval) :
2883 ADJUST_YEAR(date2isoyear(tm->tm_year,
2886 is_interval)) % 10);
2887 if (S_THth(n->suffix))
2888 str_numth(s, s, S_TH_TYPE(n->suffix));
2894 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
2895 rm_months_upper[MONTHS_PER_YEAR - tm->tm_mon]);
2901 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
2902 rm_months_lower[MONTHS_PER_YEAR - tm->tm_mon]);
2906 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
2907 if (S_THth(n->suffix))
2908 str_numth(s, s, S_TH_TYPE(n->suffix));
2912 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
2913 if (S_THth(n->suffix))
2914 str_numth(s, s, S_TH_TYPE(n->suffix));
2924 * Process a string as denoted by a list of FormatNodes.
2925 * The TmFromChar struct pointed to by 'out' is populated with the results.
2927 * Note: we currently don't have any to_interval() function, so there
2928 * is no need here for INVALID_FOR_INTERVAL checks.
2932 DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
2938 bool fx_mode = false;
2940 for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
2942 if (n->type != NODE_TYPE_ACTION)
2945 * Separator, so consume one character from input string. Notice
2946 * we don't insist that the consumed character match the format's
2953 /* Ignore spaces before fields when not in FX (fixed width) mode */
2954 if (!fx_mode && n->key->id != DCH_FX)
2956 while (*s != '\0' && isspace((unsigned char) *s))
2960 from_char_set_mode(out, n->key->date_mode);
2971 from_char_seq_search(&value, &s, ampm_strings_long,
2972 ALL_UPPER, n->key->len, n);
2973 from_char_set_int(&out->pm, value % 2, n);
2974 out->clock = CLOCK_12_HOUR;
2980 from_char_seq_search(&value, &s, ampm_strings,
2981 ALL_UPPER, n->key->len, n);
2982 from_char_set_int(&out->pm, value % 2, n);
2983 out->clock = CLOCK_12_HOUR;
2987 from_char_parse_int_len(&out->hh, &s, 2, n);
2988 out->clock = CLOCK_12_HOUR;
2989 SKIP_THth(s, n->suffix);
2992 from_char_parse_int_len(&out->hh, &s, 2, n);
2993 SKIP_THth(s, n->suffix);
2996 from_char_parse_int(&out->mi, &s, n);
2997 SKIP_THth(s, n->suffix);
3000 from_char_parse_int(&out->ss, &s, n);
3001 SKIP_THth(s, n->suffix);
3003 case DCH_MS: /* millisecond */
3004 len = from_char_parse_int_len(&out->ms, &s, 3, n);
3007 * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
3009 out->ms *= len == 1 ? 100 :
3012 SKIP_THth(s, n->suffix);
3014 case DCH_US: /* microsecond */
3015 len = from_char_parse_int_len(&out->us, &s, 6, n);
3017 out->us *= len == 1 ? 100000 :
3023 SKIP_THth(s, n->suffix);
3026 from_char_parse_int(&out->ssss, &s, n);
3027 SKIP_THth(s, n->suffix);
3033 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3034 errmsg("\"TZ\"/\"tz\"/\"OF\" format patterns are not supported in to_date")));
3039 from_char_seq_search(&value, &s, adbc_strings_long,
3040 ALL_UPPER, n->key->len, n);
3041 from_char_set_int(&out->bc, value % 2, n);
3047 from_char_seq_search(&value, &s, adbc_strings,
3048 ALL_UPPER, n->key->len, n);
3049 from_char_set_int(&out->bc, value % 2, n);
3054 from_char_seq_search(&value, &s, months_full, ONE_UPPER,
3056 from_char_set_int(&out->mm, value + 1, n);
3061 from_char_seq_search(&value, &s, months, ONE_UPPER,
3063 from_char_set_int(&out->mm, value + 1, n);
3066 from_char_parse_int(&out->mm, &s, n);
3067 SKIP_THth(s, n->suffix);
3072 from_char_seq_search(&value, &s, days, ONE_UPPER,
3074 from_char_set_int(&out->d, value, n);
3080 from_char_seq_search(&value, &s, days, ONE_UPPER,
3082 from_char_set_int(&out->d, value, n);
3086 from_char_parse_int(&out->ddd, &s, n);
3087 SKIP_THth(s, n->suffix);
3090 from_char_parse_int_len(&out->ddd, &s, 3, n);
3091 SKIP_THth(s, n->suffix);
3094 from_char_parse_int(&out->dd, &s, n);
3095 SKIP_THth(s, n->suffix);
3098 from_char_parse_int(&out->d, &s, n);
3099 SKIP_THth(s, n->suffix);
3102 from_char_parse_int_len(&out->d, &s, 1, n);
3103 /* Shift numbering to match Gregorian where Sunday = 1 */
3106 SKIP_THth(s, n->suffix);
3110 from_char_parse_int(&out->ww, &s, n);
3111 SKIP_THth(s, n->suffix);
3116 * We ignore 'Q' when converting to date because it is unclear
3117 * which date in the quarter to use, and some people specify
3118 * both quarter and month, so if it was honored it might
3119 * conflict with the supplied month. That is also why we don't
3122 * We still parse the source string for an integer, but it
3123 * isn't stored anywhere in 'out'.
3125 from_char_parse_int((int *) NULL, &s, n);
3126 SKIP_THth(s, n->suffix);
3129 from_char_parse_int(&out->cc, &s, n);
3130 SKIP_THth(s, n->suffix);
3139 matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch);
3142 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3143 errmsg("invalid input string for \"Y,YYY\"")));
3144 years += (millennia * 1000);
3145 from_char_set_int(&out->year, years, n);
3148 SKIP_THth(s, n->suffix);
3153 from_char_parse_int(&out->year, &s, n);
3155 SKIP_THth(s, n->suffix);
3159 if (from_char_parse_int(&out->year, &s, n) < 4)
3160 out->year = adjust_partial_year_to_2020(out->year);
3162 SKIP_THth(s, n->suffix);
3166 if (from_char_parse_int(&out->year, &s, n) < 4)
3167 out->year = adjust_partial_year_to_2020(out->year);
3169 SKIP_THth(s, n->suffix);
3173 if (from_char_parse_int(&out->year, &s, n) < 4)
3174 out->year = adjust_partial_year_to_2020(out->year);
3176 SKIP_THth(s, n->suffix);
3179 from_char_seq_search(&value, &s, rm_months_upper,
3180 ALL_UPPER, MAX_RM_LEN, n);
3181 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
3184 from_char_seq_search(&value, &s, rm_months_lower,
3185 ALL_LOWER, MAX_RM_LEN, n);
3186 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
3189 from_char_parse_int(&out->w, &s, n);
3190 SKIP_THth(s, n->suffix);
3193 from_char_parse_int(&out->j, &s, n);
3194 SKIP_THth(s, n->suffix);
3200 /* select a DCHCacheEntry to hold the given format picture */
3201 static DCHCacheEntry *
3202 DCH_cache_getnew(const char *str)
3206 /* counter overflow check - paranoia? */
3207 if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES))
3211 for (ent = DCHCache; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++)
3212 ent->age = (++DCHCounter);
3216 * If cache is full, remove oldest entry (or recycle first not-valid one)
3218 if (n_DCHCache >= DCH_CACHE_ENTRIES)
3220 DCHCacheEntry *old = DCHCache + 0;
3222 #ifdef DEBUG_TO_FROM_CHAR
3223 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3227 for (ent = DCHCache + 1; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++)
3234 if (ent->age < old->age)
3238 #ifdef DEBUG_TO_FROM_CHAR
3239 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3242 StrNCpy(old->str, str, DCH_CACHE_SIZE + 1);
3243 old->age = (++DCHCounter);
3244 /* caller is expected to fill format, then set valid */
3249 #ifdef DEBUG_TO_FROM_CHAR
3250 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3252 ent = DCHCache + n_DCHCache;
3254 StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1);
3255 ent->age = (++DCHCounter);
3256 /* caller is expected to fill format, then set valid */
3262 /* look for an existing DCHCacheEntry matching the given format picture */
3263 static DCHCacheEntry *
3264 DCH_cache_search(const char *str)
3269 /* counter overflow check - paranoia? */
3270 if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES))
3274 for (ent = DCHCache; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++)
3275 ent->age = (++DCHCounter);
3278 for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++)
3280 if (ent->valid && strcmp(ent->str, str) == 0)
3282 ent->age = (++DCHCounter);
3290 /* Find or create a DCHCacheEntry for the given format picture */
3291 static DCHCacheEntry *
3292 DCH_cache_fetch(const char *str)
3296 if ((ent = DCH_cache_search(str)) == NULL)
3299 * Not in the cache, must run parser and save a new format-picture to
3300 * the cache. Do not mark the cache entry valid until parsing
3303 ent = DCH_cache_getnew(str);
3305 parse_format(ent->format, str, DCH_keywords,
3306 DCH_suff, DCH_index, DCH_TYPE, NULL);
3314 * Format a date/time or interval into a string according to fmt.
3315 * We parse fmt into a list of FormatNodes. This is then passed to DCH_to_char
3319 datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
3329 * Convert fmt to C string
3331 fmt_str = text_to_cstring(fmt);
3332 fmt_len = strlen(fmt_str);
3335 * Allocate workspace for result as C string
3337 result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
3340 if (fmt_len > DCH_CACHE_SIZE)
3343 * Allocate new memory if format picture is bigger than static cache
3344 * and do not use cache (call parser always)
3348 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3350 parse_format(format, fmt_str, DCH_keywords,
3351 DCH_suff, DCH_index, DCH_TYPE, NULL);
3358 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str);
3361 format = ent->format;
3364 /* The real work is here */
3365 DCH_to_char(format, is_interval, tmtc, result, collid);
3372 /* convert C-string result to TEXT format */
3373 res = cstring_to_text(result);
3379 /****************************************************************************
3381 ***************************************************************************/
3383 /* -------------------
3384 * TIMESTAMP to_char()
3385 * -------------------
3388 timestamp_to_char(PG_FUNCTION_ARGS)
3390 Timestamp dt = PG_GETARG_TIMESTAMP(0);
3391 text *fmt = PG_GETARG_TEXT_P(1),
3397 if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
3403 if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0)
3405 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3406 errmsg("timestamp out of range")));
3408 thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3409 tm->tm_wday = (thisdate + 1) % 7;
3410 tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
3412 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
3415 PG_RETURN_TEXT_P(res);
3419 timestamptz_to_char(PG_FUNCTION_ARGS)
3421 TimestampTz dt = PG_GETARG_TIMESTAMP(0);
3422 text *fmt = PG_GETARG_TEXT_P(1),
3429 if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
3435 if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
3437 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3438 errmsg("timestamp out of range")));
3440 thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3441 tm->tm_wday = (thisdate + 1) % 7;
3442 tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
3444 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
3447 PG_RETURN_TEXT_P(res);
3451 /* -------------------
3452 * INTERVAL to_char()
3453 * -------------------
3456 interval_to_char(PG_FUNCTION_ARGS)
3458 Interval *it = PG_GETARG_INTERVAL_P(0);
3459 text *fmt = PG_GETARG_TEXT_P(1),
3464 if ((VARSIZE(fmt) - VARHDRSZ) <= 0)
3470 if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0)
3473 /* wday is meaningless, yday approximates the total span in days */
3474 tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
3476 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
3479 PG_RETURN_TEXT_P(res);
3482 /* ---------------------
3485 * Make Timestamp from date_str which is formatted at argument 'fmt'
3486 * ( to_timestamp is reverse to_char() )
3487 * ---------------------
3490 to_timestamp(PG_FUNCTION_ARGS)
3492 text *date_txt = PG_GETARG_TEXT_P(0);
3493 text *fmt = PG_GETARG_TEXT_P(1);
3499 do_to_timestamp(date_txt, fmt, &tm, &fsec);
3501 tz = DetermineTimeZoneOffset(&tm, session_timezone);
3503 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
3505 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3506 errmsg("timestamp out of range")));
3508 PG_RETURN_TIMESTAMP(result);
3513 * Make Date from date_str which is formated at argument 'fmt'
3517 to_date(PG_FUNCTION_ARGS)
3519 text *date_txt = PG_GETARG_TEXT_P(0);
3520 text *fmt = PG_GETARG_TEXT_P(1);
3525 do_to_timestamp(date_txt, fmt, &tm, &fsec);
3527 /* Prevent overflow in Julian-day routines */
3528 if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
3530 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3531 errmsg("date out of range: \"%s\"",
3532 text_to_cstring(date_txt))));
3534 result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
3536 /* Now check for just-out-of-range dates */
3537 if (!IS_VALID_DATE(result))
3539 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3540 errmsg("date out of range: \"%s\"",
3541 text_to_cstring(date_txt))));
3543 PG_RETURN_DATEADT(result);
3547 * do_to_timestamp: shared code for to_timestamp and to_date
3549 * Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm
3550 * and fractional seconds.
3552 * We parse 'fmt' into a list of FormatNodes, which is then passed to
3553 * DCH_from_char to populate a TmFromChar with the parsed contents of
3556 * The TmFromChar is then analysed and converted into the final results in
3557 * struct 'tm' and 'fsec'.
3560 do_to_timestamp(text *date_txt, text *fmt,
3561 struct pg_tm * tm, fsec_t *fsec)
3569 date_str = text_to_cstring(date_txt);
3574 fmask = 0; /* bit mask for ValidateDate() */
3576 fmt_len = VARSIZE_ANY_EXHDR(fmt);
3583 fmt_str = text_to_cstring(fmt);
3585 if (fmt_len > DCH_CACHE_SIZE)
3588 * Allocate new memory if format picture is bigger than static
3589 * cache and do not use cache (call parser always)
3593 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3595 parse_format(format, fmt_str, DCH_keywords,
3596 DCH_suff, DCH_index, DCH_TYPE, NULL);
3603 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str);
3606 format = ent->format;
3609 #ifdef DEBUG_TO_FROM_CHAR
3610 /* dump_node(format, fmt_len); */
3611 /* dump_index(DCH_keywords, DCH_index); */
3614 DCH_from_char(format, date_str, &tmfc);
3624 * Convert to_date/to_timestamp input fields to standard 'tm'
3630 tm->tm_hour = x / SECS_PER_HOUR;
3632 tm->tm_min = x / SECS_PER_MINUTE;
3633 x %= SECS_PER_MINUTE;
3638 tm->tm_sec = tmfc.ss;
3640 tm->tm_min = tmfc.mi;
3642 tm->tm_hour = tmfc.hh;
3644 if (tmfc.clock == CLOCK_12_HOUR)
3646 if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
3648 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3649 errmsg("hour \"%d\" is invalid for the 12-hour clock",
3651 errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
3653 if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
3654 tm->tm_hour += HOURS_PER_DAY / 2;
3655 else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
3662 * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
3663 * the year in the given century. Keep in mind that the 21st century
3664 * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
3667 if (tmfc.cc && tmfc.yysz <= 2)
3671 tm->tm_year = tmfc.year % 100;
3675 tm->tm_year += (tmfc.cc - 1) * 100;
3677 tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1;
3681 /* find century year for dates ending in "00" */
3682 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
3687 /* If a 4-digit year is provided, we use that and ignore CC. */
3688 tm->tm_year = tmfc.year;
3689 if (tmfc.bc && tm->tm_year > 0)
3690 tm->tm_year = -(tm->tm_year - 1);
3692 fmask |= DTK_M(YEAR);
3696 /* use first year of century */
3700 /* +1 because 21st century started in 2001 */
3701 tm->tm_year = (tmfc.cc - 1) * 100 + 1;
3703 /* +1 because year == 599 is 600 BC */
3704 tm->tm_year = tmfc.cc * 100 + 1;
3705 fmask |= DTK_M(YEAR);
3710 j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3711 fmask |= DTK_DATE_M;
3716 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
3719 * If tmfc.d is not set, then the date is left at the beginning of
3720 * the ISO week (Monday).
3723 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3725 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3726 fmask |= DTK_DATE_M;
3729 tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
3733 tmfc.dd = (tmfc.w - 1) * 7 + 1;
3736 tm->tm_mday = tmfc.dd;
3737 fmask |= DTK_M(DAY);
3741 tm->tm_mon = tmfc.mm;
3742 fmask |= DTK_M(MONTH);
3745 if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
3748 * The month and day field have not been set, so we use the
3749 * day-of-year field to populate them. Depending on the date mode,
3750 * this field may be interpreted as a Gregorian day-of-year, or an ISO
3751 * week date day-of-year.
3754 if (!tm->tm_year && !tmfc.bc)
3756 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3757 errmsg("cannot calculate day of year without year information")));
3759 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
3761 int j0; /* zeroth day of the ISO year, in Julian */
3763 j0 = isoweek2j(tm->tm_year, 1) - 1;
3765 j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3766 fmask |= DTK_DATE_M;
3773 static const int ysum[2][13] = {
3774 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
3775 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
3777 y = ysum[isleap(tm->tm_year)];
3779 for (i = 1; i <= MONTHS_PER_YEAR; i++)
3781 if (tmfc.ddd <= y[i])
3784 if (tm->tm_mon <= 1)
3787 if (tm->tm_mday <= 1)
3788 tm->tm_mday = tmfc.ddd - y[i - 1];
3790 fmask |= DTK_M(MONTH) | DTK_M(DAY);
3794 #ifdef HAVE_INT64_TIMESTAMP
3796 *fsec += tmfc.ms * 1000;
3801 *fsec += (double) tmfc.ms / 1000;
3803 *fsec += (double) tmfc.us / 1000000;
3806 /* Range-check date fields according to bit mask computed above */
3809 /* We already dealt with AD/BC, so pass isjulian = true */
3810 int dterr = ValidateDate(fmask, true, false, false, tm);
3815 * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
3816 * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
3817 * irrelevant hint about datestyle.
3819 DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp");
3823 /* Range-check time fields too */
3824 if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY ||
3825 tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR ||
3826 tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
3827 #ifdef HAVE_INT64_TIMESTAMP
3828 *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC
3830 *fsec < 0 || *fsec >= 1
3833 DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp");
3841 /**********************************************************************
3842 * the NUMBER version part
3843 *********************************************************************/
3847 fill_str(char *str, int c, int max)
3849 memset(str, c, max);
3850 *(str + max) = '\0';
3854 #define zeroize_NUM(_n) \
3860 (_n)->pre_lsign_num = 0; \
3861 (_n)->need_locale = 0; \
3863 (_n)->zero_start = 0; \
3864 (_n)->zero_end = 0; \
3867 /* select a NUMCacheEntry to hold the given format picture */
3868 static NUMCacheEntry *
3869 NUM_cache_getnew(const char *str)
3873 /* counter overflow check - paranoia? */
3874 if (NUMCounter >= (INT_MAX - NUM_CACHE_ENTRIES))
3878 for (ent = NUMCache; ent < (NUMCache + NUM_CACHE_ENTRIES); ent++)
3879 ent->age = (++NUMCounter);
3883 * If cache is full, remove oldest entry (or recycle first not-valid one)
3885 if (n_NUMCache >= NUM_CACHE_ENTRIES)
3887 NUMCacheEntry *old = NUMCache + 0;
3889 #ifdef DEBUG_TO_FROM_CHAR
3890 elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
3894 for (ent = NUMCache + 1; ent < (NUMCache + NUM_CACHE_ENTRIES); ent++)
3901 if (ent->age < old->age)
3905 #ifdef DEBUG_TO_FROM_CHAR
3906 elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
3909 StrNCpy(old->str, str, NUM_CACHE_SIZE + 1);
3910 old->age = (++NUMCounter);
3911 /* caller is expected to fill format and Num, then set valid */
3916 #ifdef DEBUG_TO_FROM_CHAR
3917 elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
3919 ent = NUMCache + n_NUMCache;
3921 StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1);
3922 ent->age = (++NUMCounter);
3923 /* caller is expected to fill format and Num, then set valid */
3929 /* look for an existing NUMCacheEntry matching the given format picture */
3930 static NUMCacheEntry *
3931 NUM_cache_search(const char *str)
3936 /* counter overflow check - paranoia? */
3937 if (NUMCounter >= (INT_MAX - NUM_CACHE_ENTRIES))
3941 for (ent = NUMCache; ent < (NUMCache + NUM_CACHE_ENTRIES); ent++)
3942 ent->age = (++NUMCounter);
3945 for (i = 0, ent = NUMCache; i < n_NUMCache; i++, ent++)
3947 if (ent->valid && strcmp(ent->str, str) == 0)
3949 ent->age = (++NUMCounter);
3957 /* Find or create a NUMCacheEntry for the given format picture */
3958 static NUMCacheEntry *
3959 NUM_cache_fetch(const char *str)
3963 if ((ent = NUM_cache_search(str)) == NULL)
3966 * Not in the cache, must run parser and save a new format-picture to
3967 * the cache. Do not mark the cache entry valid until parsing
3970 ent = NUM_cache_getnew(str);
3972 zeroize_NUM(&ent->Num);
3974 parse_format(ent->format, str, NUM_keywords,
3975 NULL, NUM_index, NUM_TYPE, &ent->Num);
3983 * Cache routine for NUM to_char version
3987 NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
3989 FormatNode *format = NULL;
3992 str = text_to_cstring(pars_str);
3994 if (len > NUM_CACHE_SIZE)
3997 * Allocate new memory if format picture is bigger than static cache
3998 * and do not use cache (call parser always)
4000 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
4006 parse_format(format, str, NUM_keywords,
4007 NULL, NUM_index, NUM_TYPE, Num);
4014 NUMCacheEntry *ent = NUM_cache_fetch(str);
4016 *shouldFree = false;
4018 format = ent->format;
4021 * Copy cache to used struct
4023 Num->flag = ent->Num.flag;
4024 Num->lsign = ent->Num.lsign;
4025 Num->pre = ent->Num.pre;
4026 Num->post = ent->Num.post;
4027 Num->pre_lsign_num = ent->Num.pre_lsign_num;
4028 Num->need_locale = ent->Num.need_locale;
4029 Num->multi = ent->Num.multi;
4030 Num->zero_start = ent->Num.zero_start;
4031 Num->zero_end = ent->Num.zero_end;
4034 #ifdef DEBUG_TO_FROM_CHAR
4035 /* dump_node(format, len); */
4036 dump_index(NUM_keywords, NUM_index);
4045 int_to_roman(int number)
4053 result = (char *) palloc(16);
4056 if (number > 3999 || number < 1)
4058 fill_str(result, '#', 15);
4061 len = snprintf(numstr, sizeof(numstr), "%d", number);
4063 for (p = numstr; *p != '\0'; p++, --len)
4065 num = *p - 49; /* 48 ascii + 1 */
4072 strcat(result, "M");
4077 strcat(result, rm100[num]);
4079 strcat(result, rm10[num]);
4081 strcat(result, rm1[num]);
4094 NUM_prepare_locale(NUMProc *Np)
4096 if (Np->Num->need_locale)
4098 struct lconv *lconv;
4103 lconv = PGLC_localeconv();
4106 * Positive / Negative number sign
4108 if (lconv->negative_sign && *lconv->negative_sign)
4109 Np->L_negative_sign = lconv->negative_sign;
4111 Np->L_negative_sign = "-";
4113 if (lconv->positive_sign && *lconv->positive_sign)
4114 Np->L_positive_sign = lconv->positive_sign;
4116 Np->L_positive_sign = "+";
4119 * Number decimal point
4121 if (lconv->decimal_point && *lconv->decimal_point)
4122 Np->decimal = lconv->decimal_point;
4127 if (!IS_LDECIMAL(Np->Num))
4131 * Number thousands separator
4133 * Some locales (e.g. broken glibc pt_BR), have a comma for decimal,
4134 * but "" for thousands_sep, so we set the thousands_sep too.
4135 * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php
4137 if (lconv->thousands_sep && *lconv->thousands_sep)
4138 Np->L_thousands_sep = lconv->thousands_sep;
4139 /* Make sure thousands separator doesn't match decimal point symbol. */
4140 else if (strcmp(Np->decimal, ",") !=0)
4141 Np->L_thousands_sep = ",";
4143 Np->L_thousands_sep = ".";
4148 if (lconv->currency_symbol && *lconv->currency_symbol)
4149 Np->L_currency_symbol = lconv->currency_symbol;
4151 Np->L_currency_symbol = " ";
4158 Np->L_negative_sign = "-";
4159 Np->L_positive_sign = "+";
4162 Np->L_thousands_sep = ",";
4163 Np->L_currency_symbol = " ";
4168 * Return pointer of last relevant number after decimal point
4169 * 12.0500 --> last relevant is '5'
4170 * 12.0000 --> last relevant is '.'
4171 * If there is no decimal point, return NULL (which will result in same
4172 * behavior as if FM hadn't been specified).
4176 get_last_relevant_decnum(char *num)
4179 *p = strchr(num, '.');
4181 #ifdef DEBUG_TO_FROM_CHAR
4182 elog(DEBUG_elog_output, "get_last_relevant_decnum()");
4200 * Number extraction for TO_NUMBER()
4204 NUM_numpart_from_char(NUMProc *Np, int id, int input_len)
4206 bool isread = FALSE;
4208 #ifdef DEBUG_TO_FROM_CHAR
4209 elog(DEBUG_elog_output, " --- scan start --- id=%s",
4210 (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
4213 #define OVERLOAD_TEST (Np->inout_p >= Np->inout + input_len)
4214 #define AMOUNT_TEST(_s) (input_len-(Np->inout_p-Np->inout) >= _s)
4219 if (*Np->inout_p == ' ')
4226 * read sign before number
4228 if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
4229 (Np->read_pre + Np->read_post) == 0)
4231 #ifdef DEBUG_TO_FROM_CHAR
4232 elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
4233 *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
4239 if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
4243 #ifdef DEBUG_TO_FROM_CHAR
4244 elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
4246 if ((x = strlen(Np->L_negative_sign)) &&
4248 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
4253 else if ((x = strlen(Np->L_positive_sign)) &&
4255 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
4263 #ifdef DEBUG_TO_FROM_CHAR
4264 elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
4270 if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
4271 *Np->inout_p == '<'))
4273 *Np->number = '-'; /* set - */
4276 else if (*Np->inout_p == '+')
4278 *Np->number = '+'; /* set + */
4287 #ifdef DEBUG_TO_FROM_CHAR
4288 elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
4292 * read digit or decimal point
4294 if (isdigit((unsigned char) *Np->inout_p))
4296 if (Np->read_dec && Np->read_post == Np->Num->post)
4299 *Np->number_p = *Np->inout_p;
4309 #ifdef DEBUG_TO_FROM_CHAR
4310 elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
4313 else if (IS_DECIMAL(Np->Num) && Np->read_dec == FALSE)
4316 * We need not test IS_LDECIMAL(Np->Num) explicitly here, because
4317 * Np->decimal is always just "." if we don't have a D format token.
4318 * So we just unconditionally match to Np->decimal.
4320 int x = strlen(Np->decimal);
4322 #ifdef DEBUG_TO_FROM_CHAR
4323 elog(DEBUG_elog_output, "Try read decimal point (%c)",
4326 if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
4328 Np->inout_p += x - 1;
4329 *Np->number_p = '.';
4331 Np->read_dec = TRUE;
4340 * Read sign behind "last" number
4342 * We need sign detection because determine exact position of post-sign is
4345 * FM9999.9999999S -> 123.001- 9.9S -> .5- FM9.999999MI ->
4348 if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
4351 * locale sign (NUM_S) is always anchored behind a last number, if: -
4352 * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
4353 * next char is not digit
4355 if (IS_LSIGN(Np->Num) && isread &&
4356 (Np->inout_p + 1) < Np->inout + input_len &&
4357 !isdigit((unsigned char) *(Np->inout_p + 1)))
4360 char *tmp = Np->inout_p++;
4362 #ifdef DEBUG_TO_FROM_CHAR
4363 elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
4365 if ((x = strlen(Np->L_negative_sign)) &&
4367 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
4369 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
4372 else if ((x = strlen(Np->L_positive_sign)) &&
4374 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
4376 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
4379 if (*Np->number == ' ')
4385 * try read non-locale sign, it's happen only if format is not exact
4386 * and we cannot determine sign position of MI/PL/SG, an example:
4388 * FM9.999999MI -> 5.01-
4390 * if (.... && IS_LSIGN(Np->Num)==FALSE) prevents read wrong formats
4391 * like to_number('1 -', '9S') where sign is not anchored to last
4394 else if (isread == FALSE && IS_LSIGN(Np->Num) == FALSE &&
4395 (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
4397 #ifdef DEBUG_TO_FROM_CHAR
4398 elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
4404 if (*Np->inout_p == '-' || *Np->inout_p == '+')
4405 /* NUM_processor() do inout_p++ */
4406 *Np->number = *Np->inout_p;
4411 #define IS_PREDEC_SPACE(_n) \
4412 (IS_ZERO((_n)->Num)==FALSE && \
4413 (_n)->number == (_n)->number_p && \
4414 *(_n)->number == '0' && \
4415 (_n)->Num->post != 0)
4418 * Add digit or sign to number-string
4422 NUM_numpart_to_char(NUMProc *Np, int id)
4426 if (IS_ROMAN(Np->Num))
4429 /* Note: in this elog() output not set '\0' in 'inout' */
4431 #ifdef DEBUG_TO_FROM_CHAR
4434 * Np->num_curr is number of current item in format-picture, it is not
4435 * current position in inout!
4437 elog(DEBUG_elog_output,
4438 "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
4447 * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
4448 * handle "9.9" --> " .1"
4450 if (Np->sign_wrote == FALSE &&
4451 (Np->num_curr >= Np->out_pre_spaces || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
4452 (IS_PREDEC_SPACE(Np) == FALSE || (Np->last_relevant && *Np->last_relevant == '.')))
4454 if (IS_LSIGN(Np->Num))
4456 if (Np->Num->lsign == NUM_LSIGN_PRE)
4458 if (Np->sign == '-')
4459 strcpy(Np->inout_p, Np->L_negative_sign);
4461 strcpy(Np->inout_p, Np->L_positive_sign);
4462 Np->inout_p += strlen(Np->inout_p);
4463 Np->sign_wrote = TRUE;
4466 else if (IS_BRACKET(Np->Num))
4468 *Np->inout_p = Np->sign == '+' ? ' ' : '<';
4470 Np->sign_wrote = TRUE;
4472 else if (Np->sign == '+')
4474 if (!IS_FILLMODE(Np->Num))
4476 *Np->inout_p = ' '; /* Write + */
4479 Np->sign_wrote = TRUE;
4481 else if (Np->sign == '-')
4485 Np->sign_wrote = TRUE;
4491 * digits / FM / Zero / Dec. point
4493 if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
4495 if (Np->num_curr < Np->out_pre_spaces &&
4496 (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
4501 if (!IS_FILLMODE(Np->Num))
4503 *Np->inout_p = ' '; /* Write ' ' */
4507 else if (IS_ZERO(Np->Num) &&
4508 Np->num_curr < Np->out_pre_spaces &&
4509 Np->Num->zero_start <= Np->num_curr)
4514 *Np->inout_p = '0'; /* Write '0' */
4521 * Write Decimal point
4523 if (*Np->number_p == '.')
4525 if (!Np->last_relevant || *Np->last_relevant != '.')
4527 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
4528 Np->inout_p += strlen(Np->inout_p);
4532 * Ora 'n' -- FM9.9 --> 'n.'
4534 else if (IS_FILLMODE(Np->Num) &&
4535 Np->last_relevant && *Np->last_relevant == '.')
4537 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
4538 Np->inout_p += strlen(Np->inout_p);
4546 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
4551 * '0.1' -- 9.9 --> ' .1'
4553 else if (IS_PREDEC_SPACE(Np))
4555 if (!IS_FILLMODE(Np->Num))
4562 * '0' -- FM9.9 --> '0.'
4564 else if (Np->last_relevant && *Np->last_relevant == '.')
4572 *Np->inout_p = *Np->number_p; /* Write DIGIT */
4577 /* do no exceed string length */
4582 end = Np->num_count + (Np->out_pre_spaces ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
4584 if (Np->last_relevant && Np->last_relevant == Np->number_p)
4587 if (Np->num_curr + 1 == end)
4589 if (Np->sign_wrote == TRUE && IS_BRACKET(Np->Num))
4591 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
4594 else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
4596 if (Np->sign == '-')
4597 strcpy(Np->inout_p, Np->L_negative_sign);
4599 strcpy(Np->inout_p, Np->L_positive_sign);
4600 Np->inout_p += strlen(Np->inout_p);
4609 NUM_processor(FormatNode *node, NUMDesc *Num, char *inout,
4610 char *number, int from_char_input_len, int to_char_out_pre_spaces,
4611 int sign, bool is_to_char, Oid collid)
4617 MemSet(Np, 0, sizeof(NUMProc));
4620 Np->is_to_char = is_to_char;
4621 Np->number = number;
4623 Np->last_relevant = NULL;
4626 Np->read_dec = FALSE;
4628 if (Np->Num->zero_start)
4629 --Np->Num->zero_start;
4631 if (IS_EEEE(Np->Num))
4633 if (!Np->is_to_char)
4635 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4636 errmsg("\"EEEE\" not supported for input")));
4637 return strcpy(inout, number);
4643 if (IS_ROMAN(Np->Num))
4645 if (!Np->is_to_char)
4647 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4648 errmsg("\"RN\" not supported for input")));
4650 Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->post =
4651 Np->Num->pre = Np->out_pre_spaces = Np->sign = 0;
4653 if (IS_FILLMODE(Np->Num))
4656 Np->Num->flag |= NUM_F_FILLMODE;
4660 Np->Num->flag |= NUM_F_ROMAN;
4670 /* MI/PL/SG - write sign itself and not in number */
4671 if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
4673 if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == FALSE)
4674 Np->sign_wrote = FALSE; /* need sign */
4676 Np->sign_wrote = TRUE; /* needn't sign */
4680 if (Np->sign != '-')
4682 if (IS_BRACKET(Np->Num) && IS_FILLMODE(Np->Num))
4683 Np->Num->flag &= ~NUM_F_BRACKET;
4684 if (IS_MINUS(Np->Num))
4685 Np->Num->flag &= ~NUM_F_MINUS;
4687 else if (Np->sign != '+' && IS_PLUS(Np->Num))
4688 Np->Num->flag &= ~NUM_F_PLUS;
4690 if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == FALSE)
4691 Np->sign_wrote = TRUE; /* needn't sign */
4693 Np->sign_wrote = FALSE; /* need sign */
4695 if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
4696 Np->Num->lsign = NUM_LSIGN_POST;
4705 Np->num_count = Np->Num->post + Np->Num->pre - 1;
4709 Np->out_pre_spaces = to_char_out_pre_spaces;
4711 if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
4713 Np->last_relevant = get_last_relevant_decnum(Np->number);
4716 * If any '0' specifiers are present, make sure we don't strip
4719 if (Np->last_relevant && Np->Num->zero_end > Np->out_pre_spaces)
4723 last_zero = Np->number + (Np->Num->zero_end - Np->out_pre_spaces);
4724 if (Np->last_relevant < last_zero)
4725 Np->last_relevant = last_zero;
4729 if (Np->sign_wrote == FALSE && Np->out_pre_spaces == 0)
4734 Np->out_pre_spaces = 0;
4735 *Np->number = ' '; /* sign space */
4736 *(Np->number + 1) = '\0';
4742 #ifdef DEBUG_TO_FROM_CHAR
4743 elog(DEBUG_elog_output,
4744 "\n\tSIGN: '%c'\n\tNUM: '%s'\n\tPRE: %d\n\tPOST: %d\n\tNUM_COUNT: %d\n\tNUM_PRE: %d\n\tSIGN_WROTE: %s\n\tZERO: %s\n\tZERO_START: %d\n\tZERO_END: %d\n\tLAST_RELEVANT: %s\n\tBRACKET: %s\n\tPLUS: %s\n\tMINUS: %s\n\tFILLMODE: %s\n\tROMAN: %s\n\tEEEE: %s",
4751 Np->sign_wrote ? "Yes" : "No",
4752 IS_ZERO(Np->Num) ? "Yes" : "No",
4753 Np->Num->zero_start,
4755 Np->last_relevant ? Np->last_relevant : "<not set>",
4756 IS_BRACKET(Np->Num) ? "Yes" : "No",
4757 IS_PLUS(Np->Num) ? "Yes" : "No",
4758 IS_MINUS(Np->Num) ? "Yes" : "No",
4759 IS_FILLMODE(Np->Num) ? "Yes" : "No",
4760 IS_ROMAN(Np->Num) ? "Yes" : "No",
4761 IS_EEEE(Np->Num) ? "Yes" : "No"
4768 NUM_prepare_locale(Np);
4771 * Processor direct cycle
4774 Np->number_p = Np->number;
4776 Np->number_p = Np->number + 1; /* first char is space for sign */
4778 for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
4780 if (!Np->is_to_char)
4783 * Check non-string inout end
4785 if (Np->inout_p >= Np->inout + from_char_input_len)
4790 * Format pictures actions
4792 if (n->type == NODE_TYPE_ACTION)
4795 * Create/reading digit/zero/blank/sing
4797 * 'NUM_S' note: The locale sign is anchored to number and we
4798 * read/write it when we work with first or last number
4799 * (NUM_0/NUM_9). This is reason why NUM_S missing in follow
4810 NUM_numpart_to_char(Np, n->key->id);
4811 continue; /* for() */
4815 NUM_numpart_from_char(Np, n->key->id, from_char_input_len);
4816 break; /* switch() case: */
4824 if (IS_FILLMODE(Np->Num))
4836 if (IS_FILLMODE(Np->Num))
4847 if (IS_FILLMODE(Np->Num))
4851 int x = strlen(Np->L_thousands_sep);
4853 memset(Np->inout_p, ' ', x);
4854 Np->inout_p += x - 1;
4859 strcpy(Np->inout_p, Np->L_thousands_sep);
4860 Np->inout_p += strlen(Np->inout_p) - 1;
4867 if (IS_FILLMODE(Np->Num))
4870 Np->inout_p += strlen(Np->L_thousands_sep) - 1;
4877 strcpy(Np->inout_p, Np->L_currency_symbol);
4878 Np->inout_p += strlen(Np->inout_p) - 1;
4881 Np->inout_p += strlen(Np->L_currency_symbol) - 1;
4885 if (IS_FILLMODE(Np->Num))
4887 strcpy(Np->inout_p, Np->number_p);
4888 Np->inout_p += strlen(Np->inout_p) - 1;
4892 sprintf(Np->inout_p, "%15s", Np->number_p);
4893 Np->inout_p += strlen(Np->inout_p) - 1;
4898 if (IS_FILLMODE(Np->Num))
4900 strcpy(Np->inout_p, asc_tolower_z(Np->number_p));
4901 Np->inout_p += strlen(Np->inout_p) - 1;
4905 sprintf(Np->inout_p, "%15s", asc_tolower_z(Np->number_p));
4906 Np->inout_p += strlen(Np->inout_p) - 1;
4911 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
4912 Np->sign == '-' || IS_DECIMAL(Np->Num))
4916 strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
4921 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
4922 Np->sign == '-' || IS_DECIMAL(Np->Num))
4926 strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
4933 if (Np->sign == '-')
4935 else if (IS_FILLMODE(Np->Num))
4942 if (*Np->inout_p == '-')
4950 if (Np->sign == '+')
4952 else if (IS_FILLMODE(Np->Num))
4959 if (*Np->inout_p == '+')
4966 *Np->inout_p = Np->sign;
4970 if (*Np->inout_p == '-')
4972 else if (*Np->inout_p == '+')
4986 * Remove to output char from input in TO_CHAR
4989 *Np->inout_p = n->character;
4996 *Np->inout_p = '\0';
5001 if (*(Np->number_p - 1) == '.')
5002 *(Np->number_p - 1) = '\0';
5004 *Np->number_p = '\0';
5007 * Correction - precision of dec. number
5009 Np->Num->post = Np->read_post;
5011 #ifdef DEBUG_TO_FROM_CHAR
5012 elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
5019 * MACRO: Start part of NUM - for all NUM's to_char variants
5020 * (sorry, but I hate copy same code - macro is better..)
5023 #define NUM_TOCHAR_prepare \
5025 int len = VARSIZE_ANY_EXHDR(fmt); \
5026 if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
5027 PG_RETURN_TEXT_P(cstring_to_text("")); \
5028 result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
5029 format = NUM_cache(len, &Num, fmt, &shouldFree); \
5033 * MACRO: Finish part of NUM
5036 #define NUM_TOCHAR_finish \
5040 NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \
5046 * Convert null-terminated representation of result to standard text. \
5047 * The result is usually much bigger than it needs to be, but there \
5048 * seems little point in realloc'ing it smaller. \
5050 len = strlen(VARDATA(result)); \
5051 SET_VARSIZE(result, len + VARHDRSZ); \
5054 /* -------------------
5055 * NUMERIC to_number() (convert string to numeric)
5056 * -------------------
5059 numeric_to_number(PG_FUNCTION_ARGS)
5061 text *value = PG_GETARG_TEXT_P(0);
5062 text *fmt = PG_GETARG_TEXT_P(1);
5072 len = VARSIZE(fmt) - VARHDRSZ;
5074 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
5077 format = NUM_cache(len, &Num, fmt, &shouldFree);
5079 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
5081 NUM_processor(format, &Num, VARDATA(value), numstr,
5082 VARSIZE(value) - VARHDRSZ, 0, 0, false, PG_GET_COLLATION());
5085 precision = Num.pre + Num.multi + scale;
5090 result = DirectFunctionCall3(numeric_in,
5091 CStringGetDatum(numstr),
5092 ObjectIdGetDatum(InvalidOid),
5093 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
5098 Numeric a = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
5099 Int32GetDatum(10)));
5100 Numeric b = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
5101 Int32GetDatum(-Num.multi)));
5103 x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
5105 NumericGetDatum(b)));
5106 result = DirectFunctionCall2(numeric_mul,
5108 NumericGetDatum(x));
5115 /* ------------------
5117 * ------------------
5120 numeric_to_char(PG_FUNCTION_ARGS)
5122 Numeric value = PG_GETARG_NUMERIC(0);
5123 text *fmt = PG_GETARG_TEXT_P(1);
5128 int out_pre_spaces = 0,
5138 * On DateType depend part (numeric)
5142 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5143 NumericGetDatum(value),
5146 int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
5147 NumericGetDatum(x))));
5149 else if (IS_EEEE(&Num))
5151 orgnum = numeric_out_sci(value, Num.post);
5154 * numeric_out_sci() does not emit a sign for positive numbers. We
5155 * need to add a space in this case so that positive and negative
5156 * numbers are aligned. We also have to do the right thing for NaN.
5158 if (strcmp(orgnum, "NaN") == 0)
5161 * Allow 6 characters for the leading sign, the decimal point,
5162 * "e", the exponent's sign and two exponent digits.
5164 numstr = (char *) palloc(Num.pre + Num.post + 7);
5165 fill_str(numstr, '#', Num.pre + Num.post + 6);
5167 *(numstr + Num.pre + 1) = '.';
5169 else if (*orgnum != '-')
5171 numstr = (char *) palloc(strlen(orgnum) + 2);
5173 strcpy(numstr + 1, orgnum);
5183 Numeric val = value;
5187 Numeric a = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
5188 Int32GetDatum(10)));
5189 Numeric b = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
5190 Int32GetDatum(Num.multi)));
5192 x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
5194 NumericGetDatum(b)));
5195 val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
5196 NumericGetDatum(value),
5197 NumericGetDatum(x)));
5198 Num.pre += Num.multi;
5201 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5202 NumericGetDatum(val),
5203 Int32GetDatum(Num.post)));
5204 orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
5205 NumericGetDatum(x)));
5210 numstr = orgnum + 1;
5218 if ((p = strchr(numstr, '.')))
5219 numstr_pre_len = p - numstr;
5221 numstr_pre_len = strlen(numstr);
5223 /* needs padding? */
5224 if (numstr_pre_len < Num.pre)
5225 out_pre_spaces = Num.pre - numstr_pre_len;
5226 /* overflowed prefix digit format? */
5227 else if (numstr_pre_len > Num.pre)
5229 numstr = (char *) palloc(Num.pre + Num.post + 2);
5230 fill_str(numstr, '#', Num.pre + Num.post + 1);
5231 *(numstr + Num.pre) = '.';
5236 PG_RETURN_TEXT_P(result);
5244 int4_to_char(PG_FUNCTION_ARGS)
5246 int32 value = PG_GETARG_INT32(0);
5247 text *fmt = PG_GETARG_TEXT_P(1);
5252 int out_pre_spaces = 0,
5260 * On DateType depend part (int32)
5263 numstr = orgnum = int_to_roman(value);
5264 else if (IS_EEEE(&Num))
5266 /* we can do it easily because float8 won't lose any precision */
5267 float8 val = (float8) value;
5269 orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5270 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val);
5273 * Swap a leading positive sign for a space.
5286 orgnum = DatumGetCString(DirectFunctionCall1(int4out,
5287 Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
5288 Num.pre += Num.multi;
5292 orgnum = DatumGetCString(DirectFunctionCall1(int4out,
5293 Int32GetDatum(value)));
5304 numstr_pre_len = strlen(orgnum);
5306 /* post-decimal digits? Pad out with zeros. */
5309 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
5310 strcpy(numstr, orgnum);
5311 *(numstr + numstr_pre_len) = '.';
5312 memset(numstr + numstr_pre_len + 1, '0', Num.post);
5313 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
5318 /* needs padding? */
5319 if (numstr_pre_len < Num.pre)
5320 out_pre_spaces = Num.pre - numstr_pre_len;
5321 /* overflowed prefix digit format? */
5322 else if (numstr_pre_len > Num.pre)
5324 numstr = (char *) palloc(Num.pre + Num.post + 2);
5325 fill_str(numstr, '#', Num.pre + Num.post + 1);
5326 *(numstr + Num.pre) = '.';
5331 PG_RETURN_TEXT_P(result);
5339 int8_to_char(PG_FUNCTION_ARGS)
5341 int64 value = PG_GETARG_INT64(0);
5342 text *fmt = PG_GETARG_TEXT_P(1);
5347 int out_pre_spaces = 0,
5355 * On DateType depend part (int32)
5359 /* Currently don't support int8 conversion to roman... */
5360 numstr = orgnum = int_to_roman(DatumGetInt32(
5361 DirectFunctionCall1(int84, Int64GetDatum(value))));
5363 else if (IS_EEEE(&Num))
5365 /* to avoid loss of precision, must go via numeric not float8 */
5368 val = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
5369 Int64GetDatum(value)));
5370 orgnum = numeric_out_sci(val, Num.post);
5373 * numeric_out_sci() does not emit a sign for positive numbers. We
5374 * need to add a space in this case so that positive and negative
5375 * numbers are aligned. We don't have to worry about NaN here.
5379 numstr = (char *) palloc(strlen(orgnum) + 2);
5381 strcpy(numstr + 1, orgnum);
5394 double multi = pow((double) 10, (double) Num.multi);
5396 value = DatumGetInt64(DirectFunctionCall2(int8mul,
5397 Int64GetDatum(value),
5398 DirectFunctionCall1(dtoi8,
5399 Float8GetDatum(multi))));
5400 Num.pre += Num.multi;
5403 orgnum = DatumGetCString(DirectFunctionCall1(int8out,
5404 Int64GetDatum(value)));
5414 numstr_pre_len = strlen(orgnum);
5416 /* post-decimal digits? Pad out with zeros. */
5419 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
5420 strcpy(numstr, orgnum);
5421 *(numstr + numstr_pre_len) = '.';
5422 memset(numstr + numstr_pre_len + 1, '0', Num.post);
5423 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
5428 /* needs padding? */
5429 if (numstr_pre_len < Num.pre)
5430 out_pre_spaces = Num.pre - numstr_pre_len;
5431 /* overflowed prefix digit format? */
5432 else if (numstr_pre_len > Num.pre)
5434 numstr = (char *) palloc(Num.pre + Num.post + 2);
5435 fill_str(numstr, '#', Num.pre + Num.post + 1);
5436 *(numstr + Num.pre) = '.';
5441 PG_RETURN_TEXT_P(result);
5444 /* -----------------
5449 float4_to_char(PG_FUNCTION_ARGS)
5451 float4 value = PG_GETARG_FLOAT4(0);
5452 text *fmt = PG_GETARG_TEXT_P(1);
5457 int out_pre_spaces = 0,
5466 numstr = orgnum = int_to_roman((int) rint(value));
5467 else if (IS_EEEE(&Num))
5469 numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5470 if (isnan(value) || is_infinite(value))
5473 * Allow 6 characters for the leading sign, the decimal point,
5474 * "e", the exponent's sign and two exponent digits.
5476 numstr = (char *) palloc(Num.pre + Num.post + 7);
5477 fill_str(numstr, '#', Num.pre + Num.post + 6);
5479 *(numstr + Num.pre + 1) = '.';
5483 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5486 * Swap a leading positive sign for a space.
5501 float multi = pow((double) 10, (double) Num.multi);
5503 val = value * multi;
5504 Num.pre += Num.multi;
5507 orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
5508 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
5509 numstr_pre_len = strlen(orgnum);
5511 /* adjust post digits to fit max float digits */
5512 if (numstr_pre_len >= FLT_DIG)
5514 else if (numstr_pre_len + Num.post > FLT_DIG)
5515 Num.post = FLT_DIG - numstr_pre_len;
5516 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
5521 numstr = orgnum + 1;
5529 if ((p = strchr(numstr, '.')))
5530 numstr_pre_len = p - numstr;
5532 numstr_pre_len = strlen(numstr);
5534 /* needs padding? */
5535 if (numstr_pre_len < Num.pre)
5536 out_pre_spaces = Num.pre - numstr_pre_len;
5537 /* overflowed prefix digit format? */
5538 else if (numstr_pre_len > Num.pre)
5540 numstr = (char *) palloc(Num.pre + Num.post + 2);
5541 fill_str(numstr, '#', Num.pre + Num.post + 1);
5542 *(numstr + Num.pre) = '.';
5547 PG_RETURN_TEXT_P(result);
5550 /* -----------------
5555 float8_to_char(PG_FUNCTION_ARGS)
5557 float8 value = PG_GETARG_FLOAT8(0);
5558 text *fmt = PG_GETARG_TEXT_P(1);
5563 int out_pre_spaces = 0,
5572 numstr = orgnum = int_to_roman((int) rint(value));
5573 else if (IS_EEEE(&Num))
5575 numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5576 if (isnan(value) || is_infinite(value))
5579 * Allow 6 characters for the leading sign, the decimal point,
5580 * "e", the exponent's sign and two exponent digits.
5582 numstr = (char *) palloc(Num.pre + Num.post + 7);
5583 fill_str(numstr, '#', Num.pre + Num.post + 6);
5585 *(numstr + Num.pre + 1) = '.';
5589 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5592 * Swap a leading positive sign for a space.
5607 double multi = pow((double) 10, (double) Num.multi);
5609 val = value * multi;
5610 Num.pre += Num.multi;
5612 orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5613 numstr_pre_len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val));
5615 /* adjust post digits to fit max double digits */
5616 if (numstr_pre_len >= DBL_DIG)
5618 else if (numstr_pre_len + Num.post > DBL_DIG)
5619 Num.post = DBL_DIG - numstr_pre_len;
5620 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
5625 numstr = orgnum + 1;
5633 if ((p = strchr(numstr, '.')))
5634 numstr_pre_len = p - numstr;
5636 numstr_pre_len = strlen(numstr);
5638 /* needs padding? */
5639 if (numstr_pre_len < Num.pre)
5640 out_pre_spaces = Num.pre - numstr_pre_len;
5641 /* overflowed prefix digit format? */
5642 else if (numstr_pre_len > Num.pre)
5644 numstr = (char *) palloc(Num.pre + Num.post + 2);
5645 fill_str(numstr, '#', Num.pre + Num.post + 1);
5646 *(numstr + Num.pre) = '.';
5651 PG_RETURN_TEXT_P(result);