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