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