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