Coverage Report

Created: 2026-11-12 07:20

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