Coverage Report

Created: 2025-07-03 06:49

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