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