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