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