1 /* -----------------------------------------------------------------------
4 * src/backend/utils/adt/formatting.c
7 * Portions Copyright (c) 1999-2014, 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 9 /* max julian day */
114 #define NUM_MAX_ITEM_SIZ 8 /* roman number (RN has 15 chars) */
120 #define MAXFLOATWIDTH 60
121 #define MAXDOUBLEWIDTH 500
125 * External (defined in PgSQL datetime.c (timestamp utils))
128 extern char *months[], /* month abbreviation */
129 *days[]; /* full days */
132 * Format parser structs
137 char *name; /* suffix string */
138 int len, /* suffix length */
139 id, /* used in node->suffix */
140 type; /* prefix / postfix */
147 * This value is used to nominate one of several distinct (and mutually
148 * exclusive) date conventions that a keyword can belong to.
152 FROM_CHAR_DATE_NONE = 0, /* Value does not affect date mode. */
153 FROM_CHAR_DATE_GREGORIAN, /* Gregorian (day, month, year) style date */
154 FROM_CHAR_DATE_ISOWEEK /* ISO 8601 week date */
157 typedef struct FormatNode FormatNode;
165 FromCharDateMode date_mode;
170 int type; /* node type */
171 const KeyWord *key; /* if node type is KEYWORD */
172 char character; /* if node type is CHAR */
173 int suffix; /* keyword suffix */
176 #define NODE_TYPE_END 1
177 #define NODE_TYPE_ACTION 2
178 #define NODE_TYPE_CHAR 3
180 #define SUFFTYPE_PREFIX 1
181 #define SUFFTYPE_POSTFIX 2
183 #define CLOCK_24_HOUR 0
184 #define CLOCK_12_HOUR 1
191 static char *months_full[] = {
192 "January", "February", "March", "April", "May", "June", "July",
193 "August", "September", "October", "November", "December", NULL
196 static char *days_short[] = {
197 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
203 * There is no 0 AD. Years go from 1 BC to 1 AD, so we make it
204 * positive and map year == -1 to year zero, and shift all negative
205 * years up one. For interval years, we just return the year.
207 #define ADJUST_YEAR(year, is_interval) ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
209 #define A_D_STR "A.D."
210 #define a_d_STR "a.d."
214 #define B_C_STR "B.C."
215 #define b_c_STR "b.c."
220 * AD / BC strings for seq_search.
222 * These are given in two variants, a long form with periods and a standard
225 * The array is laid out such that matches for AD have an even index, and
226 * matches for BC have an odd index. So the boolean value for BC is given by
227 * taking the array index of the match, modulo 2.
229 static char *adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL};
230 static char *adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL};
236 #define A_M_STR "A.M."
237 #define a_m_STR "a.m."
241 #define P_M_STR "P.M."
242 #define p_m_STR "p.m."
247 * AM / PM strings for seq_search.
249 * These are given in two variants, a long form with periods and a standard
252 * The array is laid out such that matches for AM have an even index, and
253 * matches for PM have an odd index. So the boolean value for PM is given by
254 * taking the array index of the match, modulo 2.
256 static char *ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL};
257 static char *ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL};
260 * Months in roman-numeral
261 * (Must be in reverse order for seq_search (in FROM_CHAR), because
262 * 'VIII' must have higher precedence than 'V')
265 static char *rm_months_upper[] =
266 {"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};
268 static char *rm_months_lower[] =
269 {"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};
275 static char *rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};
276 static char *rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};
277 static char *rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};
283 static char *numTH[] = {"ST", "ND", "RD", "TH", NULL};
284 static char *numth[] = {"st", "nd", "rd", "th", NULL};
290 #define ONE_UPPER 1 /* Name */
291 #define ALL_UPPER 2 /* NAME */
292 #define ALL_LOWER 3 /* name */
296 #define MAX_MONTH_LEN 9
297 #define MAX_MON_LEN 3
298 #define MAX_DAY_LEN 9
306 * Number description struct
311 int pre, /* (count) numbers before decimal */
312 post, /* (count) numbers after decimal */
313 lsign, /* want locales sign */
314 flag, /* number parameters */
315 pre_lsign_num, /* tmp value for lsign */
316 multi, /* multiplier for 'V' */
317 zero_start, /* position of first zero */
318 zero_end, /* position of last zero */
319 need_locale; /* needs it locale */
323 * Flags for NUMBER version
326 #define NUM_F_DECIMAL (1 << 1)
327 #define NUM_F_LDECIMAL (1 << 2)
328 #define NUM_F_ZERO (1 << 3)
329 #define NUM_F_BLANK (1 << 4)
330 #define NUM_F_FILLMODE (1 << 5)
331 #define NUM_F_LSIGN (1 << 6)
332 #define NUM_F_BRACKET (1 << 7)
333 #define NUM_F_MINUS (1 << 8)
334 #define NUM_F_PLUS (1 << 9)
335 #define NUM_F_ROMAN (1 << 10)
336 #define NUM_F_MULTI (1 << 11)
337 #define NUM_F_PLUS_POST (1 << 12)
338 #define NUM_F_MINUS_POST (1 << 13)
339 #define NUM_F_EEEE (1 << 14)
341 #define NUM_LSIGN_PRE (-1)
342 #define NUM_LSIGN_POST 1
343 #define NUM_LSIGN_NONE 0
349 #define IS_DECIMAL(_f) ((_f)->flag & NUM_F_DECIMAL)
350 #define IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL)
351 #define IS_ZERO(_f) ((_f)->flag & NUM_F_ZERO)
352 #define IS_BLANK(_f) ((_f)->flag & NUM_F_BLANK)
353 #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE)
354 #define IS_BRACKET(_f) ((_f)->flag & NUM_F_BRACKET)
355 #define IS_MINUS(_f) ((_f)->flag & NUM_F_MINUS)
356 #define IS_LSIGN(_f) ((_f)->flag & NUM_F_LSIGN)
357 #define IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
358 #define IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN)
359 #define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI)
360 #define IS_EEEE(_f) ((_f)->flag & NUM_F_EEEE)
363 * Format picture cache
365 * Number part = NUM_CACHE_SIZE * NUM_CACHE_FIELDS
366 * Date-time part = DCH_CACHE_SIZE * DCH_CACHE_FIELDS
370 #define NUM_CACHE_SIZE 64
371 #define NUM_CACHE_FIELDS 16
372 #define DCH_CACHE_SIZE 128
373 #define DCH_CACHE_FIELDS 16
377 FormatNode format[DCH_CACHE_SIZE + 1];
378 char str[DCH_CACHE_SIZE + 1];
384 FormatNode format[NUM_CACHE_SIZE + 1];
385 char str[NUM_CACHE_SIZE + 1];
390 /* global cache for --- date/time part */
391 static DCHCacheEntry DCHCache[DCH_CACHE_FIELDS + 1];
393 static int n_DCHCache = 0; /* number of entries */
394 static int DCHCounter = 0;
396 /* global cache for --- number part */
397 static NUMCacheEntry NUMCache[NUM_CACHE_FIELDS + 1];
399 static int n_NUMCache = 0; /* number of entries */
400 static int NUMCounter = 0;
401 static NUMCacheEntry *last_NUMCacheEntry = NUMCache + 0;
404 * For char->date/time conversion
409 FromCharDateMode mode;
415 d, /* stored as 1-7, Sunday = 1, 0 means missing */
427 yysz, /* is it YY or YYYY ? */
428 clock; /* 12 or 24 hour clock? */
431 #define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
437 #ifdef DEBUG_TO_FROM_CHAR
438 #define DEBUG_TMFC(_X) \
439 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", \
440 (_X)->mode, (_X)->hh, (_X)->pm, (_X)->mi, (_X)->ss, (_X)->ssss, \
441 (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, (_X)->year, \
442 (_X)->bc, (_X)->ww, (_X)->w, (_X)->cc, (_X)->j, (_X)->us, \
443 (_X)->yysz, (_X)->clock);
444 #define DEBUG_TM(_X) \
445 elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
446 (_X)->tm_sec, (_X)->tm_year,\
447 (_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\
448 (_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)
450 #define DEBUG_TMFC(_X)
455 * Datetime to char conversion
458 typedef struct TmToChar
460 struct pg_tm tm; /* classic 'tm' struct */
461 fsec_t fsec; /* fractional seconds */
462 const char *tzn; /* timezone */
465 #define tmtcTm(_X) (&(_X)->tm)
466 #define tmtcTzn(_X) ((_X)->tzn)
467 #define tmtcFsec(_X) ((_X)->fsec)
469 #define ZERO_tm(_X) \
471 (_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
472 (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
473 (_X)->tm_mday = (_X)->tm_mon = 1; \
476 #define ZERO_tmtc(_X) \
478 ZERO_tm( tmtcTm(_X) ); \
480 tmtcTzn(_X) = NULL; \
484 * to_char(time) appears to to_char() as an interval, so this check
485 * is really for interval and time data types.
487 #define INVALID_FOR_INTERVAL \
491 (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
492 errmsg("invalid format specification for an interval value"), \
493 errhint("Intervals are not tied to specific calendar dates."))); \
496 /*****************************************************************************
497 * KeyWord definitions
498 *****************************************************************************/
504 #define DCH_S_FM 0x01
505 #define DCH_S_TH 0x02
506 #define DCH_S_th 0x04
507 #define DCH_S_SP 0x08
508 #define DCH_S_TM 0x10
514 #define S_THth(_s) ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)
515 #define S_TH(_s) (((_s) & DCH_S_TH) ? 1 : 0)
516 #define S_th(_s) (((_s) & DCH_S_th) ? 1 : 0)
517 #define S_TH_TYPE(_s) (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)
519 /* Oracle toggles FM behavior, we don't; see docs. */
520 #define S_FM(_s) (((_s) & DCH_S_FM) ? 1 : 0)
521 #define S_SP(_s) (((_s) & DCH_S_SP) ? 1 : 0)
522 #define S_TM(_s) (((_s) & DCH_S_TM) ? 1 : 0)
525 * Suffixes definition for DATE-TIME TO/FROM CHAR
528 static KeySuffix DCH_suff[] = {
529 {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
530 {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
531 {"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX},
532 {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
533 {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
534 {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
535 {"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 num_pre, /* space before first number */
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(char *str, const KeyWord *kw,
953 static KeySuffix *suff_search(char *str, KeySuffix *suf, int type);
954 static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
955 static void parse_format(FormatNode *node, char *str, const KeyWord *kw,
956 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 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 int strdigits_len(char *str);
972 static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode);
973 static void from_char_set_int(int *dest, const int value, const FormatNode *node);
974 static int from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node);
975 static int from_char_parse_int(int *dest, char **src, FormatNode *node);
976 static int seq_search(char *name, char **array, int type, int max, int *len);
977 static int from_char_seq_search(int *dest, char **src, char **array, int type, int max, FormatNode *node);
978 static void do_to_timestamp(text *date_txt, text *fmt,
979 struct pg_tm * tm, fsec_t *fsec);
980 static char *fill_str(char *str, int c, int max);
981 static FormatNode *NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree);
982 static char *int_to_roman(int number);
983 static void NUM_prepare_locale(NUMProc *Np);
984 static char *get_last_relevant_decnum(char *num);
985 static void NUM_numpart_from_char(NUMProc *Np, int id, int plen);
986 static void NUM_numpart_to_char(NUMProc *Np, int id);
987 static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
988 int plen, int sign, bool is_to_char, Oid collid);
989 static DCHCacheEntry *DCH_cache_search(char *str);
990 static DCHCacheEntry *DCH_cache_getnew(char *str);
992 static NUMCacheEntry *NUM_cache_search(char *str);
993 static NUMCacheEntry *NUM_cache_getnew(char *str);
994 static void NUM_cache_remove(NUMCacheEntry *ent);
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(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);
1028 suff_search(char *str, 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)
1054 * In case of an error, we need to remove the numeric from the cache. Use
1055 * a PG_TRY block to ensure that this happens.
1059 if (IS_EEEE(num) && n->key->id != NUM_E)
1061 (errcode(ERRCODE_SYNTAX_ERROR),
1062 errmsg("\"EEEE\" must be the last pattern used")));
1067 if (IS_BRACKET(num))
1069 (errcode(ERRCODE_SYNTAX_ERROR),
1070 errmsg("\"9\" must be ahead of \"PR\"")));
1076 if (IS_DECIMAL(num))
1083 if (IS_BRACKET(num))
1085 (errcode(ERRCODE_SYNTAX_ERROR),
1086 errmsg("\"0\" must be ahead of \"PR\"")));
1087 if (!IS_ZERO(num) && !IS_DECIMAL(num))
1089 num->flag |= NUM_F_ZERO;
1090 num->zero_start = num->pre + 1;
1092 if (!IS_DECIMAL(num))
1097 num->zero_end = num->pre + num->post;
1101 if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num)))
1102 num->flag |= NUM_F_BLANK;
1106 num->flag |= NUM_F_LDECIMAL;
1107 num->need_locale = TRUE;
1110 if (IS_DECIMAL(num))
1112 (errcode(ERRCODE_SYNTAX_ERROR),
1113 errmsg("multiple decimal points")));
1116 (errcode(ERRCODE_SYNTAX_ERROR),
1117 errmsg("cannot use \"V\" and decimal point together")));
1118 num->flag |= NUM_F_DECIMAL;
1122 num->flag |= NUM_F_FILLMODE;
1128 (errcode(ERRCODE_SYNTAX_ERROR),
1129 errmsg("cannot use \"S\" twice")));
1130 if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
1132 (errcode(ERRCODE_SYNTAX_ERROR),
1133 errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
1134 if (!IS_DECIMAL(num))
1136 num->lsign = NUM_LSIGN_PRE;
1137 num->pre_lsign_num = num->pre;
1138 num->need_locale = TRUE;
1139 num->flag |= NUM_F_LSIGN;
1141 else if (num->lsign == NUM_LSIGN_NONE)
1143 num->lsign = NUM_LSIGN_POST;
1144 num->need_locale = TRUE;
1145 num->flag |= NUM_F_LSIGN;
1152 (errcode(ERRCODE_SYNTAX_ERROR),
1153 errmsg("cannot use \"S\" and \"MI\" together")));
1154 num->flag |= NUM_F_MINUS;
1155 if (IS_DECIMAL(num))
1156 num->flag |= NUM_F_MINUS_POST;
1162 (errcode(ERRCODE_SYNTAX_ERROR),
1163 errmsg("cannot use \"S\" and \"PL\" together")));
1164 num->flag |= NUM_F_PLUS;
1165 if (IS_DECIMAL(num))
1166 num->flag |= NUM_F_PLUS_POST;
1172 (errcode(ERRCODE_SYNTAX_ERROR),
1173 errmsg("cannot use \"S\" and \"SG\" together")));
1174 num->flag |= NUM_F_MINUS;
1175 num->flag |= NUM_F_PLUS;
1179 if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
1181 (errcode(ERRCODE_SYNTAX_ERROR),
1182 errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
1183 num->flag |= NUM_F_BRACKET;
1188 num->flag |= NUM_F_ROMAN;
1193 num->need_locale = TRUE;
1197 if (IS_DECIMAL(num))
1199 (errcode(ERRCODE_SYNTAX_ERROR),
1200 errmsg("cannot use \"V\" and decimal point together")));
1201 num->flag |= NUM_F_MULTI;
1207 (errcode(ERRCODE_SYNTAX_ERROR),
1208 errmsg("cannot use \"EEEE\" twice")));
1209 if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) ||
1210 IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) ||
1211 IS_ROMAN(num) || IS_MULTI(num))
1213 (errcode(ERRCODE_SYNTAX_ERROR),
1214 errmsg("\"EEEE\" is incompatible with other formats"),
1215 errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
1216 num->flag |= NUM_F_EEEE;
1222 NUM_cache_remove(last_NUMCacheEntry);
1232 * Format parser, search small keywords and keyword's suffixes, and make
1235 * for DATE-TIME & NUMBER version
1239 parse_format(FormatNode *node, char *str, const KeyWord *kw,
1240 KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
1248 #ifdef DEBUG_TO_FROM_CHAR
1249 elog(DEBUG_elog_output, "to_char/number(): run parser");
1261 if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
1271 if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
1273 n->type = NODE_TYPE_ACTION;
1280 * NUM version: Prepare global NUMDesc struct
1282 if (ver == NUM_TYPE)
1283 NUMDesc_prepare(Num, n);
1288 if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
1298 * Special characters '\' and '"'
1300 if (*str == '"' && last != '\\')
1306 if (*str == '"' && x != '\\')
1311 else if (*str == '\\' && x != '\\')
1316 n->type = NODE_TYPE_CHAR;
1317 n->character = *str;
1327 else if (*str && *str == '\\' && last != '\\' && *(str + 1) == '"')
1334 n->type = NODE_TYPE_CHAR;
1335 n->character = *str;
1346 if (n->type == NODE_TYPE_ACTION)
1355 n->type = NODE_TYPE_END;
1361 * DEBUG: Dump the FormatNode Tree (debug)
1364 #ifdef DEBUG_TO_FROM_CHAR
1366 #define DUMP_THth(_suf) (S_TH(_suf) ? "TH" : (S_th(_suf) ? "th" : " "))
1367 #define DUMP_FM(_suf) (S_FM(_suf) ? "FM" : " ")
1370 dump_node(FormatNode *node, int max)
1375 elog(DEBUG_elog_output, "to_from-char(): DUMP FORMAT");
1377 for (a = 0, n = node; a <= max; n++, a++)
1379 if (n->type == NODE_TYPE_ACTION)
1380 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)",
1381 a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix));
1382 else if (n->type == NODE_TYPE_CHAR)
1383 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character);
1384 else if (n->type == NODE_TYPE_END)
1386 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_END", a);
1390 elog(DEBUG_elog_output, "%d:\t unknown NODE!", a);
1395 /*****************************************************************************
1397 *****************************************************************************/
1400 * Return ST/ND/RD/TH for simple (1..9) numbers
1401 * type --> 0 upper, 1 lower
1405 get_th(char *num, int type)
1407 int len = strlen(num),
1411 last = *(num + (len - 1));
1412 if (!isdigit((unsigned char) last))
1414 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1415 errmsg("\"%s\" is not a number", num)));
1418 * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1419 * 'ST/st', 'ND/nd', 'RD/rd', respectively
1421 if ((len > 1) && ((seclast = num[len - 2]) == '1'))
1427 if (type == TH_UPPER)
1431 if (type == TH_UPPER)
1435 if (type == TH_UPPER)
1439 if (type == TH_UPPER)
1446 * Convert string-number to ordinal string-number
1447 * type --> 0 upper, 1 lower
1451 str_numth(char *dest, char *num, int type)
1455 strcat(dest, get_th(num, type));
1459 /*****************************************************************************
1460 * upper/lower/initcap functions
1461 *****************************************************************************/
1464 * If the system provides the needed functions for wide-character manipulation
1465 * (which are all standardized by C99), then we implement upper/lower/initcap
1466 * using wide-character functions, if necessary. Otherwise we use the
1467 * traditional <ctype.h> functions, which of course will not work as desired
1468 * in multibyte character sets. Note that in either case we are effectively
1469 * assuming that the database character encoding matches the encoding implied
1472 * If the system provides locale_t and associated functions (which are
1473 * standardized by Open Group's XBD), we can support collations that are
1474 * neither default nor C. The code is written to handle both combinations
1475 * of have-wide-characters and have-locale_t, though it's rather unlikely
1476 * a platform would have the latter without the former.
1480 * collation-aware, wide-character-aware lower function
1482 * We pass the number of bytes so we can pass varlena and char*
1483 * to this function. The result is a palloc'd, null-terminated string.
1486 str_tolower(const char *buff, size_t nbytes, Oid collid)
1493 /* C/POSIX collations use this path regardless of database encoding */
1494 if (lc_ctype_is_c(collid))
1496 result = asc_tolower(buff, nbytes);
1498 #ifdef USE_WIDE_UPPER_LOWER
1499 else if (pg_database_encoding_max_length() > 1)
1501 pg_locale_t mylocale = 0;
1506 if (collid != DEFAULT_COLLATION_OID)
1508 if (!OidIsValid(collid))
1511 * This typically means that the parser could not resolve a
1512 * conflict of implicit collations, so report it that way.
1515 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1516 errmsg("could not determine which collation to use for lower() function"),
1517 errhint("Use the COLLATE clause to set the collation explicitly.")));
1519 mylocale = pg_newlocale_from_collation(collid);
1522 /* Overflow paranoia */
1523 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1525 (errcode(ERRCODE_OUT_OF_MEMORY),
1526 errmsg("out of memory")));
1528 /* Output workspace cannot have more codes than input bytes */
1529 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1531 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1533 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1535 #ifdef HAVE_LOCALE_T
1537 workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
1540 workspace[curr_char] = towlower(workspace[curr_char]);
1543 /* Make result large enough; case change might change number of bytes */
1544 result_size = curr_char * pg_database_encoding_max_length() + 1;
1545 result = palloc(result_size);
1547 wchar2char(result, workspace, result_size, mylocale);
1550 #endif /* USE_WIDE_UPPER_LOWER */
1553 #ifdef HAVE_LOCALE_T
1554 pg_locale_t mylocale = 0;
1558 if (collid != DEFAULT_COLLATION_OID)
1560 if (!OidIsValid(collid))
1563 * This typically means that the parser could not resolve a
1564 * conflict of implicit collations, so report it that way.
1567 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1568 errmsg("could not determine which collation to use for lower() function"),
1569 errhint("Use the COLLATE clause to set the collation explicitly.")));
1571 #ifdef HAVE_LOCALE_T
1572 mylocale = pg_newlocale_from_collation(collid);
1576 result = pnstrdup(buff, nbytes);
1579 * Note: we assume that tolower_l() will not be so broken as to need
1580 * an isupper_l() guard test. When using the default collation, we
1581 * apply the traditional Postgres behavior that forces ASCII-style
1582 * treatment of I/i, but in non-default collations you get exactly
1583 * what the collation says.
1585 for (p = result; *p; p++)
1587 #ifdef HAVE_LOCALE_T
1589 *p = tolower_l((unsigned char) *p, mylocale);
1592 *p = pg_tolower((unsigned char) *p);
1600 * collation-aware, wide-character-aware upper function
1602 * We pass the number of bytes so we can pass varlena and char*
1603 * to this function. The result is a palloc'd, null-terminated string.
1606 str_toupper(const char *buff, size_t nbytes, Oid collid)
1613 /* C/POSIX collations use this path regardless of database encoding */
1614 if (lc_ctype_is_c(collid))
1616 result = asc_toupper(buff, nbytes);
1618 #ifdef USE_WIDE_UPPER_LOWER
1619 else if (pg_database_encoding_max_length() > 1)
1621 pg_locale_t mylocale = 0;
1626 if (collid != DEFAULT_COLLATION_OID)
1628 if (!OidIsValid(collid))
1631 * This typically means that the parser could not resolve a
1632 * conflict of implicit collations, so report it that way.
1635 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1636 errmsg("could not determine which collation to use for upper() function"),
1637 errhint("Use the COLLATE clause to set the collation explicitly.")));
1639 mylocale = pg_newlocale_from_collation(collid);
1642 /* Overflow paranoia */
1643 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1645 (errcode(ERRCODE_OUT_OF_MEMORY),
1646 errmsg("out of memory")));
1648 /* Output workspace cannot have more codes than input bytes */
1649 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1651 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1653 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1655 #ifdef HAVE_LOCALE_T
1657 workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
1660 workspace[curr_char] = towupper(workspace[curr_char]);
1663 /* Make result large enough; case change might change number of bytes */
1664 result_size = curr_char * pg_database_encoding_max_length() + 1;
1665 result = palloc(result_size);
1667 wchar2char(result, workspace, result_size, mylocale);
1670 #endif /* USE_WIDE_UPPER_LOWER */
1673 #ifdef HAVE_LOCALE_T
1674 pg_locale_t mylocale = 0;
1678 if (collid != DEFAULT_COLLATION_OID)
1680 if (!OidIsValid(collid))
1683 * This typically means that the parser could not resolve a
1684 * conflict of implicit collations, so report it that way.
1687 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1688 errmsg("could not determine which collation to use for upper() function"),
1689 errhint("Use the COLLATE clause to set the collation explicitly.")));
1691 #ifdef HAVE_LOCALE_T
1692 mylocale = pg_newlocale_from_collation(collid);
1696 result = pnstrdup(buff, nbytes);
1699 * Note: we assume that toupper_l() will not be so broken as to need
1700 * an islower_l() guard test. When using the default collation, we
1701 * apply the traditional Postgres behavior that forces ASCII-style
1702 * treatment of I/i, but in non-default collations you get exactly
1703 * what the collation says.
1705 for (p = result; *p; p++)
1707 #ifdef HAVE_LOCALE_T
1709 *p = toupper_l((unsigned char) *p, mylocale);
1712 *p = pg_toupper((unsigned char) *p);
1720 * collation-aware, wide-character-aware initcap function
1722 * We pass the number of bytes so we can pass varlena and char*
1723 * to this function. The result is a palloc'd, null-terminated string.
1726 str_initcap(const char *buff, size_t nbytes, Oid collid)
1729 int wasalnum = false;
1734 /* C/POSIX collations use this path regardless of database encoding */
1735 if (lc_ctype_is_c(collid))
1737 result = asc_initcap(buff, nbytes);
1739 #ifdef USE_WIDE_UPPER_LOWER
1740 else if (pg_database_encoding_max_length() > 1)
1742 pg_locale_t mylocale = 0;
1747 if (collid != DEFAULT_COLLATION_OID)
1749 if (!OidIsValid(collid))
1752 * This typically means that the parser could not resolve a
1753 * conflict of implicit collations, so report it that way.
1756 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1757 errmsg("could not determine which collation to use for initcap() function"),
1758 errhint("Use the COLLATE clause to set the collation explicitly.")));
1760 mylocale = pg_newlocale_from_collation(collid);
1763 /* Overflow paranoia */
1764 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1766 (errcode(ERRCODE_OUT_OF_MEMORY),
1767 errmsg("out of memory")));
1769 /* Output workspace cannot have more codes than input bytes */
1770 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1772 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1774 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1776 #ifdef HAVE_LOCALE_T
1780 workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
1782 workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
1783 wasalnum = iswalnum_l(workspace[curr_char], mylocale);
1789 workspace[curr_char] = towlower(workspace[curr_char]);
1791 workspace[curr_char] = towupper(workspace[curr_char]);
1792 wasalnum = iswalnum(workspace[curr_char]);
1796 /* Make result large enough; case change might change number of bytes */
1797 result_size = curr_char * pg_database_encoding_max_length() + 1;
1798 result = palloc(result_size);
1800 wchar2char(result, workspace, result_size, mylocale);
1803 #endif /* USE_WIDE_UPPER_LOWER */
1806 #ifdef HAVE_LOCALE_T
1807 pg_locale_t mylocale = 0;
1811 if (collid != DEFAULT_COLLATION_OID)
1813 if (!OidIsValid(collid))
1816 * This typically means that the parser could not resolve a
1817 * conflict of implicit collations, so report it that way.
1820 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1821 errmsg("could not determine which collation to use for initcap() function"),
1822 errhint("Use the COLLATE clause to set the collation explicitly.")));
1824 #ifdef HAVE_LOCALE_T
1825 mylocale = pg_newlocale_from_collation(collid);
1829 result = pnstrdup(buff, nbytes);
1832 * Note: we assume that toupper_l()/tolower_l() will not be so broken
1833 * as to need guard tests. When using the default collation, we apply
1834 * the traditional Postgres behavior that forces ASCII-style treatment
1835 * of I/i, but in non-default collations you get exactly what the
1838 for (p = result; *p; p++)
1840 #ifdef HAVE_LOCALE_T
1844 *p = tolower_l((unsigned char) *p, mylocale);
1846 *p = toupper_l((unsigned char) *p, mylocale);
1847 wasalnum = isalnum_l((unsigned char) *p, mylocale);
1853 *p = pg_tolower((unsigned char) *p);
1855 *p = pg_toupper((unsigned char) *p);
1856 wasalnum = isalnum((unsigned char) *p);
1865 * ASCII-only lower function
1867 * We pass the number of bytes so we can pass varlena and char*
1868 * to this function. The result is a palloc'd, null-terminated string.
1871 asc_tolower(const char *buff, size_t nbytes)
1879 result = pnstrdup(buff, nbytes);
1881 for (p = result; *p; p++)
1882 *p = pg_ascii_tolower((unsigned char) *p);
1888 * ASCII-only upper function
1890 * We pass the number of bytes so we can pass varlena and char*
1891 * to this function. The result is a palloc'd, null-terminated string.
1894 asc_toupper(const char *buff, size_t nbytes)
1902 result = pnstrdup(buff, nbytes);
1904 for (p = result; *p; p++)
1905 *p = pg_ascii_toupper((unsigned char) *p);
1911 * ASCII-only initcap function
1913 * We pass the number of bytes so we can pass varlena and char*
1914 * to this function. The result is a palloc'd, null-terminated string.
1917 asc_initcap(const char *buff, size_t nbytes)
1921 int wasalnum = false;
1926 result = pnstrdup(buff, nbytes);
1928 for (p = result; *p; p++)
1933 *p = c = pg_ascii_tolower((unsigned char) *p);
1935 *p = c = pg_ascii_toupper((unsigned char) *p);
1936 /* we don't trust isalnum() here */
1937 wasalnum = ((c >= 'A' && c <= 'Z') ||
1938 (c >= 'a' && c <= 'z') ||
1939 (c >= '0' && c <= '9'));
1945 /* convenience routines for when the input is null-terminated */
1948 str_tolower_z(const char *buff, Oid collid)
1950 return str_tolower(buff, strlen(buff), collid);
1954 str_toupper_z(const char *buff, Oid collid)
1956 return str_toupper(buff, strlen(buff), collid);
1960 str_initcap_z(const char *buff, Oid collid)
1962 return str_initcap(buff, strlen(buff), collid);
1966 asc_tolower_z(const char *buff)
1968 return asc_tolower(buff, strlen(buff));
1972 asc_toupper_z(const char *buff)
1974 return asc_toupper(buff, strlen(buff));
1977 /* asc_initcap_z is not currently needed */
1981 * Skip TM / th in FROM_CHAR
1984 #define SKIP_THth(_suf) (S_THth(_suf) ? 2 : 0)
1986 #ifdef DEBUG_TO_FROM_CHAR
1988 * DEBUG: Call for debug and for index checking; (Show ASCII char
1989 * and defined keyword for each used position
1993 dump_index(const KeyWord *k, const int *index)
1999 elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:");
2001 for (i = 0; i < KeyWord_INDEX_SIZE; i++)
2005 elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name);
2011 elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]);
2014 elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d",
2020 * Return TRUE if next format picture is not digit value
2024 is_next_separator(FormatNode *n)
2026 if (n->type == NODE_TYPE_END)
2029 if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
2037 /* end of format string is treated like a non-digit separator */
2038 if (n->type == NODE_TYPE_END)
2041 if (n->type == NODE_TYPE_ACTION)
2043 if (n->key->is_digit)
2048 else if (isdigit((unsigned char) n->character))
2051 return TRUE; /* some non-digit input (separator) */
2056 adjust_partial_year_to_2020(int year)
2059 * Adjust all dates toward 2020; this is effectively what happens when we
2060 * assume '70' is 1970 and '69' is 2069.
2062 /* Force 0-69 into the 2000's */
2065 /* Force 70-99 into the 1900's */
2066 else if (year < 100)
2068 /* Force 100-519 into the 2000's */
2069 else if (year < 520)
2071 /* Force 520-999 into the 1000's */
2072 else if (year < 1000)
2080 strspace_len(char *str)
2084 while (*str && isspace((unsigned char) *str))
2093 strdigits_len(char *str)
2098 len = strspace_len(str);
2101 while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ)
2110 * Set the date mode of a from-char conversion.
2112 * Puke if the date mode has already been set, and the caller attempts to set
2113 * it to a conflicting mode.
2116 from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode)
2118 if (mode != FROM_CHAR_DATE_NONE)
2120 if (tmfc->mode == FROM_CHAR_DATE_NONE)
2122 else if (tmfc->mode != mode)
2124 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2125 errmsg("invalid combination of date conventions"),
2126 errhint("Do not mix Gregorian and ISO week date "
2127 "conventions in a formatting template.")));
2132 * Set the integer pointed to by 'dest' to the given value.
2134 * Puke if the destination integer has previously been set to some other
2138 from_char_set_int(int *dest, const int value, const FormatNode *node)
2140 if (*dest != 0 && *dest != value)
2142 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2143 errmsg("conflicting values for \"%s\" field in formatting string",
2145 errdetail("This value contradicts a previous setting for "
2146 "the same field type.")));
2151 * Read a single integer from the source string, into the int pointed to by
2152 * 'dest'. If 'dest' is NULL, the result is discarded.
2154 * In fixed-width mode (the node does not have the FM suffix), consume at most
2155 * 'len' characters. However, any leading whitespace isn't counted in 'len'.
2157 * We use strtol() to recover the integer value from the source string, in
2158 * accordance with the given FormatNode.
2160 * If the conversion completes successfully, src will have been advanced to
2161 * point at the character immediately following the last character used in the
2164 * Return the number of characters consumed.
2166 * Note that from_char_parse_int() provides a more convenient wrapper where
2167 * the length of the field is the same as the length of the format keyword (as
2171 from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node)
2174 char copy[DCH_MAX_ITEM_SIZ + 1];
2179 * Skip any whitespace before parsing the integer.
2181 *src += strspace_len(*src);
2183 Assert(len <= DCH_MAX_ITEM_SIZ);
2184 used = (int) strlcpy(copy, *src, len + 1);
2186 if (S_FM(node->suffix) || is_next_separator(node))
2189 * This node is in Fill Mode, or the next node is known to be a
2190 * non-digit value, so we just slurp as many characters as we can get.
2193 result = strtol(init, src, 10);
2198 * We need to pull exactly the number of characters given in 'len' out
2199 * of the string, and convert those.
2205 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2206 errmsg("source string too short for \"%s\" formatting field",
2208 errdetail("Field requires %d characters, but only %d "
2211 errhint("If your source string is not fixed-width, try "
2212 "using the \"FM\" modifier.")));
2215 result = strtol(copy, &last, 10);
2218 if (used > 0 && used < len)
2220 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2221 errmsg("invalid value \"%s\" for \"%s\"",
2222 copy, node->key->name),
2223 errdetail("Field requires %d characters, but only %d "
2224 "could be parsed.", len, used),
2225 errhint("If your source string is not fixed-width, try "
2226 "using the \"FM\" modifier.")));
2233 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2234 errmsg("invalid value \"%s\" for \"%s\"",
2235 copy, node->key->name),
2236 errdetail("Value must be an integer.")));
2238 if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
2240 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2241 errmsg("value for \"%s\" in source string is out of range",
2243 errdetail("Value must be in the range %d to %d.",
2244 INT_MIN, INT_MAX)));
2247 from_char_set_int(dest, (int) result, node);
2252 * Call from_char_parse_int_len(), using the length of the format keyword as
2253 * the expected length of the field.
2255 * Don't call this function if the field differs in length from the format
2256 * keyword (as with HH24; the keyword length is 4, but the field length is 2).
2257 * In such cases, call from_char_parse_int_len() instead to specify the
2258 * required length explicitly.
2261 from_char_parse_int(int *dest, char **src, FormatNode *node)
2263 return from_char_parse_int_len(dest, src, node->key->len, node);
2267 * Sequential search with to upper/lower conversion
2271 seq_search(char *name, char **array, int type, int max, int *len)
2284 /* set first char */
2285 if (type == ONE_UPPER || type == ALL_UPPER)
2286 *name = pg_toupper((unsigned char) *name);
2287 else if (type == ALL_LOWER)
2288 *name = pg_tolower((unsigned char) *name);
2290 for (last = 0, a = array; *a != NULL; a++)
2292 /* comperate first chars */
2296 for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++)
2298 /* search fragment (max) only */
2299 if (max && i == max)
2310 /* Not found in array 'a' */
2315 * Convert (but convert new chars only)
2319 if (type == ONE_UPPER || type == ALL_LOWER)
2320 *n = pg_tolower((unsigned char) *n);
2321 else if (type == ALL_UPPER)
2322 *n = pg_toupper((unsigned char) *n);
2326 #ifdef DEBUG_TO_FROM_CHAR
2327 elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)",
2339 * Perform a sequential search in 'array' for text matching the first 'max'
2340 * characters of the source string.
2342 * If a match is found, copy the array index of the match into the integer
2343 * pointed to by 'dest', advance 'src' to the end of the part of the string
2344 * which matched, and return the number of characters consumed.
2346 * If the string doesn't match, throw an error.
2349 from_char_seq_search(int *dest, char **src, char **array, int type, int max,
2354 *dest = seq_search(*src, array, type, max, &len);
2357 char copy[DCH_MAX_ITEM_SIZ + 1];
2359 Assert(max <= DCH_MAX_ITEM_SIZ);
2360 strlcpy(copy, *src, max + 1);
2363 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2364 errmsg("invalid value \"%s\" for \"%s\"",
2365 copy, node->key->name),
2366 errdetail("The given value did not match any of the allowed "
2367 "values for this field.")));
2374 * Process a TmToChar struct as denoted by a list of FormatNodes.
2375 * The formatted data is written to the string pointed to by 'out'.
2379 DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
2383 struct pg_tm *tm = &in->tm;
2386 /* cache localized days and months */
2387 cache_locale_time();
2390 for (n = node; n->type != NODE_TYPE_END; n++)
2392 if (n->type != NODE_TYPE_ACTION)
2403 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2404 ? P_M_STR : A_M_STR);
2409 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2415 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2416 ? p_m_STR : a_m_STR);
2421 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2429 * display time as shown on a 12-hour clock, even for
2432 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2433 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? HOURS_PER_DAY / 2 :
2434 tm->tm_hour % (HOURS_PER_DAY / 2));
2435 if (S_THth(n->suffix))
2436 str_numth(s, s, S_TH_TYPE(n->suffix));
2440 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_hour);
2441 if (S_THth(n->suffix))
2442 str_numth(s, s, S_TH_TYPE(n->suffix));
2446 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_min);
2447 if (S_THth(n->suffix))
2448 str_numth(s, s, S_TH_TYPE(n->suffix));
2452 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_sec);
2453 if (S_THth(n->suffix))
2454 str_numth(s, s, S_TH_TYPE(n->suffix));
2457 case DCH_MS: /* millisecond */
2458 #ifdef HAVE_INT64_TIMESTAMP
2459 sprintf(s, "%03d", (int) (in->fsec / INT64CONST(1000)));
2461 /* No rint() because we can't overflow and we might print US */
2462 sprintf(s, "%03d", (int) (in->fsec * 1000));
2464 if (S_THth(n->suffix))
2465 str_numth(s, s, S_TH_TYPE(n->suffix));
2468 case DCH_US: /* microsecond */
2469 #ifdef HAVE_INT64_TIMESTAMP
2470 sprintf(s, "%06d", (int) in->fsec);
2472 /* don't use rint() because we can't overflow 1000 */
2473 sprintf(s, "%06d", (int) (in->fsec * 1000000));
2475 if (S_THth(n->suffix))
2476 str_numth(s, s, S_TH_TYPE(n->suffix));
2480 sprintf(s, "%d", tm->tm_hour * SECS_PER_HOUR +
2481 tm->tm_min * SECS_PER_MINUTE +
2483 if (S_THth(n->suffix))
2484 str_numth(s, s, S_TH_TYPE(n->suffix));
2488 INVALID_FOR_INTERVAL;
2491 /* We assume here that timezone names aren't localized */
2492 char *p = asc_tolower_z(tmtcTzn(in));
2500 INVALID_FOR_INTERVAL;
2503 strcpy(s, tmtcTzn(in));
2508 INVALID_FOR_INTERVAL;
2509 sprintf(s, "%+0*ld", S_FM(n->suffix) ? 0 : 3, tm->tm_gmtoff / SECS_PER_HOUR);
2511 if (tm->tm_gmtoff % SECS_PER_HOUR != 0)
2513 sprintf(s, ":%02ld", (tm->tm_gmtoff % SECS_PER_HOUR) / SECS_PER_MINUTE);
2519 INVALID_FOR_INTERVAL;
2520 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2525 INVALID_FOR_INTERVAL;
2526 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2531 INVALID_FOR_INTERVAL;
2532 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2537 INVALID_FOR_INTERVAL;
2538 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2542 INVALID_FOR_INTERVAL;
2545 if (S_TM(n->suffix))
2546 strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1], collid));
2548 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2549 asc_toupper_z(months_full[tm->tm_mon - 1]));
2553 INVALID_FOR_INTERVAL;
2556 if (S_TM(n->suffix))
2557 strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1], collid));
2559 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2560 months_full[tm->tm_mon - 1]);
2564 INVALID_FOR_INTERVAL;
2567 if (S_TM(n->suffix))
2568 strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1], collid));
2570 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2571 asc_tolower_z(months_full[tm->tm_mon - 1]));
2575 INVALID_FOR_INTERVAL;
2578 if (S_TM(n->suffix))
2579 strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2581 strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2585 INVALID_FOR_INTERVAL;
2588 if (S_TM(n->suffix))
2589 strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2591 strcpy(s, months[tm->tm_mon - 1]);
2595 INVALID_FOR_INTERVAL;
2598 if (S_TM(n->suffix))
2599 strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid));
2601 strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
2605 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mon);
2606 if (S_THth(n->suffix))
2607 str_numth(s, s, S_TH_TYPE(n->suffix));
2611 INVALID_FOR_INTERVAL;
2612 if (S_TM(n->suffix))
2613 strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday], collid));
2615 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2616 asc_toupper_z(days[tm->tm_wday]));
2620 INVALID_FOR_INTERVAL;
2621 if (S_TM(n->suffix))
2622 strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday], collid));
2624 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2629 INVALID_FOR_INTERVAL;
2630 if (S_TM(n->suffix))
2631 strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday], collid));
2633 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2634 asc_tolower_z(days[tm->tm_wday]));
2638 INVALID_FOR_INTERVAL;
2639 if (S_TM(n->suffix))
2640 strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday], collid));
2642 strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
2646 INVALID_FOR_INTERVAL;
2647 if (S_TM(n->suffix))
2648 strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday], collid));
2650 strcpy(s, days_short[tm->tm_wday]);
2654 INVALID_FOR_INTERVAL;
2655 if (S_TM(n->suffix))
2656 strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday], collid));
2658 strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
2663 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
2664 (n->key->id == DCH_DDD) ?
2666 date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday));
2667 if (S_THth(n->suffix))
2668 str_numth(s, s, S_TH_TYPE(n->suffix));
2672 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
2673 if (S_THth(n->suffix))
2674 str_numth(s, s, S_TH_TYPE(n->suffix));
2678 INVALID_FOR_INTERVAL;
2679 sprintf(s, "%d", tm->tm_wday + 1);
2680 if (S_THth(n->suffix))
2681 str_numth(s, s, S_TH_TYPE(n->suffix));
2685 INVALID_FOR_INTERVAL;
2686 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
2687 if (S_THth(n->suffix))
2688 str_numth(s, s, S_TH_TYPE(n->suffix));
2692 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2693 (tm->tm_yday - 1) / 7 + 1);
2694 if (S_THth(n->suffix))
2695 str_numth(s, s, S_TH_TYPE(n->suffix));
2699 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2700 date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
2701 if (S_THth(n->suffix))
2702 str_numth(s, s, S_TH_TYPE(n->suffix));
2708 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
2709 if (S_THth(n->suffix))
2710 str_numth(s, s, S_TH_TYPE(n->suffix));
2714 if (is_interval) /* straight calculation */
2715 i = tm->tm_year / 100;
2718 if (tm->tm_year > 0)
2719 /* Century 20 == 1901 - 2000 */
2720 i = (tm->tm_year - 1) / 100 + 1;
2722 /* Century 6BC == 600BC - 501BC */
2723 i = tm->tm_year / 100 - 1;
2725 if (i <= 99 && i >= -99)
2726 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, i);
2728 sprintf(s, "%d", i);
2729 if (S_THth(n->suffix))
2730 str_numth(s, s, S_TH_TYPE(n->suffix));
2734 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
2735 sprintf(s, "%d,%03d", i,
2736 ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
2737 if (S_THth(n->suffix))
2738 str_numth(s, s, S_TH_TYPE(n->suffix));
2744 S_FM(n->suffix) ? 0 : 4,
2745 (n->key->id == DCH_YYYY ?
2746 ADJUST_YEAR(tm->tm_year, is_interval) :
2747 ADJUST_YEAR(date2isoyear(tm->tm_year,
2751 if (S_THth(n->suffix))
2752 str_numth(s, s, S_TH_TYPE(n->suffix));
2758 S_FM(n->suffix) ? 0 : 3,
2759 (n->key->id == DCH_YYY ?
2760 ADJUST_YEAR(tm->tm_year, is_interval) :
2761 ADJUST_YEAR(date2isoyear(tm->tm_year,
2764 is_interval)) % 1000);
2765 if (S_THth(n->suffix))
2766 str_numth(s, s, S_TH_TYPE(n->suffix));
2772 S_FM(n->suffix) ? 0 : 2,
2773 (n->key->id == DCH_YY ?
2774 ADJUST_YEAR(tm->tm_year, is_interval) :
2775 ADJUST_YEAR(date2isoyear(tm->tm_year,
2778 is_interval)) % 100);
2779 if (S_THth(n->suffix))
2780 str_numth(s, s, S_TH_TYPE(n->suffix));
2786 (n->key->id == DCH_Y ?
2787 ADJUST_YEAR(tm->tm_year, is_interval) :
2788 ADJUST_YEAR(date2isoyear(tm->tm_year,
2791 is_interval)) % 10);
2792 if (S_THth(n->suffix))
2793 str_numth(s, s, S_TH_TYPE(n->suffix));
2799 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
2800 rm_months_upper[MONTHS_PER_YEAR - tm->tm_mon]);
2806 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
2807 rm_months_lower[MONTHS_PER_YEAR - tm->tm_mon]);
2811 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
2812 if (S_THth(n->suffix))
2813 str_numth(s, s, S_TH_TYPE(n->suffix));
2817 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
2818 if (S_THth(n->suffix))
2819 str_numth(s, s, S_TH_TYPE(n->suffix));
2829 * Process a string as denoted by a list of FormatNodes.
2830 * The TmFromChar struct pointed to by 'out' is populated with the results.
2832 * Note: we currently don't have any to_interval() function, so there
2833 * is no need here for INVALID_FOR_INTERVAL checks.
2837 DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
2843 bool fx_mode = false;
2845 for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
2847 if (n->type != NODE_TYPE_ACTION)
2850 /* Ignore spaces when not in FX (fixed width) mode */
2851 if (isspace((unsigned char) n->character) && !fx_mode)
2853 while (*s != '\0' && isspace((unsigned char) *s))
2859 from_char_set_mode(out, n->key->date_mode);
2870 from_char_seq_search(&value, &s, ampm_strings_long,
2871 ALL_UPPER, n->key->len, n);
2872 from_char_set_int(&out->pm, value % 2, n);
2873 out->clock = CLOCK_12_HOUR;
2879 from_char_seq_search(&value, &s, ampm_strings,
2880 ALL_UPPER, n->key->len, n);
2881 from_char_set_int(&out->pm, value % 2, n);
2882 out->clock = CLOCK_12_HOUR;
2886 from_char_parse_int_len(&out->hh, &s, 2, n);
2887 out->clock = CLOCK_12_HOUR;
2888 s += SKIP_THth(n->suffix);
2891 from_char_parse_int_len(&out->hh, &s, 2, n);
2892 s += SKIP_THth(n->suffix);
2895 from_char_parse_int(&out->mi, &s, n);
2896 s += SKIP_THth(n->suffix);
2899 from_char_parse_int(&out->ss, &s, n);
2900 s += SKIP_THth(n->suffix);
2902 case DCH_MS: /* millisecond */
2903 len = from_char_parse_int_len(&out->ms, &s, 3, n);
2906 * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
2908 out->ms *= len == 1 ? 100 :
2911 s += SKIP_THth(n->suffix);
2913 case DCH_US: /* microsecond */
2914 len = from_char_parse_int_len(&out->us, &s, 6, n);
2916 out->us *= len == 1 ? 100000 :
2922 s += SKIP_THth(n->suffix);
2925 from_char_parse_int(&out->ssss, &s, n);
2926 s += SKIP_THth(n->suffix);
2932 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2933 errmsg("\"TZ\"/\"tz\"/\"OF\" format patterns are not supported in to_date")));
2938 from_char_seq_search(&value, &s, adbc_strings_long,
2939 ALL_UPPER, n->key->len, n);
2940 from_char_set_int(&out->bc, value % 2, n);
2946 from_char_seq_search(&value, &s, adbc_strings,
2947 ALL_UPPER, n->key->len, n);
2948 from_char_set_int(&out->bc, value % 2, n);
2953 from_char_seq_search(&value, &s, months_full, ONE_UPPER,
2955 from_char_set_int(&out->mm, value + 1, n);
2960 from_char_seq_search(&value, &s, months, ONE_UPPER,
2962 from_char_set_int(&out->mm, value + 1, n);
2965 from_char_parse_int(&out->mm, &s, n);
2966 s += SKIP_THth(n->suffix);
2971 from_char_seq_search(&value, &s, days, ONE_UPPER,
2973 from_char_set_int(&out->d, value, n);
2979 from_char_seq_search(&value, &s, days, ONE_UPPER,
2981 from_char_set_int(&out->d, value, n);
2985 from_char_parse_int(&out->ddd, &s, n);
2986 s += SKIP_THth(n->suffix);
2989 from_char_parse_int_len(&out->ddd, &s, 3, n);
2990 s += SKIP_THth(n->suffix);
2993 from_char_parse_int(&out->dd, &s, n);
2994 s += SKIP_THth(n->suffix);
2997 from_char_parse_int(&out->d, &s, n);
2998 s += SKIP_THth(n->suffix);
3001 from_char_parse_int_len(&out->d, &s, 1, n);
3002 /* Shift numbering to match Gregorian where Sunday = 1 */
3005 s += SKIP_THth(n->suffix);
3009 from_char_parse_int(&out->ww, &s, n);
3010 s += SKIP_THth(n->suffix);
3015 * We ignore 'Q' when converting to date because it is unclear
3016 * which date in the quarter to use, and some people specify
3017 * both quarter and month, so if it was honored it might
3018 * conflict with the supplied month. That is also why we don't
3021 * We still parse the source string for an integer, but it
3022 * isn't stored anywhere in 'out'.
3024 from_char_parse_int((int *) NULL, &s, n);
3025 s += SKIP_THth(n->suffix);
3028 from_char_parse_int(&out->cc, &s, n);
3029 s += SKIP_THth(n->suffix);
3037 matched = sscanf(s, "%d,%03d", &millenia, &years);
3040 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3041 errmsg("invalid input string for \"Y,YYY\"")));
3042 years += (millenia * 1000);
3043 from_char_set_int(&out->year, years, n);
3045 s += strdigits_len(s) + 4 + SKIP_THth(n->suffix);
3050 from_char_parse_int(&out->year, &s, n);
3052 s += SKIP_THth(n->suffix);
3056 if (from_char_parse_int(&out->year, &s, n) < 4)
3057 out->year = adjust_partial_year_to_2020(out->year);
3059 s += SKIP_THth(n->suffix);
3063 if (from_char_parse_int(&out->year, &s, n) < 4)
3064 out->year = adjust_partial_year_to_2020(out->year);
3066 s += SKIP_THth(n->suffix);
3070 if (from_char_parse_int(&out->year, &s, n) < 4)
3071 out->year = adjust_partial_year_to_2020(out->year);
3073 s += SKIP_THth(n->suffix);
3076 from_char_seq_search(&value, &s, rm_months_upper,
3077 ALL_UPPER, MAX_RM_LEN, n);
3078 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
3081 from_char_seq_search(&value, &s, rm_months_lower,
3082 ALL_LOWER, MAX_RM_LEN, n);
3083 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
3086 from_char_parse_int(&out->w, &s, n);
3087 s += SKIP_THth(n->suffix);
3090 from_char_parse_int(&out->j, &s, n);
3091 s += SKIP_THth(n->suffix);
3097 static DCHCacheEntry *
3098 DCH_cache_getnew(char *str)
3102 /* counter overflow check - paranoia? */
3103 if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
3107 for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
3108 ent->age = (++DCHCounter);
3112 * If cache is full, remove oldest entry
3114 if (n_DCHCache > DCH_CACHE_FIELDS)
3116 DCHCacheEntry *old = DCHCache + 0;
3118 #ifdef DEBUG_TO_FROM_CHAR
3119 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3121 for (ent = DCHCache + 1; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
3123 if (ent->age < old->age)
3126 #ifdef DEBUG_TO_FROM_CHAR
3127 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3129 StrNCpy(old->str, str, DCH_CACHE_SIZE + 1);
3130 /* old->format fill parser */
3131 old->age = (++DCHCounter);
3136 #ifdef DEBUG_TO_FROM_CHAR
3137 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3139 ent = DCHCache + n_DCHCache;
3140 StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1);
3141 /* ent->format fill parser */
3142 ent->age = (++DCHCounter);
3148 static DCHCacheEntry *
3149 DCH_cache_search(char *str)
3154 /* counter overflow check - paranoia? */
3155 if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
3159 for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
3160 ent->age = (++DCHCounter);
3163 for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++)
3165 if (strcmp(ent->str, str) == 0)
3167 ent->age = (++DCHCounter);
3176 * Format a date/time or interval into a string according to fmt.
3177 * We parse fmt into a list of FormatNodes. This is then passed to DCH_to_char
3181 datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
3191 * Convert fmt to C string
3193 fmt_str = text_to_cstring(fmt);
3194 fmt_len = strlen(fmt_str);
3197 * Allocate workspace for result as C string
3199 result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
3203 * Allocate new memory if format picture is bigger than static cache and
3204 * not use cache (call parser always)
3206 if (fmt_len > DCH_CACHE_SIZE)
3208 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3211 parse_format(format, fmt_str, DCH_keywords,
3212 DCH_suff, DCH_index, DCH_TYPE, NULL);
3214 (format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */
3225 if ((ent = DCH_cache_search(fmt_str)) == NULL)
3227 ent = DCH_cache_getnew(fmt_str);
3230 * Not in the cache, must run parser and save a new format-picture
3233 parse_format(ent->format, fmt_str, DCH_keywords,
3234 DCH_suff, DCH_index, DCH_TYPE, NULL);
3236 (ent->format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */
3238 #ifdef DEBUG_TO_FROM_CHAR
3239 /* dump_node(ent->format, fmt_len); */
3240 /* dump_index(DCH_keywords, DCH_index); */
3243 format = ent->format;
3246 /* The real work is here */
3247 DCH_to_char(format, is_interval, tmtc, result, collid);
3254 /* convert C-string result to TEXT format */
3255 res = cstring_to_text(result);
3261 /****************************************************************************
3263 ***************************************************************************/
3265 /* -------------------
3266 * TIMESTAMP to_char()
3267 * -------------------
3270 timestamp_to_char(PG_FUNCTION_ARGS)
3272 Timestamp dt = PG_GETARG_TIMESTAMP(0);
3273 text *fmt = PG_GETARG_TEXT_P(1),
3279 if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
3285 if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0)
3287 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3288 errmsg("timestamp out of range")));
3290 thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3291 tm->tm_wday = (thisdate + 1) % 7;
3292 tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
3294 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
3297 PG_RETURN_TEXT_P(res);
3301 timestamptz_to_char(PG_FUNCTION_ARGS)
3303 TimestampTz dt = PG_GETARG_TIMESTAMP(0);
3304 text *fmt = PG_GETARG_TEXT_P(1),
3311 if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
3317 if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
3319 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3320 errmsg("timestamp out of range")));
3322 thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
3323 tm->tm_wday = (thisdate + 1) % 7;
3324 tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
3326 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
3329 PG_RETURN_TEXT_P(res);
3333 /* -------------------
3334 * INTERVAL to_char()
3335 * -------------------
3338 interval_to_char(PG_FUNCTION_ARGS)
3340 Interval *it = PG_GETARG_INTERVAL_P(0);
3341 text *fmt = PG_GETARG_TEXT_P(1),
3346 if ((VARSIZE(fmt) - VARHDRSZ) <= 0)
3352 if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0)
3355 /* wday is meaningless, yday approximates the total span in days */
3356 tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
3358 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
3361 PG_RETURN_TEXT_P(res);
3364 /* ---------------------
3367 * Make Timestamp from date_str which is formatted at argument 'fmt'
3368 * ( to_timestamp is reverse to_char() )
3369 * ---------------------
3372 to_timestamp(PG_FUNCTION_ARGS)
3374 text *date_txt = PG_GETARG_TEXT_P(0);
3375 text *fmt = PG_GETARG_TEXT_P(1);
3381 do_to_timestamp(date_txt, fmt, &tm, &fsec);
3383 tz = DetermineTimeZoneOffset(&tm, session_timezone);
3385 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
3387 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3388 errmsg("timestamp out of range")));
3390 PG_RETURN_TIMESTAMP(result);
3395 * Make Date from date_str which is formated at argument 'fmt'
3399 to_date(PG_FUNCTION_ARGS)
3401 text *date_txt = PG_GETARG_TEXT_P(0);
3402 text *fmt = PG_GETARG_TEXT_P(1);
3407 do_to_timestamp(date_txt, fmt, &tm, &fsec);
3409 if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
3411 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3412 errmsg("date out of range: \"%s\"",
3413 text_to_cstring(date_txt))));
3415 result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
3417 PG_RETURN_DATEADT(result);
3421 * do_to_timestamp: shared code for to_timestamp and to_date
3423 * Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm
3424 * and fractional seconds.
3426 * We parse 'fmt' into a list of FormatNodes, which is then passed to
3427 * DCH_from_char to populate a TmFromChar with the parsed contents of
3430 * The TmFromChar is then analysed and converted into the final results in
3431 * struct 'tm' and 'fsec'.
3433 * This function does very little error checking, e.g.
3434 * to_timestamp('20096040','YYYYMMDD') works
3437 do_to_timestamp(text *date_txt, text *fmt,
3438 struct pg_tm * tm, fsec_t *fsec)
3448 fmt_len = VARSIZE_ANY_EXHDR(fmt);
3456 fmt_str = text_to_cstring(fmt);
3459 * Allocate new memory if format picture is bigger than static cache
3460 * and not use cache (call parser always)
3462 if (fmt_len > DCH_CACHE_SIZE)
3464 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3467 parse_format(format, fmt_str, DCH_keywords,
3468 DCH_suff, DCH_index, DCH_TYPE, NULL);
3470 (format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */
3481 if ((ent = DCH_cache_search(fmt_str)) == NULL)
3483 ent = DCH_cache_getnew(fmt_str);
3486 * Not in the cache, must run parser and save a new
3487 * format-picture to the cache.
3489 parse_format(ent->format, fmt_str, DCH_keywords,
3490 DCH_suff, DCH_index, DCH_TYPE, NULL);
3492 (ent->format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */
3493 #ifdef DEBUG_TO_FROM_CHAR
3494 /* dump_node(ent->format, fmt_len); */
3495 /* dump_index(DCH_keywords, DCH_index); */
3498 format = ent->format;
3501 #ifdef DEBUG_TO_FROM_CHAR
3502 /* dump_node(format, fmt_len); */
3505 date_str = text_to_cstring(date_txt);
3507 DCH_from_char(format, date_str, &tmfc);
3518 * Convert values that user define for FROM_CHAR (to_date/to_timestamp) to
3525 tm->tm_hour = x / SECS_PER_HOUR;
3527 tm->tm_min = x / SECS_PER_MINUTE;
3528 x %= SECS_PER_MINUTE;
3533 tm->tm_sec = tmfc.ss;
3535 tm->tm_min = tmfc.mi;
3537 tm->tm_hour = tmfc.hh;
3539 if (tmfc.clock == CLOCK_12_HOUR)
3541 if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
3543 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3544 errmsg("hour \"%d\" is invalid for the 12-hour clock",
3546 errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
3548 if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
3549 tm->tm_hour += HOURS_PER_DAY / 2;
3550 else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
3557 * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
3558 * the year in the given century. Keep in mind that the 21st century
3559 * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
3562 if (tmfc.cc && tmfc.yysz <= 2)
3566 tm->tm_year = tmfc.year % 100;
3570 tm->tm_year += (tmfc.cc - 1) * 100;
3572 tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1;
3575 /* find century year for dates ending in "00" */
3576 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
3579 /* If a 4-digit year is provided, we use that and ignore CC. */
3581 tm->tm_year = tmfc.year;
3582 if (tmfc.bc && tm->tm_year > 0)
3583 tm->tm_year = -(tm->tm_year - 1);
3586 else if (tmfc.cc) /* use first year of century */
3591 /* +1 becuase 21st century started in 2001 */
3592 tm->tm_year = (tmfc.cc - 1) * 100 + 1;
3594 /* +1 because year == 599 is 600 BC */
3595 tm->tm_year = tmfc.cc * 100 + 1;
3599 j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3603 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
3606 * If tmfc.d is not set, then the date is left at the beginning of
3607 * the ISO week (Monday).
3610 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3612 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3615 tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
3619 tmfc.dd = (tmfc.w - 1) * 7 + 1;
3621 tm->tm_wday = tmfc.d - 1; /* convert to native numbering */
3623 tm->tm_mday = tmfc.dd;
3625 tm->tm_yday = tmfc.ddd;
3627 tm->tm_mon = tmfc.mm;
3629 if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
3632 * The month and day field have not been set, so we use the
3633 * day-of-year field to populate them. Depending on the date mode,
3634 * this field may be interpreted as a Gregorian day-of-year, or an ISO
3635 * week date day-of-year.
3638 if (!tm->tm_year && !tmfc.bc)
3640 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3641 errmsg("cannot calculate day of year without year information")));
3643 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
3645 int j0; /* zeroth day of the ISO year, in Julian */
3647 j0 = isoweek2j(tm->tm_year, 1) - 1;
3649 j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3656 static const int ysum[2][13] = {
3657 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
3658 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
3660 y = ysum[isleap(tm->tm_year)];
3662 for (i = 1; i <= MONTHS_PER_YEAR; i++)
3664 if (tmfc.ddd < y[i])
3667 if (tm->tm_mon <= 1)
3670 if (tm->tm_mday <= 1)
3671 tm->tm_mday = tmfc.ddd - y[i - 1];
3675 #ifdef HAVE_INT64_TIMESTAMP
3677 *fsec += tmfc.ms * 1000;
3682 *fsec += (double) tmfc.ms / 1000;
3684 *fsec += (double) tmfc.us / 1000000;
3691 /**********************************************************************
3692 * the NUMBER version part
3693 *********************************************************************/
3697 fill_str(char *str, int c, int max)
3699 memset(str, c, max);
3700 *(str + max) = '\0';
3704 #define zeroize_NUM(_n) \
3710 (_n)->pre_lsign_num = 0; \
3711 (_n)->need_locale = 0; \
3713 (_n)->zero_start = 0; \
3714 (_n)->zero_end = 0; \
3717 static NUMCacheEntry *
3718 NUM_cache_getnew(char *str)
3722 /* counter overflow check - paranoia? */
3723 if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
3727 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3728 ent->age = (++NUMCounter);
3732 * If cache is full, remove oldest entry
3734 if (n_NUMCache > NUM_CACHE_FIELDS)
3736 NUMCacheEntry *old = NUMCache + 0;
3738 #ifdef DEBUG_TO_FROM_CHAR
3739 elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
3741 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3744 * entry removed via NUM_cache_remove() can be used here, which is
3745 * why it's worth scanning first entry again
3747 if (ent->str[0] == '\0')
3752 if (ent->age < old->age)
3755 #ifdef DEBUG_TO_FROM_CHAR
3756 elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
3758 StrNCpy(old->str, str, NUM_CACHE_SIZE + 1);
3759 /* old->format fill parser */
3760 old->age = (++NUMCounter);
3765 #ifdef DEBUG_TO_FROM_CHAR
3766 elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
3768 ent = NUMCache + n_NUMCache;
3769 StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1);
3770 /* ent->format fill parser */
3771 ent->age = (++NUMCounter);
3775 zeroize_NUM(&ent->Num);
3777 last_NUMCacheEntry = ent;
3781 static NUMCacheEntry *
3782 NUM_cache_search(char *str)
3787 /* counter overflow check - paranoia? */
3788 if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
3792 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
3793 ent->age = (++NUMCounter);
3796 for (i = 0, ent = NUMCache; i < n_NUMCache; i++, ent++)
3798 if (strcmp(ent->str, str) == 0)
3800 ent->age = (++NUMCounter);
3801 last_NUMCacheEntry = ent;
3810 NUM_cache_remove(NUMCacheEntry *ent)
3812 #ifdef DEBUG_TO_FROM_CHAR
3813 elog(DEBUG_elog_output, "REMOVING ENTRY (%s)", ent->str);
3820 * Cache routine for NUM to_char version
3824 NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
3826 FormatNode *format = NULL;
3829 str = text_to_cstring(pars_str);
3832 * Allocate new memory if format picture is bigger than static cache and
3833 * not use cache (call parser always). This branches sets shouldFree to
3834 * true, accordingly.
3836 if (len > NUM_CACHE_SIZE)
3838 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
3844 parse_format(format, str, NUM_keywords,
3845 NULL, NUM_index, NUM_TYPE, Num);
3847 (format + len)->type = NODE_TYPE_END; /* Paranoia? */
3856 *shouldFree = false;
3858 if ((ent = NUM_cache_search(str)) == NULL)
3860 ent = NUM_cache_getnew(str);
3863 * Not in the cache, must run parser and save a new format-picture
3866 parse_format(ent->format, str, NUM_keywords,
3867 NULL, NUM_index, NUM_TYPE, &ent->Num);
3869 (ent->format + len)->type = NODE_TYPE_END; /* Paranoia? */
3872 format = ent->format;
3875 * Copy cache to used struct
3877 Num->flag = ent->Num.flag;
3878 Num->lsign = ent->Num.lsign;
3879 Num->pre = ent->Num.pre;
3880 Num->post = ent->Num.post;
3881 Num->pre_lsign_num = ent->Num.pre_lsign_num;
3882 Num->need_locale = ent->Num.need_locale;
3883 Num->multi = ent->Num.multi;
3884 Num->zero_start = ent->Num.zero_start;
3885 Num->zero_end = ent->Num.zero_end;
3888 #ifdef DEBUG_TO_FROM_CHAR
3889 /* dump_node(format, len); */
3890 dump_index(NUM_keywords, NUM_index);
3899 int_to_roman(int number)
3907 result = (char *) palloc(16);
3910 if (number > 3999 || number < 1)
3912 fill_str(result, '#', 15);
3915 len = snprintf(numstr, sizeof(numstr), "%d", number);
3917 for (p = numstr; *p != '\0'; p++, --len)
3919 num = *p - 49; /* 48 ascii + 1 */
3926 strcat(result, "M");
3931 strcat(result, rm100[num]);
3933 strcat(result, rm10[num]);
3935 strcat(result, rm1[num]);
3948 NUM_prepare_locale(NUMProc *Np)
3950 if (Np->Num->need_locale)
3952 struct lconv *lconv;
3957 lconv = PGLC_localeconv();
3960 * Positive / Negative number sign
3962 if (lconv->negative_sign && *lconv->negative_sign)
3963 Np->L_negative_sign = lconv->negative_sign;
3965 Np->L_negative_sign = "-";
3967 if (lconv->positive_sign && *lconv->positive_sign)
3968 Np->L_positive_sign = lconv->positive_sign;
3970 Np->L_positive_sign = "+";
3973 * Number decimal point
3975 if (lconv->decimal_point && *lconv->decimal_point)
3976 Np->decimal = lconv->decimal_point;
3981 if (!IS_LDECIMAL(Np->Num))
3985 * Number thousands separator
3987 * Some locales (e.g. broken glibc pt_BR), have a comma for decimal,
3988 * but "" for thousands_sep, so we set the thousands_sep too.
3989 * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php
3991 if (lconv->thousands_sep && *lconv->thousands_sep)
3992 Np->L_thousands_sep = lconv->thousands_sep;
3993 /* Make sure thousands separator doesn't match decimal point symbol. */
3994 else if (strcmp(Np->decimal, ",") !=0)
3995 Np->L_thousands_sep = ",";
3997 Np->L_thousands_sep = ".";
4002 if (lconv->currency_symbol && *lconv->currency_symbol)
4003 Np->L_currency_symbol = lconv->currency_symbol;
4005 Np->L_currency_symbol = " ";
4012 Np->L_negative_sign = "-";
4013 Np->L_positive_sign = "+";
4016 Np->L_thousands_sep = ",";
4017 Np->L_currency_symbol = " ";
4022 * Return pointer of last relevant number after decimal point
4023 * 12.0500 --> last relevant is '5'
4024 * 12.0000 --> last relevant is '.'
4025 * If there is no decimal point, return NULL (which will result in same
4026 * behavior as if FM hadn't been specified).
4030 get_last_relevant_decnum(char *num)
4033 *p = strchr(num, '.');
4035 #ifdef DEBUG_TO_FROM_CHAR
4036 elog(DEBUG_elog_output, "get_last_relevant_decnum()");
4054 * Number extraction for TO_NUMBER()
4058 NUM_numpart_from_char(NUMProc *Np, int id, int plen)
4060 bool isread = FALSE;
4062 #ifdef DEBUG_TO_FROM_CHAR
4063 elog(DEBUG_elog_output, " --- scan start --- id=%s",
4064 (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
4067 if (*Np->inout_p == ' ')
4070 #define OVERLOAD_TEST (Np->inout_p >= Np->inout + plen)
4071 #define AMOUNT_TEST(_s) (plen-(Np->inout_p-Np->inout) >= _s)
4073 if (*Np->inout_p == ' ')
4080 * read sign before number
4082 if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
4083 (Np->read_pre + Np->read_post) == 0)
4085 #ifdef DEBUG_TO_FROM_CHAR
4086 elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
4087 *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
4093 if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
4097 #ifdef DEBUG_TO_FROM_CHAR
4098 elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
4100 if ((x = strlen(Np->L_negative_sign)) &&
4102 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
4107 else if ((x = strlen(Np->L_positive_sign)) &&
4109 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
4117 #ifdef DEBUG_TO_FROM_CHAR
4118 elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
4124 if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
4125 *Np->inout_p == '<'))
4127 *Np->number = '-'; /* set - */
4130 else if (*Np->inout_p == '+')
4132 *Np->number = '+'; /* set + */
4141 #ifdef DEBUG_TO_FROM_CHAR
4142 elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
4146 * read digit or decimal point
4148 if (isdigit((unsigned char) *Np->inout_p))
4150 if (Np->read_dec && Np->read_post == Np->Num->post)
4153 *Np->number_p = *Np->inout_p;
4163 #ifdef DEBUG_TO_FROM_CHAR
4164 elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
4167 else if (IS_DECIMAL(Np->Num) && Np->read_dec == FALSE)
4170 * We need not test IS_LDECIMAL(Np->Num) explicitly here, because
4171 * Np->decimal is always just "." if we don't have a D format token.
4172 * So we just unconditionally match to Np->decimal.
4174 int x = strlen(Np->decimal);
4176 #ifdef DEBUG_TO_FROM_CHAR
4177 elog(DEBUG_elog_output, "Try read decimal point (%c)",
4180 if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
4182 Np->inout_p += x - 1;
4183 *Np->number_p = '.';
4185 Np->read_dec = TRUE;
4194 * Read sign behind "last" number
4196 * We need sign detection because determine exact position of post-sign is
4199 * FM9999.9999999S -> 123.001- 9.9S -> .5- FM9.999999MI ->
4202 if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
4205 * locale sign (NUM_S) is always anchored behind a last number, if: -
4206 * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
4207 * next char is not digit
4209 if (IS_LSIGN(Np->Num) && isread &&
4210 (Np->inout_p + 1) <= Np->inout + plen &&
4211 !isdigit((unsigned char) *(Np->inout_p + 1)))
4214 char *tmp = Np->inout_p++;
4216 #ifdef DEBUG_TO_FROM_CHAR
4217 elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
4219 if ((x = strlen(Np->L_negative_sign)) &&
4221 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
4223 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
4226 else if ((x = strlen(Np->L_positive_sign)) &&
4228 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
4230 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
4233 if (*Np->number == ' ')
4239 * try read non-locale sign, it's happen only if format is not exact
4240 * and we cannot determine sign position of MI/PL/SG, an example:
4242 * FM9.999999MI -> 5.01-
4244 * if (.... && IS_LSIGN(Np->Num)==FALSE) prevents read wrong formats
4245 * like to_number('1 -', '9S') where sign is not anchored to last
4248 else if (isread == FALSE && IS_LSIGN(Np->Num) == FALSE &&
4249 (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
4251 #ifdef DEBUG_TO_FROM_CHAR
4252 elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
4258 if (*Np->inout_p == '-' || *Np->inout_p == '+')
4259 /* NUM_processor() do inout_p++ */
4260 *Np->number = *Np->inout_p;
4265 #define IS_PREDEC_SPACE(_n) \
4266 (IS_ZERO((_n)->Num)==FALSE && \
4267 (_n)->number == (_n)->number_p && \
4268 *(_n)->number == '0' && \
4269 (_n)->Num->post != 0)
4272 * Add digit or sign to number-string
4276 NUM_numpart_to_char(NUMProc *Np, int id)
4280 if (IS_ROMAN(Np->Num))
4283 /* Note: in this elog() output not set '\0' in 'inout' */
4285 #ifdef DEBUG_TO_FROM_CHAR
4288 * Np->num_curr is number of current item in format-picture, it is not
4289 * current position in inout!
4291 elog(DEBUG_elog_output,
4292 "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
4301 * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
4302 * handle "9.9" --> " .1"
4304 if (Np->sign_wrote == FALSE &&
4305 (Np->num_curr >= Np->num_pre || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
4306 (IS_PREDEC_SPACE(Np) == FALSE || (Np->last_relevant && *Np->last_relevant == '.')))
4308 if (IS_LSIGN(Np->Num))
4310 if (Np->Num->lsign == NUM_LSIGN_PRE)
4312 if (Np->sign == '-')
4313 strcpy(Np->inout_p, Np->L_negative_sign);
4315 strcpy(Np->inout_p, Np->L_positive_sign);
4316 Np->inout_p += strlen(Np->inout_p);
4317 Np->sign_wrote = TRUE;
4320 else if (IS_BRACKET(Np->Num))
4322 *Np->inout_p = Np->sign == '+' ? ' ' : '<';
4324 Np->sign_wrote = TRUE;
4326 else if (Np->sign == '+')
4328 if (!IS_FILLMODE(Np->Num))
4330 *Np->inout_p = ' '; /* Write + */
4333 Np->sign_wrote = TRUE;
4335 else if (Np->sign == '-')
4339 Np->sign_wrote = TRUE;
4345 * digits / FM / Zero / Dec. point
4347 if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
4349 if (Np->num_curr < Np->num_pre &&
4350 (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
4355 if (!IS_FILLMODE(Np->Num))
4357 *Np->inout_p = ' '; /* Write ' ' */
4361 else if (IS_ZERO(Np->Num) &&
4362 Np->num_curr < Np->num_pre &&
4363 Np->Num->zero_start <= Np->num_curr)
4368 *Np->inout_p = '0'; /* Write '0' */
4375 * Write Decimal point
4377 if (*Np->number_p == '.')
4379 if (!Np->last_relevant || *Np->last_relevant != '.')
4381 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
4382 Np->inout_p += strlen(Np->inout_p);
4386 * Ora 'n' -- FM9.9 --> 'n.'
4388 else if (IS_FILLMODE(Np->Num) &&
4389 Np->last_relevant && *Np->last_relevant == '.')
4391 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
4392 Np->inout_p += strlen(Np->inout_p);
4400 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
4405 * '0.1' -- 9.9 --> ' .1'
4407 else if (IS_PREDEC_SPACE(Np))
4409 if (!IS_FILLMODE(Np->Num))
4416 * '0' -- FM9.9 --> '0.'
4418 else if (Np->last_relevant && *Np->last_relevant == '.')
4426 *Np->inout_p = *Np->number_p; /* Write DIGIT */
4434 end = Np->num_count + (Np->num_pre ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
4436 if (Np->last_relevant && Np->last_relevant == Np->number_p)
4439 if (Np->num_curr + 1 == end)
4441 if (Np->sign_wrote == TRUE && IS_BRACKET(Np->Num))
4443 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
4446 else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
4448 if (Np->sign == '-')
4449 strcpy(Np->inout_p, Np->L_negative_sign);
4451 strcpy(Np->inout_p, Np->L_positive_sign);
4452 Np->inout_p += strlen(Np->inout_p);
4461 * Note: 'plen' is used in FROM_CHAR conversion and it's length of
4462 * input (inout). In TO_CHAR conversion it's space before first number.
4465 NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
4466 int plen, int sign, bool is_to_char, Oid collid)
4472 MemSet(Np, 0, sizeof(NUMProc));
4475 Np->is_to_char = is_to_char;
4476 Np->number = number;
4478 Np->last_relevant = NULL;
4481 Np->read_dec = FALSE;
4483 if (Np->Num->zero_start)
4484 --Np->Num->zero_start;
4486 if (IS_EEEE(Np->Num))
4488 if (!Np->is_to_char)
4490 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4491 errmsg("\"EEEE\" not supported for input")));
4492 return strcpy(inout, number);
4498 if (IS_ROMAN(Np->Num))
4500 if (!Np->is_to_char)
4502 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4503 errmsg("\"RN\" not supported for input")));
4505 Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->post =
4506 Np->Num->pre = Np->num_pre = Np->sign = 0;
4508 if (IS_FILLMODE(Np->Num))
4511 Np->Num->flag |= NUM_F_FILLMODE;
4515 Np->Num->flag |= NUM_F_ROMAN;
4525 /* MI/PL/SG - write sign itself and not in number */
4526 if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
4528 if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == FALSE)
4529 Np->sign_wrote = FALSE; /* need sign */
4531 Np->sign_wrote = TRUE; /* needn't sign */
4535 if (Np->sign != '-')
4537 if (IS_BRACKET(Np->Num) && IS_FILLMODE(Np->Num))
4538 Np->Num->flag &= ~NUM_F_BRACKET;
4539 if (IS_MINUS(Np->Num))
4540 Np->Num->flag &= ~NUM_F_MINUS;
4542 else if (Np->sign != '+' && IS_PLUS(Np->Num))
4543 Np->Num->flag &= ~NUM_F_PLUS;
4545 if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == FALSE)
4546 Np->sign_wrote = TRUE; /* needn't sign */
4548 Np->sign_wrote = FALSE; /* need sign */
4550 if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
4551 Np->Num->lsign = NUM_LSIGN_POST;
4560 Np->num_count = Np->Num->post + Np->Num->pre - 1;
4566 if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
4568 Np->last_relevant = get_last_relevant_decnum(Np->number);
4571 * If any '0' specifiers are present, make sure we don't strip
4574 if (Np->last_relevant && Np->Num->zero_end > Np->num_pre)
4578 last_zero = Np->number + (Np->Num->zero_end - Np->num_pre);
4579 if (Np->last_relevant < last_zero)
4580 Np->last_relevant = last_zero;
4584 if (Np->sign_wrote == FALSE && Np->num_pre == 0)
4590 *Np->number = ' '; /* sign space */
4591 *(Np->number + 1) = '\0';
4597 #ifdef DEBUG_TO_FROM_CHAR
4598 elog(DEBUG_elog_output,
4599 "\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",
4606 Np->sign_wrote ? "Yes" : "No",
4607 IS_ZERO(Np->Num) ? "Yes" : "No",
4608 Np->Num->zero_start,
4610 Np->last_relevant ? Np->last_relevant : "<not set>",
4611 IS_BRACKET(Np->Num) ? "Yes" : "No",
4612 IS_PLUS(Np->Num) ? "Yes" : "No",
4613 IS_MINUS(Np->Num) ? "Yes" : "No",
4614 IS_FILLMODE(Np->Num) ? "Yes" : "No",
4615 IS_ROMAN(Np->Num) ? "Yes" : "No",
4616 IS_EEEE(Np->Num) ? "Yes" : "No"
4623 NUM_prepare_locale(Np);
4626 * Processor direct cycle
4629 Np->number_p = Np->number;
4631 Np->number_p = Np->number + 1; /* first char is space for sign */
4633 for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
4635 if (!Np->is_to_char)
4638 * Check non-string inout end
4640 if (Np->inout_p >= Np->inout + plen)
4645 * Format pictures actions
4647 if (n->type == NODE_TYPE_ACTION)
4650 * Create/reading digit/zero/blank/sing
4652 * 'NUM_S' note: The locale sign is anchored to number and we
4653 * read/write it when we work with first or last number
4654 * (NUM_0/NUM_9). This is reason why NUM_S missing in follow
4665 NUM_numpart_to_char(Np, n->key->id);
4666 continue; /* for() */
4670 NUM_numpart_from_char(Np, n->key->id, plen);
4671 break; /* switch() case: */
4679 if (IS_FILLMODE(Np->Num))
4691 if (IS_FILLMODE(Np->Num))
4702 if (IS_FILLMODE(Np->Num))
4706 int x = strlen(Np->L_thousands_sep);
4708 memset(Np->inout_p, ' ', x);
4709 Np->inout_p += x - 1;
4714 strcpy(Np->inout_p, Np->L_thousands_sep);
4715 Np->inout_p += strlen(Np->inout_p) - 1;
4722 if (IS_FILLMODE(Np->Num))
4725 Np->inout_p += strlen(Np->L_thousands_sep) - 1;
4732 strcpy(Np->inout_p, Np->L_currency_symbol);
4733 Np->inout_p += strlen(Np->inout_p) - 1;
4736 Np->inout_p += strlen(Np->L_currency_symbol) - 1;
4740 if (IS_FILLMODE(Np->Num))
4742 strcpy(Np->inout_p, Np->number_p);
4743 Np->inout_p += strlen(Np->inout_p) - 1;
4747 sprintf(Np->inout_p, "%15s", Np->number_p);
4748 Np->inout_p += strlen(Np->inout_p) - 1;
4753 if (IS_FILLMODE(Np->Num))
4755 strcpy(Np->inout_p, asc_tolower_z(Np->number_p));
4756 Np->inout_p += strlen(Np->inout_p) - 1;
4760 sprintf(Np->inout_p, "%15s", asc_tolower_z(Np->number_p));
4761 Np->inout_p += strlen(Np->inout_p) - 1;
4766 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
4767 Np->sign == '-' || IS_DECIMAL(Np->Num))
4771 strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
4776 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
4777 Np->sign == '-' || IS_DECIMAL(Np->Num))
4781 strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
4788 if (Np->sign == '-')
4790 else if (IS_FILLMODE(Np->Num))
4797 if (*Np->inout_p == '-')
4805 if (Np->sign == '+')
4807 else if (IS_FILLMODE(Np->Num))
4814 if (*Np->inout_p == '+')
4821 *Np->inout_p = Np->sign;
4825 if (*Np->inout_p == '-')
4827 else if (*Np->inout_p == '+')
4841 * Remove to output char from input in TO_CHAR
4844 *Np->inout_p = n->character;
4851 *Np->inout_p = '\0';
4856 if (*(Np->number_p - 1) == '.')
4857 *(Np->number_p - 1) = '\0';
4859 *Np->number_p = '\0';
4862 * Correction - precision of dec. number
4864 Np->Num->post = Np->read_post;
4866 #ifdef DEBUG_TO_FROM_CHAR
4867 elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
4874 * MACRO: Start part of NUM - for all NUM's to_char variants
4875 * (sorry, but I hate copy same code - macro is better..)
4878 #define NUM_TOCHAR_prepare \
4880 int len = VARSIZE_ANY_EXHDR(fmt); \
4881 if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
4882 PG_RETURN_TEXT_P(cstring_to_text("")); \
4883 result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
4884 format = NUM_cache(len, &Num, fmt, &shouldFree); \
4888 * MACRO: Finish part of NUM
4891 #define NUM_TOCHAR_finish \
4895 NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true, PG_GET_COLLATION()); \
4901 * Convert null-terminated representation of result to standard text. \
4902 * The result is usually much bigger than it needs to be, but there \
4903 * seems little point in realloc'ing it smaller. \
4905 len = strlen(VARDATA(result)); \
4906 SET_VARSIZE(result, len + VARHDRSZ); \
4909 /* -------------------
4910 * NUMERIC to_number() (convert string to numeric)
4911 * -------------------
4914 numeric_to_number(PG_FUNCTION_ARGS)
4916 text *value = PG_GETARG_TEXT_P(0);
4917 text *fmt = PG_GETARG_TEXT_P(1);
4927 len = VARSIZE(fmt) - VARHDRSZ;
4929 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
4932 format = NUM_cache(len, &Num, fmt, &shouldFree);
4934 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
4936 NUM_processor(format, &Num, VARDATA(value), numstr,
4937 VARSIZE(value) - VARHDRSZ, 0, false, PG_GET_COLLATION());
4940 precision = Max(0, Num.pre) + scale;
4945 result = DirectFunctionCall3(numeric_in,
4946 CStringGetDatum(numstr),
4947 ObjectIdGetDatum(InvalidOid),
4948 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
4953 /* ------------------
4955 * ------------------
4958 numeric_to_char(PG_FUNCTION_ARGS)
4960 Numeric value = PG_GETARG_NUMERIC(0);
4961 text *fmt = PG_GETARG_TEXT_P(1);
4976 * On DateType depend part (numeric)
4980 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
4981 NumericGetDatum(value),
4984 int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
4985 NumericGetDatum(x))));
4987 else if (IS_EEEE(&Num))
4989 orgnum = numeric_out_sci(value, Num.post);
4992 * numeric_out_sci() does not emit a sign for positive numbers. We
4993 * need to add a space in this case so that positive and negative
4994 * numbers are aligned. We also have to do the right thing for NaN.
4996 if (strcmp(orgnum, "NaN") == 0)
4999 * Allow 6 characters for the leading sign, the decimal point,
5000 * "e", the exponent's sign and two exponent digits.
5002 numstr = (char *) palloc(Num.pre + Num.post + 7);
5003 fill_str(numstr, '#', Num.pre + Num.post + 6);
5005 *(numstr + Num.pre + 1) = '.';
5007 else if (*orgnum != '-')
5009 numstr = (char *) palloc(strlen(orgnum) + 2);
5011 strcpy(numstr + 1, orgnum);
5021 Numeric val = value;
5025 Numeric a = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
5026 Int32GetDatum(10)));
5027 Numeric b = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
5028 Int32GetDatum(Num.multi)));
5030 x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
5032 NumericGetDatum(b)));
5033 val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
5034 NumericGetDatum(value),
5035 NumericGetDatum(x)));
5036 Num.pre += Num.multi;
5039 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
5040 NumericGetDatum(val),
5041 Int32GetDatum(Num.post)));
5042 orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
5043 NumericGetDatum(x)));
5048 numstr = orgnum + 1;
5055 if ((p = strchr(numstr, '.')))
5058 len = strlen(numstr);
5061 plen = Num.pre - len;
5062 else if (len > Num.pre)
5064 numstr = (char *) palloc(Num.pre + Num.post + 2);
5065 fill_str(numstr, '#', Num.pre + Num.post + 1);
5066 *(numstr + Num.pre) = '.';
5071 PG_RETURN_TEXT_P(result);
5079 int4_to_char(PG_FUNCTION_ARGS)
5081 int32 value = PG_GETARG_INT32(0);
5082 text *fmt = PG_GETARG_TEXT_P(1);
5095 * On DateType depend part (int32)
5098 numstr = orgnum = int_to_roman(value);
5099 else if (IS_EEEE(&Num))
5101 /* we can do it easily because float8 won't lose any precision */
5102 float8 val = (float8) value;
5104 orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5105 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val);
5108 * Swap a leading positive sign for a space.
5121 orgnum = DatumGetCString(DirectFunctionCall1(int4out,
5122 Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
5123 Num.pre += Num.multi;
5127 orgnum = DatumGetCString(DirectFunctionCall1(int4out,
5128 Int32GetDatum(value)));
5138 len = strlen(orgnum);
5142 numstr = (char *) palloc(len + Num.post + 2);
5143 strcpy(numstr, orgnum);
5144 *(numstr + len) = '.';
5145 memset(numstr + len + 1, '0', Num.post);
5146 *(numstr + len + Num.post + 1) = '\0';
5152 plen = Num.pre - len;
5153 else if (len > Num.pre)
5155 numstr = (char *) palloc(Num.pre + Num.post + 2);
5156 fill_str(numstr, '#', Num.pre + Num.post + 1);
5157 *(numstr + Num.pre) = '.';
5162 PG_RETURN_TEXT_P(result);
5170 int8_to_char(PG_FUNCTION_ARGS)
5172 int64 value = PG_GETARG_INT64(0);
5173 text *fmt = PG_GETARG_TEXT_P(1);
5186 * On DateType depend part (int32)
5190 /* Currently don't support int8 conversion to roman... */
5191 numstr = orgnum = int_to_roman(DatumGetInt32(
5192 DirectFunctionCall1(int84, Int64GetDatum(value))));
5194 else if (IS_EEEE(&Num))
5196 /* to avoid loss of precision, must go via numeric not float8 */
5199 val = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
5200 Int64GetDatum(value)));
5201 orgnum = numeric_out_sci(val, Num.post);
5204 * numeric_out_sci() does not emit a sign for positive numbers. We
5205 * need to add a space in this case so that positive and negative
5206 * numbers are aligned. We don't have to worry about NaN here.
5210 numstr = (char *) palloc(strlen(orgnum) + 2);
5212 strcpy(numstr + 1, orgnum);
5225 double multi = pow((double) 10, (double) Num.multi);
5227 value = DatumGetInt64(DirectFunctionCall2(int8mul,
5228 Int64GetDatum(value),
5229 DirectFunctionCall1(dtoi8,
5230 Float8GetDatum(multi))));
5231 Num.pre += Num.multi;
5234 orgnum = DatumGetCString(DirectFunctionCall1(int8out,
5235 Int64GetDatum(value)));
5244 len = strlen(orgnum);
5248 numstr = (char *) palloc(len + Num.post + 2);
5249 strcpy(numstr, orgnum);
5250 *(numstr + len) = '.';
5251 memset(numstr + len + 1, '0', Num.post);
5252 *(numstr + len + Num.post + 1) = '\0';
5258 plen = Num.pre - len;
5259 else if (len > Num.pre)
5261 numstr = (char *) palloc(Num.pre + Num.post + 2);
5262 fill_str(numstr, '#', Num.pre + Num.post + 1);
5263 *(numstr + Num.pre) = '.';
5268 PG_RETURN_TEXT_P(result);
5271 /* -----------------
5276 float4_to_char(PG_FUNCTION_ARGS)
5278 float4 value = PG_GETARG_FLOAT4(0);
5279 text *fmt = PG_GETARG_TEXT_P(1);
5293 numstr = orgnum = int_to_roman((int) rint(value));
5294 else if (IS_EEEE(&Num))
5296 numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5297 if (isnan(value) || is_infinite(value))
5300 * Allow 6 characters for the leading sign, the decimal point,
5301 * "e", the exponent's sign and two exponent digits.
5303 numstr = (char *) palloc(Num.pre + Num.post + 7);
5304 fill_str(numstr, '#', Num.pre + Num.post + 6);
5306 *(numstr + Num.pre + 1) = '.';
5310 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5313 * Swap a leading positive sign for a space.
5328 float multi = pow((double) 10, (double) Num.multi);
5330 val = value * multi;
5331 Num.pre += Num.multi;
5334 orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
5335 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
5336 len = strlen(orgnum);
5338 plen = Num.pre - len;
5341 else if (Num.post + len > FLT_DIG)
5342 Num.post = FLT_DIG - len;
5343 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
5348 numstr = orgnum + 1;
5355 if ((p = strchr(numstr, '.')))
5358 len = strlen(numstr);
5361 plen = Num.pre - len;
5362 else if (len > Num.pre)
5364 numstr = (char *) palloc(Num.pre + Num.post + 2);
5365 fill_str(numstr, '#', Num.pre + Num.post + 1);
5366 *(numstr + Num.pre) = '.';
5371 PG_RETURN_TEXT_P(result);
5374 /* -----------------
5379 float8_to_char(PG_FUNCTION_ARGS)
5381 float8 value = PG_GETARG_FLOAT8(0);
5382 text *fmt = PG_GETARG_TEXT_P(1);
5396 numstr = orgnum = int_to_roman((int) rint(value));
5397 else if (IS_EEEE(&Num))
5399 numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5400 if (isnan(value) || is_infinite(value))
5403 * Allow 6 characters for the leading sign, the decimal point,
5404 * "e", the exponent's sign and two exponent digits.
5406 numstr = (char *) palloc(Num.pre + Num.post + 7);
5407 fill_str(numstr, '#', Num.pre + Num.post + 6);
5409 *(numstr + Num.pre + 1) = '.';
5413 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5416 * Swap a leading positive sign for a space.
5431 double multi = pow((double) 10, (double) Num.multi);
5433 val = value * multi;
5434 Num.pre += Num.multi;
5436 orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5437 len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val));
5439 plen = Num.pre - len;
5442 else if (Num.post + len > DBL_DIG)
5443 Num.post = DBL_DIG - len;
5444 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
5449 numstr = orgnum + 1;
5456 if ((p = strchr(numstr, '.')))
5459 len = strlen(numstr);
5462 plen = Num.pre - len;
5463 else if (len > Num.pre)
5465 numstr = (char *) palloc(Num.pre + Num.post + 2);
5466 fill_str(numstr, '#', Num.pre + Num.post + 1);
5467 *(numstr + Num.pre) = '.';
5472 PG_RETURN_TEXT_P(result);