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