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