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