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