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