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