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