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