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