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