Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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 Assert(len > 0);
1569
1570 last = *(num + (len - 1));
1571 if (!isdigit((unsigned char) last))
1572 ereport(ERROR,
1573 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1574 errmsg("\"%s\" is not a number", num)));
1575
1576 /*
1577 * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1578 * 'ST/st', 'ND/nd', 'RD/rd', respectively
1579 */
1580 if ((len > 1) && (num[len - 2] == '1'))
1581 last = 0;
1582
1583 switch (last)
1584 {
1585 case '1':
1586 if (type == TH_UPPER)
1587 return numTH[0];
1588 return numth[0];
1589 case '2':
1590 if (type == TH_UPPER)
1591 return numTH[1];
1592 return numth[1];
1593 case '3':
1594 if (type == TH_UPPER)
1595 return numTH[2];
1596 return numth[2];
1597 default:
1598 if (type == TH_UPPER)
1599 return numTH[3];
1600 return numth[3];
1601 }
1602}
1603
1604/* ----------
1605 * Convert string-number to ordinal string-number
1606 * type --> 0 upper, 1 lower
1607 * ----------
1608 */
1609static char *
1610str_numth(char *dest, char *num, int type)
1611{
1612 if (dest != num)
1613 strcpy(dest, num);
1614 strcat(dest, get_th(num, type));
1615 return dest;
1616}
1617
1618/*****************************************************************************
1619 * upper/lower/initcap functions
1620 *****************************************************************************/
1621
1622/*
1623 * If the system provides the needed functions for wide-character manipulation
1624 * (which are all standardized by C99), then we implement upper/lower/initcap
1625 * using wide-character functions, if necessary. Otherwise we use the
1626 * traditional <ctype.h> functions, which of course will not work as desired
1627 * in multibyte character sets. Note that in either case we are effectively
1628 * assuming that the database character encoding matches the encoding implied
1629 * by LC_CTYPE.
1630 */
1631
1632/*
1633 * collation-aware, wide-character-aware lower function
1634 *
1635 * We pass the number of bytes so we can pass varlena and char*
1636 * to this function. The result is a palloc'd, null-terminated string.
1637 */
1638char *
1639str_tolower(const char *buff, size_t nbytes, Oid collid)
1640{
1641 char *result;
1642 pg_locale_t mylocale;
1643
1644 if (!buff)
1645 return NULL;
1646
1647 if (!OidIsValid(collid))
1648 {
1649 /*
1650 * This typically means that the parser could not resolve a conflict
1651 * of implicit collations, so report it that way.
1652 */
1653 ereport(ERROR,
1654 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1655 errmsg("could not determine which collation to use for %s function",
1656 "lower()"),
1657 errhint("Use the COLLATE clause to set the collation explicitly.")));
1658 }
1659
1661
1662 /* C/POSIX collations use this path regardless of database encoding */
1663 if (mylocale->ctype_is_c)
1664 {
1665 result = asc_tolower(buff, nbytes);
1666 }
1667 else
1668 {
1669 const char *src = buff;
1670 size_t srclen = nbytes;
1671 size_t dstsize;
1672 char *dst;
1673 size_t needed;
1674
1675 /* first try buffer of equal size plus terminating NUL */
1676 dstsize = srclen + 1;
1677 dst = palloc(dstsize);
1678
1679 needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
1680 if (needed + 1 > dstsize)
1681 {
1682 /* grow buffer if needed and retry */
1683 dstsize = needed + 1;
1684 dst = repalloc(dst, dstsize);
1685 needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
1686 Assert(needed + 1 <= dstsize);
1687 }
1688
1689 Assert(dst[needed] == '\0');
1690 result = dst;
1691 }
1692
1693 return result;
1694}
1695
1696/*
1697 * collation-aware, wide-character-aware upper function
1698 *
1699 * We pass the number of bytes so we can pass varlena and char*
1700 * to this function. The result is a palloc'd, null-terminated string.
1701 */
1702char *
1703str_toupper(const char *buff, size_t nbytes, Oid collid)
1704{
1705 char *result;
1706 pg_locale_t mylocale;
1707
1708 if (!buff)
1709 return NULL;
1710
1711 if (!OidIsValid(collid))
1712 {
1713 /*
1714 * This typically means that the parser could not resolve a conflict
1715 * of implicit collations, so report it that way.
1716 */
1717 ereport(ERROR,
1718 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1719 errmsg("could not determine which collation to use for %s function",
1720 "upper()"),
1721 errhint("Use the COLLATE clause to set the collation explicitly.")));
1722 }
1723
1725
1726 /* C/POSIX collations use this path regardless of database encoding */
1727 if (mylocale->ctype_is_c)
1728 {
1729 result = asc_toupper(buff, nbytes);
1730 }
1731 else
1732 {
1733 const char *src = buff;
1734 size_t srclen = nbytes;
1735 size_t dstsize;
1736 char *dst;
1737 size_t needed;
1738
1739 /* first try buffer of equal size plus terminating NUL */
1740 dstsize = srclen + 1;
1741 dst = palloc(dstsize);
1742
1743 needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
1744 if (needed + 1 > dstsize)
1745 {
1746 /* grow buffer if needed and retry */
1747 dstsize = needed + 1;
1748 dst = repalloc(dst, dstsize);
1749 needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
1750 Assert(needed + 1 <= dstsize);
1751 }
1752
1753 Assert(dst[needed] == '\0');
1754 result = dst;
1755 }
1756
1757 return result;
1758}
1759
1760/*
1761 * collation-aware, wide-character-aware initcap function
1762 *
1763 * We pass the number of bytes so we can pass varlena and char*
1764 * to this function. The result is a palloc'd, null-terminated string.
1765 */
1766char *
1767str_initcap(const char *buff, size_t nbytes, Oid collid)
1768{
1769 char *result;
1770 pg_locale_t mylocale;
1771
1772 if (!buff)
1773 return NULL;
1774
1775 if (!OidIsValid(collid))
1776 {
1777 /*
1778 * This typically means that the parser could not resolve a conflict
1779 * of implicit collations, so report it that way.
1780 */
1781 ereport(ERROR,
1782 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1783 errmsg("could not determine which collation to use for %s function",
1784 "initcap()"),
1785 errhint("Use the COLLATE clause to set the collation explicitly.")));
1786 }
1787
1789
1790 /* C/POSIX collations use this path regardless of database encoding */
1791 if (mylocale->ctype_is_c)
1792 {
1793 result = asc_initcap(buff, nbytes);
1794 }
1795 else
1796 {
1797 const char *src = buff;
1798 size_t srclen = nbytes;
1799 size_t dstsize;
1800 char *dst;
1801 size_t needed;
1802
1803 /* first try buffer of equal size plus terminating NUL */
1804 dstsize = srclen + 1;
1805 dst = palloc(dstsize);
1806
1807 needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
1808 if (needed + 1 > dstsize)
1809 {
1810 /* grow buffer if needed and retry */
1811 dstsize = needed + 1;
1812 dst = repalloc(dst, dstsize);
1813 needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
1814 Assert(needed + 1 <= dstsize);
1815 }
1816
1817 Assert(dst[needed] == '\0');
1818 result = dst;
1819 }
1820
1821 return result;
1822}
1823
1824/*
1825 * collation-aware, wide-character-aware case folding
1826 *
1827 * We pass the number of bytes so we can pass varlena and char*
1828 * to this function. The result is a palloc'd, null-terminated string.
1829 */
1830char *
1831str_casefold(const char *buff, size_t nbytes, Oid collid)
1832{
1833 char *result;
1834 pg_locale_t mylocale;
1835
1836 if (!buff)
1837 return NULL;
1838
1839 if (!OidIsValid(collid))
1840 {
1841 /*
1842 * This typically means that the parser could not resolve a conflict
1843 * of implicit collations, so report it that way.
1844 */
1845 ereport(ERROR,
1846 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1847 errmsg("could not determine which collation to use for %s function",
1848 "lower()"),
1849 errhint("Use the COLLATE clause to set the collation explicitly.")));
1850 }
1851
1853 ereport(ERROR,
1854 (errcode(ERRCODE_SYNTAX_ERROR),
1855 errmsg("Unicode case folding can only be performed if server encoding is UTF8")));
1856
1858
1859 /* C/POSIX collations use this path regardless of database encoding */
1860 if (mylocale->ctype_is_c)
1861 {
1862 result = asc_tolower(buff, nbytes);
1863 }
1864 else
1865 {
1866 const char *src = buff;
1867 size_t srclen = nbytes;
1868 size_t dstsize;
1869 char *dst;
1870 size_t needed;
1871
1872 /* first try buffer of equal size plus terminating NUL */
1873 dstsize = srclen + 1;
1874 dst = palloc(dstsize);
1875
1876 needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
1877 if (needed + 1 > dstsize)
1878 {
1879 /* grow buffer if needed and retry */
1880 dstsize = needed + 1;
1881 dst = repalloc(dst, dstsize);
1882 needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
1883 Assert(needed + 1 <= dstsize);
1884 }
1885
1886 Assert(dst[needed] == '\0');
1887 result = dst;
1888 }
1889
1890 return result;
1891}
1892
1893/*
1894 * ASCII-only lower function
1895 *
1896 * We pass the number of bytes so we can pass varlena and char*
1897 * to this function. The result is a palloc'd, null-terminated string.
1898 */
1899char *
1900asc_tolower(const char *buff, size_t nbytes)
1901{
1902 char *result;
1903 char *p;
1904
1905 if (!buff)
1906 return NULL;
1907
1908 result = pnstrdup(buff, nbytes);
1909
1910 for (p = result; *p; p++)
1911 *p = pg_ascii_tolower((unsigned char) *p);
1912
1913 return result;
1914}
1915
1916/*
1917 * ASCII-only upper function
1918 *
1919 * We pass the number of bytes so we can pass varlena and char*
1920 * to this function. The result is a palloc'd, null-terminated string.
1921 */
1922char *
1923asc_toupper(const char *buff, size_t nbytes)
1924{
1925 char *result;
1926 char *p;
1927
1928 if (!buff)
1929 return NULL;
1930
1931 result = pnstrdup(buff, nbytes);
1932
1933 for (p = result; *p; p++)
1934 *p = pg_ascii_toupper((unsigned char) *p);
1935
1936 return result;
1937}
1938
1939/*
1940 * ASCII-only initcap function
1941 *
1942 * We pass the number of bytes so we can pass varlena and char*
1943 * to this function. The result is a palloc'd, null-terminated string.
1944 */
1945char *
1946asc_initcap(const char *buff, size_t nbytes)
1947{
1948 char *result;
1949 char *p;
1950 int wasalnum = false;
1951
1952 if (!buff)
1953 return NULL;
1954
1955 result = pnstrdup(buff, nbytes);
1956
1957 for (p = result; *p; p++)
1958 {
1959 char c;
1960
1961 if (wasalnum)
1962 *p = c = pg_ascii_tolower((unsigned char) *p);
1963 else
1964 *p = c = pg_ascii_toupper((unsigned char) *p);
1965 /* we don't trust isalnum() here */
1966 wasalnum = ((c >= 'A' && c <= 'Z') ||
1967 (c >= 'a' && c <= 'z') ||
1968 (c >= '0' && c <= '9'));
1969 }
1970
1971 return result;
1972}
1973
1974/* convenience routines for when the input is null-terminated */
1975
1976static char *
1977str_tolower_z(const char *buff, Oid collid)
1978{
1979 return str_tolower(buff, strlen(buff), collid);
1980}
1981
1982static char *
1983str_toupper_z(const char *buff, Oid collid)
1984{
1985 return str_toupper(buff, strlen(buff), collid);
1986}
1987
1988static char *
1989str_initcap_z(const char *buff, Oid collid)
1990{
1991 return str_initcap(buff, strlen(buff), collid);
1992}
1993
1994static char *
1995asc_tolower_z(const char *buff)
1996{
1997 return asc_tolower(buff, strlen(buff));
1998}
1999
2000static char *
2001asc_toupper_z(const char *buff)
2002{
2003 return asc_toupper(buff, strlen(buff));
2004}
2005
2006/* asc_initcap_z is not currently needed */
2007
2008
2009/* ----------
2010 * Skip TM / th in FROM_CHAR
2011 *
2012 * If S_THth is on, skip two chars, assuming there are two available
2013 * ----------
2014 */
2015#define SKIP_THth(ptr, _suf) \
2016 do { \
2017 if (S_THth(_suf)) \
2018 { \
2019 if (*(ptr)) (ptr) += pg_mblen(ptr); \
2020 if (*(ptr)) (ptr) += pg_mblen(ptr); \
2021 } \
2022 } while (0)
2023
2024
2025#ifdef DEBUG_TO_FROM_CHAR
2026/* -----------
2027 * DEBUG: Call for debug and for index checking; (Show ASCII char
2028 * and defined keyword for each used position
2029 * ----------
2030 */
2031static void
2032dump_index(const KeyWord *k, const int *index)
2033{
2034 int i,
2035 count = 0,
2036 free_i = 0;
2037
2038 elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:");
2039
2040 for (i = 0; i < KeyWord_INDEX_SIZE; i++)
2041 {
2042 if (index[i] != -1)
2043 {
2044 elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name);
2045 count++;
2046 }
2047 else
2048 {
2049 free_i++;
2050 elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]);
2051 }
2052 }
2053 elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d",
2054 count, free_i);
2055}
2056#endif /* DEBUG */
2057
2058/* ----------
2059 * Return true if next format picture is not digit value
2060 * ----------
2061 */
2062static bool
2064{
2065 if (n->type == NODE_TYPE_END)
2066 return false;
2067
2068 if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
2069 return true;
2070
2071 /*
2072 * Next node
2073 */
2074 n++;
2075
2076 /* end of format string is treated like a non-digit separator */
2077 if (n->type == NODE_TYPE_END)
2078 return true;
2079
2080 if (n->type == NODE_TYPE_ACTION)
2081 {
2082 if (n->key->is_digit)
2083 return false;
2084
2085 return true;
2086 }
2087 else if (n->character[1] == '\0' &&
2088 isdigit((unsigned char) n->character[0]))
2089 return false;
2090
2091 return true; /* some non-digit input (separator) */
2092}
2093
2094
2095static int
2097{
2098 /*
2099 * Adjust all dates toward 2020; this is effectively what happens when we
2100 * assume '70' is 1970 and '69' is 2069.
2101 */
2102 /* Force 0-69 into the 2000's */
2103 if (year < 70)
2104 return year + 2000;
2105 /* Force 70-99 into the 1900's */
2106 else if (year < 100)
2107 return year + 1900;
2108 /* Force 100-519 into the 2000's */
2109 else if (year < 520)
2110 return year + 2000;
2111 /* Force 520-999 into the 1000's */
2112 else if (year < 1000)
2113 return year + 1000;
2114 else
2115 return year;
2116}
2117
2118
2119static int
2120strspace_len(const char *str)
2121{
2122 int len = 0;
2123
2124 while (*str && isspace((unsigned char) *str))
2125 {
2126 str++;
2127 len++;
2128 }
2129 return len;
2130}
2131
2132/*
2133 * Set the date mode of a from-char conversion.
2134 *
2135 * Puke if the date mode has already been set, and the caller attempts to set
2136 * it to a conflicting mode.
2137 *
2138 * Returns true on success, false on failure (if escontext points to an
2139 * ErrorSaveContext; otherwise errors are thrown).
2140 */
2141static bool
2143 Node *escontext)
2144{
2146 {
2147 if (tmfc->mode == FROM_CHAR_DATE_NONE)
2148 tmfc->mode = mode;
2149 else if (tmfc->mode != mode)
2150 ereturn(escontext, false,
2151 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2152 errmsg("invalid combination of date conventions"),
2153 errhint("Do not mix Gregorian and ISO week date "
2154 "conventions in a formatting template.")));
2155 }
2156 return true;
2157}
2158
2159/*
2160 * Set the integer pointed to by 'dest' to the given value.
2161 *
2162 * Puke if the destination integer has previously been set to some other
2163 * non-zero value.
2164 *
2165 * Returns true on success, false on failure (if escontext points to an
2166 * ErrorSaveContext; otherwise errors are thrown).
2167 */
2168static bool
2169from_char_set_int(int *dest, const int value, const FormatNode *node,
2170 Node *escontext)
2171{
2172 if (*dest != 0 && *dest != value)
2173 ereturn(escontext, false,
2174 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2175 errmsg("conflicting values for \"%s\" field in formatting string",
2176 node->key->name),
2177 errdetail("This value contradicts a previous setting "
2178 "for the same field type.")));
2179 *dest = value;
2180 return true;
2181}
2182
2183/*
2184 * Read a single integer from the source string, into the int pointed to by
2185 * 'dest'. If 'dest' is NULL, the result is discarded.
2186 *
2187 * In fixed-width mode (the node does not have the FM suffix), consume at most
2188 * 'len' characters. However, any leading whitespace isn't counted in 'len'.
2189 *
2190 * We use strtol() to recover the integer value from the source string, in
2191 * accordance with the given FormatNode.
2192 *
2193 * If the conversion completes successfully, src will have been advanced to
2194 * point at the character immediately following the last character used in the
2195 * conversion.
2196 *
2197 * Returns the number of characters consumed, or -1 on error (if escontext
2198 * points to an ErrorSaveContext; otherwise errors are thrown).
2199 *
2200 * Note that from_char_parse_int() provides a more convenient wrapper where
2201 * the length of the field is the same as the length of the format keyword (as
2202 * with DD and MI).
2203 */
2204static int
2205from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode *node,
2206 Node *escontext)
2207{
2208 long result;
2209 char copy[DCH_MAX_ITEM_SIZ + 1];
2210 const char *init = *src;
2211 int used;
2212
2213 /*
2214 * Skip any whitespace before parsing the integer.
2215 */
2216 *src += strspace_len(*src);
2217
2219 used = (int) strlcpy(copy, *src, len + 1);
2220
2221 if (S_FM(node->suffix) || is_next_separator(node))
2222 {
2223 /*
2224 * This node is in Fill Mode, or the next node is known to be a
2225 * non-digit value, so we just slurp as many characters as we can get.
2226 */
2227 char *endptr;
2228
2229 errno = 0;
2230 result = strtol(init, &endptr, 10);
2231 *src = endptr;
2232 }
2233 else
2234 {
2235 /*
2236 * We need to pull exactly the number of characters given in 'len' out
2237 * of the string, and convert those.
2238 */
2239 char *last;
2240
2241 if (used < len)
2242 ereturn(escontext, -1,
2243 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2244 errmsg("source string too short for \"%s\" formatting field",
2245 node->key->name),
2246 errdetail("Field requires %d characters, but only %d remain.",
2247 len, used),
2248 errhint("If your source string is not fixed-width, "
2249 "try using the \"FM\" modifier.")));
2250
2251 errno = 0;
2252 result = strtol(copy, &last, 10);
2253 used = last - copy;
2254
2255 if (used > 0 && used < len)
2256 ereturn(escontext, -1,
2257 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2258 errmsg("invalid value \"%s\" for \"%s\"",
2259 copy, node->key->name),
2260 errdetail("Field requires %d characters, but only %d could be parsed.",
2261 len, used),
2262 errhint("If your source string is not fixed-width, "
2263 "try using the \"FM\" modifier.")));
2264
2265 *src += used;
2266 }
2267
2268 if (*src == init)
2269 ereturn(escontext, -1,
2270 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2271 errmsg("invalid value \"%s\" for \"%s\"",
2272 copy, node->key->name),
2273 errdetail("Value must be an integer.")));
2274
2275 if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
2276 ereturn(escontext, -1,
2277 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2278 errmsg("value for \"%s\" in source string is out of range",
2279 node->key->name),
2280 errdetail("Value must be in the range %d to %d.",
2281 INT_MIN, INT_MAX)));
2282
2283 if (dest != NULL)
2284 {
2285 if (!from_char_set_int(dest, (int) result, node, escontext))
2286 return -1;
2287 }
2288
2289 return *src - init;
2290}
2291
2292/*
2293 * Call from_char_parse_int_len(), using the length of the format keyword as
2294 * the expected length of the field.
2295 *
2296 * Don't call this function if the field differs in length from the format
2297 * keyword (as with HH24; the keyword length is 4, but the field length is 2).
2298 * In such cases, call from_char_parse_int_len() instead to specify the
2299 * required length explicitly.
2300 */
2301static int
2302from_char_parse_int(int *dest, const char **src, FormatNode *node,
2303 Node *escontext)
2304{
2305 return from_char_parse_int_len(dest, src, node->key->len, node, escontext);
2306}
2307
2308/*
2309 * Sequentially search null-terminated "array" for a case-insensitive match
2310 * to the initial character(s) of "name".
2311 *
2312 * Returns array index of match, or -1 for no match.
2313 *
2314 * *len is set to the length of the match, or 0 for no match.
2315 *
2316 * Case-insensitivity is defined per pg_ascii_tolower, so this is only
2317 * suitable for comparisons to ASCII strings.
2318 */
2319static int
2320seq_search_ascii(const char *name, const char *const *array, int *len)
2321{
2322 unsigned char firstc;
2323 const char *const *a;
2324
2325 *len = 0;
2326
2327 /* empty string can't match anything */
2328 if (!*name)
2329 return -1;
2330
2331 /* we handle first char specially to gain some speed */
2332 firstc = pg_ascii_tolower((unsigned char) *name);
2333
2334 for (a = array; *a != NULL; a++)
2335 {
2336 const char *p;
2337 const char *n;
2338
2339 /* compare first chars */
2340 if (pg_ascii_tolower((unsigned char) **a) != firstc)
2341 continue;
2342
2343 /* compare rest of string */
2344 for (p = *a + 1, n = name + 1;; p++, n++)
2345 {
2346 /* return success if we matched whole array entry */
2347 if (*p == '\0')
2348 {
2349 *len = n - name;
2350 return a - array;
2351 }
2352 /* else, must have another character in "name" ... */
2353 if (*n == '\0')
2354 break;
2355 /* ... and it must match */
2356 if (pg_ascii_tolower((unsigned char) *p) !=
2357 pg_ascii_tolower((unsigned char) *n))
2358 break;
2359 }
2360 }
2361
2362 return -1;
2363}
2364
2365/*
2366 * Sequentially search an array of possibly non-English words for
2367 * a case-insensitive match to the initial character(s) of "name".
2368 *
2369 * This has the same API as seq_search_ascii(), but we use a more general
2370 * case-folding transformation to achieve case-insensitivity. Case folding
2371 * is done per the rules of the collation identified by "collid".
2372 *
2373 * The array is treated as const, but we don't declare it that way because
2374 * the arrays exported by pg_locale.c aren't const.
2375 */
2376static int
2377seq_search_localized(const char *name, char **array, int *len, Oid collid)
2378{
2379 char **a;
2380 char *upper_name;
2381 char *lower_name;
2382
2383 *len = 0;
2384
2385 /* empty string can't match anything */
2386 if (!*name)
2387 return -1;
2388
2389 /*
2390 * The case-folding processing done below is fairly expensive, so before
2391 * doing that, make a quick pass to see if there is an exact match.
2392 */
2393 for (a = array; *a != NULL; a++)
2394 {
2395 int element_len = strlen(*a);
2396
2397 if (strncmp(name, *a, element_len) == 0)
2398 {
2399 *len = element_len;
2400 return a - array;
2401 }
2402 }
2403
2404 /*
2405 * Fold to upper case, then to lower case, so that we can match reliably
2406 * even in languages in which case conversions are not injective.
2407 */
2408 upper_name = str_toupper(name, strlen(name), collid);
2409 lower_name = str_tolower(upper_name, strlen(upper_name), collid);
2410 pfree(upper_name);
2411
2412 for (a = array; *a != NULL; a++)
2413 {
2414 char *upper_element;
2415 char *lower_element;
2416 int element_len;
2417
2418 /* Likewise upper/lower-case array element */
2419 upper_element = str_toupper(*a, strlen(*a), collid);
2420 lower_element = str_tolower(upper_element, strlen(upper_element),
2421 collid);
2422 pfree(upper_element);
2423 element_len = strlen(lower_element);
2424
2425 /* Match? */
2426 if (strncmp(lower_name, lower_element, element_len) == 0)
2427 {
2428 *len = element_len;
2429 pfree(lower_element);
2430 pfree(lower_name);
2431 return a - array;
2432 }
2433 pfree(lower_element);
2434 }
2435
2436 pfree(lower_name);
2437 return -1;
2438}
2439
2440/*
2441 * Perform a sequential search in 'array' (or 'localized_array', if that's
2442 * not NULL) for an entry matching the first character(s) of the 'src'
2443 * string case-insensitively.
2444 *
2445 * The 'array' is presumed to be English words (all-ASCII), but
2446 * if 'localized_array' is supplied, that might be non-English
2447 * so we need a more expensive case-folding transformation
2448 * (which will follow the rules of the collation 'collid').
2449 *
2450 * If a match is found, copy the array index of the match into the integer
2451 * pointed to by 'dest' and advance 'src' to the end of the part of the string
2452 * which matched.
2453 *
2454 * Returns true on match, false on failure (if escontext points to an
2455 * ErrorSaveContext; otherwise errors are thrown).
2456 *
2457 * 'node' is used only for error reports: node->key->name identifies the
2458 * field type we were searching for.
2459 */
2460static bool
2461from_char_seq_search(int *dest, const char **src, const char *const *array,
2462 char **localized_array, Oid collid,
2463 FormatNode *node, Node *escontext)
2464{
2465 int len;
2466
2467 if (localized_array == NULL)
2468 *dest = seq_search_ascii(*src, array, &len);
2469 else
2470 *dest = seq_search_localized(*src, localized_array, &len, collid);
2471
2472 if (len <= 0)
2473 {
2474 /*
2475 * In the error report, truncate the string at the next whitespace (if
2476 * any) to avoid including irrelevant data.
2477 */
2478 char *copy = pstrdup(*src);
2479 char *c;
2480
2481 for (c = copy; *c; c++)
2482 {
2483 if (scanner_isspace(*c))
2484 {
2485 *c = '\0';
2486 break;
2487 }
2488 }
2489
2490 ereturn(escontext, false,
2491 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2492 errmsg("invalid value \"%s\" for \"%s\"",
2493 copy, node->key->name),
2494 errdetail("The given value did not match any of "
2495 "the allowed values for this field.")));
2496 }
2497 *src += len;
2498 return true;
2499}
2500
2501/* ----------
2502 * Process a TmToChar struct as denoted by a list of FormatNodes.
2503 * The formatted data is written to the string pointed to by 'out'.
2504 * ----------
2505 */
2506static void
2507DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
2508{
2509 FormatNode *n;
2510 char *s;
2511 struct fmt_tm *tm = &in->tm;
2512 int i;
2513
2514 /* cache localized days and months */
2516
2517 s = out;
2518 for (n = node; n->type != NODE_TYPE_END; n++)
2519 {
2520 if (n->type != NODE_TYPE_ACTION)
2521 {
2522 strcpy(s, n->character);
2523 s += strlen(s);
2524 continue;
2525 }
2526
2527 switch (n->key->id)
2528 {
2529 case DCH_A_M:
2530 case DCH_P_M:
2531 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2532 ? P_M_STR : A_M_STR);
2533 s += strlen(s);
2534 break;
2535 case DCH_AM:
2536 case DCH_PM:
2537 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2538 ? PM_STR : AM_STR);
2539 s += strlen(s);
2540 break;
2541 case DCH_a_m:
2542 case DCH_p_m:
2543 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2544 ? p_m_STR : a_m_STR);
2545 s += strlen(s);
2546 break;
2547 case DCH_am:
2548 case DCH_pm:
2549 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2550 ? pm_STR : am_STR);
2551 s += strlen(s);
2552 break;
2553 case DCH_HH:
2554 case DCH_HH12:
2555
2556 /*
2557 * display time as shown on a 12-hour clock, even for
2558 * intervals
2559 */
2560 sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2561 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ?
2562 (long long) (HOURS_PER_DAY / 2) :
2563 (long long) (tm->tm_hour % (HOURS_PER_DAY / 2)));
2564 if (S_THth(n->suffix))
2565 str_numth(s, s, S_TH_TYPE(n->suffix));
2566 s += strlen(s);
2567 break;
2568 case DCH_HH24:
2569 sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2570 (long long) tm->tm_hour);
2571 if (S_THth(n->suffix))
2572 str_numth(s, s, S_TH_TYPE(n->suffix));
2573 s += strlen(s);
2574 break;
2575 case DCH_MI:
2576 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2577 tm->tm_min);
2578 if (S_THth(n->suffix))
2579 str_numth(s, s, S_TH_TYPE(n->suffix));
2580 s += strlen(s);
2581 break;
2582 case DCH_SS:
2583 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2584 tm->tm_sec);
2585 if (S_THth(n->suffix))
2586 str_numth(s, s, S_TH_TYPE(n->suffix));
2587 s += strlen(s);
2588 break;
2589
2590#define DCH_to_char_fsec(frac_fmt, frac_val) \
2591 sprintf(s, frac_fmt, (int) (frac_val)); \
2592 if (S_THth(n->suffix)) \
2593 str_numth(s, s, S_TH_TYPE(n->suffix)); \
2594 s += strlen(s)
2595
2596 case DCH_FF1: /* tenth of second */
2597 DCH_to_char_fsec("%01d", in->fsec / 100000);
2598 break;
2599 case DCH_FF2: /* hundredth of second */
2600 DCH_to_char_fsec("%02d", in->fsec / 10000);
2601 break;
2602 case DCH_FF3:
2603 case DCH_MS: /* millisecond */
2604 DCH_to_char_fsec("%03d", in->fsec / 1000);
2605 break;
2606 case DCH_FF4: /* tenth of a millisecond */
2607 DCH_to_char_fsec("%04d", in->fsec / 100);
2608 break;
2609 case DCH_FF5: /* hundredth of a millisecond */
2610 DCH_to_char_fsec("%05d", in->fsec / 10);
2611 break;
2612 case DCH_FF6:
2613 case DCH_US: /* microsecond */
2614 DCH_to_char_fsec("%06d", in->fsec);
2615 break;
2616#undef DCH_to_char_fsec
2617 case DCH_SSSS:
2618 sprintf(s, "%lld",
2619 (long long) (tm->tm_hour * SECS_PER_HOUR +
2621 tm->tm_sec));
2622 if (S_THth(n->suffix))
2623 str_numth(s, s, S_TH_TYPE(n->suffix));
2624 s += strlen(s);
2625 break;
2626 case DCH_tz:
2628 if (tmtcTzn(in))
2629 {
2630 /* We assume here that timezone names aren't localized */
2631 char *p = asc_tolower_z(tmtcTzn(in));
2632
2633 strcpy(s, p);
2634 pfree(p);
2635 s += strlen(s);
2636 }
2637 break;
2638 case DCH_TZ:
2640 if (tmtcTzn(in))
2641 {
2642 strcpy(s, tmtcTzn(in));
2643 s += strlen(s);
2644 }
2645 break;
2646 case DCH_TZH:
2648 sprintf(s, "%c%02d",
2649 (tm->tm_gmtoff >= 0) ? '+' : '-',
2650 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2651 s += strlen(s);
2652 break;
2653 case DCH_TZM:
2655 sprintf(s, "%02d",
2656 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2657 s += strlen(s);
2658 break;
2659 case DCH_OF:
2661 sprintf(s, "%c%0*d",
2662 (tm->tm_gmtoff >= 0) ? '+' : '-',
2663 S_FM(n->suffix) ? 0 : 2,
2664 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2665 s += strlen(s);
2666 if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2667 {
2668 sprintf(s, ":%02d",
2669 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2670 s += strlen(s);
2671 }
2672 break;
2673 case DCH_A_D:
2674 case DCH_B_C:
2676 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2677 s += strlen(s);
2678 break;
2679 case DCH_AD:
2680 case DCH_BC:
2682 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2683 s += strlen(s);
2684 break;
2685 case DCH_a_d:
2686 case DCH_b_c:
2688 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2689 s += strlen(s);
2690 break;
2691 case DCH_ad:
2692 case DCH_bc:
2694 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2695 s += strlen(s);
2696 break;
2697 case DCH_MONTH:
2699 if (!tm->tm_mon)
2700 break;
2701 if (S_TM(n->suffix))
2702 {
2704
2705 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2706 strcpy(s, str);
2707 else
2708 ereport(ERROR,
2709 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2710 errmsg("localized string format value too long")));
2711 }
2712 else
2713 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2715 s += strlen(s);
2716 break;
2717 case DCH_Month:
2719 if (!tm->tm_mon)
2720 break;
2721 if (S_TM(n->suffix))
2722 {
2724
2725 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2726 strcpy(s, str);
2727 else
2728 ereport(ERROR,
2729 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2730 errmsg("localized string format value too long")));
2731 }
2732 else
2733 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2734 months_full[tm->tm_mon - 1]);
2735 s += strlen(s);
2736 break;
2737 case DCH_month:
2739 if (!tm->tm_mon)
2740 break;
2741 if (S_TM(n->suffix))
2742 {
2744
2745 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2746 strcpy(s, str);
2747 else
2748 ereport(ERROR,
2749 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2750 errmsg("localized string format value too long")));
2751 }
2752 else
2753 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2755 s += strlen(s);
2756 break;
2757 case DCH_MON:
2759 if (!tm->tm_mon)
2760 break;
2761 if (S_TM(n->suffix))
2762 {
2764
2765 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2766 strcpy(s, str);
2767 else
2768 ereport(ERROR,
2769 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2770 errmsg("localized string format value too long")));
2771 }
2772 else
2773 strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2774 s += strlen(s);
2775 break;
2776 case DCH_Mon:
2778 if (!tm->tm_mon)
2779 break;
2780 if (S_TM(n->suffix))
2781 {
2783
2784 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2785 strcpy(s, str);
2786 else
2787 ereport(ERROR,
2788 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2789 errmsg("localized string format value too long")));
2790 }
2791 else
2792 strcpy(s, months[tm->tm_mon - 1]);
2793 s += strlen(s);
2794 break;
2795 case DCH_mon:
2797 if (!tm->tm_mon)
2798 break;
2799 if (S_TM(n->suffix))
2800 {
2802
2803 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2804 strcpy(s, str);
2805 else
2806 ereport(ERROR,
2807 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2808 errmsg("localized string format value too long")));
2809 }
2810 else
2811 strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
2812 s += strlen(s);
2813 break;
2814 case DCH_MM:
2815 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
2816 tm->tm_mon);
2817 if (S_THth(n->suffix))
2818 str_numth(s, s, S_TH_TYPE(n->suffix));
2819 s += strlen(s);
2820 break;
2821 case DCH_DAY:
2823 if (S_TM(n->suffix))
2824 {
2826
2827 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2828 strcpy(s, str);
2829 else
2830 ereport(ERROR,
2831 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2832 errmsg("localized string format value too long")));
2833 }
2834 else
2835 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2837 s += strlen(s);
2838 break;
2839 case DCH_Day:
2841 if (S_TM(n->suffix))
2842 {
2844
2845 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2846 strcpy(s, str);
2847 else
2848 ereport(ERROR,
2849 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2850 errmsg("localized string format value too long")));
2851 }
2852 else
2853 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2854 days[tm->tm_wday]);
2855 s += strlen(s);
2856 break;
2857 case DCH_day:
2859 if (S_TM(n->suffix))
2860 {
2862
2863 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2864 strcpy(s, str);
2865 else
2866 ereport(ERROR,
2867 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2868 errmsg("localized string format value too long")));
2869 }
2870 else
2871 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2873 s += strlen(s);
2874 break;
2875 case DCH_DY:
2877 if (S_TM(n->suffix))
2878 {
2880
2881 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2882 strcpy(s, str);
2883 else
2884 ereport(ERROR,
2885 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2886 errmsg("localized string format value too long")));
2887 }
2888 else
2889 strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
2890 s += strlen(s);
2891 break;
2892 case DCH_Dy:
2894 if (S_TM(n->suffix))
2895 {
2897
2898 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2899 strcpy(s, str);
2900 else
2901 ereport(ERROR,
2902 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2903 errmsg("localized string format value too long")));
2904 }
2905 else
2906 strcpy(s, days_short[tm->tm_wday]);
2907 s += strlen(s);
2908 break;
2909 case DCH_dy:
2911 if (S_TM(n->suffix))
2912 {
2914
2915 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2916 strcpy(s, str);
2917 else
2918 ereport(ERROR,
2919 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2920 errmsg("localized string format value too long")));
2921 }
2922 else
2923 strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
2924 s += strlen(s);
2925 break;
2926 case DCH_DDD:
2927 case DCH_IDDD:
2928 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
2929 (n->key->id == DCH_DDD) ?
2930 tm->tm_yday :
2932 if (S_THth(n->suffix))
2933 str_numth(s, s, S_TH_TYPE(n->suffix));
2934 s += strlen(s);
2935 break;
2936 case DCH_DD:
2937 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
2938 if (S_THth(n->suffix))
2939 str_numth(s, s, S_TH_TYPE(n->suffix));
2940 s += strlen(s);
2941 break;
2942 case DCH_D:
2944 sprintf(s, "%d", tm->tm_wday + 1);
2945 if (S_THth(n->suffix))
2946 str_numth(s, s, S_TH_TYPE(n->suffix));
2947 s += strlen(s);
2948 break;
2949 case DCH_ID:
2951 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
2952 if (S_THth(n->suffix))
2953 str_numth(s, s, S_TH_TYPE(n->suffix));
2954 s += strlen(s);
2955 break;
2956 case DCH_WW:
2957 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2958 (tm->tm_yday - 1) / 7 + 1);
2959 if (S_THth(n->suffix))
2960 str_numth(s, s, S_TH_TYPE(n->suffix));
2961 s += strlen(s);
2962 break;
2963 case DCH_IW:
2964 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2966 if (S_THth(n->suffix))
2967 str_numth(s, s, S_TH_TYPE(n->suffix));
2968 s += strlen(s);
2969 break;
2970 case DCH_Q:
2971 if (!tm->tm_mon)
2972 break;
2973 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
2974 if (S_THth(n->suffix))
2975 str_numth(s, s, S_TH_TYPE(n->suffix));
2976 s += strlen(s);
2977 break;
2978 case DCH_CC:
2979 if (is_interval) /* straight calculation */
2980 i = tm->tm_year / 100;
2981 else
2982 {
2983 if (tm->tm_year > 0)
2984 /* Century 20 == 1901 - 2000 */
2985 i = (tm->tm_year - 1) / 100 + 1;
2986 else
2987 /* Century 6BC == 600BC - 501BC */
2988 i = tm->tm_year / 100 - 1;
2989 }
2990 if (i <= 99 && i >= -99)
2991 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
2992 else
2993 sprintf(s, "%d", i);
2994 if (S_THth(n->suffix))
2995 str_numth(s, s, S_TH_TYPE(n->suffix));
2996 s += strlen(s);
2997 break;
2998 case DCH_Y_YYY:
2999 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
3000 sprintf(s, "%d,%03d", i,
3001 ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
3002 if (S_THth(n->suffix))
3003 str_numth(s, s, S_TH_TYPE(n->suffix));
3004 s += strlen(s);
3005 break;
3006 case DCH_YYYY:
3007 case DCH_IYYY:
3008 sprintf(s, "%0*d",
3009 S_FM(n->suffix) ? 0 :
3010 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
3011 (n->key->id == DCH_YYYY ?
3012 ADJUST_YEAR(tm->tm_year, is_interval) :
3014 tm->tm_mon,
3015 tm->tm_mday),
3016 is_interval)));
3017 if (S_THth(n->suffix))
3018 str_numth(s, s, S_TH_TYPE(n->suffix));
3019 s += strlen(s);
3020 break;
3021 case DCH_YYY:
3022 case DCH_IYY:
3023 sprintf(s, "%0*d",
3024 S_FM(n->suffix) ? 0 :
3025 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
3026 (n->key->id == DCH_YYY ?
3027 ADJUST_YEAR(tm->tm_year, is_interval) :
3029 tm->tm_mon,
3030 tm->tm_mday),
3031 is_interval)) % 1000);
3032 if (S_THth(n->suffix))
3033 str_numth(s, s, S_TH_TYPE(n->suffix));
3034 s += strlen(s);
3035 break;
3036 case DCH_YY:
3037 case DCH_IY:
3038 sprintf(s, "%0*d",
3039 S_FM(n->suffix) ? 0 :
3040 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
3041 (n->key->id == DCH_YY ?
3042 ADJUST_YEAR(tm->tm_year, is_interval) :
3044 tm->tm_mon,
3045 tm->tm_mday),
3046 is_interval)) % 100);
3047 if (S_THth(n->suffix))
3048 str_numth(s, s, S_TH_TYPE(n->suffix));
3049 s += strlen(s);
3050 break;
3051 case DCH_Y:
3052 case DCH_I:
3053 sprintf(s, "%1d",
3054 (n->key->id == DCH_Y ?
3055 ADJUST_YEAR(tm->tm_year, is_interval) :
3057 tm->tm_mon,
3058 tm->tm_mday),
3059 is_interval)) % 10);
3060 if (S_THth(n->suffix))
3061 str_numth(s, s, S_TH_TYPE(n->suffix));
3062 s += strlen(s);
3063 break;
3064 case DCH_RM:
3065 /* FALLTHROUGH */
3066 case DCH_rm:
3067
3068 /*
3069 * For intervals, values like '12 month' will be reduced to 0
3070 * month and some years. These should be processed.
3071 */
3072 if (!tm->tm_mon && !tm->tm_year)
3073 break;
3074 else
3075 {
3076 int mon = 0;
3077 const char *const *months;
3078
3079 if (n->key->id == DCH_RM)
3081 else
3083
3084 /*
3085 * Compute the position in the roman-numeral array. Note
3086 * that the contents of the array are reversed, December
3087 * being first and January last.
3088 */
3089 if (tm->tm_mon == 0)
3090 {
3091 /*
3092 * This case is special, and tracks the case of full
3093 * interval years.
3094 */
3095 mon = tm->tm_year >= 0 ? 0 : MONTHS_PER_YEAR - 1;
3096 }
3097 else if (tm->tm_mon < 0)
3098 {
3099 /*
3100 * Negative case. In this case, the calculation is
3101 * reversed, where -1 means December, -2 November,
3102 * etc.
3103 */
3104 mon = -1 * (tm->tm_mon + 1);
3105 }
3106 else
3107 {
3108 /*
3109 * Common case, with a strictly positive value. The
3110 * position in the array matches with the value of
3111 * tm_mon.
3112 */
3113 mon = MONTHS_PER_YEAR - tm->tm_mon;
3114 }
3115
3116 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
3117 months[mon]);
3118 s += strlen(s);
3119 }
3120 break;
3121 case DCH_W:
3122 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
3123 if (S_THth(n->suffix))
3124 str_numth(s, s, S_TH_TYPE(n->suffix));
3125 s += strlen(s);
3126 break;
3127 case DCH_J:
3128 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
3129 if (S_THth(n->suffix))
3130 str_numth(s, s, S_TH_TYPE(n->suffix));
3131 s += strlen(s);
3132 break;
3133 }
3134 }
3135
3136 *s = '\0';
3137}
3138
3139/*
3140 * Process the string 'in' as denoted by the array of FormatNodes 'node[]'.
3141 * The TmFromChar struct pointed to by 'out' is populated with the results.
3142 *
3143 * 'collid' identifies the collation to use, if needed.
3144 * 'std' specifies standard parsing mode.
3145 *
3146 * If escontext points to an ErrorSaveContext, data errors will be reported
3147 * by filling that struct; the caller must test SOFT_ERROR_OCCURRED() to see
3148 * whether an error occurred. Otherwise, errors are thrown.
3149 *
3150 * Note: we currently don't have any to_interval() function, so there
3151 * is no need here for INVALID_FOR_INTERVAL checks.
3152 */
3153static void
3154DCH_from_char(FormatNode *node, const char *in, TmFromChar *out,
3155 Oid collid, bool std, Node *escontext)
3156{
3157 FormatNode *n;
3158 const char *s;
3159 int len,
3160 value;
3161 bool fx_mode = std;
3162
3163 /* number of extra skipped characters (more than given in format string) */
3164 int extra_skip = 0;
3165
3166 /* cache localized days and months */
3168
3169 for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
3170 {
3171 /*
3172 * Ignore spaces at the beginning of the string and before fields when
3173 * not in FX (fixed width) mode.
3174 */
3175 if (!fx_mode && (n->type != NODE_TYPE_ACTION || n->key->id != DCH_FX) &&
3176 (n->type == NODE_TYPE_ACTION || n == node))
3177 {
3178 while (*s != '\0' && isspace((unsigned char) *s))
3179 {
3180 s++;
3181 extra_skip++;
3182 }
3183 }
3184
3185 if (n->type == NODE_TYPE_SPACE || n->type == NODE_TYPE_SEPARATOR)
3186 {
3187 if (std)
3188 {
3189 /*
3190 * Standard mode requires strict matching between format
3191 * string separators/spaces and input string.
3192 */
3193 Assert(n->character[0] && !n->character[1]);
3194
3195 if (*s == n->character[0])
3196 s++;
3197 else
3198 ereturn(escontext,,
3199 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3200 errmsg("unmatched format separator \"%c\"",
3201 n->character[0])));
3202 }
3203 else if (!fx_mode)
3204 {
3205 /*
3206 * In non FX (fixed format) mode one format string space or
3207 * separator match to one space or separator in input string.
3208 * Or match nothing if there is no space or separator in the
3209 * current position of input string.
3210 */
3211 extra_skip--;
3212 if (isspace((unsigned char) *s) || is_separator_char(s))
3213 {
3214 s++;
3215 extra_skip++;
3216 }
3217 }
3218 else
3219 {
3220 /*
3221 * In FX mode, on format string space or separator we consume
3222 * exactly one character from input string. Notice we don't
3223 * insist that the consumed character match the format's
3224 * character.
3225 */
3226 s += pg_mblen(s);
3227 }
3228 continue;
3229 }
3230 else if (n->type != NODE_TYPE_ACTION)
3231 {
3232 /*
3233 * Text character, so consume one character from input string.
3234 * Notice we don't insist that the consumed character match the
3235 * format's character.
3236 */
3237 if (!fx_mode)
3238 {
3239 /*
3240 * In non FX mode we might have skipped some extra characters
3241 * (more than specified in format string) before. In this
3242 * case we don't skip input string character, because it might
3243 * be part of field.
3244 */
3245 if (extra_skip > 0)
3246 extra_skip--;
3247 else
3248 s += pg_mblen(s);
3249 }
3250 else
3251 {
3252 int chlen = pg_mblen(s);
3253
3254 /*
3255 * Standard mode requires strict match of format characters.
3256 */
3257 if (std && n->type == NODE_TYPE_CHAR &&
3258 strncmp(s, n->character, chlen) != 0)
3259 ereturn(escontext,,
3260 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3261 errmsg("unmatched format character \"%s\"",
3262 n->character)));
3263
3264 s += chlen;
3265 }
3266 continue;
3267 }
3268
3269 if (!from_char_set_mode(out, n->key->date_mode, escontext))
3270 return;
3271
3272 switch (n->key->id)
3273 {
3274 case DCH_FX:
3275 fx_mode = true;
3276 break;
3277 case DCH_A_M:
3278 case DCH_P_M:
3279 case DCH_a_m:
3280 case DCH_p_m:
3282 NULL, InvalidOid,
3283 n, escontext))
3284 return;
3285 if (!from_char_set_int(&out->pm, value % 2, n, escontext))
3286 return;
3287 out->clock = CLOCK_12_HOUR;
3288 break;
3289 case DCH_AM:
3290 case DCH_PM:
3291 case DCH_am:
3292 case DCH_pm:
3294 NULL, InvalidOid,
3295 n, escontext))
3296 return;
3297 if (!from_char_set_int(&out->pm, value % 2, n, escontext))
3298 return;
3299 out->clock = CLOCK_12_HOUR;
3300 break;
3301 case DCH_HH:
3302 case DCH_HH12:
3303 if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
3304 return;
3305 out->clock = CLOCK_12_HOUR;
3306 SKIP_THth(s, n->suffix);
3307 break;
3308 case DCH_HH24:
3309 if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
3310 return;
3311 SKIP_THth(s, n->suffix);
3312 break;
3313 case DCH_MI:
3314 if (from_char_parse_int(&out->mi, &s, n, escontext) < 0)
3315 return;
3316 SKIP_THth(s, n->suffix);
3317 break;
3318 case DCH_SS:
3319 if (from_char_parse_int(&out->ss, &s, n, escontext) < 0)
3320 return;
3321 SKIP_THth(s, n->suffix);
3322 break;
3323 case DCH_MS: /* millisecond */
3324 len = from_char_parse_int_len(&out->ms, &s, 3, n, escontext);
3325 if (len < 0)
3326 return;
3327
3328 /*
3329 * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
3330 */
3331 out->ms *= len == 1 ? 100 :
3332 len == 2 ? 10 : 1;
3333
3334 SKIP_THth(s, n->suffix);
3335 break;
3336 case DCH_FF1:
3337 case DCH_FF2:
3338 case DCH_FF3:
3339 case DCH_FF4:
3340 case DCH_FF5:
3341 case DCH_FF6:
3342 out->ff = n->key->id - DCH_FF1 + 1;
3343 /* FALLTHROUGH */
3344 case DCH_US: /* microsecond */
3345 len = from_char_parse_int_len(&out->us, &s,
3346 n->key->id == DCH_US ? 6 :
3347 out->ff, n, escontext);
3348 if (len < 0)
3349 return;
3350
3351 out->us *= len == 1 ? 100000 :
3352 len == 2 ? 10000 :
3353 len == 3 ? 1000 :
3354 len == 4 ? 100 :
3355 len == 5 ? 10 : 1;
3356
3357 SKIP_THth(s, n->suffix);
3358 break;
3359 case DCH_SSSS:
3360 if (from_char_parse_int(&out->ssss, &s, n, escontext) < 0)
3361 return;
3362 SKIP_THth(s, n->suffix);
3363 break;
3364 case DCH_tz:
3365 case DCH_TZ:
3366 {
3367 int tzlen;
3368
3370 &out->gmtoffset,
3371 &out->tzp);
3372 if (tzlen > 0)
3373 {
3374 out->has_tz = true;
3375 /* we only need the zone abbrev for DYNTZ case */
3376 if (out->tzp)
3377 out->abbrev = pnstrdup(s, tzlen);
3378 out->tzsign = 0; /* drop any earlier TZH/TZM info */
3379 s += tzlen;
3380 break;
3381 }
3382 else if (isalpha((unsigned char) *s))
3383 {
3384 /*
3385 * It doesn't match any abbreviation, but it starts
3386 * with a letter. OF format certainly won't succeed;
3387 * assume it's a misspelled abbreviation and complain
3388 * accordingly.
3389 */
3390 ereturn(escontext,,
3391 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3392 errmsg("invalid value \"%s\" for \"%s\"",
3393 s, n->key->name),
3394 errdetail("Time zone abbreviation is not recognized.")));
3395 }
3396 /* otherwise parse it like OF */
3397 }
3398 /* FALLTHROUGH */
3399 case DCH_OF:
3400 /* OF is equivalent to TZH or TZH:TZM */
3401 /* see TZH comments below */
3402 if (*s == '+' || *s == '-' || *s == ' ')
3403 {
3404 out->tzsign = *s == '-' ? -1 : +1;
3405 s++;
3406 }
3407 else
3408 {
3409 if (extra_skip > 0 && *(s - 1) == '-')
3410 out->tzsign = -1;
3411 else
3412 out->tzsign = +1;
3413 }
3414 if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
3415 return;
3416 if (*s == ':')
3417 {
3418 s++;
3419 if (from_char_parse_int_len(&out->tzm, &s, 2, n,
3420 escontext) < 0)
3421 return;
3422 }
3423 break;
3424 case DCH_TZH:
3425
3426 /*
3427 * Value of TZH might be negative. And the issue is that we
3428 * might swallow minus sign as the separator. So, if we have
3429 * skipped more characters than specified in the format
3430 * string, then we consider prepending last skipped minus to
3431 * TZH.
3432 */
3433 if (*s == '+' || *s == '-' || *s == ' ')
3434 {
3435 out->tzsign = *s == '-' ? -1 : +1;
3436 s++;
3437 }
3438 else
3439 {
3440 if (extra_skip > 0 && *(s - 1) == '-')
3441 out->tzsign = -1;
3442 else
3443 out->tzsign = +1;
3444 }
3445
3446 if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
3447 return;
3448 break;
3449 case DCH_TZM:
3450 /* assign positive timezone sign if TZH was not seen before */
3451 if (!out->tzsign)
3452 out->tzsign = +1;
3453 if (from_char_parse_int_len(&out->tzm, &s, 2, n, escontext) < 0)
3454 return;
3455 break;
3456 case DCH_A_D:
3457 case DCH_B_C:
3458 case DCH_a_d:
3459 case DCH_b_c:
3461 NULL, InvalidOid,
3462 n, escontext))
3463 return;
3464 if (!from_char_set_int(&out->bc, value % 2, n, escontext))
3465 return;
3466 break;
3467 case DCH_AD:
3468 case DCH_BC:
3469 case DCH_ad:
3470 case DCH_bc:
3472 NULL, InvalidOid,
3473 n, escontext))
3474 return;
3475 if (!from_char_set_int(&out->bc, value % 2, n, escontext))
3476 return;
3477 break;
3478 case DCH_MONTH:
3479 case DCH_Month:
3480 case DCH_month:
3482 S_TM(n->suffix) ? localized_full_months : NULL,
3483 collid,
3484 n, escontext))
3485 return;
3486 if (!from_char_set_int(&out->mm, value + 1, n, escontext))
3487 return;
3488 break;
3489 case DCH_MON:
3490 case DCH_Mon:
3491 case DCH_mon:
3493 S_TM(n->suffix) ? localized_abbrev_months : NULL,
3494 collid,
3495 n, escontext))
3496 return;
3497 if (!from_char_set_int(&out->mm, value + 1, n, escontext))
3498 return;
3499 break;
3500 case DCH_MM:
3501 if (from_char_parse_int(&out->mm, &s, n, escontext) < 0)
3502 return;
3503 SKIP_THth(s, n->suffix);
3504 break;
3505 case DCH_DAY:
3506 case DCH_Day:
3507 case DCH_day:
3508 if (!from_char_seq_search(&value, &s, days,
3509 S_TM(n->suffix) ? localized_full_days : NULL,
3510 collid,
3511 n, escontext))
3512 return;
3513 if (!from_char_set_int(&out->d, value, n, escontext))
3514 return;
3515 out->d++;
3516 break;
3517 case DCH_DY:
3518 case DCH_Dy:
3519 case DCH_dy:
3521 S_TM(n->suffix) ? localized_abbrev_days : NULL,
3522 collid,
3523 n, escontext))
3524 return;
3525 if (!from_char_set_int(&out->d, value, n, escontext))
3526 return;
3527 out->d++;
3528 break;
3529 case DCH_DDD:
3530 if (from_char_parse_int(&out->ddd, &s, n, escontext) < 0)
3531 return;
3532 SKIP_THth(s, n->suffix);
3533 break;
3534 case DCH_IDDD:
3535 if (from_char_parse_int_len(&out->ddd, &s, 3, n, escontext) < 0)
3536 return;
3537 SKIP_THth(s, n->suffix);
3538 break;
3539 case DCH_DD:
3540 if (from_char_parse_int(&out->dd, &s, n, escontext) < 0)
3541 return;
3542 SKIP_THth(s, n->suffix);
3543 break;
3544 case DCH_D:
3545 if (from_char_parse_int(&out->d, &s, n, escontext) < 0)
3546 return;
3547 SKIP_THth(s, n->suffix);
3548 break;
3549 case DCH_ID:
3550 if (from_char_parse_int_len(&out->d, &s, 1, n, escontext) < 0)
3551 return;
3552 /* Shift numbering to match Gregorian where Sunday = 1 */
3553 if (++out->d > 7)
3554 out->d = 1;
3555 SKIP_THth(s, n->suffix);
3556 break;
3557 case DCH_WW:
3558 case DCH_IW:
3559 if (from_char_parse_int(&out->ww, &s, n, escontext) < 0)
3560 return;
3561 SKIP_THth(s, n->suffix);
3562 break;
3563 case DCH_Q:
3564
3565 /*
3566 * We ignore 'Q' when converting to date because it is unclear
3567 * which date in the quarter to use, and some people specify
3568 * both quarter and month, so if it was honored it might
3569 * conflict with the supplied month. That is also why we don't
3570 * throw an error.
3571 *
3572 * We still parse the source string for an integer, but it
3573 * isn't stored anywhere in 'out'.
3574 */
3575 if (from_char_parse_int((int *) NULL, &s, n, escontext) < 0)
3576 return;
3577 SKIP_THth(s, n->suffix);
3578 break;
3579 case DCH_CC:
3580 if (from_char_parse_int(&out->cc, &s, n, escontext) < 0)
3581 return;
3582 SKIP_THth(s, n->suffix);
3583 break;
3584 case DCH_Y_YYY:
3585 {
3586 int matched,
3587 years,
3588 millennia,
3589 nch;
3590
3591 matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch);
3592 if (matched < 2)
3593 ereturn(escontext,,
3594 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3595 errmsg("invalid value \"%s\" for \"%s\"",
3596 s, "Y,YYY")));
3597
3598 /* years += (millennia * 1000); */
3599 if (pg_mul_s32_overflow(millennia, 1000, &millennia) ||
3600 pg_add_s32_overflow(years, millennia, &years))
3601 ereturn(escontext,,
3602 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3603 errmsg("value for \"%s\" in source string is out of range", "Y,YYY")));
3604
3605 if (!from_char_set_int(&out->year, years, n, escontext))
3606 return;
3607 out->yysz = 4;
3608 s += nch;
3609 SKIP_THth(s, n->suffix);
3610 }
3611 break;
3612 case DCH_YYYY:
3613 case DCH_IYYY:
3614 if (from_char_parse_int(&out->year, &s, n, escontext) < 0)
3615 return;
3616 out->yysz = 4;
3617 SKIP_THth(s, n->suffix);
3618 break;
3619 case DCH_YYY:
3620 case DCH_IYY:
3621 len = from_char_parse_int(&out->year, &s, n, escontext);
3622 if (len < 0)
3623 return;
3624 if (len < 4)
3626 out->yysz = 3;
3627 SKIP_THth(s, n->suffix);
3628 break;
3629 case DCH_YY:
3630 case DCH_IY:
3631 len = from_char_parse_int(&out->year, &s, n, escontext);
3632 if (len < 0)
3633 return;
3634 if (len < 4)
3636 out->yysz = 2;
3637 SKIP_THth(s, n->suffix);
3638 break;
3639 case DCH_Y:
3640 case DCH_I:
3641 len = from_char_parse_int(&out->year, &s, n, escontext);
3642 if (len < 0)
3643 return;
3644 if (len < 4)
3646 out->yysz = 1;
3647 SKIP_THth(s, n->suffix);
3648 break;
3649 case DCH_RM:
3650 case DCH_rm:
3652 NULL, InvalidOid,
3653 n, escontext))
3654 return;
3655 if (!from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n,
3656 escontext))
3657 return;
3658 break;
3659 case DCH_W:
3660 if (from_char_parse_int(&out->w, &s, n, escontext) < 0)
3661 return;
3662 SKIP_THth(s, n->suffix);
3663 break;
3664 case DCH_J:
3665 if (from_char_parse_int(&out->j, &s, n, escontext) < 0)
3666 return;
3667 SKIP_THth(s, n->suffix);
3668 break;
3669 }
3670
3671 /* Ignore all spaces after fields */
3672 if (!fx_mode)
3673 {
3674 extra_skip = 0;
3675 while (*s != '\0' && isspace((unsigned char) *s))
3676 {
3677 s++;
3678 extra_skip++;
3679 }
3680 }
3681 }
3682
3683 /*
3684 * Standard parsing mode doesn't allow unmatched format patterns or
3685 * trailing characters in the input string.
3686 */
3687 if (std)
3688 {
3689 if (n->type != NODE_TYPE_END)
3690 ereturn(escontext,,
3691 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3692 errmsg("input string is too short for datetime format")));
3693
3694 while (*s != '\0' && isspace((unsigned char) *s))
3695 s++;
3696
3697 if (*s != '\0')
3698 ereturn(escontext,,
3699 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3700 errmsg("trailing characters remain in input string after datetime format")));
3701 }
3702}
3703
3704/*
3705 * The invariant for DCH cache entry management is that DCHCounter is equal
3706 * to the maximum age value among the existing entries, and we increment it
3707 * whenever an access occurs. If we approach overflow, deal with that by
3708 * halving all the age values, so that we retain a fairly accurate idea of
3709 * which entries are oldest.
3710 */
3711static inline void
3713{
3714 if (DCHCounter >= (INT_MAX - 1))
3715 {
3716 for (int i = 0; i < n_DCHCache; i++)
3717 DCHCache[i]->age >>= 1;
3718 DCHCounter >>= 1;
3719 }
3720}
3721
3722/*
3723 * Get mask of date/time/zone components present in format nodes.
3724 */
3725static int
3727{
3728 FormatNode *n;
3729 int flags = 0;
3730
3731 for (n = node; n->type != NODE_TYPE_END; n++)
3732 {
3733 if (n->type != NODE_TYPE_ACTION)
3734 continue;
3735
3736 switch (n->key->id)
3737 {
3738 case DCH_FX:
3739 break;
3740 case DCH_A_M:
3741 case DCH_P_M:
3742 case DCH_a_m:
3743 case DCH_p_m:
3744 case DCH_AM:
3745 case DCH_PM:
3746 case DCH_am:
3747 case DCH_pm:
3748 case DCH_HH:
3749 case DCH_HH12:
3750 case DCH_HH24:
3751 case DCH_MI:
3752 case DCH_SS:
3753 case DCH_MS: /* millisecond */
3754 case DCH_US: /* microsecond */
3755 case DCH_FF1:
3756 case DCH_FF2:
3757 case DCH_FF3:
3758 case DCH_FF4:
3759 case DCH_FF5:
3760 case DCH_FF6:
3761 case DCH_SSSS:
3762 flags |= DCH_TIMED;
3763 break;
3764 case DCH_tz:
3765 case DCH_TZ:
3766 case DCH_OF:
3767 case DCH_TZH:
3768 case DCH_TZM:
3769 flags |= DCH_ZONED;
3770 break;
3771 case DCH_A_D:
3772 case DCH_B_C:
3773 case DCH_a_d:
3774 case DCH_b_c:
3775 case DCH_AD:
3776 case DCH_BC:
3777 case DCH_ad:
3778 case DCH_bc:
3779 case DCH_MONTH:
3780 case DCH_Month:
3781 case DCH_month:
3782 case DCH_MON:
3783 case DCH_Mon:
3784 case DCH_mon:
3785 case DCH_MM:
3786 case DCH_DAY:
3787 case DCH_Day:
3788 case DCH_day:
3789 case DCH_DY:
3790 case DCH_Dy:
3791 case DCH_dy:
3792 case DCH_DDD:
3793 case DCH_IDDD:
3794 case DCH_DD:
3795 case DCH_D:
3796 case DCH_ID:
3797 case DCH_WW:
3798 case DCH_Q:
3799 case DCH_CC:
3800 case DCH_Y_YYY:
3801 case DCH_YYYY:
3802 case DCH_IYYY:
3803 case DCH_YYY:
3804 case DCH_IYY:
3805 case DCH_YY:
3806 case DCH_IY:
3807 case DCH_Y:
3808 case DCH_I:
3809 case DCH_RM:
3810 case DCH_rm:
3811 case DCH_W:
3812 case DCH_J:
3813 flags |= DCH_DATED;
3814 break;
3815 }
3816 }
3817
3818 return flags;
3819}
3820
3821/* select a DCHCacheEntry to hold the given format picture */
3822static DCHCacheEntry *
3823DCH_cache_getnew(const char *str, bool std)
3824{
3825 DCHCacheEntry *ent;
3826
3827 /* Ensure we can advance DCHCounter below */
3829
3830 /*
3831 * If cache is full, remove oldest entry (or recycle first not-valid one)
3832 */
3834 {
3835 DCHCacheEntry *old = DCHCache[0];
3836
3837#ifdef DEBUG_TO_FROM_CHAR
3838 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3839#endif
3840 if (old->valid)
3841 {
3842 for (int i = 1; i < DCH_CACHE_ENTRIES; i++)
3843 {
3844 ent = DCHCache[i];
3845 if (!ent->valid)
3846 {
3847 old = ent;
3848 break;
3849 }
3850 if (ent->age < old->age)
3851 old = ent;
3852 }
3853 }
3854#ifdef DEBUG_TO_FROM_CHAR
3855 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3856#endif
3857 old->valid = false;
3858 strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
3859 old->age = (++DCHCounter);
3860 /* caller is expected to fill format, then set valid */
3861 return old;
3862 }
3863 else
3864 {
3865#ifdef DEBUG_TO_FROM_CHAR
3866 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3867#endif
3868 Assert(DCHCache[n_DCHCache] == NULL);
3869 DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
3871 ent->valid = false;
3872 strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
3873 ent->std = std;
3874 ent->age = (++DCHCounter);
3875 /* caller is expected to fill format, then set valid */
3876 ++n_DCHCache;
3877 return ent;
3878 }
3879}
3880
3881/* look for an existing DCHCacheEntry matching the given format picture */
3882static DCHCacheEntry *
3883DCH_cache_search(const char *str, bool std)
3884{
3885 /* Ensure we can advance DCHCounter below */
3887
3888 for (int i = 0; i < n_DCHCache; i++)
3889 {
3890 DCHCacheEntry *ent = DCHCache[i];
3891
3892 if (ent->valid && strcmp(ent->str, str) == 0 && ent->std == std)
3893 {
3894 ent->age = (++DCHCounter);
3895 return ent;
3896 }
3897 }
3898
3899 return NULL;
3900}
3901
3902/* Find or create a DCHCacheEntry for the given format picture */
3903static DCHCacheEntry *
3904DCH_cache_fetch(const char *str, bool std)
3905{
3906 DCHCacheEntry *ent;
3907
3908 if ((ent = DCH_cache_search(str, std)) == NULL)
3909 {
3910 /*
3911 * Not in the cache, must run parser and save a new format-picture to
3912 * the cache. Do not mark the cache entry valid until parsing
3913 * succeeds.
3914 */
3915 ent = DCH_cache_getnew(str, std);
3916
3918 DCH_FLAG | (std ? STD_FLAG : 0), NULL);
3919
3920 ent->valid = true;
3921 }
3922 return ent;
3923}
3924
3925/*
3926 * Format a date/time or interval into a string according to fmt.
3927 * We parse fmt into a list of FormatNodes. This is then passed to DCH_to_char
3928 * for formatting.
3929 */
3930static text *
3931datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
3932{
3934 char *fmt_str,
3935 *result;
3936 bool incache;
3937 int fmt_len;
3938 text *res;
3939
3940 /*
3941 * Convert fmt to C string
3942 */
3943 fmt_str = text_to_cstring(fmt);
3944 fmt_len = strlen(fmt_str);
3945
3946 /*
3947 * Allocate workspace for result as C string
3948 */
3949 result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
3950 *result = '\0';
3951
3952 if (fmt_len > DCH_CACHE_SIZE)
3953 {
3954 /*
3955 * Allocate new memory if format picture is bigger than static cache
3956 * and do not use cache (call parser always)
3957 */
3958 incache = false;
3959
3960 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3961
3963 DCH_suff, DCH_index, DCH_FLAG, NULL);
3964 }
3965 else
3966 {
3967 /*
3968 * Use cache buffers
3969 */
3970 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
3971
3972 incache = true;
3973 format = ent->format;
3974 }
3975
3976 /* The real work is here */
3977 DCH_to_char(format, is_interval, tmtc, result, collid);
3978
3979 if (!incache)
3980 pfree(format);
3981
3982 pfree(fmt_str);
3983
3984 /* convert C-string result to TEXT format */
3985 res = cstring_to_text(result);
3986
3987 pfree(result);
3988 return res;
3989}
3990
3991/****************************************************************************
3992 * Public routines
3993 ***************************************************************************/
3994
3995/* -------------------
3996 * TIMESTAMP to_char()
3997 * -------------------
3998 */
3999Datum
4001{
4003 text *fmt = PG_GETARG_TEXT_PP(1),
4004 *res;
4005 TmToChar tmtc;
4006 struct pg_tm tt;
4007 struct fmt_tm *tm;
4008 int thisdate;
4009
4010 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
4012
4013 ZERO_tmtc(&tmtc);
4014 tm = tmtcTm(&tmtc);
4015
4016 if (timestamp2tm(dt, NULL, &tt, &tmtcFsec(&tmtc), NULL, NULL) != 0)
4017 ereport(ERROR,
4018 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4019 errmsg("timestamp out of range")));
4020
4021 /* calculate wday and yday, because timestamp2tm doesn't */
4022 thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
4023 tt.tm_wday = (thisdate + 1) % 7;
4024 tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
4025
4026 COPY_tm(tm, &tt);
4027
4028 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
4030
4031 PG_RETURN_TEXT_P(res);
4032}
4033
4034Datum
4036{
4038 text *fmt = PG_GETARG_TEXT_PP(1),
4039 *res;
4040 TmToChar tmtc;
4041 int tz;
4042 struct pg_tm tt;
4043 struct fmt_tm *tm;
4044 int thisdate;
4045
4046 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
4048
4049 ZERO_tmtc(&tmtc);
4050 tm = tmtcTm(&tmtc);
4051
4052 if (timestamp2tm(dt, &tz, &tt, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
4053 ereport(ERROR,
4054 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4055 errmsg("timestamp out of range")));
4056
4057 /* calculate wday and yday, because timestamp2tm doesn't */
4058 thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
4059 tt.tm_wday = (thisdate + 1) % 7;
4060 tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
4061
4062 COPY_tm(tm, &tt);
4063
4064 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
4066
4067 PG_RETURN_TEXT_P(res);
4068}
4069
4070
4071/* -------------------
4072 * INTERVAL to_char()
4073 * -------------------
4074 */
4075Datum
4077{
4079 text *fmt = PG_GETARG_TEXT_PP(1),
4080 *res;
4081 TmToChar tmtc;
4082 struct fmt_tm *tm;
4083 struct pg_itm tt,
4084 *itm = &tt;
4085
4086 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || INTERVAL_NOT_FINITE(it))
4088
4089 ZERO_tmtc(&tmtc);
4090 tm = tmtcTm(&tmtc);
4091
4092 interval2itm(*it, itm);
4093 tmtc.fsec = itm->tm_usec;
4094 tm->tm_sec = itm->tm_sec;
4095 tm->tm_min = itm->tm_min;
4096 tm->tm_hour = itm->tm_hour;
4097 tm->tm_mday = itm->tm_mday;
4098 tm->tm_mon = itm->tm_mon;
4099 tm->tm_year = itm->tm_year;
4100
4101 /* wday is meaningless, yday approximates the total span in days */
4103
4104 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4106
4107 PG_RETURN_TEXT_P(res);
4108}
4109
4110/* ---------------------
4111 * TO_TIMESTAMP()
4112 *
4113 * Make Timestamp from date_str which is formatted at argument 'fmt'
4114 * ( to_timestamp is reverse to_char() )
4115 * ---------------------
4116 */
4117Datum
4119{
4120 text *date_txt = PG_GETARG_TEXT_PP(0);
4121 text *fmt = PG_GETARG_TEXT_PP(1);
4123 Timestamp result;
4124 int tz;
4125 struct pg_tm tm;
4126 struct fmt_tz ftz;
4127 fsec_t fsec;
4128 int fprec;
4129
4130 do_to_timestamp(date_txt, fmt, collid, false,
4131 &tm, &fsec, &ftz, &fprec, NULL, NULL);
4132
4133 /* Use the specified time zone, if any. */
4134 if (ftz.has_tz)
4135 tz = ftz.gmtoffset;
4136 else
4138
4139 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
4140 ereport(ERROR,
4141 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4142 errmsg("timestamp out of range")));
4143
4144 /* Use the specified fractional precision, if any. */
4145 if (fprec)
4146 AdjustTimestampForTypmod(&result, fprec, NULL);
4147
4148 PG_RETURN_TIMESTAMP(result);
4149}
4150
4151/* ----------
4152 * TO_DATE
4153 * Make Date from date_str which is formatted at argument 'fmt'
4154 * ----------
4155 */
4156Datum
4158{
4159 text *date_txt = PG_GETARG_TEXT_PP(0);
4160 text *fmt = PG_GETARG_TEXT_PP(1);
4162 DateADT result;
4163 struct pg_tm tm;
4164 struct fmt_tz ftz;
4165 fsec_t fsec;
4166
4167 do_to_timestamp(date_txt, fmt, collid, false,
4168 &tm, &fsec, &ftz, NULL, NULL, NULL);
4169
4170 /* Prevent overflow in Julian-day routines */
4172 ereport(ERROR,
4173 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4174 errmsg("date out of range: \"%s\"",
4175 text_to_cstring(date_txt))));
4176
4178
4179 /* Now check for just-out-of-range dates */
4180 if (!IS_VALID_DATE(result))
4181 ereport(ERROR,
4182 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4183 errmsg("date out of range: \"%s\"",
4184 text_to_cstring(date_txt))));
4185
4186 PG_RETURN_DATEADT(result);
4187}
4188
4189/*
4190 * Convert the 'date_txt' input to a datetime type using argument 'fmt'
4191 * as a format string. The collation 'collid' may be used for case-folding
4192 * rules in some cases. 'strict' specifies standard parsing mode.
4193 *
4194 * The actual data type (returned in 'typid', 'typmod') is determined by
4195 * the presence of date/time/zone components in the format string.
4196 *
4197 * When a timezone component is present, the corresponding offset is
4198 * returned in '*tz'.
4199 *
4200 * If escontext points to an ErrorSaveContext, data errors will be reported
4201 * by filling that struct; the caller must test SOFT_ERROR_OCCURRED() to see
4202 * whether an error occurred. Otherwise, errors are thrown.
4203 */
4204Datum
4205parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict,
4206 Oid *typid, int32 *typmod, int *tz,
4207 Node *escontext)
4208{
4209 struct pg_tm tm;
4210 struct fmt_tz ftz;
4211 fsec_t fsec;
4212 int fprec;
4213 uint32 flags;
4214
4215 if (!do_to_timestamp(date_txt, fmt, collid, strict,
4216 &tm, &fsec, &ftz, &fprec, &flags, escontext))
4217 return (Datum) 0;
4218
4219 *typmod = fprec ? fprec : -1; /* fractional part precision */
4220
4221 if (flags & DCH_DATED)
4222 {
4223 if (flags & DCH_TIMED)
4224 {
4225 if (flags & DCH_ZONED)
4226 {
4227 TimestampTz result;
4228
4229 if (ftz.has_tz)
4230 {
4231 *tz = ftz.gmtoffset;
4232 }
4233 else
4234 {
4235 /*
4236 * Time zone is present in format string, but not in input
4237 * string. Assuming do_to_timestamp() triggers no error
4238 * this should be possible only in non-strict case.
4239 */
4240 Assert(!strict);
4241
4242 ereturn(escontext, (Datum) 0,
4243 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4244 errmsg("missing time zone in input string for type timestamptz")));
4245 }
4246
4247 if (tm2timestamp(&tm, fsec, tz, &result) != 0)
4248 ereturn(escontext, (Datum) 0,
4249 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4250 errmsg("timestamptz out of range")));
4251
4252 AdjustTimestampForTypmod(&result, *typmod, escontext);
4253
4254 *typid = TIMESTAMPTZOID;
4255 return TimestampTzGetDatum(result);
4256 }
4257 else
4258 {
4259 Timestamp result;
4260
4261 if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
4262 ereturn(escontext, (Datum) 0,
4263 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4264 errmsg("timestamp out of range")));
4265
4266 AdjustTimestampForTypmod(&result, *typmod, escontext);
4267
4268 *typid = TIMESTAMPOID;
4269 return TimestampGetDatum(result);
4270 }
4271 }
4272 else
4273 {
4274 if (flags & DCH_ZONED)
4275 {
4276 ereturn(escontext, (Datum) 0,
4277 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4278 errmsg("datetime format is zoned but not timed")));
4279 }
4280 else
4281 {
4282 DateADT result;
4283
4284 /* Prevent overflow in Julian-day routines */
4286 ereturn(escontext, (Datum) 0,
4287 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4288 errmsg("date out of range: \"%s\"",
4289 text_to_cstring(date_txt))));
4290
4291 result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) -
4293
4294 /* Now check for just-out-of-range dates */
4295 if (!IS_VALID_DATE(result))
4296 ereturn(escontext, (Datum) 0,
4297 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4298 errmsg("date out of range: \"%s\"",
4299 text_to_cstring(date_txt))));
4300
4301 *typid = DATEOID;
4302 return DateADTGetDatum(result);
4303 }
4304 }
4305 }
4306 else if (flags & DCH_TIMED)
4307 {
4308 if (flags & DCH_ZONED)
4309 {
4310 TimeTzADT *result = palloc(sizeof(TimeTzADT));
4311
4312 if (ftz.has_tz)
4313 {
4314 *tz = ftz.gmtoffset;
4315 }
4316 else
4317 {
4318 /*
4319 * Time zone is present in format string, but not in input
4320 * string. Assuming do_to_timestamp() triggers no error this
4321 * should be possible only in non-strict case.
4322 */
4323 Assert(!strict);
4324
4325 ereturn(escontext, (Datum) 0,
4326 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4327 errmsg("missing time zone in input string for type timetz")));
4328 }
4329
4330 if (tm2timetz(&tm, fsec, *tz, result) != 0)
4331 ereturn(escontext, (Datum) 0,
4332 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4333 errmsg("timetz out of range")));
4334
4335 AdjustTimeForTypmod(&result->time, *typmod);
4336
4337 *typid = TIMETZOID;
4338 return TimeTzADTPGetDatum(result);
4339 }
4340 else
4341 {
4342 TimeADT result;
4343
4344 if (tm2time(&tm, fsec, &result) != 0)
4345 ereturn(escontext, (Datum) 0,
4346 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4347 errmsg("time out of range")));
4348
4349 AdjustTimeForTypmod(&result, *typmod);
4350
4351 *typid = TIMEOID;
4352 return TimeADTGetDatum(result);
4353 }
4354 }
4355 else
4356 {
4357 ereturn(escontext, (Datum) 0,
4358 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4359 errmsg("datetime format is not dated and not timed")));
4360 }
4361}
4362
4363/*
4364 * Parses the datetime format string in 'fmt_str' and returns true if it
4365 * contains a timezone specifier, false if not.
4366 */
4367bool
4368datetime_format_has_tz(const char *fmt_str)
4369{
4370 bool incache;
4371 int fmt_len = strlen(fmt_str);
4372 int result;
4374
4375 if (fmt_len > DCH_CACHE_SIZE)
4376 {
4377 /*
4378 * Allocate new memory if format picture is bigger than static cache
4379 * and do not use cache (call parser always)
4380 */
4381 incache = false;
4382
4383 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4384
4386 DCH_suff, DCH_index, DCH_FLAG, NULL);
4387 }
4388 else
4389 {
4390 /*
4391 * Use cache buffers
4392 */
4393 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4394
4395 incache = true;
4396 format = ent->format;
4397 }
4398
4399 result = DCH_datetime_type(format);
4400
4401 if (!incache)
4402 pfree(format);
4403
4404 return result & DCH_ZONED;
4405}
4406
4407/*
4408 * do_to_timestamp: shared code for to_timestamp and to_date
4409 *
4410 * Parse the 'date_txt' according to 'fmt', return results as a struct pg_tm,
4411 * fractional seconds, struct fmt_tz, and fractional precision.
4412 *
4413 * 'collid' identifies the collation to use, if needed.
4414 * 'std' specifies standard parsing mode.
4415 *
4416 * Bit mask of date/time/zone components found in 'fmt' is returned in 'flags',
4417 * if that is not NULL.
4418 *
4419 * Returns true on success, false on failure (if escontext points to an
4420 * ErrorSaveContext; otherwise errors are thrown). Note that currently,
4421 * soft-error behavior is provided for bad data but not bad format.
4422 *
4423 * We parse 'fmt' into a list of FormatNodes, which is then passed to
4424 * DCH_from_char to populate a TmFromChar with the parsed contents of
4425 * 'date_txt'.
4426 *
4427 * The TmFromChar is then analysed and converted into the final results in
4428 * struct 'tm', 'fsec', struct 'tz', and 'fprec'.
4429 */
4430static bool
4431do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std,
4432 struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz,
4433 int *fprec, uint32 *flags, Node *escontext)
4434{
4435 FormatNode *format = NULL;
4436 TmFromChar tmfc;
4437 int fmt_len;
4438 char *date_str;
4439 int fmask;
4440 bool incache = false;
4441
4442 Assert(tm != NULL);
4443 Assert(fsec != NULL);
4444
4445 date_str = text_to_cstring(date_txt);
4446
4447 ZERO_tmfc(&tmfc);
4448 ZERO_tm(tm);
4449 *fsec = 0;
4450 tz->has_tz = false;
4451 if (fprec)
4452 *fprec = 0;
4453 if (flags)
4454 *flags = 0;
4455 fmask = 0; /* bit mask for ValidateDate() */
4456
4457 fmt_len = VARSIZE_ANY_EXHDR(fmt);
4458
4459 if (fmt_len)
4460 {
4461 char *fmt_str;
4462
4463 fmt_str = text_to_cstring(fmt);
4464
4465 if (fmt_len > DCH_CACHE_SIZE)
4466 {
4467 /*
4468 * Allocate new memory if format picture is bigger than static
4469 * cache and do not use cache (call parser always)
4470 */
4471 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4472
4474 DCH_FLAG | (std ? STD_FLAG : 0), NULL);
4475 }
4476 else
4477 {
4478 /*
4479 * Use cache buffers
4480 */
4481 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, std);
4482
4483 incache = true;
4484 format = ent->format;
4485 }
4486
4487#ifdef DEBUG_TO_FROM_CHAR
4488 /* dump_node(format, fmt_len); */
4489 /* dump_index(DCH_keywords, DCH_index); */
4490#endif
4491
4492 DCH_from_char(format, date_str, &tmfc, collid, std, escontext);
4493 pfree(fmt_str);
4494 if (SOFT_ERROR_OCCURRED(escontext))
4495 goto fail;
4496
4497 if (flags)
4498 *flags = DCH_datetime_type(format);
4499
4500 if (!incache)
4501 {
4502 pfree(format);
4503 format = NULL;
4504 }
4505 }
4506
4507 DEBUG_TMFC(&tmfc);
4508
4509 /*
4510 * Convert to_date/to_timestamp input fields to standard 'tm'
4511 */
4512 if (tmfc.ssss)
4513 {
4514 int x = tmfc.ssss;
4515
4517 x %= SECS_PER_HOUR;
4519 x %= SECS_PER_MINUTE;
4520 tm->tm_sec = x;
4521 }
4522
4523 if (tmfc.ss)
4524 tm->tm_sec = tmfc.ss;
4525 if (tmfc.mi)
4526 tm->tm_min = tmfc.mi;
4527 if (tmfc.hh)
4528 tm->tm_hour = tmfc.hh;
4529
4530 if (tmfc.clock == CLOCK_12_HOUR)
4531 {
4532 if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
4533 {
4534 errsave(escontext,
4535 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4536 errmsg("hour \"%d\" is invalid for the 12-hour clock",
4537 tm->tm_hour),
4538 errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
4539 goto fail;
4540 }
4541
4542 if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
4543 tm->tm_hour += HOURS_PER_DAY / 2;
4544 else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
4545 tm->tm_hour = 0;
4546 }
4547
4548 if (tmfc.year)
4549 {
4550 /*
4551 * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
4552 * the year in the given century. Keep in mind that the 21st century
4553 * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
4554 * 600BC to 501BC.
4555 */
4556 if (tmfc.cc && tmfc.yysz <= 2)
4557 {
4558 if (tmfc.bc)
4559 tmfc.cc = -tmfc.cc;
4560 tm->tm_year = tmfc.year % 100;
4561 if (tm->tm_year)
4562 {
4563 int tmp;
4564
4565 if (tmfc.cc >= 0)
4566 {
4567 /* tm->tm_year += (tmfc.cc - 1) * 100; */
4568 tmp = tmfc.cc - 1;
4569 if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
4571 {
4573 text_to_cstring(date_txt), "timestamp",
4574 escontext);
4575 goto fail;
4576 }
4577 }
4578 else
4579 {
4580 /* tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1; */
4581 tmp = tmfc.cc + 1;
4582 if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
4583 pg_sub_s32_overflow(tmp, tm->tm_year, &tmp) ||
4584 pg_add_s32_overflow(tmp, 1, &tm->tm_year))
4585 {
4587 text_to_cstring(date_txt), "timestamp",
4588 escontext);
4589 goto fail;
4590 }
4591 }
4592 }
4593 else
4594 {
4595 /* find century year for dates ending in "00" */
4596 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
4597 }
4598 }
4599 else
4600 {
4601 /* If a 4-digit year is provided, we use that and ignore CC. */
4602 tm->tm_year = tmfc.year;
4603 if (tmfc.bc)
4604 tm->tm_year = -tm->tm_year;
4605 /* correct for our representation of BC years */
4606 if (tm->tm_year < 0)
4607 tm->tm_year++;
4608 }
4609 fmask |= DTK_M(YEAR);
4610 }
4611 else if (tmfc.cc)
4612 {
4613 /* use first year of century */
4614 if (tmfc.bc)
4615 tmfc.cc = -tmfc.cc;
4616 if (tmfc.cc >= 0)
4617 {
4618 /* +1 because 21st century started in 2001 */
4619 /* tm->tm_year = (tmfc.cc - 1) * 100 + 1; */
4620 if (pg_mul_s32_overflow(tmfc.cc - 1, 100, &tm->tm_year) ||
4622 {
4624 text_to_cstring(date_txt), "timestamp",
4625 escontext);
4626 goto fail;
4627 }
4628 }
4629 else
4630 {
4631 /* +1 because year == 599 is 600 BC */
4632 /* tm->tm_year = tmfc.cc * 100 + 1; */
4633 if (pg_mul_s32_overflow(tmfc.cc, 100, &tm->tm_year) ||
4635 {
4637 text_to_cstring(date_txt), "timestamp",
4638 escontext);
4639 goto fail;
4640 }
4641 }
4642 fmask |= DTK_M(YEAR);
4643 }
4644
4645 if (tmfc.j)
4646 {
4647 j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4648 fmask |= DTK_DATE_M;
4649 }
4650
4651 if (tmfc.ww)
4652 {
4653 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4654 {
4655 /*
4656 * If tmfc.d is not set, then the date is left at the beginning of
4657 * the ISO week (Monday).
4658 */
4659 if (tmfc.d)
4660 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4661 else
4662 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4663 fmask |= DTK_DATE_M;
4664 }
4665 else
4666 {
4667 /* tmfc.ddd = (tmfc.ww - 1) * 7 + 1; */
4668 if (pg_sub_s32_overflow(tmfc.ww, 1, &tmfc.ddd) ||
4669 pg_mul_s32_overflow(tmfc.ddd, 7, &tmfc.ddd) ||
4670 pg_add_s32_overflow(tmfc.ddd, 1, &tmfc.ddd))
4671 {
4673 date_str, "timestamp", escontext);
4674 goto fail;
4675 }
4676 }
4677 }
4678
4679 if (tmfc.w)
4680 {
4681 /* tmfc.dd = (tmfc.w - 1) * 7 + 1; */
4682 if (pg_sub_s32_overflow(tmfc.w, 1, &tmfc.dd) ||
4683 pg_mul_s32_overflow(tmfc.dd, 7, &tmfc.dd) ||
4684 pg_add_s32_overflow(tmfc.dd, 1, &tmfc.dd))
4685 {
4687 date_str, "timestamp", escontext);
4688 goto fail;
4689 }
4690 }
4691 if (tmfc.dd)
4692 {
4693 tm->tm_mday = tmfc.dd;
4694 fmask |= DTK_M(DAY);
4695 }
4696 if (tmfc.mm)
4697 {
4698 tm->tm_mon = tmfc.mm;
4699 fmask |= DTK_M(MONTH);
4700 }
4701
4702 if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
4703 {
4704 /*
4705 * The month and day field have not been set, so we use the
4706 * day-of-year field to populate them. Depending on the date mode,
4707 * this field may be interpreted as a Gregorian day-of-year, or an ISO
4708 * week date day-of-year.
4709 */
4710
4711 if (!tm->tm_year && !tmfc.bc)
4712 {
4713 errsave(escontext,
4714 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4715 errmsg("cannot calculate day of year without year information")));
4716 goto fail;
4717 }
4718
4719 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4720 {
4721 int j0; /* zeroth day of the ISO year, in Julian */
4722
4723 j0 = isoweek2j(tm->tm_year, 1) - 1;
4724
4725 j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4726 fmask |= DTK_DATE_M;
4727 }
4728 else
4729 {
4730 const int *y;
4731 int i;
4732
4733 static const int ysum[2][13] = {
4734 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
4735 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
4736
4737 y = ysum[isleap(tm->tm_year)];
4738
4739 for (i = 1; i <= MONTHS_PER_YEAR; i++)
4740 {
4741 if (tmfc.ddd <= y[i])
4742 break;
4743 }
4744 if (tm->tm_mon <= 1)
4745 tm->tm_mon = i;
4746
4747 if (tm->tm_mday <= 1)
4748 tm->tm_mday = tmfc.ddd - y[i - 1];
4749
4750 fmask |= DTK_M(MONTH) | DTK_M(DAY);
4751 }
4752 }
4753
4754 if (tmfc.ms)
4755 {
4756 int tmp = 0;
4757
4758 /* *fsec += tmfc.ms * 1000; */
4759 if (pg_mul_s32_overflow(tmfc.ms, 1000, &tmp) ||
4760 pg_add_s32_overflow(*fsec, tmp, fsec))
4761 {
4763 date_str, "timestamp", escontext);
4764 goto fail;
4765 }
4766 }
4767 if (tmfc.us)
4768 *fsec += tmfc.us;
4769 if (fprec)
4770 *fprec = tmfc.ff; /* fractional precision, if specified */
4771
4772 /* Range-check date fields according to bit mask computed above */
4773 if (fmask != 0)
4774 {
4775 /* We already dealt with AD/BC, so pass isjulian = true */
4776 int dterr = ValidateDate(fmask, true, false, false, tm);
4777
4778 if (dterr != 0)
4779 {
4780 /*
4781 * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
4782 * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
4783 * irrelevant hint about datestyle.
4784 */
4786 date_str, "timestamp", escontext);
4787 goto fail;
4788 }
4789 }
4790
4791 /* Range-check time fields too */
4792 if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY ||
4793 tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR ||
4794 tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
4795 *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
4796 {
4798 date_str, "timestamp", escontext);
4799 goto fail;
4800 }
4801
4802 /*
4803 * If timezone info was present, reduce it to a GMT offset. (We cannot do
4804 * this until we've filled all of the tm struct, since the zone's offset
4805 * might be time-varying.)
4806 */
4807 if (tmfc.tzsign)
4808 {
4809 /* TZH and/or TZM fields */
4810 if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
4811 tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
4812 {
4814 date_str, "timestamp", escontext);
4815 goto fail;
4816 }
4817
4818 tz->has_tz = true;
4819 tz->gmtoffset = (tmfc.tzh * MINS_PER_HOUR + tmfc.tzm) * SECS_PER_MINUTE;
4820 /* note we are flipping the sign convention here */
4821 if (tmfc.tzsign > 0)
4822 tz->gmtoffset = -tz->gmtoffset;
4823 }
4824 else if (tmfc.has_tz)
4825 {
4826 /* TZ field */
4827 tz->has_tz = true;
4828 if (tmfc.tzp == NULL)
4829 {
4830 /* fixed-offset abbreviation; flip the sign convention */
4831 tz->gmtoffset = -tmfc.gmtoffset;
4832 }
4833 else
4834 {
4835 /* dynamic-offset abbreviation, resolve using specified time */
4837 tmfc.tzp);
4838 }
4839 }
4840
4841 DEBUG_TM(tm);
4842
4843 if (format && !incache)
4844 pfree(format);
4845 pfree(date_str);
4846
4847 return true;
4848
4849fail:
4850 if (format && !incache)
4851 pfree(format);
4852 pfree(date_str);
4853
4854 return false;
4855}
4856
4857
4858/**********************************************************************
4859 * the NUMBER version part
4860 *********************************************************************/
4861
4862
4863static char *
4864fill_str(char *str, int c, int max)
4865{
4866 memset(str, c, max);
4867 *(str + max) = '\0';
4868 return str;
4869}
4870
4871#define zeroize_NUM(_n) \
4872do { \
4873 (_n)->flag = 0; \
4874 (_n)->lsign = 0; \
4875 (_n)->pre = 0; \
4876 (_n)->post = 0; \
4877 (_n)->pre_lsign_num = 0; \
4878 (_n)->need_locale = 0; \
4879 (_n)->multi = 0; \
4880 (_n)->zero_start = 0; \
4881 (_n)->zero_end = 0; \
4882} while(0)
4883
4884/* This works the same as DCH_prevent_counter_overflow */
4885static inline void
4887{
4888 if (NUMCounter >= (INT_MAX - 1))
4889 {
4890 for (int i = 0; i < n_NUMCache; i++)
4891 NUMCache[i]->age >>= 1;
4892 NUMCounter >>= 1;
4893 }
4894}
4895
4896/* select a NUMCacheEntry to hold the given format picture */
4897static NUMCacheEntry *
4899{
4900 NUMCacheEntry *ent;
4901
4902 /* Ensure we can advance NUMCounter below */
4904
4905 /*
4906 * If cache is full, remove oldest entry (or recycle first not-valid one)
4907 */
4909 {
4910 NUMCacheEntry *old = NUMCache[0];
4911
4912#ifdef DEBUG_TO_FROM_CHAR
4913 elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
4914#endif
4915 if (old->valid)
4916 {
4917 for (int i = 1; i < NUM_CACHE_ENTRIES; i++)
4918 {
4919 ent = NUMCache[i];
4920 if (!ent->valid)
4921 {
4922 old = ent;
4923 break;
4924 }
4925 if (ent->age < old->age)
4926 old = ent;
4927 }
4928 }
4929#ifdef DEBUG_TO_FROM_CHAR
4930 elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
4931#endif
4932 old->valid = false;
4933 strlcpy(old->str, str, NUM_CACHE_SIZE + 1);
4934 old->age = (++NUMCounter);
4935 /* caller is expected to fill format and Num, then set valid */
4936 return old;
4937 }
4938 else
4939 {
4940#ifdef DEBUG_TO_FROM_CHAR
4941 elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
4942#endif
4943 Assert(NUMCache[n_NUMCache] == NULL);
4944 NUMCache[n_NUMCache] = ent = (NUMCacheEntry *)
4946 ent->valid = false;
4947 strlcpy(ent->str, str, NUM_CACHE_SIZE + 1);
4948 ent->age = (++NUMCounter);
4949 /* caller is expected to fill format and Num, then set valid */
4950 ++n_NUMCache;
4951 return ent;
4952 }
4953}
4954
4955/* look for an existing NUMCacheEntry matching the given format picture */
4956static NUMCacheEntry *
4958{
4959 /* Ensure we can advance NUMCounter below */
4961
4962 for (int i = 0; i < n_NUMCache; i++)
4963 {
4964 NUMCacheEntry *ent = NUMCache[i];
4965
4966 if (ent->valid && strcmp(ent->str, str) == 0)
4967 {
4968 ent->age = (++NUMCounter);
4969 return ent;
4970 }
4971 }
4972
4973 return NULL;
4974}
4975
4976/* Find or create a NUMCacheEntry for the given format picture */
4977static NUMCacheEntry *
4979{
4980 NUMCacheEntry *ent;
4981
4982 if ((ent = NUM_cache_search(str)) == NULL)
4983 {
4984 /*
4985 * Not in the cache, must run parser and save a new format-picture to
4986 * the cache. Do not mark the cache entry valid until parsing
4987 * succeeds.
4988 */
4989 ent = NUM_cache_getnew(str);
4990
4991 zeroize_NUM(&ent->Num);
4992
4994 NULL, NUM_index, NUM_FLAG, &ent->Num);
4995
4996 ent->valid = true;
4997 }
4998 return ent;
4999}
5000
5001/* ----------
5002 * Cache routine for NUM to_char version
5003 * ----------
5004 */
5005static FormatNode *
5006NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
5007{
5008 FormatNode *format = NULL;
5009 char *str;
5010
5011 str = text_to_cstring(pars_str);
5012
5013 if (len > NUM_CACHE_SIZE)
5014 {
5015 /*
5016 * Allocate new memory if format picture is bigger than static cache
5017 * and do not use cache (call parser always)
5018 */
5019 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
5020
5021 *shouldFree = true;
5022
5023 zeroize_NUM(Num);
5024
5026 NULL, NUM_index, NUM_FLAG, Num);
5027 }
5028 else
5029 {
5030 /*
5031 * Use cache buffers
5032 */
5034
5035 *shouldFree = false;
5036
5037 format = ent->format;
5038
5039 /*
5040 * Copy cache to used struct
5041 */
5042 Num->flag = ent->Num.flag;
5043 Num->lsign = ent->Num.lsign;
5044 Num->pre = ent->Num.pre;
5045 Num->post = ent->Num.post;
5046 Num->pre_lsign_num = ent->Num.pre_lsign_num;
5047 Num->need_locale = ent->Num.need_locale;
5048 Num->multi = ent->Num.multi;
5049 Num->zero_start = ent->Num.zero_start;
5050 Num->zero_end = ent->Num.zero_end;
5051 }
5052
5053#ifdef DEBUG_TO_FROM_CHAR
5054 /* dump_node(format, len); */
5055 dump_index(NUM_keywords, NUM_index);
5056#endif
5057
5058 pfree(str);
5059 return format;
5060}
5061
5062
5063/*
5064 * Convert integer to Roman numerals
5065 * Result is upper-case and not blank-padded (NUM_processor converts as needed)
5066 * If input is out-of-range, produce '###############'
5067 */
5068static char *
5069int_to_roman(int number)
5070{
5071 int len,
5072 num;
5073 char *p,
5074 *result,
5075 numstr[12];
5076
5077 result = (char *) palloc(MAX_ROMAN_LEN + 1);
5078 *result = '\0';
5079
5080 /*
5081 * This range limit is the same as in Oracle(TM). The difficulty with
5082 * handling 4000 or more is that we'd need to use more than 3 "M"'s, and
5083 * more than 3 of the same digit isn't considered a valid Roman string.
5084 */
5085 if (number > 3999 || number < 1)
5086 {
5087 fill_str(result, '#', MAX_ROMAN_LEN);
5088 return result;
5089 }
5090
5091 /* Convert to decimal, then examine each digit */
5092 len = snprintf(numstr, sizeof(numstr), "%d", number);
5093 Assert(len > 0 && len <= 4);
5094
5095 for (p = numstr; *p != '\0'; p++, --len)
5096 {
5097 num = *p - ('0' + 1);
5098 if (num < 0)
5099 continue; /* ignore zeroes */
5100 /* switch on current column position */
5101 switch (len)
5102 {
5103 case 4:
5104 while (num-- >= 0)
5105 strcat(result, "M");
5106 break;
5107 case 3:
5108 strcat(result, rm100[num]);
5109 break;
5110 case 2:
5111 strcat(result, rm10[num]);
5112 break;
5113 case 1:
5114 strcat(result, rm1[num]);
5115 break;
5116 }
5117 }
5118 return result;
5119}
5120
5121/*
5122 * Convert a roman numeral (standard form) to an integer.
5123 * Result is an integer between 1 and 3999.
5124 * Np->inout_p is advanced past the characters consumed.
5125 *
5126 * If input is invalid, return -1.
5127 */
5128static int
5129roman_to_int(NUMProc *Np, int input_len)
5130{
5131 int result = 0;
5132 int len;
5133 char romanChars[MAX_ROMAN_LEN];
5134 int romanValues[MAX_ROMAN_LEN];
5135 int repeatCount = 1;
5136 int vCount = 0,
5137 lCount = 0,
5138 dCount = 0;
5139 bool subtractionEncountered = false;
5140 int lastSubtractedValue = 0;
5141
5142 /*
5143 * Skip any leading whitespace. Perhaps we should limit the amount of
5144 * space skipped to MAX_ROMAN_LEN, but that seems unnecessarily picky.
5145 */
5146 while (!OVERLOAD_TEST && isspace((unsigned char) *Np->inout_p))
5147 Np->inout_p++;
5148
5149 /*
5150 * Collect and decode valid roman numerals, consuming at most
5151 * MAX_ROMAN_LEN characters. We do this in a separate loop to avoid
5152 * repeated decoding and because the main loop needs to know when it's at
5153 * the last numeral.
5154 */
5155 for (len = 0; len < MAX_ROMAN_LEN && !OVERLOAD_TEST; len++)
5156 {
5157 char currChar = pg_ascii_toupper(*Np->inout_p);
5158 int currValue = ROMAN_VAL(currChar);
5159
5160 if (currValue == 0)
5161 break; /* Not a valid roman numeral. */
5162 romanChars[len] = currChar;
5163 romanValues[len] = currValue;
5164 Np->inout_p++;
5165 }
5166
5167 if (len == 0)
5168 return -1; /* No valid roman numerals. */
5169
5170 /* Check for valid combinations and compute the represented value. */
5171 for (int i = 0; i < len; i++)
5172 {
5173 char currChar = romanChars[i];
5174 int currValue = romanValues[i];
5175
5176 /*
5177 * Ensure no numeral greater than or equal to the subtracted numeral
5178 * appears after a subtraction.
5179 */
5180 if (subtractionEncountered && currValue >= lastSubtractedValue)
5181 return -1;
5182
5183 /*
5184 * V, L, and D should not appear before a larger numeral, nor should
5185 * they be repeated.
5186 */
5187 if ((vCount && currValue >= ROMAN_VAL('V')) ||
5188 (lCount && currValue >= ROMAN_VAL('L')) ||
5189 (dCount && currValue >= ROMAN_VAL('D')))
5190 return -1;
5191 if (currChar == 'V')
5192 vCount++;
5193 else if (currChar == 'L')
5194 lCount++;
5195 else if (currChar == 'D')
5196 dCount++;
5197
5198 if (i < len - 1)
5199 {
5200 /* Compare current numeral to next numeral. */
5201 char nextChar = romanChars[i + 1];
5202 int nextValue = romanValues[i + 1];
5203
5204 /*
5205 * If the current value is less than the next value, handle
5206 * subtraction. Verify valid subtractive combinations and update
5207 * the result accordingly.
5208 */
5209 if (currValue < nextValue)
5210 {
5211 if (!IS_VALID_SUB_COMB(currChar, nextChar))
5212 return -1;
5213
5214 /*
5215 * Reject cases where same numeral is repeated with
5216 * subtraction (e.g. 'MCCM' or 'DCCCD').
5217 */
5218 if (repeatCount > 1)
5219 return -1;
5220
5221 /*
5222 * We are going to skip nextChar, so first make checks needed
5223 * for V, L, and D. These are the same as we'd have applied
5224 * if we reached nextChar without a subtraction.
5225 */
5226 if ((vCount && nextValue >= ROMAN_VAL('V')) ||
5227 (lCount && nextValue >= ROMAN_VAL('L')) ||
5228 (dCount && nextValue >= ROMAN_VAL('D')))
5229 return -1;
5230 if (nextChar == 'V')
5231 vCount++;
5232 else if (nextChar == 'L')
5233 lCount++;
5234 else if (nextChar == 'D')
5235 dCount++;
5236
5237 /*
5238 * Skip the next numeral as it is part of the subtractive
5239 * combination.
5240 */
5241 i++;
5242
5243 /* Update state. */
5244 repeatCount = 1;
5245 subtractionEncountered = true;
5246 lastSubtractedValue = currValue;
5247 result += (nextValue - currValue);
5248 }
5249 else
5250 {
5251 /* For same numerals, check for repetition. */
5252 if (currChar == nextChar)
5253 {
5254 repeatCount++;
5255 if (repeatCount > 3)
5256 return -1;
5257 }
5258 else
5259 repeatCount = 1;
5260 result += currValue;
5261 }
5262 }
5263 else
5264 {
5265 /* This is the last numeral; just add it to the result. */
5266 result += currValue;
5267 }
5268 }
5269
5270 return result;
5271}
5272
5273
5274/* ----------
5275 * Locale
5276 * ----------
5277 */
5278static void
5280{
5281 if (Np->Num->need_locale)
5282 {
5283 struct lconv *lconv;
5284
5285 /*
5286 * Get locales
5287 */
5288 lconv = PGLC_localeconv();
5289
5290 /*
5291 * Positive / Negative number sign
5292 */
5293 if (lconv->negative_sign && *lconv->negative_sign)
5294 Np->L_negative_sign = lconv->negative_sign;
5295 else
5296 Np->L_negative_sign = "-";
5297
5298 if (lconv->positive_sign && *lconv->positive_sign)
5299 Np->L_positive_sign = lconv->positive_sign;
5300 else
5301 Np->L_positive_sign = "+";
5302
5303 /*
5304 * Number decimal point
5305 */
5306 if (lconv->decimal_point && *lconv->decimal_point)
5307 Np->decimal = lconv->decimal_point;
5308
5309 else
5310 Np->decimal = ".";
5311
5312 if (!IS_LDECIMAL(Np->Num))
5313 Np->decimal = ".";
5314
5315 /*
5316 * Number thousands separator
5317 *
5318 * Some locales (e.g. broken glibc pt_BR), have a comma for decimal,
5319 * but "" for thousands_sep, so we set the thousands_sep too.
5320 * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php
5321 */
5322 if (lconv->thousands_sep && *lconv->thousands_sep)
5323 Np->L_thousands_sep = lconv->thousands_sep;
5324 /* Make sure thousands separator doesn't match decimal point symbol. */
5325 else if (strcmp(Np->decimal, ",") != 0)
5326 Np->L_thousands_sep = ",";
5327 else
5328 Np->L_thousands_sep = ".";
5329
5330 /*
5331 * Currency symbol
5332 */
5333 if (lconv->currency_symbol && *lconv->currency_symbol)
5334 Np->L_currency_symbol = lconv->currency_symbol;
5335 else
5336 Np->L_currency_symbol = " ";
5337 }
5338 else
5339 {
5340 /*
5341 * Default values
5342 */
5343 Np->L_negative_sign = "-";
5344 Np->L_positive_sign = "+";
5345 Np->decimal = ".";
5346
5347 Np->L_thousands_sep = ",";
5348 Np->L_currency_symbol = " ";
5349 }
5350}
5351
5352/* ----------
5353 * Return pointer of last relevant number after decimal point
5354 * 12.0500 --> last relevant is '5'
5355 * 12.0000 --> last relevant is '.'
5356 * If there is no decimal point, return NULL (which will result in same
5357 * behavior as if FM hadn't been specified).
5358 * ----------
5359 */
5360static char *
5362{
5363 char *result,
5364 *p = strchr(num, '.');
5365
5366#ifdef DEBUG_TO_FROM_CHAR
5367 elog(DEBUG_elog_output, "get_last_relevant_decnum()");
5368#endif
5369
5370 if (!p)
5371 return NULL;
5372
5373 result = p;
5374
5375 while (*(++p))
5376 {
5377 if (*p != '0')
5378 result = p;
5379 }
5380
5381 return result;
5382}
5383
5384/* ----------
5385 * Number extraction for TO_NUMBER()
5386 * ----------
5387 */
5388static void
5389NUM_numpart_from_char(NUMProc *Np, int id, int input_len)
5390{
5391 bool isread = false;
5392
5393#ifdef DEBUG_TO_FROM_CHAR
5394 elog(DEBUG_elog_output, " --- scan start --- id=%s",
5395 (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
5396#endif
5397
5398 if (OVERLOAD_TEST)
5399 return;
5400
5401 if (*Np->inout_p == ' ')
5402 Np->inout_p++;
5403
5404 if (OVERLOAD_TEST)
5405 return;
5406
5407 /*
5408 * read sign before number
5409 */
5410 if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
5411 (Np->read_pre + Np->read_post) == 0)
5412 {
5413#ifdef DEBUG_TO_FROM_CHAR
5414 elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
5415 *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
5416#endif
5417
5418 /*
5419 * locale sign
5420 */
5421 if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
5422 {
5423 int x = 0;
5424
5425#ifdef DEBUG_TO_FROM_CHAR
5426 elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
5427#endif
5428 if ((x = strlen(Np->L_negative_sign)) &&
5429 AMOUNT_TEST(x) &&
5430 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
5431 {
5432 Np->inout_p += x;
5433 *Np->number = '-';
5434 }
5435 else if ((x = strlen(Np->L_positive_sign)) &&
5436 AMOUNT_TEST(x) &&
5437 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
5438 {
5439 Np->inout_p += x;
5440 *Np->number = '+';
5441 }
5442 }
5443 else
5444 {
5445#ifdef DEBUG_TO_FROM_CHAR
5446 elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
5447#endif
5448
5449 /*
5450 * simple + - < >
5451 */
5452 if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
5453 *Np->inout_p == '<'))
5454 {
5455 *Np->number = '-'; /* set - */
5456 Np->inout_p++;
5457 }
5458 else if (*Np->inout_p == '+')
5459 {
5460 *Np->number = '+'; /* set + */
5461 Np->inout_p++;
5462 }
5463 }
5464 }
5465
5466 if (OVERLOAD_TEST)
5467 return;
5468
5469#ifdef DEBUG_TO_FROM_CHAR
5470 elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
5471#endif
5472
5473 /*
5474 * read digit or decimal point
5475 */
5476 if (isdigit((unsigned char) *Np->inout_p))
5477 {
5478 if (Np->read_dec && Np->read_post == Np->Num->post)
5479 return;
5480
5481 *Np->number_p = *Np->inout_p;
5482 Np->number_p++;
5483
5484 if (Np->read_dec)
5485 Np->read_post++;
5486 else
5487 Np->read_pre++;
5488
5489 isread = true;
5490
5491#ifdef DEBUG_TO_FROM_CHAR
5492 elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
5493#endif
5494 }
5495 else if (IS_DECIMAL(Np->Num) && Np->read_dec == false)
5496 {
5497 /*
5498 * We need not test IS_LDECIMAL(Np->Num) explicitly here, because
5499 * Np->decimal is always just "." if we don't have a D format token.
5500 * So we just unconditionally match to Np->decimal.
5501 */
5502 int x = strlen(Np->decimal);
5503
5504#ifdef DEBUG_TO_FROM_CHAR
5505 elog(DEBUG_elog_output, "Try read decimal point (%c)",
5506 *Np->inout_p);
5507#endif
5508 if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
5509 {
5510 Np->inout_p += x - 1;
5511 *Np->number_p = '.';
5512 Np->number_p++;
5513 Np->read_dec = true;
5514 isread = true;
5515 }
5516 }
5517
5518 if (OVERLOAD_TEST)
5519 return;
5520
5521 /*
5522 * Read sign behind "last" number
5523 *
5524 * We need sign detection because determine exact position of post-sign is
5525 * difficult:
5526 *
5527 * FM9999.9999999S -> 123.001- 9.9S -> .5- FM9.999999MI ->
5528 * 5.01-
5529 */
5530 if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
5531 {
5532 /*
5533 * locale sign (NUM_S) is always anchored behind a last number, if: -
5534 * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
5535 * next char is not digit
5536 */
5537 if (IS_LSIGN(Np->Num) && isread &&
5538 (Np->inout_p + 1) < Np->inout + input_len &&
5539 !isdigit((unsigned char) *(Np->inout_p + 1)))
5540 {
5541 int x;
5542 char *tmp = Np->inout_p++;
5543
5544#ifdef DEBUG_TO_FROM_CHAR
5545 elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
5546#endif
5547 if ((x = strlen(Np->L_negative_sign)) &&
5548 AMOUNT_TEST(x) &&
5549 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
5550 {
5551 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
5552 *Np->number = '-';
5553 }
5554 else if ((x = strlen(Np->L_positive_sign)) &&
5555 AMOUNT_TEST(x) &&
5556 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
5557 {
5558 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
5559 *Np->number = '+';
5560 }
5561 if (*Np->number == ' ')
5562 /* no sign read */
5563 Np->inout_p = tmp;
5564 }
5565
5566 /*
5567 * try read non-locale sign, which happens only if format is not exact
5568 * and we cannot determine sign position of MI/PL/SG, an example:
5569 *
5570 * FM9.999999MI -> 5.01-
5571 *
5572 * if (.... && IS_LSIGN(Np->Num)==false) prevents read wrong formats
5573 * like to_number('1 -', '9S') where sign is not anchored to last
5574 * number.
5575 */
5576 else if (isread == false && IS_LSIGN(Np->Num) == false &&
5577 (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
5578 {
5579#ifdef DEBUG_TO_FROM_CHAR
5580 elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
5581#endif
5582
5583 /*
5584 * simple + -
5585 */
5586 if (*Np->inout_p == '-' || *Np->inout_p == '+')
5587 /* NUM_processor() do inout_p++ */
5588 *Np->number = *Np->inout_p;
5589 }
5590 }
5591}
5592
5593#define IS_PREDEC_SPACE(_n) \
5594 (IS_ZERO((_n)->Num)==false && \
5595 (_n)->number == (_n)->number_p && \
5596 *(_n)->number == '0' && \
5597 (_n)->Num->post != 0)
5598
5599/* ----------
5600 * Add digit or sign to number-string
5601 * ----------
5602 */
5603static void
5605{
5606 int end;
5607
5608 if (IS_ROMAN(Np->Num))
5609 return;
5610
5611 /* Note: in this elog() output not set '\0' in 'inout' */
5612
5613#ifdef DEBUG_TO_FROM_CHAR
5614
5615 /*
5616 * Np->num_curr is number of current item in format-picture, it is not
5617 * current position in inout!
5618 */
5619 elog(DEBUG_elog_output,
5620 "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
5621 Np->sign_wrote,
5622 Np->num_curr,
5623 Np->number_p,
5624 Np->inout);
5625#endif
5626 Np->num_in = false;
5627
5628 /*
5629 * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
5630 * handle "9.9" --> " .1"
5631 */
5632 if (Np->sign_wrote == false &&
5633 (Np->num_curr >= Np->out_pre_spaces || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
5634 (IS_PREDEC_SPACE(Np) == false || (Np->last_relevant && *Np->last_relevant == '.')))
5635 {
5636 if (IS_LSIGN(Np->Num))
5637 {
5638 if (Np->Num->lsign == NUM_LSIGN_PRE)
5639 {
5640 if (Np->sign == '-')
5641 strcpy(Np->inout_p, Np->L_negative_sign);
5642 else
5643 strcpy(Np->inout_p, Np->L_positive_sign);
5644 Np->inout_p += strlen(Np->inout_p);
5645 Np->sign_wrote = true;
5646 }
5647 }
5648 else if (IS_BRACKET(Np->Num))
5649 {
5650 *Np->inout_p = Np->sign == '+' ? ' ' : '<';
5651 ++Np->inout_p;
5652 Np->sign_wrote = true;
5653 }
5654 else if (Np->sign == '+')
5655 {
5656 if (!IS_FILLMODE(Np->Num))
5657 {
5658 *Np->inout_p = ' '; /* Write + */
5659 ++Np->inout_p;
5660 }
5661 Np->sign_wrote = true;
5662 }
5663 else if (Np->sign == '-')
5664 { /* Write - */
5665 *Np->inout_p = '-';
5666 ++Np->inout_p;
5667 Np->sign_wrote = true;
5668 }
5669 }
5670
5671
5672 /*
5673 * digits / FM / Zero / Dec. point
5674 */
5675 if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
5676 {
5677 if (Np->num_curr < Np->out_pre_spaces &&
5678 (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
5679 {
5680 /*
5681 * Write blank space
5682 */
5683 if (!IS_FILLMODE(Np->Num))
5684 {
5685 *Np->inout_p = ' '; /* Write ' ' */
5686 ++Np->inout_p;
5687 }
5688 }
5689 else if (IS_ZERO(Np->Num) &&
5690 Np->num_curr < Np->out_pre_spaces &&
5691 Np->Num->zero_start <= Np->num_curr)
5692 {
5693 /*
5694 * Write ZERO
5695 */
5696 *Np->inout_p = '0'; /* Write '0' */
5697 ++Np->inout_p;
5698 Np->num_in = true;
5699 }
5700 else
5701 {
5702 /*
5703 * Write Decimal point
5704 */
5705 if (*Np->number_p == '.')
5706 {
5707 if (!Np->last_relevant || *Np->last_relevant != '.')
5708 {
5709 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
5710 Np->inout_p += strlen(Np->inout_p);
5711 }
5712
5713 /*
5714 * Ora 'n' -- FM9.9 --> 'n.'
5715 */
5716 else if (IS_FILLMODE(Np->Num) &&
5717 Np->last_relevant && *Np->last_relevant == '.')
5718 {
5719 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
5720 Np->inout_p += strlen(Np->inout_p);
5721 }
5722 }
5723 else
5724 {
5725 /*
5726 * Write Digits
5727 */
5728 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
5729 id != NUM_0)
5730 ;
5731
5732 /*
5733 * '0.1' -- 9.9 --> ' .1'
5734 */
5735 else if (IS_PREDEC_SPACE(Np))
5736 {
5737 if (!IS_FILLMODE(Np->Num))
5738 {
5739 *Np->inout_p = ' ';
5740 ++Np->inout_p;
5741 }
5742
5743 /*
5744 * '0' -- FM9.9 --> '0.'
5745 */
5746 else if (Np->last_relevant && *Np->last_relevant == '.')
5747 {
5748 *Np->inout_p = '0';
5749 ++Np->inout_p;
5750 }
5751 }
5752 else
5753 {
5754 *Np->inout_p = *Np->number_p; /* Write DIGIT */
5755 ++Np->inout_p;
5756 Np->num_in = true;
5757 }
5758 }
5759 /* do no exceed string length */
5760 if (*Np->number_p)
5761 ++Np->number_p;
5762 }
5763
5764 end = Np->num_count + (Np->out_pre_spaces ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
5765
5766 if (Np->last_relevant && Np->last_relevant == Np->number_p)
5767 end = Np->num_curr;
5768
5769 if (Np->num_curr + 1 == end)
5770 {
5771 if (Np->sign_wrote == true && IS_BRACKET(Np->Num))
5772 {
5773 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
5774 ++Np->inout_p;
5775 }
5776 else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
5777 {
5778 if (Np->sign == '-')
5779 strcpy(Np->inout_p, Np->L_negative_sign);
5780 else
5781 strcpy(Np->inout_p, Np->L_positive_sign);
5782 Np->inout_p += strlen(Np->inout_p);
5783 }
5784 }
5785 }
5786
5787 ++Np->num_curr;
5788}
5789
5790/*
5791 * Skip over "n" input characters, but only if they aren't numeric data
5792 */
5793static void
5794NUM_eat_non_data_chars(NUMProc *Np, int n, int input_len)
5795{
5796 while (n-- > 0)
5797 {
5798 if (OVERLOAD_TEST)
5799 break; /* end of input */
5800 if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
5801 break; /* it's a data character */
5802 Np->inout_p += pg_mblen(Np->inout_p);
5803 }
5804}
5805
5806static char *
5807NUM_processor(FormatNode *node, NUMDesc *Num, char *inout,
5808 char *number, int input_len, int to_char_out_pre_spaces,
5809 int sign, bool is_to_char, Oid collid)
5810{
5811 FormatNode *n;
5812 NUMProc _Np,
5813 *Np = &_Np;
5814 const char *pattern;
5815 int pattern_len;
5816
5817 MemSet(Np, 0, sizeof(NUMProc));
5818
5819 Np->Num = Num;
5820 Np->is_to_char = is_to_char;
5821 Np->number = number;
5822 Np->inout = inout;
5823 Np->last_relevant = NULL;
5824 Np->read_post = 0;
5825 Np->read_pre = 0;
5826 Np->read_dec = false;
5827
5828 if (Np->Num->zero_start)
5829 --Np->Num->zero_start;
5830
5831 if (IS_EEEE(Np->Num))
5832 {
5833 if (!Np->is_to_char)
5834 ereport(ERROR,
5835 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5836 errmsg("\"EEEE\" not supported for input")));
5837 return strcpy(inout, number);
5838 }
5839
5840 /*
5841 * Sign
5842 */
5843 if (is_to_char)
5844 {
5845 Np->sign = sign;
5846
5847 /* MI/PL/SG - write sign itself and not in number */
5848 if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
5849 {
5850 if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == false)
5851 Np->sign_wrote = false; /* need sign */
5852 else
5853 Np->sign_wrote = true; /* needn't sign */
5854 }
5855 else
5856 {
5857 if (Np->sign != '-')
5858 {
5859 if (IS_FILLMODE(Np->Num))
5860 Np->Num->flag &= ~NUM_F_BRACKET;
5861 }
5862
5863 if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == false)
5864 Np->sign_wrote = true; /* needn't sign */
5865 else
5866 Np->sign_wrote = false; /* need sign */
5867
5868 if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
5869 Np->Num->lsign = NUM_LSIGN_POST;
5870 }
5871 }
5872 else
5873 Np->sign = false;
5874
5875 /*
5876 * Count
5877 */
5878 Np->num_count = Np->Num->post + Np->Num->pre - 1;
5879
5880 if (is_to_char)
5881 {
5882 Np->out_pre_spaces = to_char_out_pre_spaces;
5883
5884 if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
5885 {
5887
5888 /*
5889 * If any '0' specifiers are present, make sure we don't strip
5890 * those digits. But don't advance last_relevant beyond the last
5891 * character of the Np->number string, which is a hazard if the
5892 * number got shortened due to precision limitations.
5893 */
5894 if (Np->last_relevant && Np->Num->zero_end > Np->out_pre_spaces)
5895 {
5896 int last_zero_pos;
5897 char *last_zero;
5898
5899 /* note that Np->number cannot be zero-length here */
5900 last_zero_pos = strlen(Np->number) - 1;
5901 last_zero_pos = Min(last_zero_pos,
5902 Np->Num->zero_end - Np->out_pre_spaces);
5903 last_zero = Np->number + last_zero_pos;
5904 if (Np->last_relevant < last_zero)
5905 Np->last_relevant = last_zero;
5906 }
5907 }
5908
5909 if (Np->sign_wrote == false && Np->out_pre_spaces == 0)
5910 ++Np->num_count;
5911 }
5912 else
5913 {
5914 Np->out_pre_spaces = 0;
5915 *Np->number = ' '; /* sign space */
5916 *(Np->number + 1) = '\0';
5917 }
5918
5919 Np->num_in = 0;
5920 Np->num_curr = 0;
5921
5922#ifdef DEBUG_TO_FROM_CHAR
5923 elog(DEBUG_elog_output,
5924 "\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",
5925 Np->sign,
5926 Np->number,
5927 Np->Num->pre,
5928 Np->Num->post,
5929 Np->num_count,
5930 Np->out_pre_spaces,
5931 Np->sign_wrote ? "Yes" : "No",
5932 IS_ZERO(Np->Num) ? "Yes" : "No",
5933 Np->Num->zero_start,
5934 Np->Num->zero_end,
5935 Np->last_relevant ? Np->last_relevant : "<not set>",
5936 IS_BRACKET(Np->Num) ? "Yes" : "No",
5937 IS_PLUS(Np->Num) ? "Yes" : "No",
5938 IS_MINUS(Np->Num) ? "Yes" : "No",
5939 IS_FILLMODE(Np->Num) ? "Yes" : "No",
5940 IS_ROMAN(Np->Num) ? "Yes" : "No",
5941 IS_EEEE(Np->Num) ? "Yes" : "No"
5942 );
5943#endif
5944
5945 /*
5946 * Locale
5947 */
5949
5950 /*
5951 * Processor direct cycle
5952 */
5953 if (Np->is_to_char)
5954 Np->number_p = Np->number;
5955 else
5956 Np->number_p = Np->number + 1; /* first char is space for sign */
5957
5958 for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
5959 {
5960 if (!Np->is_to_char)
5961 {
5962 /*
5963 * Check at least one byte remains to be scanned. (In actions
5964 * below, must use AMOUNT_TEST if we want to read more bytes than
5965 * that.)
5966 */
5967 if (OVERLOAD_TEST)
5968 break;
5969 }
5970
5971 /*
5972 * Format pictures actions
5973 */
5974 if (n->type == NODE_TYPE_ACTION)
5975 {
5976 /*
5977 * Create/read digit/zero/blank/sign/special-case
5978 *
5979 * 'NUM_S' note: The locale sign is anchored to number and we
5980 * read/write it when we work with first or last number
5981 * (NUM_0/NUM_9). This is why NUM_S is missing in switch().
5982 *
5983 * Notice the "Np->inout_p++" at the bottom of the loop. This is
5984 * why most of the actions advance inout_p one less than you might
5985 * expect. In cases where we don't want that increment to happen,
5986 * a switch case ends with "continue" not "break".
5987 */
5988 switch (n->key->id)
5989 {
5990 case NUM_9:
5991 case NUM_0:
5992 case NUM_DEC:
5993 case NUM_D:
5994 if (Np->is_to_char)
5995 {
5996 NUM_numpart_to_char(Np, n->key->id);
5997 continue; /* for() */
5998 }
5999 else
6000 {
6001 NUM_numpart_from_char(Np, n->key->id, input_len);
6002 break; /* switch() case: */
6003 }
6004
6005 case NUM_COMMA:
6006 if (Np->is_to_char)
6007 {
6008 if (!Np->num_in)
6009 {
6010 if (IS_FILLMODE(Np->Num))
6011 continue;
6012 else
6013 *Np->inout_p = ' ';
6014 }
6015 else
6016 *Np->inout_p = ',';
6017 }
6018 else
6019 {
6020 if (!Np->num_in)
6021 {
6022 if (IS_FILLMODE(Np->Num))
6023 continue;
6024 }
6025 if (*Np->inout_p != ',')
6026 continue;
6027 }
6028 break;
6029
6030 case NUM_G:
6031 pattern = Np->L_thousands_sep;
6032 pattern_len = strlen(pattern);
6033 if (Np->is_to_char)
6034 {
6035 if (!Np->num_in)
6036 {
6037 if (IS_FILLMODE(Np->Num))
6038 continue;
6039 else
6040 {
6041 /* just in case there are MB chars */
6042 pattern_len = pg_mbstrlen(pattern);
6043 memset(Np->inout_p, ' ', pattern_len);
6044 Np->inout_p += pattern_len - 1;
6045 }
6046 }
6047 else
6048 {
6049 strcpy(Np->inout_p, pattern);
6050 Np->inout_p += pattern_len - 1;
6051 }
6052 }
6053 else
6054 {
6055 if (!Np->num_in)
6056 {
6057 if (IS_FILLMODE(Np->Num))
6058 continue;
6059 }
6060
6061 /*
6062 * Because L_thousands_sep typically contains data
6063 * characters (either '.' or ','), we can't use
6064 * NUM_eat_non_data_chars here. Instead skip only if
6065 * the input matches L_thousands_sep.
6066 */
6067 if (AMOUNT_TEST(pattern_len) &&
6068 strncmp(Np->inout_p, pattern, pattern_len) == 0)
6069 Np->inout_p += pattern_len - 1;
6070 else
6071 continue;
6072 }
6073 break;
6074
6075 case NUM_L:
6076 pattern = Np->L_currency_symbol;
6077 if (Np->is_to_char)
6078 {
6079 strcpy(Np->inout_p, pattern);
6080 Np->inout_p += strlen(pattern) - 1;
6081 }
6082 else
6083 {
6084 NUM_eat_non_data_chars(Np, pg_mbstrlen(pattern), input_len);
6085 continue;
6086 }
6087 break;
6088
6089 case NUM_RN:
6090 case NUM_rn:
6091 if (Np->is_to_char)
6092 {
6093 const char *number_p;
6094
6095 if (n->key->id == NUM_rn)
6096 number_p = asc_tolower_z(Np->number_p);
6097 else
6098 number_p = Np->number_p;
6099 if (IS_FILLMODE(Np->Num))
6100 strcpy(Np->inout_p, number_p);
6101 else
6102 sprintf(Np->inout_p, "%15s", number_p);
6103 Np->inout_p += strlen(Np->inout_p) - 1;
6104 }
6105 else
6106 {
6107 int roman_result = roman_to_int(Np, input_len);
6108 int numlen;
6109
6110 if (roman_result < 0)
6111 ereport(ERROR,
6112 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
6113 errmsg("invalid Roman numeral")));
6114 numlen = sprintf(Np->number_p, "%d", roman_result);
6115 Np->number_p += numlen;
6116 Np->Num->pre = numlen;
6117 Np->Num->post = 0;
6118 continue; /* roman_to_int ate all the chars */
6119 }
6120 break;
6121
6122 case NUM_th:
6123 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
6124 Np->sign == '-' || IS_DECIMAL(Np->Num))
6125 continue;
6126
6127 if (Np->is_to_char)
6128 {
6129 strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
6130 Np->inout_p += 1;
6131 }
6132 else
6133 {
6134 /* All variants of 'th' occupy 2 characters */
6135 NUM_eat_non_data_chars(Np, 2, input_len);
6136 continue;
6137 }
6138 break;
6139
6140 case NUM_TH:
6141 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
6142 Np->sign == '-' || IS_DECIMAL(Np->Num))
6143 continue;
6144
6145 if (Np->is_to_char)
6146 {
6147 strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
6148 Np->inout_p += 1;
6149 }
6150 else
6151 {
6152 /* All variants of 'TH' occupy 2 characters */
6153 NUM_eat_non_data_chars(Np, 2, input_len);
6154 continue;
6155 }
6156 break;
6157
6158 case NUM_MI:
6159 if (Np->is_to_char)
6160 {
6161 if (Np->sign == '-')
6162 *Np->inout_p = '-';
6163 else if (IS_FILLMODE(Np->Num))
6164 continue;
6165 else
6166 *Np->inout_p = ' ';
6167 }
6168 else
6169 {
6170 if (*Np->inout_p == '-')
6171 *Np->number = '-';
6172 else
6173 {
6174 NUM_eat_non_data_chars(Np, 1, input_len);
6175 continue;
6176 }
6177 }
6178 break;
6179
6180 case NUM_PL:
6181 if (Np->is_to_char)
6182 {
6183 if (Np->sign == '+')
6184 *Np->inout_p = '+';
6185 else if (IS_FILLMODE(Np->Num))
6186 continue;
6187 else
6188 *Np->inout_p = ' ';
6189 }
6190 else
6191 {
6192 if (*Np->inout_p == '+')
6193 *Np->number = '+';
6194 else
6195 {
6196 NUM_eat_non_data_chars(Np, 1, input_len);
6197 continue;
6198 }
6199 }
6200 break;
6201
6202 case NUM_SG:
6203 if (Np->is_to_char)
6204 *Np->inout_p = Np->sign;
6205 else
6206 {
6207 if (*Np->inout_p == '-')
6208 *Np->number = '-';
6209 else if (*Np->inout_p == '+')
6210 *Np->number = '+';
6211 else
6212 {
6213 NUM_eat_non_data_chars(Np, 1, input_len);
6214 continue;
6215 }
6216 }
6217 break;
6218
6219 default:
6220 continue;
6221 break;
6222 }
6223 }
6224 else
6225 {
6226 /*
6227 * In TO_CHAR, non-pattern characters in the format are copied to
6228 * the output. In TO_NUMBER, we skip one input character for each
6229 * non-pattern format character, whether or not it matches the
6230 * format character.
6231 */
6232 if (Np->is_to_char)
6233 {
6234 strcpy(Np->inout_p, n->character);
6235 Np->inout_p += strlen(Np->inout_p);
6236 }
6237 else
6238 {
6239 Np->inout_p += pg_mblen(Np->inout_p);
6240 }
6241 continue;
6242 }
6243 Np->inout_p++;
6244 }
6245
6246 if (Np->is_to_char)
6247 {
6248 *Np->inout_p = '\0';
6249 return Np->inout;
6250 }
6251 else
6252 {
6253 if (*(Np->number_p - 1) == '.')
6254 *(Np->number_p - 1) = '\0';
6255 else
6256 *Np->number_p = '\0';
6257
6258 /*
6259 * Correction - precision of dec. number
6260 */
6261 Np->Num->post = Np->read_post;
6262
6263#ifdef DEBUG_TO_FROM_CHAR
6264 elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
6265#endif
6266 return Np->number;
6267 }
6268}
6269
6270/* ----------
6271 * MACRO: Start part of NUM - for all NUM's to_char variants
6272 * (sorry, but I hate copy same code - macro is better..)
6273 * ----------
6274 */
6275#define NUM_TOCHAR_prepare \
6276do { \
6277 int len = VARSIZE_ANY_EXHDR(fmt); \
6278 if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
6279 PG_RETURN_TEXT_P(cstring_to_text("")); \
6280 result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
6281 format = NUM_cache(len, &Num, fmt, &shouldFree); \
6282} while (0)
6283
6284/* ----------
6285 * MACRO: Finish part of NUM
6286 * ----------
6287 */
6288#define NUM_TOCHAR_finish \
6289do { \
6290 int len; \
6291 \
6292 NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \
6293 \
6294 if (shouldFree) \
6295 pfree(format); \
6296 \
6297 /* \
6298 * Convert null-terminated representation of result to standard text. \
6299 * The result is usually much bigger than it needs to be, but there \
6300 * seems little point in realloc'ing it smaller. \
6301 */ \
6302 len = strlen(VARDATA(result)); \
6303 SET_VARSIZE(result, len + VARHDRSZ); \
6304} while (0)
6305
6306/* -------------------
6307 * NUMERIC to_number() (convert string to numeric)
6308 * -------------------
6309 */
6310Datum
6312{
6314 text *fmt = PG_GETARG_TEXT_PP(1);
6315 NUMDesc Num;
6316 Datum result;
6318 char *numstr;
6319 bool shouldFree;
6320 int len = 0;
6321 int scale,
6322 precision;
6323
6324 len = VARSIZE_ANY_EXHDR(fmt);
6325
6326 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
6328
6329 format = NUM_cache(len, &Num, fmt, &shouldFree);
6330
6331 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
6332
6333 NUM_processor(format, &Num, VARDATA_ANY(value), numstr,
6334 VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
6335
6336 scale = Num.post;
6337 precision = Num.pre + Num.multi + scale;
6338
6339 if (shouldFree)
6340 pfree(format);
6341
6343 CStringGetDatum(numstr),
6345 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
6346
6347 if (IS_MULTI(&Num))
6348 {
6349 Numeric x;
6352
6355 NumericGetDatum(b)));
6357 result,
6359 }
6360
6361 pfree(numstr);
6362 return result;
6363}
6364
6365/* ------------------
6366 * NUMERIC to_char()
6367 * ------------------
6368 */
6369Datum
6371{
6373 text *fmt = PG_GETARG_TEXT_PP(1);
6374 NUMDesc Num;
6376 text *result;
6377 bool shouldFree;
6378 int out_pre_spaces = 0,
6379 sign = 0;
6380 char *numstr,
6381 *orgnum,
6382 *p;
6383
6385
6386 /*
6387 * On DateType depend part (numeric)
6388 */
6389 if (IS_ROMAN(&Num))
6390 {
6391 int32 intvalue;
6392 ErrorSaveContext escontext = {T_ErrorSaveContext};
6393
6394 /* Round and convert to int */
6395 intvalue = numeric_int4_safe(value, (Node *) &escontext);
6396 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6397 if (escontext.error_occurred)
6398 intvalue = PG_INT32_MAX;
6399 numstr = int_to_roman(intvalue);
6400 }
6401 else if (IS_EEEE(&Num))
6402 {
6403 orgnum = numeric_out_sci(value, Num.post);
6404
6405 /*
6406 * numeric_out_sci() does not emit a sign for positive numbers. We
6407 * need to add a space in this case so that positive and negative
6408 * numbers are aligned. Also must check for NaN/infinity cases, which
6409 * we handle the same way as in float8_to_char.
6410 */
6411 if (strcmp(orgnum, "NaN") == 0 ||
6412 strcmp(orgnum, "Infinity") == 0 ||
6413 strcmp(orgnum, "-Infinity") == 0)
6414 {
6415 /*
6416 * Allow 6 characters for the leading sign, the decimal point,
6417 * "e", the exponent's sign and two exponent digits.
6418 */
6419 numstr = (char *) palloc(Num.pre + Num.post + 7);
6420 fill_str(numstr, '#', Num.pre + Num.post + 6);
6421 *numstr = ' ';
6422 *(numstr + Num.pre + 1) = '.';
6423 }
6424 else if (*orgnum != '-')
6425 {
6426 numstr = (char *) palloc(strlen(orgnum) + 2);
6427 *numstr = ' ';
6428 strcpy(numstr + 1, orgnum);
6429 }
6430 else
6431 {
6432 numstr = orgnum;
6433 }
6434 }
6435 else
6436 {
6437 int numstr_pre_len;
6438 Numeric val = value;
6439 Numeric x;
6440
6441 if (IS_MULTI(&Num))
6442 {
6445
6448 NumericGetDatum(b)));
6451 NumericGetDatum(x)));
6452 Num.pre += Num.multi;
6453 }
6454
6457 Int32GetDatum(Num.post)));
6459 NumericGetDatum(x)));
6460
6461 if (*orgnum == '-')
6462 {
6463 sign = '-';
6464 numstr = orgnum + 1;
6465 }
6466 else
6467 {
6468 sign = '+';
6469 numstr = orgnum;
6470 }
6471
6472 if ((p = strchr(numstr, '.')))
6473 numstr_pre_len = p - numstr;
6474 else
6475 numstr_pre_len = strlen(numstr);
6476
6477 /* needs padding? */
6478 if (numstr_pre_len < Num.pre)
6479 out_pre_spaces = Num.pre - numstr_pre_len;
6480 /* overflowed prefix digit format? */
6481 else if (numstr_pre_len > Num.pre)
6482 {
6483 numstr = (char *) palloc(Num.pre + Num.post + 2);
6484 fill_str(numstr, '#', Num.pre + Num.post + 1);
6485 *(numstr + Num.pre) = '.';
6486 }
6487 }
6488
6490 PG_RETURN_TEXT_P(result);
6491}
6492
6493/* ---------------
6494 * INT4 to_char()
6495 * ---------------
6496 */
6497Datum
6499{
6501 text *fmt = PG_GETARG_TEXT_PP(1);
6502 NUMDesc Num;
6504 text *result;
6505 bool shouldFree;
6506 int out_pre_spaces = 0,
6507 sign = 0;
6508 char *numstr,
6509 *orgnum;
6510
6512
6513 /*
6514 * On DateType depend part (int32)
6515 */
6516 if (IS_ROMAN(&Num))
6517 numstr = int_to_roman(value);
6518 else if (IS_EEEE(&Num))
6519 {
6520 /* we can do it easily because float8 won't lose any precision */
6521 float8 val = (float8) value;
6522
6523 orgnum = (char *) psprintf("%+.*e", Num.post, val);
6524
6525 /*
6526 * Swap a leading positive sign for a space.
6527 */
6528 if (*orgnum == '+')
6529 *orgnum = ' ';
6530
6531 numstr = orgnum;
6532 }
6533 else
6534 {
6535 int numstr_pre_len;
6536
6537 if (IS_MULTI(&Num))
6538 {
6540 Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
6541 Num.pre += Num.multi;
6542 }
6543 else
6544 {
6547 }
6548
6549 if (*orgnum == '-')
6550 {
6551 sign = '-';
6552 orgnum++;
6553 }
6554 else
6555 sign = '+';
6556
6557 numstr_pre_len = strlen(orgnum);
6558
6559 /* post-decimal digits? Pad out with zeros. */
6560 if (Num.post)
6561 {
6562 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6563 strcpy(numstr, orgnum);
6564 *(numstr + numstr_pre_len) = '.';
6565 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6566 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6567 }
6568 else
6569 numstr = orgnum;
6570
6571 /* needs padding? */
6572 if (numstr_pre_len < Num.pre)
6573 out_pre_spaces = Num.pre - numstr_pre_len;
6574 /* overflowed prefix digit format? */
6575 else if (numstr_pre_len > Num.pre)
6576 {
6577 numstr = (char *) palloc(Num.pre + Num.post + 2);
6578 fill_str(numstr, '#', Num.pre + Num.post + 1);
6579 *(numstr + Num.pre) = '.';
6580 }
6581 }
6582
6584 PG_RETURN_TEXT_P(result);
6585}
6586
6587/* ---------------
6588 * INT8 to_char()
6589 * ---------------
6590 */
6591Datum
6593{
6595 text *fmt = PG_GETARG_TEXT_PP(1);
6596 NUMDesc Num;
6598 text *result;
6599 bool shouldFree;
6600 int out_pre_spaces = 0,
6601 sign = 0;
6602 char *numstr,
6603 *orgnum;
6604
6606
6607 /*
6608 * On DateType depend part (int64)
6609 */
6610 if (IS_ROMAN(&Num))
6611 {
6612 int32 intvalue;
6613
6614 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6615 if (value <= PG_INT32_MAX && value >= PG_INT32_MIN)
6616 intvalue = (int32) value;
6617 else
6618 intvalue = PG_INT32_MAX;
6619 numstr = int_to_roman(intvalue);
6620 }
6621 else if (IS_EEEE(&Num))
6622 {
6623 /* to avoid loss of precision, must go via numeric not float8 */
6625 Num.post);
6626
6627 /*
6628 * numeric_out_sci() does not emit a sign for positive numbers. We
6629 * need to add a space in this case so that positive and negative
6630 * numbers are aligned. We don't have to worry about NaN/inf here.
6631 */
6632 if (*orgnum != '-')
6633 {
6634 numstr = (char *) palloc(strlen(orgnum) + 2);
6635 *numstr = ' ';
6636 strcpy(numstr + 1, orgnum);
6637 }
6638 else
6639 {
6640 numstr = orgnum;
6641 }
6642 }
6643 else
6644 {
6645 int numstr_pre_len;
6646
6647 if (IS_MULTI(&Num))
6648 {
6649 double multi = pow((double) 10, (double) Num.multi);
6650
6654 Float8GetDatum(multi))));
6655 Num.pre += Num.multi;
6656 }
6657
6660
6661 if (*orgnum == '-')
6662 {
6663 sign = '-';
6664 orgnum++;
6665 }
6666 else
6667 sign = '+';
6668
6669 numstr_pre_len = strlen(orgnum);
6670
6671 /* post-decimal digits? Pad out with zeros. */
6672 if (Num.post)
6673 {
6674 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6675 strcpy(numstr, orgnum);
6676 *(numstr + numstr_pre_len) = '.';
6677 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6678 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6679 }
6680 else
6681 numstr = orgnum;
6682
6683 /* needs padding? */
6684 if (numstr_pre_len < Num.pre)
6685 out_pre_spaces = Num.pre - numstr_pre_len;
6686 /* overflowed prefix digit format? */
6687 else if (numstr_pre_len > Num.pre)
6688 {
6689 numstr = (char *) palloc(Num.pre + Num.post + 2);
6690 fill_str(numstr, '#', Num.pre + Num.post + 1);
6691 *(numstr + Num.pre) = '.';
6692 }
6693 }
6694
6696 PG_RETURN_TEXT_P(result);
6697}
6698
6699/* -----------------
6700 * FLOAT4 to_char()
6701 * -----------------
6702 */
6703Datum
6705{
6707 text *fmt = PG_GETARG_TEXT_PP(1);
6708 NUMDesc Num;
6710 text *result;
6711 bool shouldFree;
6712 int out_pre_spaces = 0,
6713 sign = 0;
6714 char *numstr,
6715 *p;
6716
6718
6719 if (IS_ROMAN(&Num))
6720 {
6721 int32 intvalue;
6722
6723 /* See notes in ftoi4() */
6724 value = rint(value);
6725 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6726 if (!isnan(value) && FLOAT4_FITS_IN_INT32(value))
6727 intvalue = (int32) value;
6728 else
6729 intvalue = PG_INT32_MAX;
6730 numstr = int_to_roman(intvalue);
6731 }
6732 else if (IS_EEEE(&Num))
6733 {
6734 if (isnan(value) || isinf(value))
6735 {
6736 /*
6737 * Allow 6 characters for the leading sign, the decimal point,
6738 * "e", the exponent's sign and two exponent digits.
6739 */
6740 numstr = (char *) palloc(Num.pre + Num.post + 7);
6741 fill_str(numstr, '#', Num.pre + Num.post + 6);
6742 *numstr = ' ';
6743 *(numstr + Num.pre + 1) = '.';
6744 }
6745 else
6746 {
6747 numstr = psprintf("%+.*e", Num.post, value);
6748
6749 /*
6750 * Swap a leading positive sign for a space.
6751 */
6752 if (*numstr == '+')
6753 *numstr = ' ';
6754 }
6755 }
6756 else
6757 {
6758 float4 val = value;
6759 char *orgnum;
6760 int numstr_pre_len;
6761
6762 if (IS_MULTI(&Num))
6763 {
6764 float multi = pow((double) 10, (double) Num.multi);
6765
6766 val = value * multi;
6767 Num.pre += Num.multi;
6768 }
6769
6770 orgnum = psprintf("%.0f", fabs(val));
6771 numstr_pre_len = strlen(orgnum);
6772
6773 /* adjust post digits to fit max float digits */
6774 if (numstr_pre_len >= FLT_DIG)
6775 Num.post = 0;
6776 else if (numstr_pre_len + Num.post > FLT_DIG)
6777 Num.post = FLT_DIG - numstr_pre_len;
6778 orgnum = psprintf("%.*f", Num.post, val);
6779
6780 if (*orgnum == '-')
6781 { /* < 0 */
6782 sign = '-';
6783 numstr = orgnum + 1;
6784 }
6785 else
6786 {
6787 sign = '+';
6788 numstr = orgnum;
6789 }
6790
6791 if ((p = strchr(numstr, '.')))
6792 numstr_pre_len = p - numstr;
6793 else
6794 numstr_pre_len = strlen(numstr);
6795
6796 /* needs padding? */
6797 if (numstr_pre_len < Num.pre)
6798 out_pre_spaces = Num.pre - numstr_pre_len;
6799 /* overflowed prefix digit format? */
6800 else if (numstr_pre_len > Num.pre)
6801 {
6802 numstr = (char *) palloc(Num.pre + Num.post + 2);
6803 fill_str(numstr, '#', Num.pre + Num.post + 1);
6804 *(numstr + Num.pre) = '.';
6805 }
6806 }
6807
6809 PG_RETURN_TEXT_P(result);
6810}
6811
6812/* -----------------
6813 * FLOAT8 to_char()
6814 * -----------------
6815 */
6816Datum
6818{
6820 text *fmt = PG_GETARG_TEXT_PP(1);
6821 NUMDesc Num;
6823 text *result;
6824 bool shouldFree;
6825 int out_pre_spaces = 0,
6826 sign = 0;
6827 char *numstr,
6828 *p;
6829
6831
6832 if (IS_ROMAN(&Num))
6833 {
6834 int32 intvalue;
6835
6836 /* See notes in dtoi4() */
6837 value = rint(value);
6838 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6839 if (!isnan(value) && FLOAT8_FITS_IN_INT32(value))
6840 intvalue = (int32) value;
6841 else
6842 intvalue = PG_INT32_MAX;
6843 numstr = int_to_roman(intvalue);
6844 }
6845 else if (IS_EEEE(&Num))
6846 {
6847 if (isnan(value) || isinf(value))
6848 {
6849 /*
6850 * Allow 6 characters for the leading sign, the decimal point,
6851 * "e", the exponent's sign and two exponent digits.
6852 */
6853 numstr = (char *) palloc(Num.pre + Num.post + 7);
6854 fill_str(numstr, '#', Num.pre + Num.post + 6);
6855 *numstr = ' ';
6856 *(numstr + Num.pre + 1) = '.';
6857 }
6858 else
6859 {
6860 numstr = psprintf("%+.*e", Num.post, value);
6861
6862 /*
6863 * Swap a leading positive sign for a space.
6864 */
6865 if (*numstr == '+')
6866 *numstr = ' ';
6867 }
6868 }
6869 else
6870 {
6871 float8 val = value;
6872 char *orgnum;
6873 int numstr_pre_len;
6874
6875 if (IS_MULTI(&Num))
6876 {
6877 double multi = pow((double) 10, (double) Num.multi);
6878
6879 val = value * multi;
6880 Num.pre += Num.multi;
6881 }
6882
6883 orgnum = psprintf("%.0f", fabs(val));
6884 numstr_pre_len = strlen(orgnum);
6885
6886 /* adjust post digits to fit max double digits */
6887 if (numstr_pre_len >= DBL_DIG)
6888 Num.post = 0;
6889 else if (numstr_pre_len + Num.post > DBL_DIG)
6890 Num.post = DBL_DIG - numstr_pre_len;
6891 orgnum = psprintf("%.*f", Num.post, val);
6892
6893 if (*orgnum == '-')
6894 { /* < 0 */
6895 sign = '-';
6896 numstr = orgnum + 1;
6897 }
6898 else
6899 {
6900 sign = '+';
6901 numstr = orgnum;
6902 }
6903
6904 if ((p = strchr(numstr, '.')))
6905 numstr_pre_len = p - numstr;
6906 else
6907 numstr_pre_len = strlen(numstr);
6908
6909 /* needs padding? */
6910 if (numstr_pre_len < Num.pre)
6911 out_pre_spaces = Num.pre - numstr_pre_len;
6912 /* overflowed prefix digit format? */
6913 else if (numstr_pre_len > Num.pre)
6914 {
6915 numstr = (char *) palloc(Num.pre + Num.post + 2);
6916 fill_str(numstr, '#', Num.pre + Num.post + 1);
6917 *(numstr + Num.pre) = '.';
6918 }
6919 }
6920
6922 PG_RETURN_TEXT_P(result);
6923}
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1604
void DateTimeParseError(int dterr, DateTimeErrorExtra *extra, const char *str, const char *datatype, Node *escontext)
Definition: datetime.c:4214
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2561
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:3371
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1765
char * numeric_out_sci(Numeric num, int scale)
Definition: numeric.c:975
Datum numeric_round(PG_FUNCTION_ARGS)
Definition: numeric.c:1526
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4260
int32 numeric_int4_safe(Numeric num, Node *escontext)
Definition: numeric.c:4365
Datum numeric_power(PG_FUNCTION_ARGS)
Definition: numeric.c:3912
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:799
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:626
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3016
void isoweek2date(int woy, int *year, int *mon, int *mday)
Definition: timestamp.c:5261
int isoweek2j(int year, int week)
Definition: timestamp.c:5241
int date2isoweek(int year, int mon, int mday)
Definition: timestamp.c:5292
bool AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
Definition: timestamp.c:368
int date2isoyearday(int year, int mon, int mday)
Definition: timestamp.c:5404
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:2006
void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
Definition: timestamp.c:5274
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1910
void interval2itm(Interval span, struct pg_itm *itm)
Definition: timestamp.c:2047
int date2isoyear(int year, int mon, int mday)
Definition: timestamp.c:5347
#define FLOAT4_FITS_IN_INT32(num)
Definition: c.h:1084
#define INT64CONST(x)
Definition: c.h:553
#define FLOAT8_FITS_IN_INT32(num)
Definition: c.h:1090
#define PG_INT32_MAX
Definition: c.h:595
#define Min(x, y)
Definition: c.h:1004
uint8_t uint8
Definition: c.h:537
#define VARHDRSZ
Definition: c.h:698
int64_t int64
Definition: c.h:536
double float8
Definition: c.h:636
int32_t int32
Definition: c.h:535
uint32_t uint32
Definition: c.h:539
float float4
Definition: c.h:635
#define PG_INT32_MIN
Definition: c.h:594
#define MemSet(start, val, len)
Definition: c.h:1020
#define OidIsValid(objectId)
Definition: c.h:775
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:1563
int tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
Definition: date.c:2410
void AdjustTimeForTypmod(TimeADT *time, int32 typmod)
Definition: date.c:1792
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:1207
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ereturn(context, dummy_value,...)
Definition: elog.h:278
#define errsave(context,...)
Definition: elog.h:262
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:684
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#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:686
#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:3154
#define ad_STR
Definition: formatting.c:199
#define NUM_F_MINUS
Definition: formatting.c:334
#define NUM_TOCHAR_prepare
Definition: formatting.c:6275
Datum to_timestamp(PG_FUNCTION_ARGS)
Definition: formatting.c:4118
#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:2063
#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:4864
#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:5807
#define SKIP_THth(ptr, _suf)
Definition: formatting.c:2015
#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:1767
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:4431
static bool from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode, Node *escontext)
Definition: formatting.c:2142
static const KeyWord NUM_keywords[]
Definition: formatting.c:926
static char * str_numth(char *dest, char *num, int type)
Definition: formatting.c:1610
#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:2461
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:3712
static void NUM_numpart_to_char(NUMProc *Np, int id)
Definition: formatting.c:5604
static int seq_search_localized(const char *name, char **array, int *len, Oid collid)
Definition: formatting.c:2377
static void NUM_numpart_from_char(NUMProc *Np, int id, int input_len)
Definition: formatting.c:5389
static NUMCacheEntry * NUM_cache_getnew(const char *str)
Definition: formatting.c:4898
#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:4368
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:4978
#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:6700
#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:2205
static char * str_tolower_z(const char *buff, Oid collid)
Definition: formatting.c:1977
#define NUM_TOCHAR_finish
Definition: formatting.c:6288
#define IS_MINUS(_f)
Definition: formatting.c:356
static char * asc_toupper_z(const char *buff)
Definition: formatting.c:2001
static DCHCacheEntry * DCH_cache_getnew(const char *str, bool std)
Definition: formatting.c:3823
#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:1946
#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:1923
#define NUM_F_MULTI
Definition: formatting.c:337
static int adjust_partial_year_to_2020(int year)
Definition: formatting.c:2096
static char * get_last_relevant_decnum(char *num)
Definition: formatting.c:5361
#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:4157
static char * str_toupper_z(const char *buff, Oid collid)
Definition: formatting.c:1983
static const char *const numth[]
Definition: formatting.c:297
char * str_casefold(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1831
Datum timestamp_to_char(PG_FUNCTION_ARGS)
Definition: formatting.c:4000
#define IS_ROMAN(_f)
Definition: formatting.c:359
#define zeroize_NUM(_n)
Definition: formatting.c:4871
static int roman_to_int(NUMProc *Np, int input_len)
Definition: formatting.c:5129
static void NUM_prevent_counter_overflow(void)
Definition: formatting.c:4886
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:2320
Datum float8_to_char(PG_FUNCTION_ARGS)
Definition: formatting.c:6813
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:1900
Datum parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, Node *escontext)
Definition: formatting.c:4205
#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:6366
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:6494
static const char *const days_short[]
Definition: formatting.c:183
static void NUM_prepare_locale(NUMProc *Np)
Definition: formatting.c:5279
static int DCH_datetime_type(FormatNode *node)
Definition: formatting.c:3726
#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:1989
#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:5794
static NUMCacheEntry * NUM_cache_search(const char *str)
Definition: formatting.c:4957
Datum timestamptz_to_char(PG_FUNCTION_ARGS)
Definition: formatting.c:4035
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:1703
#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:3883
#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:2507
#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:2169
#define ZERO_tmtc(_X)
Definition: formatting.c:540
static int strspace_len(const char *str)
Definition: formatting.c:2120
#define p_m_STR
Definition: formatting.c:229
Datum numeric_to_number(PG_FUNCTION_ARGS)
Definition: formatting.c:6307
#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:5593
Datum int8_to_char(PG_FUNCTION_ARGS)
Definition: formatting.c:6588
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:5006
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:1995
#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:5069
static int from_char_parse_int(int *dest, const char **src, FormatNode *node, Node *escontext)
Definition: formatting.c:2302
static text * datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
Definition: formatting.c:3931
#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:3904
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:1639
static const char *const ampm_strings_long[]
Definition: formatting.c:244
Datum interval_to_char(PG_FUNCTION_ARGS)
Definition: formatting.c:4076
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 @166 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:1250
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:76
int b
Definition: isn.c:74
int x
Definition: isn.c:75
int init
Definition: isn.c:79
int a
Definition: isn.c:73
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
static struct pg_tm tm
Definition: localtime.c:104
int GetDatabaseEncoding(void)
Definition: mbutils.c:1262
int pg_mbstrlen(const char *mbstr)
Definition: mbutils.c:1038
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1024
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1263
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1610
void pfree(void *pointer)
Definition: mcxt.c:1594
MemoryContext TopMemoryContext
Definition: mcxt.c:166
void * palloc(Size size)
Definition: mcxt.c:1365
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1770
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:53
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:64
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:81
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:76
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:695
char * localized_full_months[12+1]
Definition: pg_locale.c:100
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1166
size_t pg_strfold(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1255
size_t pg_strlower(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1234
struct lconv * PGLC_localeconv(void)
Definition: pg_locale.c:499
size_t pg_strtitle(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1241
char * localized_abbrev_months[12+1]
Definition: pg_locale.c:99
char * localized_full_days[7+1]
Definition: pg_locale.c:98
size_t pg_strupper(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1248
char * localized_abbrev_days[7+1]
Definition: pg_locale.c:97
#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 Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:393
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
static char * DatumGetCString(Datum X)
Definition: postgres.h:345
uint64_t Datum
Definition: postgres.h:70
static Datum Float8GetDatum(float8 X)
Definition: postgres.h:492
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222
#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
bool error_occurred
Definition: miscnodes.h:47
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:135
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:693
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
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486
text * cstring_to_text(const char *s)
Definition: varlena.c:181
char * text_to_cstring(const text *t)
Definition: varlena.c:214
const char * type
const char * name