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