00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 #ifdef DEBUG_TO_FROM_CHAR
00063 #define DEBUG_elog_output DEBUG3
00064 #endif
00065
00066 #include "postgres.h"
00067
00068 #include <ctype.h>
00069 #include <unistd.h>
00070 #include <math.h>
00071 #include <float.h>
00072 #include <limits.h>
00073
00074
00075
00076
00077
00078 #ifdef HAVE_WCHAR_H
00079 #include <wchar.h>
00080 #endif
00081 #ifdef HAVE_WCTYPE_H
00082 #include <wctype.h>
00083 #endif
00084
00085 #include "catalog/pg_collation.h"
00086 #include "mb/pg_wchar.h"
00087 #include "utils/builtins.h"
00088 #include "utils/date.h"
00089 #include "utils/datetime.h"
00090 #include "utils/formatting.h"
00091 #include "utils/int8.h"
00092 #include "utils/numeric.h"
00093 #include "utils/pg_locale.h"
00094
00095
00096
00097
00098
00099 #define DCH_TYPE 1
00100 #define NUM_TYPE 2
00101
00102
00103
00104
00105
00106 #define KeyWord_INDEX_SIZE ('~' - ' ')
00107 #define KeyWord_INDEX_FILTER(_c) ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
00108
00109
00110
00111
00112
00113 #define DCH_MAX_ITEM_SIZ 9
00114 #define NUM_MAX_ITEM_SIZ 8
00115
00116
00117
00118
00119
00120 #define MAXFLOATWIDTH 60
00121 #define MAXDOUBLEWIDTH 500
00122
00123
00124
00125
00126
00127
00128 extern char *months[],
00129 *days[];
00130
00131
00132
00133
00134
00135 typedef struct
00136 {
00137 char *name;
00138 int len,
00139 id,
00140 type;
00141 } KeySuffix;
00142
00143
00144
00145
00146
00147
00148
00149
00150 typedef enum
00151 {
00152 FROM_CHAR_DATE_NONE = 0,
00153 FROM_CHAR_DATE_GREGORIAN,
00154 FROM_CHAR_DATE_ISOWEEK
00155 } FromCharDateMode;
00156
00157 typedef struct FormatNode FormatNode;
00158
00159 typedef struct
00160 {
00161 const char *name;
00162 int len;
00163 int id;
00164 bool is_digit;
00165 FromCharDateMode date_mode;
00166 } KeyWord;
00167
00168 struct FormatNode
00169 {
00170 int type;
00171 const KeyWord *key;
00172 char character;
00173 int suffix;
00174 };
00175
00176 #define NODE_TYPE_END 1
00177 #define NODE_TYPE_ACTION 2
00178 #define NODE_TYPE_CHAR 3
00179
00180 #define SUFFTYPE_PREFIX 1
00181 #define SUFFTYPE_POSTFIX 2
00182
00183 #define CLOCK_24_HOUR 0
00184 #define CLOCK_12_HOUR 1
00185
00186
00187
00188
00189
00190
00191 static char *months_full[] = {
00192 "January", "February", "March", "April", "May", "June", "July",
00193 "August", "September", "October", "November", "December", NULL
00194 };
00195
00196 static char *days_short[] = {
00197 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
00198 };
00199
00200
00201
00202
00203
00204
00205
00206
00207 #define ADJUST_YEAR(year, is_interval) ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
00208
00209 #define A_D_STR "A.D."
00210 #define a_d_STR "a.d."
00211 #define AD_STR "AD"
00212 #define ad_STR "ad"
00213
00214 #define B_C_STR "B.C."
00215 #define b_c_STR "b.c."
00216 #define BC_STR "BC"
00217 #define bc_STR "bc"
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229 static char *adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL};
00230 static char *adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL};
00231
00232
00233
00234
00235
00236 #define A_M_STR "A.M."
00237 #define a_m_STR "a.m."
00238 #define AM_STR "AM"
00239 #define am_STR "am"
00240
00241 #define P_M_STR "P.M."
00242 #define p_m_STR "p.m."
00243 #define PM_STR "PM"
00244 #define pm_STR "pm"
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 static char *ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL};
00257 static char *ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL};
00258
00259
00260
00261
00262
00263
00264
00265 static char *rm_months_upper[] =
00266 {"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};
00267
00268 static char *rm_months_lower[] =
00269 {"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};
00270
00271
00272
00273
00274
00275 static char *rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};
00276 static char *rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};
00277 static char *rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};
00278
00279
00280
00281
00282
00283 static char *numTH[] = {"ST", "ND", "RD", "TH", NULL};
00284 static char *numth[] = {"st", "nd", "rd", "th", NULL};
00285
00286
00287
00288
00289
00290 #define ONE_UPPER 1
00291 #define ALL_UPPER 2
00292 #define ALL_LOWER 3
00293
00294 #define FULL_SIZ 0
00295
00296 #define MAX_MONTH_LEN 9
00297 #define MAX_MON_LEN 3
00298 #define MAX_DAY_LEN 9
00299 #define MAX_DY_LEN 3
00300 #define MAX_RM_LEN 4
00301
00302 #define TH_UPPER 1
00303 #define TH_LOWER 2
00304
00305
00306
00307
00308
00309 typedef struct
00310 {
00311 int pre,
00312 post,
00313 lsign,
00314 flag,
00315 pre_lsign_num,
00316 multi,
00317 zero_start,
00318 zero_end,
00319 need_locale;
00320 } NUMDesc;
00321
00322
00323
00324
00325
00326 #define NUM_F_DECIMAL (1 << 1)
00327 #define NUM_F_LDECIMAL (1 << 2)
00328 #define NUM_F_ZERO (1 << 3)
00329 #define NUM_F_BLANK (1 << 4)
00330 #define NUM_F_FILLMODE (1 << 5)
00331 #define NUM_F_LSIGN (1 << 6)
00332 #define NUM_F_BRACKET (1 << 7)
00333 #define NUM_F_MINUS (1 << 8)
00334 #define NUM_F_PLUS (1 << 9)
00335 #define NUM_F_ROMAN (1 << 10)
00336 #define NUM_F_MULTI (1 << 11)
00337 #define NUM_F_PLUS_POST (1 << 12)
00338 #define NUM_F_MINUS_POST (1 << 13)
00339 #define NUM_F_EEEE (1 << 14)
00340
00341 #define NUM_LSIGN_PRE (-1)
00342 #define NUM_LSIGN_POST 1
00343 #define NUM_LSIGN_NONE 0
00344
00345
00346
00347
00348
00349 #define IS_DECIMAL(_f) ((_f)->flag & NUM_F_DECIMAL)
00350 #define IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL)
00351 #define IS_ZERO(_f) ((_f)->flag & NUM_F_ZERO)
00352 #define IS_BLANK(_f) ((_f)->flag & NUM_F_BLANK)
00353 #define IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE)
00354 #define IS_BRACKET(_f) ((_f)->flag & NUM_F_BRACKET)
00355 #define IS_MINUS(_f) ((_f)->flag & NUM_F_MINUS)
00356 #define IS_LSIGN(_f) ((_f)->flag & NUM_F_LSIGN)
00357 #define IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS)
00358 #define IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN)
00359 #define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI)
00360 #define IS_EEEE(_f) ((_f)->flag & NUM_F_EEEE)
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370 #define NUM_CACHE_SIZE 64
00371 #define NUM_CACHE_FIELDS 16
00372 #define DCH_CACHE_SIZE 128
00373 #define DCH_CACHE_FIELDS 16
00374
00375 typedef struct
00376 {
00377 FormatNode format[DCH_CACHE_SIZE + 1];
00378 char str[DCH_CACHE_SIZE + 1];
00379 int age;
00380 } DCHCacheEntry;
00381
00382 typedef struct
00383 {
00384 FormatNode format[NUM_CACHE_SIZE + 1];
00385 char str[NUM_CACHE_SIZE + 1];
00386 int age;
00387 NUMDesc Num;
00388 } NUMCacheEntry;
00389
00390
00391 static DCHCacheEntry DCHCache[DCH_CACHE_FIELDS + 1];
00392
00393 static int n_DCHCache = 0;
00394 static int DCHCounter = 0;
00395
00396
00397 static NUMCacheEntry NUMCache[NUM_CACHE_FIELDS + 1];
00398
00399 static int n_NUMCache = 0;
00400 static int NUMCounter = 0;
00401 static NUMCacheEntry *last_NUMCacheEntry = NUMCache + 0;
00402
00403
00404
00405
00406
00407 typedef struct
00408 {
00409 FromCharDateMode mode;
00410 int hh,
00411 pm,
00412 mi,
00413 ss,
00414 ssss,
00415 d,
00416 dd,
00417 ddd,
00418 mm,
00419 ms,
00420 year,
00421 bc,
00422 ww,
00423 w,
00424 cc,
00425 j,
00426 us,
00427 yysz,
00428 clock;
00429 } TmFromChar;
00430
00431 #define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))
00432
00433
00434
00435
00436
00437 #ifdef DEBUG_TO_FROM_CHAR
00438 #define DEBUG_TMFC(_X) \
00439 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", \
00440 (_X)->mode, (_X)->hh, (_X)->pm, (_X)->mi, (_X)->ss, (_X)->ssss, \
00441 (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, (_X)->year, \
00442 (_X)->bc, (_X)->ww, (_X)->w, (_X)->cc, (_X)->j, (_X)->us, \
00443 (_X)->yysz, (_X)->clock);
00444 #define DEBUG_TM(_X) \
00445 elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\
00446 (_X)->tm_sec, (_X)->tm_year,\
00447 (_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\
00448 (_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)
00449 #else
00450 #define DEBUG_TMFC(_X)
00451 #define DEBUG_TM(_X)
00452 #endif
00453
00454
00455
00456
00457
00458 typedef struct TmToChar
00459 {
00460 struct pg_tm tm;
00461 fsec_t fsec;
00462 const char *tzn;
00463 } TmToChar;
00464
00465 #define tmtcTm(_X) (&(_X)->tm)
00466 #define tmtcTzn(_X) ((_X)->tzn)
00467 #define tmtcFsec(_X) ((_X)->fsec)
00468
00469 #define ZERO_tm(_X) \
00470 do { \
00471 (_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
00472 (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
00473 (_X)->tm_mday = (_X)->tm_mon = 1; \
00474 } while(0)
00475
00476 #define ZERO_tmtc(_X) \
00477 do { \
00478 ZERO_tm( tmtcTm(_X) ); \
00479 tmtcFsec(_X) = 0; \
00480 tmtcTzn(_X) = NULL; \
00481 } while(0)
00482
00483
00484
00485
00486
00487 #define INVALID_FOR_INTERVAL \
00488 do { \
00489 if (is_interval) \
00490 ereport(ERROR, \
00491 (errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
00492 errmsg("invalid format specification for an interval value"), \
00493 errhint("Intervals are not tied to specific calendar dates."))); \
00494 } while(0)
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504 #define DCH_S_FM 0x01
00505 #define DCH_S_TH 0x02
00506 #define DCH_S_th 0x04
00507 #define DCH_S_SP 0x08
00508 #define DCH_S_TM 0x10
00509
00510
00511
00512
00513
00514 #define S_THth(_s) ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)
00515 #define S_TH(_s) (((_s) & DCH_S_TH) ? 1 : 0)
00516 #define S_th(_s) (((_s) & DCH_S_th) ? 1 : 0)
00517 #define S_TH_TYPE(_s) (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)
00518
00519
00520 #define S_FM(_s) (((_s) & DCH_S_FM) ? 1 : 0)
00521 #define S_SP(_s) (((_s) & DCH_S_SP) ? 1 : 0)
00522 #define S_TM(_s) (((_s) & DCH_S_TM) ? 1 : 0)
00523
00524
00525
00526
00527
00528 static KeySuffix DCH_suff[] = {
00529 {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},
00530 {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},
00531 {"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX},
00532 {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX},
00533 {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},
00534 {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},
00535 {"SP", 2, DCH_S_SP, SUFFTYPE_POSTFIX},
00536
00537 {NULL, 0, 0, 0}
00538 };
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568 typedef enum
00569 {
00570 DCH_A_D,
00571 DCH_A_M,
00572 DCH_AD,
00573 DCH_AM,
00574 DCH_B_C,
00575 DCH_BC,
00576 DCH_CC,
00577 DCH_DAY,
00578 DCH_DDD,
00579 DCH_DD,
00580 DCH_DY,
00581 DCH_Day,
00582 DCH_Dy,
00583 DCH_D,
00584 DCH_FX,
00585 DCH_HH24,
00586 DCH_HH12,
00587 DCH_HH,
00588 DCH_IDDD,
00589 DCH_ID,
00590 DCH_IW,
00591 DCH_IYYY,
00592 DCH_IYY,
00593 DCH_IY,
00594 DCH_I,
00595 DCH_J,
00596 DCH_MI,
00597 DCH_MM,
00598 DCH_MONTH,
00599 DCH_MON,
00600 DCH_MS,
00601 DCH_Month,
00602 DCH_Mon,
00603 DCH_P_M,
00604 DCH_PM,
00605 DCH_Q,
00606 DCH_RM,
00607 DCH_SSSS,
00608 DCH_SS,
00609 DCH_TZ,
00610 DCH_US,
00611 DCH_WW,
00612 DCH_W,
00613 DCH_Y_YYY,
00614 DCH_YYYY,
00615 DCH_YYY,
00616 DCH_YY,
00617 DCH_Y,
00618 DCH_a_d,
00619 DCH_a_m,
00620 DCH_ad,
00621 DCH_am,
00622 DCH_b_c,
00623 DCH_bc,
00624 DCH_cc,
00625 DCH_day,
00626 DCH_ddd,
00627 DCH_dd,
00628 DCH_dy,
00629 DCH_d,
00630 DCH_fx,
00631 DCH_hh24,
00632 DCH_hh12,
00633 DCH_hh,
00634 DCH_iddd,
00635 DCH_id,
00636 DCH_iw,
00637 DCH_iyyy,
00638 DCH_iyy,
00639 DCH_iy,
00640 DCH_i,
00641 DCH_j,
00642 DCH_mi,
00643 DCH_mm,
00644 DCH_month,
00645 DCH_mon,
00646 DCH_ms,
00647 DCH_p_m,
00648 DCH_pm,
00649 DCH_q,
00650 DCH_rm,
00651 DCH_ssss,
00652 DCH_ss,
00653 DCH_tz,
00654 DCH_us,
00655 DCH_ww,
00656 DCH_w,
00657 DCH_y_yyy,
00658 DCH_yyyy,
00659 DCH_yyy,
00660 DCH_yy,
00661 DCH_y,
00662
00663
00664 _DCH_last_
00665 } DCH_poz;
00666
00667 typedef enum
00668 {
00669 NUM_COMMA,
00670 NUM_DEC,
00671 NUM_0,
00672 NUM_9,
00673 NUM_B,
00674 NUM_C,
00675 NUM_D,
00676 NUM_E,
00677 NUM_FM,
00678 NUM_G,
00679 NUM_L,
00680 NUM_MI,
00681 NUM_PL,
00682 NUM_PR,
00683 NUM_RN,
00684 NUM_SG,
00685 NUM_SP,
00686 NUM_S,
00687 NUM_TH,
00688 NUM_V,
00689 NUM_b,
00690 NUM_c,
00691 NUM_d,
00692 NUM_e,
00693 NUM_fm,
00694 NUM_g,
00695 NUM_l,
00696 NUM_mi,
00697 NUM_pl,
00698 NUM_pr,
00699 NUM_rn,
00700 NUM_sg,
00701 NUM_sp,
00702 NUM_s,
00703 NUM_th,
00704 NUM_v,
00705
00706
00707 _NUM_last_
00708 } NUM_poz;
00709
00710
00711
00712
00713
00714 static const KeyWord DCH_keywords[] = {
00715
00716 {"A.D.", 4, DCH_A_D, FALSE, FROM_CHAR_DATE_NONE},
00717 {"A.M.", 4, DCH_A_M, FALSE, FROM_CHAR_DATE_NONE},
00718 {"AD", 2, DCH_AD, FALSE, FROM_CHAR_DATE_NONE},
00719 {"AM", 2, DCH_AM, FALSE, FROM_CHAR_DATE_NONE},
00720 {"B.C.", 4, DCH_B_C, FALSE, FROM_CHAR_DATE_NONE},
00721 {"BC", 2, DCH_BC, FALSE, FROM_CHAR_DATE_NONE},
00722 {"CC", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE},
00723 {"DAY", 3, DCH_DAY, FALSE, FROM_CHAR_DATE_NONE},
00724 {"DDD", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00725 {"DD", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00726 {"DY", 2, DCH_DY, FALSE, FROM_CHAR_DATE_NONE},
00727 {"Day", 3, DCH_Day, FALSE, FROM_CHAR_DATE_NONE},
00728 {"Dy", 2, DCH_Dy, FALSE, FROM_CHAR_DATE_NONE},
00729 {"D", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
00730 {"FX", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE},
00731 {"HH24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE},
00732 {"HH12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
00733 {"HH", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
00734 {"IDDD", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK},
00735 {"ID", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
00736 {"IW", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
00737 {"IYYY", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00738 {"IYY", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00739 {"IY", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00740 {"I", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
00741 {"J", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE},
00742 {"MI", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE},
00743 {"MM", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
00744 {"MONTH", 5, DCH_MONTH, FALSE, FROM_CHAR_DATE_GREGORIAN},
00745 {"MON", 3, DCH_MON, FALSE, FROM_CHAR_DATE_GREGORIAN},
00746 {"MS", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
00747 {"Month", 5, DCH_Month, FALSE, FROM_CHAR_DATE_GREGORIAN},
00748 {"Mon", 3, DCH_Mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
00749 {"P.M.", 4, DCH_P_M, FALSE, FROM_CHAR_DATE_NONE},
00750 {"PM", 2, DCH_PM, FALSE, FROM_CHAR_DATE_NONE},
00751 {"Q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE},
00752 {"RM", 2, DCH_RM, FALSE, FROM_CHAR_DATE_GREGORIAN},
00753 {"SSSS", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE},
00754 {"SS", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
00755 {"TZ", 2, DCH_TZ, FALSE, FROM_CHAR_DATE_NONE},
00756 {"US", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE},
00757 {"WW", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN},
00758 {"W", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
00759 {"Y,YYY", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00760 {"YYYY", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00761 {"YYY", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00762 {"YY", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00763 {"Y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
00764 {"a.d.", 4, DCH_a_d, FALSE, FROM_CHAR_DATE_NONE},
00765 {"a.m.", 4, DCH_a_m, FALSE, FROM_CHAR_DATE_NONE},
00766 {"ad", 2, DCH_ad, FALSE, FROM_CHAR_DATE_NONE},
00767 {"am", 2, DCH_am, FALSE, FROM_CHAR_DATE_NONE},
00768 {"b.c.", 4, DCH_b_c, FALSE, FROM_CHAR_DATE_NONE},
00769 {"bc", 2, DCH_bc, FALSE, FROM_CHAR_DATE_NONE},
00770 {"cc", 2, DCH_CC, TRUE, FROM_CHAR_DATE_NONE},
00771 {"day", 3, DCH_day, FALSE, FROM_CHAR_DATE_NONE},
00772 {"ddd", 3, DCH_DDD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00773 {"dd", 2, DCH_DD, TRUE, FROM_CHAR_DATE_GREGORIAN},
00774 {"dy", 2, DCH_dy, FALSE, FROM_CHAR_DATE_NONE},
00775 {"d", 1, DCH_D, TRUE, FROM_CHAR_DATE_GREGORIAN},
00776 {"fx", 2, DCH_FX, FALSE, FROM_CHAR_DATE_NONE},
00777 {"hh24", 4, DCH_HH24, TRUE, FROM_CHAR_DATE_NONE},
00778 {"hh12", 4, DCH_HH12, TRUE, FROM_CHAR_DATE_NONE},
00779 {"hh", 2, DCH_HH, TRUE, FROM_CHAR_DATE_NONE},
00780 {"iddd", 4, DCH_IDDD, TRUE, FROM_CHAR_DATE_ISOWEEK},
00781 {"id", 2, DCH_ID, TRUE, FROM_CHAR_DATE_ISOWEEK},
00782 {"iw", 2, DCH_IW, TRUE, FROM_CHAR_DATE_ISOWEEK},
00783 {"iyyy", 4, DCH_IYYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00784 {"iyy", 3, DCH_IYY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00785 {"iy", 2, DCH_IY, TRUE, FROM_CHAR_DATE_ISOWEEK},
00786 {"i", 1, DCH_I, TRUE, FROM_CHAR_DATE_ISOWEEK},
00787 {"j", 1, DCH_J, TRUE, FROM_CHAR_DATE_NONE},
00788 {"mi", 2, DCH_MI, TRUE, FROM_CHAR_DATE_NONE},
00789 {"mm", 2, DCH_MM, TRUE, FROM_CHAR_DATE_GREGORIAN},
00790 {"month", 5, DCH_month, FALSE, FROM_CHAR_DATE_GREGORIAN},
00791 {"mon", 3, DCH_mon, FALSE, FROM_CHAR_DATE_GREGORIAN},
00792 {"ms", 2, DCH_MS, TRUE, FROM_CHAR_DATE_NONE},
00793 {"p.m.", 4, DCH_p_m, FALSE, FROM_CHAR_DATE_NONE},
00794 {"pm", 2, DCH_pm, FALSE, FROM_CHAR_DATE_NONE},
00795 {"q", 1, DCH_Q, TRUE, FROM_CHAR_DATE_NONE},
00796 {"rm", 2, DCH_rm, FALSE, FROM_CHAR_DATE_GREGORIAN},
00797 {"ssss", 4, DCH_SSSS, TRUE, FROM_CHAR_DATE_NONE},
00798 {"ss", 2, DCH_SS, TRUE, FROM_CHAR_DATE_NONE},
00799 {"tz", 2, DCH_tz, FALSE, FROM_CHAR_DATE_NONE},
00800 {"us", 2, DCH_US, TRUE, FROM_CHAR_DATE_NONE},
00801 {"ww", 2, DCH_WW, TRUE, FROM_CHAR_DATE_GREGORIAN},
00802 {"w", 1, DCH_W, TRUE, FROM_CHAR_DATE_GREGORIAN},
00803 {"y,yyy", 5, DCH_Y_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00804 {"yyyy", 4, DCH_YYYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00805 {"yyy", 3, DCH_YYY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00806 {"yy", 2, DCH_YY, TRUE, FROM_CHAR_DATE_GREGORIAN},
00807 {"y", 1, DCH_Y, TRUE, FROM_CHAR_DATE_GREGORIAN},
00808
00809
00810 {NULL, 0, 0, 0, 0}
00811 };
00812
00813
00814
00815
00816
00817
00818
00819 static const KeyWord NUM_keywords[] = {
00820
00821 {",", 1, NUM_COMMA},
00822 {".", 1, NUM_DEC},
00823 {"0", 1, NUM_0},
00824 {"9", 1, NUM_9},
00825 {"B", 1, NUM_B},
00826 {"C", 1, NUM_C},
00827 {"D", 1, NUM_D},
00828 {"EEEE", 4, NUM_E},
00829 {"FM", 2, NUM_FM},
00830 {"G", 1, NUM_G},
00831 {"L", 1, NUM_L},
00832 {"MI", 2, NUM_MI},
00833 {"PL", 2, NUM_PL},
00834 {"PR", 2, NUM_PR},
00835 {"RN", 2, NUM_RN},
00836 {"SG", 2, NUM_SG},
00837 {"SP", 2, NUM_SP},
00838 {"S", 1, NUM_S},
00839 {"TH", 2, NUM_TH},
00840 {"V", 1, NUM_V},
00841 {"b", 1, NUM_B},
00842 {"c", 1, NUM_C},
00843 {"d", 1, NUM_D},
00844 {"eeee", 4, NUM_E},
00845 {"fm", 2, NUM_FM},
00846 {"g", 1, NUM_G},
00847 {"l", 1, NUM_L},
00848 {"mi", 2, NUM_MI},
00849 {"pl", 2, NUM_PL},
00850 {"pr", 2, NUM_PR},
00851 {"rn", 2, NUM_rn},
00852 {"sg", 2, NUM_SG},
00853 {"sp", 2, NUM_SP},
00854 {"s", 1, NUM_S},
00855 {"th", 2, NUM_th},
00856 {"v", 1, NUM_V},
00857
00858
00859 {NULL, 0, 0}
00860 };
00861
00862
00863
00864
00865
00866
00867 static const int DCH_index[KeyWord_INDEX_SIZE] = {
00868
00869
00870
00871
00872
00873 -1, -1, -1, -1, -1, -1, -1, -1,
00874 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00875 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
00876 -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
00877 DCH_FX, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, -1,
00878 DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY,
00879 -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
00880 DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
00881 -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww,
00882 -1, DCH_y_yyy, -1, -1, -1, -1
00883
00884
00885 };
00886
00887
00888
00889
00890
00891 static const int NUM_index[KeyWord_INDEX_SIZE] = {
00892
00893
00894
00895
00896
00897 -1, -1, -1, -1, -1, -1, -1, -1,
00898 -1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
00899 -1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
00900 -1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
00901 NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
00902 NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
00903 -1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
00904 NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
00905 -1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
00906 -1, -1, -1, -1, -1, -1
00907
00908
00909 };
00910
00911
00912
00913
00914
00915 typedef struct NUMProc
00916 {
00917 bool is_to_char;
00918 NUMDesc *Num;
00919
00920 int sign,
00921 sign_wrote,
00922 num_count,
00923 num_in,
00924 num_curr,
00925 num_pre,
00926
00927 read_dec,
00928 read_post,
00929 read_pre;
00930
00931 char *number,
00932 *number_p,
00933 *inout,
00934 *inout_p,
00935 *last_relevant,
00936
00937 *L_negative_sign,
00938 *L_positive_sign,
00939 *decimal,
00940 *L_thousands_sep,
00941 *L_currency_symbol;
00942 } NUMProc;
00943
00944
00945
00946
00947
00948
00949 static const KeyWord *index_seq_search(char *str, const KeyWord *kw,
00950 const int *index);
00951 static KeySuffix *suff_search(char *str, KeySuffix *suf, int type);
00952 static void NUMDesc_prepare(NUMDesc *num, FormatNode *n);
00953 static void parse_format(FormatNode *node, char *str, const KeyWord *kw,
00954 KeySuffix *suf, const int *index, int ver, NUMDesc *Num);
00955
00956 static void DCH_to_char(FormatNode *node, bool is_interval,
00957 TmToChar *in, char *out, Oid collid);
00958 static void DCH_from_char(FormatNode *node, char *in, TmFromChar *out);
00959
00960 #ifdef DEBUG_TO_FROM_CHAR
00961 static void dump_index(const KeyWord *k, const int *index);
00962 static void dump_node(FormatNode *node, int max);
00963 #endif
00964
00965 static char *get_th(char *num, int type);
00966 static char *str_numth(char *dest, char *num, int type);
00967 static int adjust_partial_year_to_2020(int year);
00968 static int strspace_len(char *str);
00969 static int strdigits_len(char *str);
00970 static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode);
00971 static void from_char_set_int(int *dest, const int value, const FormatNode *node);
00972 static int from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node);
00973 static int from_char_parse_int(int *dest, char **src, FormatNode *node);
00974 static int seq_search(char *name, char **array, int type, int max, int *len);
00975 static int from_char_seq_search(int *dest, char **src, char **array, int type, int max, FormatNode *node);
00976 static void do_to_timestamp(text *date_txt, text *fmt,
00977 struct pg_tm * tm, fsec_t *fsec);
00978 static char *fill_str(char *str, int c, int max);
00979 static FormatNode *NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree);
00980 static char *int_to_roman(int number);
00981 static void NUM_prepare_locale(NUMProc *Np);
00982 static char *get_last_relevant_decnum(char *num);
00983 static void NUM_numpart_from_char(NUMProc *Np, int id, int plen);
00984 static void NUM_numpart_to_char(NUMProc *Np, int id);
00985 static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
00986 int plen, int sign, bool is_to_char, Oid collid);
00987 static DCHCacheEntry *DCH_cache_search(char *str);
00988 static DCHCacheEntry *DCH_cache_getnew(char *str);
00989
00990 static NUMCacheEntry *NUM_cache_search(char *str);
00991 static NUMCacheEntry *NUM_cache_getnew(char *str);
00992 static void NUM_cache_remove(NUMCacheEntry *ent);
00993
00994
00995
00996
00997
00998
00999
01000
01001 static const KeyWord *
01002 index_seq_search(char *str, const KeyWord *kw, const int *index)
01003 {
01004 int poz;
01005
01006 if (!KeyWord_INDEX_FILTER(*str))
01007 return NULL;
01008
01009 if ((poz = *(index + (*str - ' '))) > -1)
01010 {
01011 const KeyWord *k = kw + poz;
01012
01013 do
01014 {
01015 if (strncmp(str, k->name, k->len) == 0)
01016 return k;
01017 k++;
01018 if (!k->name)
01019 return NULL;
01020 } while (*str == *k->name);
01021 }
01022 return NULL;
01023 }
01024
01025 static KeySuffix *
01026 suff_search(char *str, KeySuffix *suf, int type)
01027 {
01028 KeySuffix *s;
01029
01030 for (s = suf; s->name != NULL; s++)
01031 {
01032 if (s->type != type)
01033 continue;
01034
01035 if (strncmp(str, s->name, s->len) == 0)
01036 return s;
01037 }
01038 return NULL;
01039 }
01040
01041
01042
01043
01044
01045 static void
01046 NUMDesc_prepare(NUMDesc *num, FormatNode *n)
01047 {
01048
01049 if (n->type != NODE_TYPE_ACTION)
01050 return;
01051
01052
01053
01054
01055
01056 PG_TRY();
01057 {
01058 if (IS_EEEE(num) && n->key->id != NUM_E)
01059 ereport(ERROR,
01060 (errcode(ERRCODE_SYNTAX_ERROR),
01061 errmsg("\"EEEE\" must be the last pattern used")));
01062
01063 switch (n->key->id)
01064 {
01065 case NUM_9:
01066 if (IS_BRACKET(num))
01067 ereport(ERROR,
01068 (errcode(ERRCODE_SYNTAX_ERROR),
01069 errmsg("\"9\" must be ahead of \"PR\"")));
01070 if (IS_MULTI(num))
01071 {
01072 ++num->multi;
01073 break;
01074 }
01075 if (IS_DECIMAL(num))
01076 ++num->post;
01077 else
01078 ++num->pre;
01079 break;
01080
01081 case NUM_0:
01082 if (IS_BRACKET(num))
01083 ereport(ERROR,
01084 (errcode(ERRCODE_SYNTAX_ERROR),
01085 errmsg("\"0\" must be ahead of \"PR\"")));
01086 if (!IS_ZERO(num) && !IS_DECIMAL(num))
01087 {
01088 num->flag |= NUM_F_ZERO;
01089 num->zero_start = num->pre + 1;
01090 }
01091 if (!IS_DECIMAL(num))
01092 ++num->pre;
01093 else
01094 ++num->post;
01095
01096 num->zero_end = num->pre + num->post;
01097 break;
01098
01099 case NUM_B:
01100 if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num)))
01101 num->flag |= NUM_F_BLANK;
01102 break;
01103
01104 case NUM_D:
01105 num->flag |= NUM_F_LDECIMAL;
01106 num->need_locale = TRUE;
01107
01108 case NUM_DEC:
01109 if (IS_DECIMAL(num))
01110 ereport(ERROR,
01111 (errcode(ERRCODE_SYNTAX_ERROR),
01112 errmsg("multiple decimal points")));
01113 if (IS_MULTI(num))
01114 ereport(ERROR,
01115 (errcode(ERRCODE_SYNTAX_ERROR),
01116 errmsg("cannot use \"V\" and decimal point together")));
01117 num->flag |= NUM_F_DECIMAL;
01118 break;
01119
01120 case NUM_FM:
01121 num->flag |= NUM_F_FILLMODE;
01122 break;
01123
01124 case NUM_S:
01125 if (IS_LSIGN(num))
01126 ereport(ERROR,
01127 (errcode(ERRCODE_SYNTAX_ERROR),
01128 errmsg("cannot use \"S\" twice")));
01129 if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
01130 ereport(ERROR,
01131 (errcode(ERRCODE_SYNTAX_ERROR),
01132 errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
01133 if (!IS_DECIMAL(num))
01134 {
01135 num->lsign = NUM_LSIGN_PRE;
01136 num->pre_lsign_num = num->pre;
01137 num->need_locale = TRUE;
01138 num->flag |= NUM_F_LSIGN;
01139 }
01140 else if (num->lsign == NUM_LSIGN_NONE)
01141 {
01142 num->lsign = NUM_LSIGN_POST;
01143 num->need_locale = TRUE;
01144 num->flag |= NUM_F_LSIGN;
01145 }
01146 break;
01147
01148 case NUM_MI:
01149 if (IS_LSIGN(num))
01150 ereport(ERROR,
01151 (errcode(ERRCODE_SYNTAX_ERROR),
01152 errmsg("cannot use \"S\" and \"MI\" together")));
01153 num->flag |= NUM_F_MINUS;
01154 if (IS_DECIMAL(num))
01155 num->flag |= NUM_F_MINUS_POST;
01156 break;
01157
01158 case NUM_PL:
01159 if (IS_LSIGN(num))
01160 ereport(ERROR,
01161 (errcode(ERRCODE_SYNTAX_ERROR),
01162 errmsg("cannot use \"S\" and \"PL\" together")));
01163 num->flag |= NUM_F_PLUS;
01164 if (IS_DECIMAL(num))
01165 num->flag |= NUM_F_PLUS_POST;
01166 break;
01167
01168 case NUM_SG:
01169 if (IS_LSIGN(num))
01170 ereport(ERROR,
01171 (errcode(ERRCODE_SYNTAX_ERROR),
01172 errmsg("cannot use \"S\" and \"SG\" together")));
01173 num->flag |= NUM_F_MINUS;
01174 num->flag |= NUM_F_PLUS;
01175 break;
01176
01177 case NUM_PR:
01178 if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
01179 ereport(ERROR,
01180 (errcode(ERRCODE_SYNTAX_ERROR),
01181 errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
01182 num->flag |= NUM_F_BRACKET;
01183 break;
01184
01185 case NUM_rn:
01186 case NUM_RN:
01187 num->flag |= NUM_F_ROMAN;
01188 break;
01189
01190 case NUM_L:
01191 case NUM_G:
01192 num->need_locale = TRUE;
01193 break;
01194
01195 case NUM_V:
01196 if (IS_DECIMAL(num))
01197 ereport(ERROR,
01198 (errcode(ERRCODE_SYNTAX_ERROR),
01199 errmsg("cannot use \"V\" and decimal point together")));
01200 num->flag |= NUM_F_MULTI;
01201 break;
01202
01203 case NUM_E:
01204 if (IS_EEEE(num))
01205 ereport(ERROR,
01206 (errcode(ERRCODE_SYNTAX_ERROR),
01207 errmsg("cannot use \"EEEE\" twice")));
01208 if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) ||
01209 IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) ||
01210 IS_ROMAN(num) || IS_MULTI(num))
01211 ereport(ERROR,
01212 (errcode(ERRCODE_SYNTAX_ERROR),
01213 errmsg("\"EEEE\" is incompatible with other formats"),
01214 errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
01215 num->flag |= NUM_F_EEEE;
01216 break;
01217 }
01218 }
01219 PG_CATCH();
01220 {
01221 NUM_cache_remove(last_NUMCacheEntry);
01222 PG_RE_THROW();
01223 }
01224 PG_END_TRY();
01225
01226
01227 return;
01228 }
01229
01230
01231
01232
01233
01234
01235
01236
01237 static void
01238 parse_format(FormatNode *node, char *str, const KeyWord *kw,
01239 KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
01240 {
01241 KeySuffix *s;
01242 FormatNode *n;
01243 int node_set = 0,
01244 suffix,
01245 last = 0;
01246
01247 #ifdef DEBUG_TO_FROM_CHAR
01248 elog(DEBUG_elog_output, "to_char/number(): run parser");
01249 #endif
01250
01251 n = node;
01252
01253 while (*str)
01254 {
01255 suffix = 0;
01256
01257
01258
01259
01260 if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
01261 {
01262 suffix |= s->id;
01263 if (s->len)
01264 str += s->len;
01265 }
01266
01267
01268
01269
01270 if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
01271 {
01272 n->type = NODE_TYPE_ACTION;
01273 n->suffix = 0;
01274 node_set = 1;
01275 if (n->key->len)
01276 str += n->key->len;
01277
01278
01279
01280
01281 if (ver == NUM_TYPE)
01282 NUMDesc_prepare(Num, n);
01283
01284
01285
01286
01287 if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
01288 {
01289 suffix |= s->id;
01290 if (s->len)
01291 str += s->len;
01292 }
01293 }
01294 else if (*str)
01295 {
01296
01297
01298
01299 if (*str == '"' && last != '\\')
01300 {
01301 int x = 0;
01302
01303 while (*(++str))
01304 {
01305 if (*str == '"' && x != '\\')
01306 {
01307 str++;
01308 break;
01309 }
01310 else if (*str == '\\' && x != '\\')
01311 {
01312 x = '\\';
01313 continue;
01314 }
01315 n->type = NODE_TYPE_CHAR;
01316 n->character = *str;
01317 n->key = NULL;
01318 n->suffix = 0;
01319 ++n;
01320 x = *str;
01321 }
01322 node_set = 0;
01323 suffix = 0;
01324 last = 0;
01325 }
01326 else if (*str && *str == '\\' && last != '\\' && *(str + 1) == '"')
01327 {
01328 last = *str;
01329 str++;
01330 }
01331 else if (*str)
01332 {
01333 n->type = NODE_TYPE_CHAR;
01334 n->character = *str;
01335 n->key = NULL;
01336 node_set = 1;
01337 last = 0;
01338 str++;
01339 }
01340 }
01341
01342
01343 if (node_set)
01344 {
01345 if (n->type == NODE_TYPE_ACTION)
01346 n->suffix = suffix;
01347 ++n;
01348
01349 n->suffix = 0;
01350 node_set = 0;
01351 }
01352 }
01353
01354 n->type = NODE_TYPE_END;
01355 n->suffix = 0;
01356 return;
01357 }
01358
01359
01360
01361
01362
01363 #ifdef DEBUG_TO_FROM_CHAR
01364
01365 #define DUMP_THth(_suf) (S_TH(_suf) ? "TH" : (S_th(_suf) ? "th" : " "))
01366 #define DUMP_FM(_suf) (S_FM(_suf) ? "FM" : " ")
01367
01368 static void
01369 dump_node(FormatNode *node, int max)
01370 {
01371 FormatNode *n;
01372 int a;
01373
01374 elog(DEBUG_elog_output, "to_from-char(): DUMP FORMAT");
01375
01376 for (a = 0, n = node; a <= max; n++, a++)
01377 {
01378 if (n->type == NODE_TYPE_ACTION)
01379 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_ACTION '%s'\t(%s,%s)",
01380 a, n->key->name, DUMP_THth(n->suffix), DUMP_FM(n->suffix));
01381 else if (n->type == NODE_TYPE_CHAR)
01382 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_CHAR '%c'", a, n->character);
01383 else if (n->type == NODE_TYPE_END)
01384 {
01385 elog(DEBUG_elog_output, "%d:\t NODE_TYPE_END", a);
01386 return;
01387 }
01388 else
01389 elog(DEBUG_elog_output, "%d:\t unknown NODE!", a);
01390 }
01391 }
01392 #endif
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403 static char *
01404 get_th(char *num, int type)
01405 {
01406 int len = strlen(num),
01407 last,
01408 seclast;
01409
01410 last = *(num + (len - 1));
01411 if (!isdigit((unsigned char) last))
01412 ereport(ERROR,
01413 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01414 errmsg("\"%s\" is not a number", num)));
01415
01416
01417
01418
01419
01420 if ((len > 1) && ((seclast = num[len - 2]) == '1'))
01421 last = 0;
01422
01423 switch (last)
01424 {
01425 case '1':
01426 if (type == TH_UPPER)
01427 return numTH[0];
01428 return numth[0];
01429 case '2':
01430 if (type == TH_UPPER)
01431 return numTH[1];
01432 return numth[1];
01433 case '3':
01434 if (type == TH_UPPER)
01435 return numTH[2];
01436 return numth[2];
01437 default:
01438 if (type == TH_UPPER)
01439 return numTH[3];
01440 return numth[3];
01441 }
01442 }
01443
01444
01445
01446
01447
01448
01449 static char *
01450 str_numth(char *dest, char *num, int type)
01451 {
01452 if (dest != num)
01453 strcpy(dest, num);
01454 strcat(dest, get_th(num, type));
01455 return dest;
01456 }
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467
01468
01469
01470
01471
01472
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483
01484 char *
01485 str_tolower(const char *buff, size_t nbytes, Oid collid)
01486 {
01487 char *result;
01488
01489 if (!buff)
01490 return NULL;
01491
01492
01493 if (lc_ctype_is_c(collid))
01494 {
01495 result = asc_tolower(buff, nbytes);
01496 }
01497 #ifdef USE_WIDE_UPPER_LOWER
01498 else if (pg_database_encoding_max_length() > 1)
01499 {
01500 pg_locale_t mylocale = 0;
01501 wchar_t *workspace;
01502 size_t curr_char;
01503 size_t result_size;
01504
01505 if (collid != DEFAULT_COLLATION_OID)
01506 {
01507 if (!OidIsValid(collid))
01508 {
01509
01510
01511
01512
01513 ereport(ERROR,
01514 (errcode(ERRCODE_INDETERMINATE_COLLATION),
01515 errmsg("could not determine which collation to use for lower() function"),
01516 errhint("Use the COLLATE clause to set the collation explicitly.")));
01517 }
01518 mylocale = pg_newlocale_from_collation(collid);
01519 }
01520
01521
01522 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
01523 ereport(ERROR,
01524 (errcode(ERRCODE_OUT_OF_MEMORY),
01525 errmsg("out of memory")));
01526
01527
01528 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
01529
01530 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
01531
01532 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
01533 {
01534 #ifdef HAVE_LOCALE_T
01535 if (mylocale)
01536 workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
01537 else
01538 #endif
01539 workspace[curr_char] = towlower(workspace[curr_char]);
01540 }
01541
01542
01543 result_size = curr_char * pg_database_encoding_max_length() + 1;
01544 result = palloc(result_size);
01545
01546 wchar2char(result, workspace, result_size, mylocale);
01547 pfree(workspace);
01548 }
01549 #endif
01550 else
01551 {
01552 #ifdef HAVE_LOCALE_T
01553 pg_locale_t mylocale = 0;
01554 #endif
01555 char *p;
01556
01557 if (collid != DEFAULT_COLLATION_OID)
01558 {
01559 if (!OidIsValid(collid))
01560 {
01561
01562
01563
01564
01565 ereport(ERROR,
01566 (errcode(ERRCODE_INDETERMINATE_COLLATION),
01567 errmsg("could not determine which collation to use for lower() function"),
01568 errhint("Use the COLLATE clause to set the collation explicitly.")));
01569 }
01570 #ifdef HAVE_LOCALE_T
01571 mylocale = pg_newlocale_from_collation(collid);
01572 #endif
01573 }
01574
01575 result = pnstrdup(buff, nbytes);
01576
01577
01578
01579
01580
01581
01582
01583
01584 for (p = result; *p; p++)
01585 {
01586 #ifdef HAVE_LOCALE_T
01587 if (mylocale)
01588 *p = tolower_l((unsigned char) *p, mylocale);
01589 else
01590 #endif
01591 *p = pg_tolower((unsigned char) *p);
01592 }
01593 }
01594
01595 return result;
01596 }
01597
01598
01599
01600
01601
01602
01603
01604 char *
01605 str_toupper(const char *buff, size_t nbytes, Oid collid)
01606 {
01607 char *result;
01608
01609 if (!buff)
01610 return NULL;
01611
01612
01613 if (lc_ctype_is_c(collid))
01614 {
01615 result = asc_toupper(buff, nbytes);
01616 }
01617 #ifdef USE_WIDE_UPPER_LOWER
01618 else if (pg_database_encoding_max_length() > 1)
01619 {
01620 pg_locale_t mylocale = 0;
01621 wchar_t *workspace;
01622 size_t curr_char;
01623 size_t result_size;
01624
01625 if (collid != DEFAULT_COLLATION_OID)
01626 {
01627 if (!OidIsValid(collid))
01628 {
01629
01630
01631
01632
01633 ereport(ERROR,
01634 (errcode(ERRCODE_INDETERMINATE_COLLATION),
01635 errmsg("could not determine which collation to use for upper() function"),
01636 errhint("Use the COLLATE clause to set the collation explicitly.")));
01637 }
01638 mylocale = pg_newlocale_from_collation(collid);
01639 }
01640
01641
01642 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
01643 ereport(ERROR,
01644 (errcode(ERRCODE_OUT_OF_MEMORY),
01645 errmsg("out of memory")));
01646
01647
01648 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
01649
01650 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
01651
01652 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
01653 {
01654 #ifdef HAVE_LOCALE_T
01655 if (mylocale)
01656 workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
01657 else
01658 #endif
01659 workspace[curr_char] = towupper(workspace[curr_char]);
01660 }
01661
01662
01663 result_size = curr_char * pg_database_encoding_max_length() + 1;
01664 result = palloc(result_size);
01665
01666 wchar2char(result, workspace, result_size, mylocale);
01667 pfree(workspace);
01668 }
01669 #endif
01670 else
01671 {
01672 #ifdef HAVE_LOCALE_T
01673 pg_locale_t mylocale = 0;
01674 #endif
01675 char *p;
01676
01677 if (collid != DEFAULT_COLLATION_OID)
01678 {
01679 if (!OidIsValid(collid))
01680 {
01681
01682
01683
01684
01685 ereport(ERROR,
01686 (errcode(ERRCODE_INDETERMINATE_COLLATION),
01687 errmsg("could not determine which collation to use for upper() function"),
01688 errhint("Use the COLLATE clause to set the collation explicitly.")));
01689 }
01690 #ifdef HAVE_LOCALE_T
01691 mylocale = pg_newlocale_from_collation(collid);
01692 #endif
01693 }
01694
01695 result = pnstrdup(buff, nbytes);
01696
01697
01698
01699
01700
01701
01702
01703
01704 for (p = result; *p; p++)
01705 {
01706 #ifdef HAVE_LOCALE_T
01707 if (mylocale)
01708 *p = toupper_l((unsigned char) *p, mylocale);
01709 else
01710 #endif
01711 *p = pg_toupper((unsigned char) *p);
01712 }
01713 }
01714
01715 return result;
01716 }
01717
01718
01719
01720
01721
01722
01723
01724 char *
01725 str_initcap(const char *buff, size_t nbytes, Oid collid)
01726 {
01727 char *result;
01728 int wasalnum = false;
01729
01730 if (!buff)
01731 return NULL;
01732
01733
01734 if (lc_ctype_is_c(collid))
01735 {
01736 result = asc_initcap(buff, nbytes);
01737 }
01738 #ifdef USE_WIDE_UPPER_LOWER
01739 else if (pg_database_encoding_max_length() > 1)
01740 {
01741 pg_locale_t mylocale = 0;
01742 wchar_t *workspace;
01743 size_t curr_char;
01744 size_t result_size;
01745
01746 if (collid != DEFAULT_COLLATION_OID)
01747 {
01748 if (!OidIsValid(collid))
01749 {
01750
01751
01752
01753
01754 ereport(ERROR,
01755 (errcode(ERRCODE_INDETERMINATE_COLLATION),
01756 errmsg("could not determine which collation to use for initcap() function"),
01757 errhint("Use the COLLATE clause to set the collation explicitly.")));
01758 }
01759 mylocale = pg_newlocale_from_collation(collid);
01760 }
01761
01762
01763 if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
01764 ereport(ERROR,
01765 (errcode(ERRCODE_OUT_OF_MEMORY),
01766 errmsg("out of memory")));
01767
01768
01769 workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
01770
01771 char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
01772
01773 for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
01774 {
01775 #ifdef HAVE_LOCALE_T
01776 if (mylocale)
01777 {
01778 if (wasalnum)
01779 workspace[curr_char] = towlower_l(workspace[curr_char], mylocale);
01780 else
01781 workspace[curr_char] = towupper_l(workspace[curr_char], mylocale);
01782 wasalnum = iswalnum_l(workspace[curr_char], mylocale);
01783 }
01784 else
01785 #endif
01786 {
01787 if (wasalnum)
01788 workspace[curr_char] = towlower(workspace[curr_char]);
01789 else
01790 workspace[curr_char] = towupper(workspace[curr_char]);
01791 wasalnum = iswalnum(workspace[curr_char]);
01792 }
01793 }
01794
01795
01796 result_size = curr_char * pg_database_encoding_max_length() + 1;
01797 result = palloc(result_size);
01798
01799 wchar2char(result, workspace, result_size, mylocale);
01800 pfree(workspace);
01801 }
01802 #endif
01803 else
01804 {
01805 #ifdef HAVE_LOCALE_T
01806 pg_locale_t mylocale = 0;
01807 #endif
01808 char *p;
01809
01810 if (collid != DEFAULT_COLLATION_OID)
01811 {
01812 if (!OidIsValid(collid))
01813 {
01814
01815
01816
01817
01818 ereport(ERROR,
01819 (errcode(ERRCODE_INDETERMINATE_COLLATION),
01820 errmsg("could not determine which collation to use for initcap() function"),
01821 errhint("Use the COLLATE clause to set the collation explicitly.")));
01822 }
01823 #ifdef HAVE_LOCALE_T
01824 mylocale = pg_newlocale_from_collation(collid);
01825 #endif
01826 }
01827
01828 result = pnstrdup(buff, nbytes);
01829
01830
01831
01832
01833
01834
01835
01836
01837 for (p = result; *p; p++)
01838 {
01839 #ifdef HAVE_LOCALE_T
01840 if (mylocale)
01841 {
01842 if (wasalnum)
01843 *p = tolower_l((unsigned char) *p, mylocale);
01844 else
01845 *p = toupper_l((unsigned char) *p, mylocale);
01846 wasalnum = isalnum_l((unsigned char) *p, mylocale);
01847 }
01848 else
01849 #endif
01850 {
01851 if (wasalnum)
01852 *p = pg_tolower((unsigned char) *p);
01853 else
01854 *p = pg_toupper((unsigned char) *p);
01855 wasalnum = isalnum((unsigned char) *p);
01856 }
01857 }
01858 }
01859
01860 return result;
01861 }
01862
01863
01864
01865
01866
01867
01868
01869 char *
01870 asc_tolower(const char *buff, size_t nbytes)
01871 {
01872 char *result;
01873 char *p;
01874
01875 if (!buff)
01876 return NULL;
01877
01878 result = pnstrdup(buff, nbytes);
01879
01880 for (p = result; *p; p++)
01881 *p = pg_ascii_tolower((unsigned char) *p);
01882
01883 return result;
01884 }
01885
01886
01887
01888
01889
01890
01891
01892 char *
01893 asc_toupper(const char *buff, size_t nbytes)
01894 {
01895 char *result;
01896 char *p;
01897
01898 if (!buff)
01899 return NULL;
01900
01901 result = pnstrdup(buff, nbytes);
01902
01903 for (p = result; *p; p++)
01904 *p = pg_ascii_toupper((unsigned char) *p);
01905
01906 return result;
01907 }
01908
01909
01910
01911
01912
01913
01914
01915 char *
01916 asc_initcap(const char *buff, size_t nbytes)
01917 {
01918 char *result;
01919 char *p;
01920 int wasalnum = false;
01921
01922 if (!buff)
01923 return NULL;
01924
01925 result = pnstrdup(buff, nbytes);
01926
01927 for (p = result; *p; p++)
01928 {
01929 char c;
01930
01931 if (wasalnum)
01932 *p = c = pg_ascii_tolower((unsigned char) *p);
01933 else
01934 *p = c = pg_ascii_toupper((unsigned char) *p);
01935
01936 wasalnum = ((c >= 'A' && c <= 'Z') ||
01937 (c >= 'a' && c <= 'z') ||
01938 (c >= '0' && c <= '9'));
01939 }
01940
01941 return result;
01942 }
01943
01944
01945
01946 static char *
01947 str_tolower_z(const char *buff, Oid collid)
01948 {
01949 return str_tolower(buff, strlen(buff), collid);
01950 }
01951
01952 static char *
01953 str_toupper_z(const char *buff, Oid collid)
01954 {
01955 return str_toupper(buff, strlen(buff), collid);
01956 }
01957
01958 static char *
01959 str_initcap_z(const char *buff, Oid collid)
01960 {
01961 return str_initcap(buff, strlen(buff), collid);
01962 }
01963
01964 static char *
01965 asc_tolower_z(const char *buff)
01966 {
01967 return asc_tolower(buff, strlen(buff));
01968 }
01969
01970 static char *
01971 asc_toupper_z(const char *buff)
01972 {
01973 return asc_toupper(buff, strlen(buff));
01974 }
01975
01976
01977
01978
01979
01980
01981
01982
01983 #define SKIP_THth(_suf) (S_THth(_suf) ? 2 : 0)
01984
01985 #ifdef DEBUG_TO_FROM_CHAR
01986
01987
01988
01989
01990
01991 static void
01992 dump_index(const KeyWord *k, const int *index)
01993 {
01994 int i,
01995 count = 0,
01996 free_i = 0;
01997
01998 elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:");
01999
02000 for (i = 0; i < KeyWord_INDEX_SIZE; i++)
02001 {
02002 if (index[i] != -1)
02003 {
02004 elog(DEBUG_elog_output, "\t%c: %s, ", i + 32, k[index[i]].name);
02005 count++;
02006 }
02007 else
02008 {
02009 free_i++;
02010 elog(DEBUG_elog_output, "\t(%d) %c %d", i, i + 32, index[i]);
02011 }
02012 }
02013 elog(DEBUG_elog_output, "\n\t\tUsed positions: %d,\n\t\tFree positions: %d",
02014 count, free_i);
02015 }
02016 #endif
02017
02018
02019
02020
02021
02022 static bool
02023 is_next_separator(FormatNode *n)
02024 {
02025 if (n->type == NODE_TYPE_END)
02026 return FALSE;
02027
02028 if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
02029 return TRUE;
02030
02031
02032
02033
02034 n++;
02035
02036
02037 if (n->type == NODE_TYPE_END)
02038 return TRUE;
02039
02040 if (n->type == NODE_TYPE_ACTION)
02041 {
02042 if (n->key->is_digit)
02043 return FALSE;
02044
02045 return TRUE;
02046 }
02047 else if (isdigit((unsigned char) n->character))
02048 return FALSE;
02049
02050 return TRUE;
02051 }
02052
02053
02054 static int
02055 adjust_partial_year_to_2020(int year)
02056 {
02057
02058
02059
02060
02061
02062 if (year < 70)
02063 return year + 2000;
02064
02065 else if (year < 100)
02066 return year + 1900;
02067
02068 else if (year < 520)
02069 return year + 2000;
02070
02071 else if (year < 1000)
02072 return year + 1000;
02073 else
02074 return year;
02075 }
02076
02077
02078 static int
02079 strspace_len(char *str)
02080 {
02081 int len = 0;
02082
02083 while (*str && isspace((unsigned char) *str))
02084 {
02085 str++;
02086 len++;
02087 }
02088 return len;
02089 }
02090
02091 static int
02092 strdigits_len(char *str)
02093 {
02094 char *p = str;
02095 int len;
02096
02097 len = strspace_len(str);
02098 p += len;
02099
02100 while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ)
02101 {
02102 len++;
02103 p++;
02104 }
02105 return len;
02106 }
02107
02108
02109
02110
02111
02112
02113
02114 static void
02115 from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode)
02116 {
02117 if (mode != FROM_CHAR_DATE_NONE)
02118 {
02119 if (tmfc->mode == FROM_CHAR_DATE_NONE)
02120 tmfc->mode = mode;
02121 else if (tmfc->mode != mode)
02122 ereport(ERROR,
02123 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02124 errmsg("invalid combination of date conventions"),
02125 errhint("Do not mix Gregorian and ISO week date "
02126 "conventions in a formatting template.")));
02127 }
02128 }
02129
02130
02131
02132
02133
02134
02135
02136 static void
02137 from_char_set_int(int *dest, const int value, const FormatNode *node)
02138 {
02139 if (*dest != 0 && *dest != value)
02140 ereport(ERROR,
02141 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02142 errmsg("conflicting values for \"%s\" field in formatting string",
02143 node->key->name),
02144 errdetail("This value contradicts a previous setting for "
02145 "the same field type.")));
02146 *dest = value;
02147 }
02148
02149
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166
02167
02168
02169 static int
02170 from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node)
02171 {
02172 long result;
02173 char copy[DCH_MAX_ITEM_SIZ + 1];
02174 char *init = *src;
02175 int used;
02176
02177
02178
02179
02180 *src += strspace_len(*src);
02181
02182 Assert(len <= DCH_MAX_ITEM_SIZ);
02183 used = (int) strlcpy(copy, *src, len + 1);
02184
02185 if (S_FM(node->suffix) || is_next_separator(node))
02186 {
02187
02188
02189
02190
02191 errno = 0;
02192 result = strtol(init, src, 10);
02193 }
02194 else
02195 {
02196
02197
02198
02199
02200 char *last;
02201
02202 if (used < len)
02203 ereport(ERROR,
02204 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02205 errmsg("source string too short for \"%s\" formatting field",
02206 node->key->name),
02207 errdetail("Field requires %d characters, but only %d "
02208 "remain.",
02209 len, used),
02210 errhint("If your source string is not fixed-width, try "
02211 "using the \"FM\" modifier.")));
02212
02213 errno = 0;
02214 result = strtol(copy, &last, 10);
02215 used = last - copy;
02216
02217 if (used > 0 && used < len)
02218 ereport(ERROR,
02219 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02220 errmsg("invalid value \"%s\" for \"%s\"",
02221 copy, node->key->name),
02222 errdetail("Field requires %d characters, but only %d "
02223 "could be parsed.", len, used),
02224 errhint("If your source string is not fixed-width, try "
02225 "using the \"FM\" modifier.")));
02226
02227 *src += used;
02228 }
02229
02230 if (*src == init)
02231 ereport(ERROR,
02232 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02233 errmsg("invalid value \"%s\" for \"%s\"",
02234 copy, node->key->name),
02235 errdetail("Value must be an integer.")));
02236
02237 if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
02238 ereport(ERROR,
02239 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
02240 errmsg("value for \"%s\" in source string is out of range",
02241 node->key->name),
02242 errdetail("Value must be in the range %d to %d.",
02243 INT_MIN, INT_MAX)));
02244
02245 if (dest != NULL)
02246 from_char_set_int(dest, (int) result, node);
02247 return *src - init;
02248 }
02249
02250
02251
02252
02253
02254
02255
02256
02257
02258
02259 static int
02260 from_char_parse_int(int *dest, char **src, FormatNode *node)
02261 {
02262 return from_char_parse_int_len(dest, src, node->key->len, node);
02263 }
02264
02265
02266
02267
02268
02269 static int
02270 seq_search(char *name, char **array, int type, int max, int *len)
02271 {
02272 char *p,
02273 *n,
02274 **a;
02275 int last,
02276 i;
02277
02278 *len = 0;
02279
02280 if (!*name)
02281 return -1;
02282
02283
02284 if (type == ONE_UPPER || type == ALL_UPPER)
02285 *name = pg_toupper((unsigned char) *name);
02286 else if (type == ALL_LOWER)
02287 *name = pg_tolower((unsigned char) *name);
02288
02289 for (last = 0, a = array; *a != NULL; a++)
02290 {
02291
02292 if (*name != **a)
02293 continue;
02294
02295 for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++)
02296 {
02297
02298 if (max && i == max)
02299 {
02300 *len = i;
02301 return a - array;
02302 }
02303
02304 if (*p == '\0')
02305 {
02306 *len = i;
02307 return a - array;
02308 }
02309
02310 if (*n == '\0')
02311 break;
02312
02313
02314
02315
02316 if (i > last)
02317 {
02318 if (type == ONE_UPPER || type == ALL_LOWER)
02319 *n = pg_tolower((unsigned char) *n);
02320 else if (type == ALL_UPPER)
02321 *n = pg_toupper((unsigned char) *n);
02322 last = i;
02323 }
02324
02325 #ifdef DEBUG_TO_FROM_CHAR
02326 elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)",
02327 *n, *p, *a, name);
02328 #endif
02329 if (*n != *p)
02330 break;
02331 }
02332 }
02333
02334 return -1;
02335 }
02336
02337
02338
02339
02340
02341
02342
02343
02344
02345
02346
02347 static int
02348 from_char_seq_search(int *dest, char **src, char **array, int type, int max,
02349 FormatNode *node)
02350 {
02351 int len;
02352
02353 *dest = seq_search(*src, array, type, max, &len);
02354 if (len <= 0)
02355 {
02356 char copy[DCH_MAX_ITEM_SIZ + 1];
02357
02358 Assert(max <= DCH_MAX_ITEM_SIZ);
02359 strlcpy(copy, *src, max + 1);
02360
02361 ereport(ERROR,
02362 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
02363 errmsg("invalid value \"%s\" for \"%s\"",
02364 copy, node->key->name),
02365 errdetail("The given value did not match any of the allowed "
02366 "values for this field.")));
02367 }
02368 *src += len;
02369 return len;
02370 }
02371
02372
02373
02374
02375
02376
02377 static void
02378 DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
02379 {
02380 FormatNode *n;
02381 char *s;
02382 struct pg_tm *tm = &in->tm;
02383 int i;
02384
02385
02386 cache_locale_time();
02387
02388 s = out;
02389 for (n = node; n->type != NODE_TYPE_END; n++)
02390 {
02391 if (n->type != NODE_TYPE_ACTION)
02392 {
02393 *s = n->character;
02394 s++;
02395 continue;
02396 }
02397
02398 switch (n->key->id)
02399 {
02400 case DCH_A_M:
02401 case DCH_P_M:
02402 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02403 ? P_M_STR : A_M_STR);
02404 s += strlen(s);
02405 break;
02406 case DCH_AM:
02407 case DCH_PM:
02408 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02409 ? PM_STR : AM_STR);
02410 s += strlen(s);
02411 break;
02412 case DCH_a_m:
02413 case DCH_p_m:
02414 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02415 ? p_m_STR : a_m_STR);
02416 s += strlen(s);
02417 break;
02418 case DCH_am:
02419 case DCH_pm:
02420 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
02421 ? pm_STR : am_STR);
02422 s += strlen(s);
02423 break;
02424 case DCH_HH:
02425 case DCH_HH12:
02426
02427
02428
02429
02430
02431 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
02432 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? HOURS_PER_DAY / 2 :
02433 tm->tm_hour % (HOURS_PER_DAY / 2));
02434 if (S_THth(n->suffix))
02435 str_numth(s, s, S_TH_TYPE(n->suffix));
02436 s += strlen(s);
02437 break;
02438 case DCH_HH24:
02439 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_hour);
02440 if (S_THth(n->suffix))
02441 str_numth(s, s, S_TH_TYPE(n->suffix));
02442 s += strlen(s);
02443 break;
02444 case DCH_MI:
02445 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_min);
02446 if (S_THth(n->suffix))
02447 str_numth(s, s, S_TH_TYPE(n->suffix));
02448 s += strlen(s);
02449 break;
02450 case DCH_SS:
02451 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_sec);
02452 if (S_THth(n->suffix))
02453 str_numth(s, s, S_TH_TYPE(n->suffix));
02454 s += strlen(s);
02455 break;
02456 case DCH_MS:
02457 #ifdef HAVE_INT64_TIMESTAMP
02458 sprintf(s, "%03d", (int) (in->fsec / INT64CONST(1000)));
02459 #else
02460
02461 sprintf(s, "%03d", (int) (in->fsec * 1000));
02462 #endif
02463 if (S_THth(n->suffix))
02464 str_numth(s, s, S_TH_TYPE(n->suffix));
02465 s += strlen(s);
02466 break;
02467 case DCH_US:
02468 #ifdef HAVE_INT64_TIMESTAMP
02469 sprintf(s, "%06d", (int) in->fsec);
02470 #else
02471
02472 sprintf(s, "%06d", (int) (in->fsec * 1000000));
02473 #endif
02474 if (S_THth(n->suffix))
02475 str_numth(s, s, S_TH_TYPE(n->suffix));
02476 s += strlen(s);
02477 break;
02478 case DCH_SSSS:
02479 sprintf(s, "%d", tm->tm_hour * SECS_PER_HOUR +
02480 tm->tm_min * SECS_PER_MINUTE +
02481 tm->tm_sec);
02482 if (S_THth(n->suffix))
02483 str_numth(s, s, S_TH_TYPE(n->suffix));
02484 s += strlen(s);
02485 break;
02486 case DCH_tz:
02487 INVALID_FOR_INTERVAL;
02488 if (tmtcTzn(in))
02489 {
02490
02491 char *p = asc_tolower_z(tmtcTzn(in));
02492
02493 strcpy(s, p);
02494 pfree(p);
02495 s += strlen(s);
02496 }
02497 break;
02498 case DCH_TZ:
02499 INVALID_FOR_INTERVAL;
02500 if (tmtcTzn(in))
02501 {
02502 strcpy(s, tmtcTzn(in));
02503 s += strlen(s);
02504 }
02505 break;
02506 case DCH_A_D:
02507 case DCH_B_C:
02508 INVALID_FOR_INTERVAL;
02509 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
02510 s += strlen(s);
02511 break;
02512 case DCH_AD:
02513 case DCH_BC:
02514 INVALID_FOR_INTERVAL;
02515 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
02516 s += strlen(s);
02517 break;
02518 case DCH_a_d:
02519 case DCH_b_c:
02520 INVALID_FOR_INTERVAL;
02521 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
02522 s += strlen(s);
02523 break;
02524 case DCH_ad:
02525 case DCH_bc:
02526 INVALID_FOR_INTERVAL;
02527 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
02528 s += strlen(s);
02529 break;
02530 case DCH_MONTH:
02531 INVALID_FOR_INTERVAL;
02532 if (!tm->tm_mon)
02533 break;
02534 if (S_TM(n->suffix))
02535 strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1], collid));
02536 else
02537 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02538 asc_toupper_z(months_full[tm->tm_mon - 1]));
02539 s += strlen(s);
02540 break;
02541 case DCH_Month:
02542 INVALID_FOR_INTERVAL;
02543 if (!tm->tm_mon)
02544 break;
02545 if (S_TM(n->suffix))
02546 strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1], collid));
02547 else
02548 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02549 months_full[tm->tm_mon - 1]);
02550 s += strlen(s);
02551 break;
02552 case DCH_month:
02553 INVALID_FOR_INTERVAL;
02554 if (!tm->tm_mon)
02555 break;
02556 if (S_TM(n->suffix))
02557 strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1], collid));
02558 else
02559 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02560 asc_tolower_z(months_full[tm->tm_mon - 1]));
02561 s += strlen(s);
02562 break;
02563 case DCH_MON:
02564 INVALID_FOR_INTERVAL;
02565 if (!tm->tm_mon)
02566 break;
02567 if (S_TM(n->suffix))
02568 strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid));
02569 else
02570 strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
02571 s += strlen(s);
02572 break;
02573 case DCH_Mon:
02574 INVALID_FOR_INTERVAL;
02575 if (!tm->tm_mon)
02576 break;
02577 if (S_TM(n->suffix))
02578 strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid));
02579 else
02580 strcpy(s, months[tm->tm_mon - 1]);
02581 s += strlen(s);
02582 break;
02583 case DCH_mon:
02584 INVALID_FOR_INTERVAL;
02585 if (!tm->tm_mon)
02586 break;
02587 if (S_TM(n->suffix))
02588 strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid));
02589 else
02590 strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
02591 s += strlen(s);
02592 break;
02593 case DCH_MM:
02594 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mon);
02595 if (S_THth(n->suffix))
02596 str_numth(s, s, S_TH_TYPE(n->suffix));
02597 s += strlen(s);
02598 break;
02599 case DCH_DAY:
02600 INVALID_FOR_INTERVAL;
02601 if (S_TM(n->suffix))
02602 strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday], collid));
02603 else
02604 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02605 asc_toupper_z(days[tm->tm_wday]));
02606 s += strlen(s);
02607 break;
02608 case DCH_Day:
02609 INVALID_FOR_INTERVAL;
02610 if (S_TM(n->suffix))
02611 strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday], collid));
02612 else
02613 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02614 days[tm->tm_wday]);
02615 s += strlen(s);
02616 break;
02617 case DCH_day:
02618 INVALID_FOR_INTERVAL;
02619 if (S_TM(n->suffix))
02620 strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday], collid));
02621 else
02622 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
02623 asc_tolower_z(days[tm->tm_wday]));
02624 s += strlen(s);
02625 break;
02626 case DCH_DY:
02627 INVALID_FOR_INTERVAL;
02628 if (S_TM(n->suffix))
02629 strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday], collid));
02630 else
02631 strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
02632 s += strlen(s);
02633 break;
02634 case DCH_Dy:
02635 INVALID_FOR_INTERVAL;
02636 if (S_TM(n->suffix))
02637 strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday], collid));
02638 else
02639 strcpy(s, days_short[tm->tm_wday]);
02640 s += strlen(s);
02641 break;
02642 case DCH_dy:
02643 INVALID_FOR_INTERVAL;
02644 if (S_TM(n->suffix))
02645 strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday], collid));
02646 else
02647 strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
02648 s += strlen(s);
02649 break;
02650 case DCH_DDD:
02651 case DCH_IDDD:
02652 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
02653 (n->key->id == DCH_DDD) ?
02654 tm->tm_yday :
02655 date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday));
02656 if (S_THth(n->suffix))
02657 str_numth(s, s, S_TH_TYPE(n->suffix));
02658 s += strlen(s);
02659 break;
02660 case DCH_DD:
02661 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
02662 if (S_THth(n->suffix))
02663 str_numth(s, s, S_TH_TYPE(n->suffix));
02664 s += strlen(s);
02665 break;
02666 case DCH_D:
02667 INVALID_FOR_INTERVAL;
02668 sprintf(s, "%d", tm->tm_wday + 1);
02669 if (S_THth(n->suffix))
02670 str_numth(s, s, S_TH_TYPE(n->suffix));
02671 s += strlen(s);
02672 break;
02673 case DCH_ID:
02674 INVALID_FOR_INTERVAL;
02675 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
02676 if (S_THth(n->suffix))
02677 str_numth(s, s, S_TH_TYPE(n->suffix));
02678 s += strlen(s);
02679 break;
02680 case DCH_WW:
02681 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
02682 (tm->tm_yday - 1) / 7 + 1);
02683 if (S_THth(n->suffix))
02684 str_numth(s, s, S_TH_TYPE(n->suffix));
02685 s += strlen(s);
02686 break;
02687 case DCH_IW:
02688 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
02689 date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
02690 if (S_THth(n->suffix))
02691 str_numth(s, s, S_TH_TYPE(n->suffix));
02692 s += strlen(s);
02693 break;
02694 case DCH_Q:
02695 if (!tm->tm_mon)
02696 break;
02697 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
02698 if (S_THth(n->suffix))
02699 str_numth(s, s, S_TH_TYPE(n->suffix));
02700 s += strlen(s);
02701 break;
02702 case DCH_CC:
02703 if (is_interval)
02704 i = tm->tm_year / 100;
02705 else
02706 {
02707 if (tm->tm_year > 0)
02708
02709 i = (tm->tm_year - 1) / 100 + 1;
02710 else
02711
02712 i = tm->tm_year / 100 - 1;
02713 }
02714 if (i <= 99 && i >= -99)
02715 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, i);
02716 else
02717 sprintf(s, "%d", i);
02718 if (S_THth(n->suffix))
02719 str_numth(s, s, S_TH_TYPE(n->suffix));
02720 s += strlen(s);
02721 break;
02722 case DCH_Y_YYY:
02723 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
02724 sprintf(s, "%d,%03d", i,
02725 ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
02726 if (S_THth(n->suffix))
02727 str_numth(s, s, S_TH_TYPE(n->suffix));
02728 s += strlen(s);
02729 break;
02730 case DCH_YYYY:
02731 case DCH_IYYY:
02732 sprintf(s, "%0*d",
02733 S_FM(n->suffix) ? 0 : 4,
02734 (n->key->id == DCH_YYYY ?
02735 ADJUST_YEAR(tm->tm_year, is_interval) :
02736 ADJUST_YEAR(date2isoyear(tm->tm_year,
02737 tm->tm_mon,
02738 tm->tm_mday),
02739 is_interval)));
02740 if (S_THth(n->suffix))
02741 str_numth(s, s, S_TH_TYPE(n->suffix));
02742 s += strlen(s);
02743 break;
02744 case DCH_YYY:
02745 case DCH_IYY:
02746 sprintf(s, "%0*d",
02747 S_FM(n->suffix) ? 0 : 3,
02748 (n->key->id == DCH_YYY ?
02749 ADJUST_YEAR(tm->tm_year, is_interval) :
02750 ADJUST_YEAR(date2isoyear(tm->tm_year,
02751 tm->tm_mon,
02752 tm->tm_mday),
02753 is_interval)) % 1000);
02754 if (S_THth(n->suffix))
02755 str_numth(s, s, S_TH_TYPE(n->suffix));
02756 s += strlen(s);
02757 break;
02758 case DCH_YY:
02759 case DCH_IY:
02760 sprintf(s, "%0*d",
02761 S_FM(n->suffix) ? 0 : 2,
02762 (n->key->id == DCH_YY ?
02763 ADJUST_YEAR(tm->tm_year, is_interval) :
02764 ADJUST_YEAR(date2isoyear(tm->tm_year,
02765 tm->tm_mon,
02766 tm->tm_mday),
02767 is_interval)) % 100);
02768 if (S_THth(n->suffix))
02769 str_numth(s, s, S_TH_TYPE(n->suffix));
02770 s += strlen(s);
02771 break;
02772 case DCH_Y:
02773 case DCH_I:
02774 sprintf(s, "%1d",
02775 (n->key->id == DCH_Y ?
02776 ADJUST_YEAR(tm->tm_year, is_interval) :
02777 ADJUST_YEAR(date2isoyear(tm->tm_year,
02778 tm->tm_mon,
02779 tm->tm_mday),
02780 is_interval)) % 10);
02781 if (S_THth(n->suffix))
02782 str_numth(s, s, S_TH_TYPE(n->suffix));
02783 s += strlen(s);
02784 break;
02785 case DCH_RM:
02786 if (!tm->tm_mon)
02787 break;
02788 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
02789 rm_months_upper[MONTHS_PER_YEAR - tm->tm_mon]);
02790 s += strlen(s);
02791 break;
02792 case DCH_rm:
02793 if (!tm->tm_mon)
02794 break;
02795 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
02796 rm_months_lower[MONTHS_PER_YEAR - tm->tm_mon]);
02797 s += strlen(s);
02798 break;
02799 case DCH_W:
02800 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
02801 if (S_THth(n->suffix))
02802 str_numth(s, s, S_TH_TYPE(n->suffix));
02803 s += strlen(s);
02804 break;
02805 case DCH_J:
02806 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
02807 if (S_THth(n->suffix))
02808 str_numth(s, s, S_TH_TYPE(n->suffix));
02809 s += strlen(s);
02810 break;
02811 }
02812 }
02813
02814 *s = '\0';
02815 }
02816
02817
02818
02819
02820
02821
02822
02823
02824
02825 static void
02826 DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
02827 {
02828 FormatNode *n;
02829 char *s;
02830 int len,
02831 value;
02832 bool fx_mode = false;
02833
02834 for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
02835 {
02836 if (n->type != NODE_TYPE_ACTION)
02837 {
02838 s++;
02839
02840 if (isspace((unsigned char) n->character) && !fx_mode)
02841 {
02842 while (*s != '\0' && isspace((unsigned char) *s))
02843 s++;
02844 }
02845 continue;
02846 }
02847
02848 from_char_set_mode(out, n->key->date_mode);
02849
02850 switch (n->key->id)
02851 {
02852 case DCH_FX:
02853 fx_mode = true;
02854 break;
02855 case DCH_A_M:
02856 case DCH_P_M:
02857 case DCH_a_m:
02858 case DCH_p_m:
02859 from_char_seq_search(&value, &s, ampm_strings_long,
02860 ALL_UPPER, n->key->len, n);
02861 from_char_set_int(&out->pm, value % 2, n);
02862 out->clock = CLOCK_12_HOUR;
02863 break;
02864 case DCH_AM:
02865 case DCH_PM:
02866 case DCH_am:
02867 case DCH_pm:
02868 from_char_seq_search(&value, &s, ampm_strings,
02869 ALL_UPPER, n->key->len, n);
02870 from_char_set_int(&out->pm, value % 2, n);
02871 out->clock = CLOCK_12_HOUR;
02872 break;
02873 case DCH_HH:
02874 case DCH_HH12:
02875 from_char_parse_int_len(&out->hh, &s, 2, n);
02876 out->clock = CLOCK_12_HOUR;
02877 s += SKIP_THth(n->suffix);
02878 break;
02879 case DCH_HH24:
02880 from_char_parse_int_len(&out->hh, &s, 2, n);
02881 s += SKIP_THth(n->suffix);
02882 break;
02883 case DCH_MI:
02884 from_char_parse_int(&out->mi, &s, n);
02885 s += SKIP_THth(n->suffix);
02886 break;
02887 case DCH_SS:
02888 from_char_parse_int(&out->ss, &s, n);
02889 s += SKIP_THth(n->suffix);
02890 break;
02891 case DCH_MS:
02892 len = from_char_parse_int_len(&out->ms, &s, 3, n);
02893
02894
02895
02896
02897 out->ms *= len == 1 ? 100 :
02898 len == 2 ? 10 : 1;
02899
02900 s += SKIP_THth(n->suffix);
02901 break;
02902 case DCH_US:
02903 len = from_char_parse_int_len(&out->us, &s, 6, n);
02904
02905 out->us *= len == 1 ? 100000 :
02906 len == 2 ? 10000 :
02907 len == 3 ? 1000 :
02908 len == 4 ? 100 :
02909 len == 5 ? 10 : 1;
02910
02911 s += SKIP_THth(n->suffix);
02912 break;
02913 case DCH_SSSS:
02914 from_char_parse_int(&out->ssss, &s, n);
02915 s += SKIP_THth(n->suffix);
02916 break;
02917 case DCH_tz:
02918 case DCH_TZ:
02919 ereport(ERROR,
02920 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02921 errmsg("\"TZ\"/\"tz\" format patterns are not supported in to_date")));
02922 case DCH_A_D:
02923 case DCH_B_C:
02924 case DCH_a_d:
02925 case DCH_b_c:
02926 from_char_seq_search(&value, &s, adbc_strings_long,
02927 ALL_UPPER, n->key->len, n);
02928 from_char_set_int(&out->bc, value % 2, n);
02929 break;
02930 case DCH_AD:
02931 case DCH_BC:
02932 case DCH_ad:
02933 case DCH_bc:
02934 from_char_seq_search(&value, &s, adbc_strings,
02935 ALL_UPPER, n->key->len, n);
02936 from_char_set_int(&out->bc, value % 2, n);
02937 break;
02938 case DCH_MONTH:
02939 case DCH_Month:
02940 case DCH_month:
02941 from_char_seq_search(&value, &s, months_full, ONE_UPPER,
02942 MAX_MONTH_LEN, n);
02943 from_char_set_int(&out->mm, value + 1, n);
02944 break;
02945 case DCH_MON:
02946 case DCH_Mon:
02947 case DCH_mon:
02948 from_char_seq_search(&value, &s, months, ONE_UPPER,
02949 MAX_MON_LEN, n);
02950 from_char_set_int(&out->mm, value + 1, n);
02951 break;
02952 case DCH_MM:
02953 from_char_parse_int(&out->mm, &s, n);
02954 s += SKIP_THth(n->suffix);
02955 break;
02956 case DCH_DAY:
02957 case DCH_Day:
02958 case DCH_day:
02959 from_char_seq_search(&value, &s, days, ONE_UPPER,
02960 MAX_DAY_LEN, n);
02961 from_char_set_int(&out->d, value, n);
02962 out->d++;
02963 break;
02964 case DCH_DY:
02965 case DCH_Dy:
02966 case DCH_dy:
02967 from_char_seq_search(&value, &s, days, ONE_UPPER,
02968 MAX_DY_LEN, n);
02969 from_char_set_int(&out->d, value, n);
02970 out->d++;
02971 break;
02972 case DCH_DDD:
02973 from_char_parse_int(&out->ddd, &s, n);
02974 s += SKIP_THth(n->suffix);
02975 break;
02976 case DCH_IDDD:
02977 from_char_parse_int_len(&out->ddd, &s, 3, n);
02978 s += SKIP_THth(n->suffix);
02979 break;
02980 case DCH_DD:
02981 from_char_parse_int(&out->dd, &s, n);
02982 s += SKIP_THth(n->suffix);
02983 break;
02984 case DCH_D:
02985 from_char_parse_int(&out->d, &s, n);
02986 s += SKIP_THth(n->suffix);
02987 break;
02988 case DCH_ID:
02989 from_char_parse_int_len(&out->d, &s, 1, n);
02990
02991 if (++out->d > 7)
02992 out->d = 1;
02993 s += SKIP_THth(n->suffix);
02994 break;
02995 case DCH_WW:
02996 case DCH_IW:
02997 from_char_parse_int(&out->ww, &s, n);
02998 s += SKIP_THth(n->suffix);
02999 break;
03000 case DCH_Q:
03001
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012 from_char_parse_int((int *) NULL, &s, n);
03013 s += SKIP_THth(n->suffix);
03014 break;
03015 case DCH_CC:
03016 from_char_parse_int(&out->cc, &s, n);
03017 s += SKIP_THth(n->suffix);
03018 break;
03019 case DCH_Y_YYY:
03020 {
03021 int matched,
03022 years,
03023 millenia;
03024
03025 matched = sscanf(s, "%d,%03d", &millenia, &years);
03026 if (matched != 2)
03027 ereport(ERROR,
03028 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
03029 errmsg("invalid input string for \"Y,YYY\"")));
03030 years += (millenia * 1000);
03031 from_char_set_int(&out->year, years, n);
03032 out->yysz = 4;
03033 s += strdigits_len(s) + 4 + SKIP_THth(n->suffix);
03034 }
03035 break;
03036 case DCH_YYYY:
03037 case DCH_IYYY:
03038 from_char_parse_int(&out->year, &s, n);
03039 out->yysz = 4;
03040 s += SKIP_THth(n->suffix);
03041 break;
03042 case DCH_YYY:
03043 case DCH_IYY:
03044 if (from_char_parse_int(&out->year, &s, n) < 4)
03045 out->year = adjust_partial_year_to_2020(out->year);
03046 out->yysz = 3;
03047 s += SKIP_THth(n->suffix);
03048 break;
03049 case DCH_YY:
03050 case DCH_IY:
03051 if (from_char_parse_int(&out->year, &s, n) < 4)
03052 out->year = adjust_partial_year_to_2020(out->year);
03053 out->yysz = 2;
03054 s += SKIP_THth(n->suffix);
03055 break;
03056 case DCH_Y:
03057 case DCH_I:
03058 if (from_char_parse_int(&out->year, &s, n) < 4)
03059 out->year = adjust_partial_year_to_2020(out->year);
03060 out->yysz = 1;
03061 s += SKIP_THth(n->suffix);
03062 break;
03063 case DCH_RM:
03064 from_char_seq_search(&value, &s, rm_months_upper,
03065 ALL_UPPER, MAX_RM_LEN, n);
03066 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
03067 break;
03068 case DCH_rm:
03069 from_char_seq_search(&value, &s, rm_months_lower,
03070 ALL_LOWER, MAX_RM_LEN, n);
03071 from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
03072 break;
03073 case DCH_W:
03074 from_char_parse_int(&out->w, &s, n);
03075 s += SKIP_THth(n->suffix);
03076 break;
03077 case DCH_J:
03078 from_char_parse_int(&out->j, &s, n);
03079 s += SKIP_THth(n->suffix);
03080 break;
03081 }
03082 }
03083 }
03084
03085 static DCHCacheEntry *
03086 DCH_cache_getnew(char *str)
03087 {
03088 DCHCacheEntry *ent;
03089
03090
03091 if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
03092 {
03093 DCHCounter = 0;
03094
03095 for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
03096 ent->age = (++DCHCounter);
03097 }
03098
03099
03100
03101
03102 if (n_DCHCache > DCH_CACHE_FIELDS)
03103 {
03104 DCHCacheEntry *old = DCHCache + 0;
03105
03106 #ifdef DEBUG_TO_FROM_CHAR
03107 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
03108 #endif
03109 for (ent = DCHCache + 1; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
03110 {
03111 if (ent->age < old->age)
03112 old = ent;
03113 }
03114 #ifdef DEBUG_TO_FROM_CHAR
03115 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
03116 #endif
03117 StrNCpy(old->str, str, DCH_CACHE_SIZE + 1);
03118
03119 old->age = (++DCHCounter);
03120 return old;
03121 }
03122 else
03123 {
03124 #ifdef DEBUG_TO_FROM_CHAR
03125 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
03126 #endif
03127 ent = DCHCache + n_DCHCache;
03128 StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1);
03129
03130 ent->age = (++DCHCounter);
03131 ++n_DCHCache;
03132 return ent;
03133 }
03134 }
03135
03136 static DCHCacheEntry *
03137 DCH_cache_search(char *str)
03138 {
03139 int i;
03140 DCHCacheEntry *ent;
03141
03142
03143 if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1))
03144 {
03145 DCHCounter = 0;
03146
03147 for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++)
03148 ent->age = (++DCHCounter);
03149 }
03150
03151 for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++)
03152 {
03153 if (strcmp(ent->str, str) == 0)
03154 {
03155 ent->age = (++DCHCounter);
03156 return ent;
03157 }
03158 }
03159
03160 return NULL;
03161 }
03162
03163
03164
03165
03166
03167
03168 static text *
03169 datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
03170 {
03171 FormatNode *format;
03172 char *fmt_str,
03173 *result;
03174 bool incache;
03175 int fmt_len;
03176 text *res;
03177
03178
03179
03180
03181 fmt_str = text_to_cstring(fmt);
03182 fmt_len = strlen(fmt_str);
03183
03184
03185
03186
03187 result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
03188 *result = '\0';
03189
03190
03191
03192
03193
03194 if (fmt_len > DCH_CACHE_SIZE)
03195 {
03196 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
03197 incache = FALSE;
03198
03199 parse_format(format, fmt_str, DCH_keywords,
03200 DCH_suff, DCH_index, DCH_TYPE, NULL);
03201
03202 (format + fmt_len)->type = NODE_TYPE_END;
03203 }
03204 else
03205 {
03206
03207
03208
03209 DCHCacheEntry *ent;
03210
03211 incache = TRUE;
03212
03213 if ((ent = DCH_cache_search(fmt_str)) == NULL)
03214 {
03215 ent = DCH_cache_getnew(fmt_str);
03216
03217
03218
03219
03220
03221 parse_format(ent->format, fmt_str, DCH_keywords,
03222 DCH_suff, DCH_index, DCH_TYPE, NULL);
03223
03224 (ent->format + fmt_len)->type = NODE_TYPE_END;
03225
03226 #ifdef DEBUG_TO_FROM_CHAR
03227
03228
03229 #endif
03230 }
03231 format = ent->format;
03232 }
03233
03234
03235 DCH_to_char(format, is_interval, tmtc, result, collid);
03236
03237 if (!incache)
03238 pfree(format);
03239
03240 pfree(fmt_str);
03241
03242
03243 res = cstring_to_text(result);
03244
03245 pfree(result);
03246 return res;
03247 }
03248
03249
03250
03251
03252
03253
03254
03255
03256
03257 Datum
03258 timestamp_to_char(PG_FUNCTION_ARGS)
03259 {
03260 Timestamp dt = PG_GETARG_TIMESTAMP(0);
03261 text *fmt = PG_GETARG_TEXT_P(1),
03262 *res;
03263 TmToChar tmtc;
03264 struct pg_tm *tm;
03265 int thisdate;
03266
03267 if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
03268 PG_RETURN_NULL();
03269
03270 ZERO_tmtc(&tmtc);
03271 tm = tmtcTm(&tmtc);
03272
03273 if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0)
03274 ereport(ERROR,
03275 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03276 errmsg("timestamp out of range")));
03277
03278 thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
03279 tm->tm_wday = (thisdate + 1) % 7;
03280 tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
03281
03282 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
03283 PG_RETURN_NULL();
03284
03285 PG_RETURN_TEXT_P(res);
03286 }
03287
03288 Datum
03289 timestamptz_to_char(PG_FUNCTION_ARGS)
03290 {
03291 TimestampTz dt = PG_GETARG_TIMESTAMP(0);
03292 text *fmt = PG_GETARG_TEXT_P(1),
03293 *res;
03294 TmToChar tmtc;
03295 int tz;
03296 struct pg_tm *tm;
03297 int thisdate;
03298
03299 if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt))
03300 PG_RETURN_NULL();
03301
03302 ZERO_tmtc(&tmtc);
03303 tm = tmtcTm(&tmtc);
03304
03305 if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
03306 ereport(ERROR,
03307 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03308 errmsg("timestamp out of range")));
03309
03310 thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday);
03311 tm->tm_wday = (thisdate + 1) % 7;
03312 tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1;
03313
03314 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
03315 PG_RETURN_NULL();
03316
03317 PG_RETURN_TEXT_P(res);
03318 }
03319
03320
03321
03322
03323
03324
03325 Datum
03326 interval_to_char(PG_FUNCTION_ARGS)
03327 {
03328 Interval *it = PG_GETARG_INTERVAL_P(0);
03329 text *fmt = PG_GETARG_TEXT_P(1),
03330 *res;
03331 TmToChar tmtc;
03332 struct pg_tm *tm;
03333
03334 if ((VARSIZE(fmt) - VARHDRSZ) <= 0)
03335 PG_RETURN_NULL();
03336
03337 ZERO_tmtc(&tmtc);
03338 tm = tmtcTm(&tmtc);
03339
03340 if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0)
03341 PG_RETURN_NULL();
03342
03343
03344 tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
03345
03346 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
03347 PG_RETURN_NULL();
03348
03349 PG_RETURN_TEXT_P(res);
03350 }
03351
03352
03353
03354
03355
03356
03357
03358
03359 Datum
03360 to_timestamp(PG_FUNCTION_ARGS)
03361 {
03362 text *date_txt = PG_GETARG_TEXT_P(0);
03363 text *fmt = PG_GETARG_TEXT_P(1);
03364 Timestamp result;
03365 int tz;
03366 struct pg_tm tm;
03367 fsec_t fsec;
03368
03369 do_to_timestamp(date_txt, fmt, &tm, &fsec);
03370
03371 tz = DetermineTimeZoneOffset(&tm, session_timezone);
03372
03373 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
03374 ereport(ERROR,
03375 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03376 errmsg("timestamp out of range")));
03377
03378 PG_RETURN_TIMESTAMP(result);
03379 }
03380
03381
03382
03383
03384
03385
03386 Datum
03387 to_date(PG_FUNCTION_ARGS)
03388 {
03389 text *date_txt = PG_GETARG_TEXT_P(0);
03390 text *fmt = PG_GETARG_TEXT_P(1);
03391 DateADT result;
03392 struct pg_tm tm;
03393 fsec_t fsec;
03394
03395 do_to_timestamp(date_txt, fmt, &tm, &fsec);
03396
03397 if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday))
03398 ereport(ERROR,
03399 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
03400 errmsg("date out of range: \"%s\"",
03401 text_to_cstring(date_txt))));
03402
03403 result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE;
03404
03405 PG_RETURN_DATEADT(result);
03406 }
03407
03408
03409
03410
03411
03412
03413
03414
03415
03416
03417
03418
03419
03420
03421
03422
03423
03424 static void
03425 do_to_timestamp(text *date_txt, text *fmt,
03426 struct pg_tm * tm, fsec_t *fsec)
03427 {
03428 FormatNode *format;
03429 TmFromChar tmfc;
03430 int fmt_len;
03431
03432 ZERO_tmfc(&tmfc);
03433 ZERO_tm(tm);
03434 *fsec = 0;
03435
03436 fmt_len = VARSIZE_ANY_EXHDR(fmt);
03437
03438 if (fmt_len)
03439 {
03440 char *fmt_str;
03441 char *date_str;
03442 bool incache;
03443
03444 fmt_str = text_to_cstring(fmt);
03445
03446
03447
03448
03449
03450 if (fmt_len > DCH_CACHE_SIZE)
03451 {
03452 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
03453 incache = FALSE;
03454
03455 parse_format(format, fmt_str, DCH_keywords,
03456 DCH_suff, DCH_index, DCH_TYPE, NULL);
03457
03458 (format + fmt_len)->type = NODE_TYPE_END;
03459 }
03460 else
03461 {
03462
03463
03464
03465 DCHCacheEntry *ent;
03466
03467 incache = TRUE;
03468
03469 if ((ent = DCH_cache_search(fmt_str)) == NULL)
03470 {
03471 ent = DCH_cache_getnew(fmt_str);
03472
03473
03474
03475
03476
03477 parse_format(ent->format, fmt_str, DCH_keywords,
03478 DCH_suff, DCH_index, DCH_TYPE, NULL);
03479
03480 (ent->format + fmt_len)->type = NODE_TYPE_END;
03481 #ifdef DEBUG_TO_FROM_CHAR
03482
03483
03484 #endif
03485 }
03486 format = ent->format;
03487 }
03488
03489 #ifdef DEBUG_TO_FROM_CHAR
03490
03491 #endif
03492
03493 date_str = text_to_cstring(date_txt);
03494
03495 DCH_from_char(format, date_str, &tmfc);
03496
03497 pfree(date_str);
03498 pfree(fmt_str);
03499 if (!incache)
03500 pfree(format);
03501 }
03502
03503 DEBUG_TMFC(&tmfc);
03504
03505
03506
03507
03508
03509 if (tmfc.ssss)
03510 {
03511 int x = tmfc.ssss;
03512
03513 tm->tm_hour = x / SECS_PER_HOUR;
03514 x %= SECS_PER_HOUR;
03515 tm->tm_min = x / SECS_PER_MINUTE;
03516 x %= SECS_PER_MINUTE;
03517 tm->tm_sec = x;
03518 }
03519
03520 if (tmfc.ss)
03521 tm->tm_sec = tmfc.ss;
03522 if (tmfc.mi)
03523 tm->tm_min = tmfc.mi;
03524 if (tmfc.hh)
03525 tm->tm_hour = tmfc.hh;
03526
03527 if (tmfc.clock == CLOCK_12_HOUR)
03528 {
03529 if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
03530 ereport(ERROR,
03531 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
03532 errmsg("hour \"%d\" is invalid for the 12-hour clock",
03533 tm->tm_hour),
03534 errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
03535
03536 if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
03537 tm->tm_hour += HOURS_PER_DAY / 2;
03538 else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
03539 tm->tm_hour = 0;
03540 }
03541
03542 if (tmfc.year)
03543 {
03544
03545
03546
03547
03548
03549
03550 if (tmfc.cc && tmfc.yysz <= 2)
03551 {
03552 if (tmfc.bc)
03553 tmfc.cc = -tmfc.cc;
03554 tm->tm_year = tmfc.year % 100;
03555 if (tm->tm_year)
03556 {
03557 if (tmfc.cc >= 0)
03558 tm->tm_year += (tmfc.cc - 1) * 100;
03559 else
03560 tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1;
03561 }
03562 else
03563
03564 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
03565 }
03566 else
03567
03568 {
03569 tm->tm_year = tmfc.year;
03570 if (tmfc.bc && tm->tm_year > 0)
03571 tm->tm_year = -(tm->tm_year - 1);
03572 }
03573 }
03574 else if (tmfc.cc)
03575 {
03576 if (tmfc.bc)
03577 tmfc.cc = -tmfc.cc;
03578 if (tmfc.cc >= 0)
03579
03580 tm->tm_year = (tmfc.cc - 1) * 100 + 1;
03581 else
03582
03583 tm->tm_year = tmfc.cc * 100 + 1;
03584 }
03585
03586 if (tmfc.j)
03587 j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03588
03589 if (tmfc.ww)
03590 {
03591 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
03592 {
03593
03594
03595
03596
03597 if (tmfc.d)
03598 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03599 else
03600 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03601 }
03602 else
03603 tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
03604 }
03605
03606 if (tmfc.w)
03607 tmfc.dd = (tmfc.w - 1) * 7 + 1;
03608 if (tmfc.d)
03609 tm->tm_wday = tmfc.d - 1;
03610 if (tmfc.dd)
03611 tm->tm_mday = tmfc.dd;
03612 if (tmfc.ddd)
03613 tm->tm_yday = tmfc.ddd;
03614 if (tmfc.mm)
03615 tm->tm_mon = tmfc.mm;
03616
03617 if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
03618 {
03619
03620
03621
03622
03623
03624
03625
03626 if (!tm->tm_year && !tmfc.bc)
03627 ereport(ERROR,
03628 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
03629 errmsg("cannot calculate day of year without year information")));
03630
03631 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
03632 {
03633 int j0;
03634
03635 j0 = isoweek2j(tm->tm_year, 1) - 1;
03636
03637 j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
03638 }
03639 else
03640 {
03641 const int *y;
03642 int i;
03643
03644 static const int ysum[2][13] = {
03645 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
03646 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
03647
03648 y = ysum[isleap(tm->tm_year)];
03649
03650 for (i = 1; i <= MONTHS_PER_YEAR; i++)
03651 {
03652 if (tmfc.ddd < y[i])
03653 break;
03654 }
03655 if (tm->tm_mon <= 1)
03656 tm->tm_mon = i;
03657
03658 if (tm->tm_mday <= 1)
03659 tm->tm_mday = tmfc.ddd - y[i - 1];
03660 }
03661 }
03662
03663 #ifdef HAVE_INT64_TIMESTAMP
03664 if (tmfc.ms)
03665 *fsec += tmfc.ms * 1000;
03666 if (tmfc.us)
03667 *fsec += tmfc.us;
03668 #else
03669 if (tmfc.ms)
03670 *fsec += (double) tmfc.ms / 1000;
03671 if (tmfc.us)
03672 *fsec += (double) tmfc.us / 1000000;
03673 #endif
03674
03675 DEBUG_TM(tm);
03676 }
03677
03678
03679
03680
03681
03682
03683
03684 static char *
03685 fill_str(char *str, int c, int max)
03686 {
03687 memset(str, c, max);
03688 *(str + max) = '\0';
03689 return str;
03690 }
03691
03692 #define zeroize_NUM(_n) \
03693 do { \
03694 (_n)->flag = 0; \
03695 (_n)->lsign = 0; \
03696 (_n)->pre = 0; \
03697 (_n)->post = 0; \
03698 (_n)->pre_lsign_num = 0; \
03699 (_n)->need_locale = 0; \
03700 (_n)->multi = 0; \
03701 (_n)->zero_start = 0; \
03702 (_n)->zero_end = 0; \
03703 } while(0)
03704
03705 static NUMCacheEntry *
03706 NUM_cache_getnew(char *str)
03707 {
03708 NUMCacheEntry *ent;
03709
03710
03711 if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
03712 {
03713 NUMCounter = 0;
03714
03715 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
03716 ent->age = (++NUMCounter);
03717 }
03718
03719
03720
03721
03722 if (n_NUMCache > NUM_CACHE_FIELDS)
03723 {
03724 NUMCacheEntry *old = NUMCache + 0;
03725
03726 #ifdef DEBUG_TO_FROM_CHAR
03727 elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
03728 #endif
03729 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
03730 {
03731
03732
03733
03734
03735 if (ent->str[0] == '\0')
03736 {
03737 old = ent;
03738 break;
03739 }
03740 if (ent->age < old->age)
03741 old = ent;
03742 }
03743 #ifdef DEBUG_TO_FROM_CHAR
03744 elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
03745 #endif
03746 StrNCpy(old->str, str, NUM_CACHE_SIZE + 1);
03747
03748 old->age = (++NUMCounter);
03749 ent = old;
03750 }
03751 else
03752 {
03753 #ifdef DEBUG_TO_FROM_CHAR
03754 elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
03755 #endif
03756 ent = NUMCache + n_NUMCache;
03757 StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1);
03758
03759 ent->age = (++NUMCounter);
03760 ++n_NUMCache;
03761 }
03762
03763 zeroize_NUM(&ent->Num);
03764
03765 last_NUMCacheEntry = ent;
03766 return ent;
03767 }
03768
03769 static NUMCacheEntry *
03770 NUM_cache_search(char *str)
03771 {
03772 int i;
03773 NUMCacheEntry *ent;
03774
03775
03776 if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1))
03777 {
03778 NUMCounter = 0;
03779
03780 for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++)
03781 ent->age = (++NUMCounter);
03782 }
03783
03784 for (i = 0, ent = NUMCache; i < n_NUMCache; i++, ent++)
03785 {
03786 if (strcmp(ent->str, str) == 0)
03787 {
03788 ent->age = (++NUMCounter);
03789 last_NUMCacheEntry = ent;
03790 return ent;
03791 }
03792 }
03793
03794 return NULL;
03795 }
03796
03797 static void
03798 NUM_cache_remove(NUMCacheEntry *ent)
03799 {
03800 #ifdef DEBUG_TO_FROM_CHAR
03801 elog(DEBUG_elog_output, "REMOVING ENTRY (%s)", ent->str);
03802 #endif
03803 ent->str[0] = '\0';
03804 ent->age = 0;
03805 }
03806
03807
03808
03809
03810
03811 static FormatNode *
03812 NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
03813 {
03814 FormatNode *format = NULL;
03815 char *str;
03816
03817 str = text_to_cstring(pars_str);
03818
03819
03820
03821
03822
03823
03824 if (len > NUM_CACHE_SIZE)
03825 {
03826 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
03827
03828 *shouldFree = true;
03829
03830 zeroize_NUM(Num);
03831
03832 parse_format(format, str, NUM_keywords,
03833 NULL, NUM_index, NUM_TYPE, Num);
03834
03835 (format + len)->type = NODE_TYPE_END;
03836 }
03837 else
03838 {
03839
03840
03841
03842 NUMCacheEntry *ent;
03843
03844 *shouldFree = false;
03845
03846 if ((ent = NUM_cache_search(str)) == NULL)
03847 {
03848 ent = NUM_cache_getnew(str);
03849
03850
03851
03852
03853
03854 parse_format(ent->format, str, NUM_keywords,
03855 NULL, NUM_index, NUM_TYPE, &ent->Num);
03856
03857 (ent->format + len)->type = NODE_TYPE_END;
03858 }
03859
03860 format = ent->format;
03861
03862
03863
03864
03865 Num->flag = ent->Num.flag;
03866 Num->lsign = ent->Num.lsign;
03867 Num->pre = ent->Num.pre;
03868 Num->post = ent->Num.post;
03869 Num->pre_lsign_num = ent->Num.pre_lsign_num;
03870 Num->need_locale = ent->Num.need_locale;
03871 Num->multi = ent->Num.multi;
03872 Num->zero_start = ent->Num.zero_start;
03873 Num->zero_end = ent->Num.zero_end;
03874 }
03875
03876 #ifdef DEBUG_TO_FROM_CHAR
03877
03878 dump_index(NUM_keywords, NUM_index);
03879 #endif
03880
03881 pfree(str);
03882 return format;
03883 }
03884
03885
03886 static char *
03887 int_to_roman(int number)
03888 {
03889 int len = 0,
03890 num = 0;
03891 char *p = NULL,
03892 *result,
03893 numstr[5];
03894
03895 result = (char *) palloc(16);
03896 *result = '\0';
03897
03898 if (number > 3999 || number < 1)
03899 {
03900 fill_str(result, '#', 15);
03901 return result;
03902 }
03903 len = snprintf(numstr, sizeof(numstr), "%d", number);
03904
03905 for (p = numstr; *p != '\0'; p++, --len)
03906 {
03907 num = *p - 49;
03908 if (num < 0)
03909 continue;
03910
03911 if (len > 3)
03912 {
03913 while (num-- != -1)
03914 strcat(result, "M");
03915 }
03916 else
03917 {
03918 if (len == 3)
03919 strcat(result, rm100[num]);
03920 else if (len == 2)
03921 strcat(result, rm10[num]);
03922 else if (len == 1)
03923 strcat(result, rm1[num]);
03924 }
03925 }
03926 return result;
03927 }
03928
03929
03930
03931
03932
03933
03934
03935 static void
03936 NUM_prepare_locale(NUMProc *Np)
03937 {
03938 if (Np->Num->need_locale)
03939 {
03940 struct lconv *lconv;
03941
03942
03943
03944
03945 lconv = PGLC_localeconv();
03946
03947
03948
03949
03950 if (lconv->negative_sign && *lconv->negative_sign)
03951 Np->L_negative_sign = lconv->negative_sign;
03952 else
03953 Np->L_negative_sign = "-";
03954
03955 if (lconv->positive_sign && *lconv->positive_sign)
03956 Np->L_positive_sign = lconv->positive_sign;
03957 else
03958 Np->L_positive_sign = "+";
03959
03960
03961
03962
03963 if (lconv->decimal_point && *lconv->decimal_point)
03964 Np->decimal = lconv->decimal_point;
03965
03966 else
03967 Np->decimal = ".";
03968
03969 if (!IS_LDECIMAL(Np->Num))
03970 Np->decimal = ".";
03971
03972
03973
03974
03975
03976
03977
03978
03979 if (lconv->thousands_sep && *lconv->thousands_sep)
03980 Np->L_thousands_sep = lconv->thousands_sep;
03981
03982 else if (strcmp(Np->decimal, ",") !=0)
03983 Np->L_thousands_sep = ",";
03984 else
03985 Np->L_thousands_sep = ".";
03986
03987
03988
03989
03990 if (lconv->currency_symbol && *lconv->currency_symbol)
03991 Np->L_currency_symbol = lconv->currency_symbol;
03992 else
03993 Np->L_currency_symbol = " ";
03994 }
03995 else
03996 {
03997
03998
03999
04000 Np->L_negative_sign = "-";
04001 Np->L_positive_sign = "+";
04002 Np->decimal = ".";
04003
04004 Np->L_thousands_sep = ",";
04005 Np->L_currency_symbol = " ";
04006 }
04007 }
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017 static char *
04018 get_last_relevant_decnum(char *num)
04019 {
04020 char *result,
04021 *p = strchr(num, '.');
04022
04023 #ifdef DEBUG_TO_FROM_CHAR
04024 elog(DEBUG_elog_output, "get_last_relevant_decnum()");
04025 #endif
04026
04027 if (!p)
04028 return NULL;
04029
04030 result = p;
04031
04032 while (*(++p))
04033 {
04034 if (*p != '0')
04035 result = p;
04036 }
04037
04038 return result;
04039 }
04040
04041
04042
04043
04044
04045 static void
04046 NUM_numpart_from_char(NUMProc *Np, int id, int plen)
04047 {
04048 bool isread = FALSE;
04049
04050 #ifdef DEBUG_TO_FROM_CHAR
04051 elog(DEBUG_elog_output, " --- scan start --- id=%s",
04052 (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
04053 #endif
04054
04055 if (*Np->inout_p == ' ')
04056 Np->inout_p++;
04057
04058 #define OVERLOAD_TEST (Np->inout_p >= Np->inout + plen)
04059 #define AMOUNT_TEST(_s) (plen-(Np->inout_p-Np->inout) >= _s)
04060
04061 if (*Np->inout_p == ' ')
04062 Np->inout_p++;
04063
04064 if (OVERLOAD_TEST)
04065 return;
04066
04067
04068
04069
04070 if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
04071 (Np->read_pre + Np->read_post) == 0)
04072 {
04073 #ifdef DEBUG_TO_FROM_CHAR
04074 elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
04075 *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
04076 #endif
04077
04078
04079
04080
04081 if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
04082 {
04083 int x = 0;
04084
04085 #ifdef DEBUG_TO_FROM_CHAR
04086 elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
04087 #endif
04088 if ((x = strlen(Np->L_negative_sign)) &&
04089 AMOUNT_TEST(x) &&
04090 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
04091 {
04092 Np->inout_p += x;
04093 *Np->number = '-';
04094 }
04095 else if ((x = strlen(Np->L_positive_sign)) &&
04096 AMOUNT_TEST(x) &&
04097 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
04098 {
04099 Np->inout_p += x;
04100 *Np->number = '+';
04101 }
04102 }
04103 else
04104 {
04105 #ifdef DEBUG_TO_FROM_CHAR
04106 elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
04107 #endif
04108
04109
04110
04111
04112 if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
04113 *Np->inout_p == '<'))
04114 {
04115 *Np->number = '-';
04116 Np->inout_p++;
04117 }
04118 else if (*Np->inout_p == '+')
04119 {
04120 *Np->number = '+';
04121 Np->inout_p++;
04122 }
04123 }
04124 }
04125
04126 if (OVERLOAD_TEST)
04127 return;
04128
04129 #ifdef DEBUG_TO_FROM_CHAR
04130 elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
04131 #endif
04132
04133
04134
04135
04136 if (isdigit((unsigned char) *Np->inout_p))
04137 {
04138 if (Np->read_dec && Np->read_post == Np->Num->post)
04139 return;
04140
04141 *Np->number_p = *Np->inout_p;
04142 Np->number_p++;
04143
04144 if (Np->read_dec)
04145 Np->read_post++;
04146 else
04147 Np->read_pre++;
04148
04149 isread = TRUE;
04150
04151 #ifdef DEBUG_TO_FROM_CHAR
04152 elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
04153 #endif
04154
04155
04156
04157
04158 }
04159 else if (IS_DECIMAL(Np->Num) && Np->read_dec == FALSE)
04160 {
04161 #ifdef DEBUG_TO_FROM_CHAR
04162 elog(DEBUG_elog_output, "Try read decimal point (%c)", *Np->inout_p);
04163 #endif
04164 if (*Np->inout_p == '.')
04165 {
04166 *Np->number_p = '.';
04167 Np->number_p++;
04168 Np->read_dec = TRUE;
04169 isread = TRUE;
04170 }
04171 else
04172 {
04173 int x = strlen(Np->decimal);
04174
04175 #ifdef DEBUG_TO_FROM_CHAR
04176 elog(DEBUG_elog_output, "Try read locale point (%c)",
04177 *Np->inout_p);
04178 #endif
04179 if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
04180 {
04181 Np->inout_p += x - 1;
04182 *Np->number_p = '.';
04183 Np->number_p++;
04184 Np->read_dec = TRUE;
04185 isread = TRUE;
04186 }
04187 }
04188 }
04189
04190 if (OVERLOAD_TEST)
04191 return;
04192
04193
04194
04195
04196
04197
04198
04199
04200
04201
04202 if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
04203 {
04204
04205
04206
04207
04208
04209 if (IS_LSIGN(Np->Num) && isread &&
04210 (Np->inout_p + 1) <= Np->inout + plen &&
04211 !isdigit((unsigned char) *(Np->inout_p + 1)))
04212 {
04213 int x;
04214 char *tmp = Np->inout_p++;
04215
04216 #ifdef DEBUG_TO_FROM_CHAR
04217 elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
04218 #endif
04219 if ((x = strlen(Np->L_negative_sign)) &&
04220 AMOUNT_TEST(x) &&
04221 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
04222 {
04223 Np->inout_p += x - 1;
04224 *Np->number = '-';
04225 }
04226 else if ((x = strlen(Np->L_positive_sign)) &&
04227 AMOUNT_TEST(x) &&
04228 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
04229 {
04230 Np->inout_p += x - 1;
04231 *Np->number = '+';
04232 }
04233 if (*Np->number == ' ')
04234
04235 Np->inout_p = tmp;
04236 }
04237
04238
04239
04240
04241
04242
04243
04244
04245
04246
04247
04248 else if (isread == FALSE && IS_LSIGN(Np->Num) == FALSE &&
04249 (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
04250 {
04251 #ifdef DEBUG_TO_FROM_CHAR
04252 elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
04253 #endif
04254
04255
04256
04257
04258 if (*Np->inout_p == '-' || *Np->inout_p == '+')
04259
04260 *Np->number = *Np->inout_p;
04261 }
04262 }
04263 }
04264
04265 #define IS_PREDEC_SPACE(_n) \
04266 (IS_ZERO((_n)->Num)==FALSE && \
04267 (_n)->number == (_n)->number_p && \
04268 *(_n)->number == '0' && \
04269 (_n)->Num->post != 0)
04270
04271
04272
04273
04274
04275 static void
04276 NUM_numpart_to_char(NUMProc *Np, int id)
04277 {
04278 int end;
04279
04280 if (IS_ROMAN(Np->Num))
04281 return;
04282
04283
04284
04285 #ifdef DEBUG_TO_FROM_CHAR
04286
04287
04288
04289
04290
04291 elog(DEBUG_elog_output,
04292 "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
04293 Np->sign_wrote,
04294 Np->num_curr,
04295 Np->number_p,
04296 Np->inout);
04297 #endif
04298 Np->num_in = FALSE;
04299
04300
04301
04302
04303
04304 if (Np->sign_wrote == FALSE &&
04305 (Np->num_curr >= Np->num_pre || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
04306 (IS_PREDEC_SPACE(Np) == FALSE || (Np->last_relevant && *Np->last_relevant == '.')))
04307 {
04308 if (IS_LSIGN(Np->Num))
04309 {
04310 if (Np->Num->lsign == NUM_LSIGN_PRE)
04311 {
04312 if (Np->sign == '-')
04313 strcpy(Np->inout_p, Np->L_negative_sign);
04314 else
04315 strcpy(Np->inout_p, Np->L_positive_sign);
04316 Np->inout_p += strlen(Np->inout_p);
04317 Np->sign_wrote = TRUE;
04318 }
04319 }
04320 else if (IS_BRACKET(Np->Num))
04321 {
04322 *Np->inout_p = Np->sign == '+' ? ' ' : '<';
04323 ++Np->inout_p;
04324 Np->sign_wrote = TRUE;
04325 }
04326 else if (Np->sign == '+')
04327 {
04328 if (!IS_FILLMODE(Np->Num))
04329 {
04330 *Np->inout_p = ' ';
04331 ++Np->inout_p;
04332 }
04333 Np->sign_wrote = TRUE;
04334 }
04335 else if (Np->sign == '-')
04336 {
04337 *Np->inout_p = '-';
04338 ++Np->inout_p;
04339 Np->sign_wrote = TRUE;
04340 }
04341 }
04342
04343
04344
04345
04346
04347 if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
04348 {
04349 if (Np->num_curr < Np->num_pre &&
04350 (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
04351 {
04352
04353
04354
04355 if (!IS_FILLMODE(Np->Num))
04356 {
04357 *Np->inout_p = ' ';
04358 ++Np->inout_p;
04359 }
04360 }
04361 else if (IS_ZERO(Np->Num) &&
04362 Np->num_curr < Np->num_pre &&
04363 Np->Num->zero_start <= Np->num_curr)
04364 {
04365
04366
04367
04368 *Np->inout_p = '0';
04369 ++Np->inout_p;
04370 Np->num_in = TRUE;
04371 }
04372 else
04373 {
04374
04375
04376
04377 if (*Np->number_p == '.')
04378 {
04379 if (!Np->last_relevant || *Np->last_relevant != '.')
04380 {
04381 strcpy(Np->inout_p, Np->decimal);
04382 Np->inout_p += strlen(Np->inout_p);
04383 }
04384
04385
04386
04387
04388 else if (IS_FILLMODE(Np->Num) &&
04389 Np->last_relevant && *Np->last_relevant == '.')
04390 {
04391 strcpy(Np->inout_p, Np->decimal);
04392 Np->inout_p += strlen(Np->inout_p);
04393 }
04394 }
04395 else
04396 {
04397
04398
04399
04400 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
04401 id != NUM_0)
04402 ;
04403
04404
04405
04406
04407 else if (IS_PREDEC_SPACE(Np))
04408 {
04409 if (!IS_FILLMODE(Np->Num))
04410 {
04411 *Np->inout_p = ' ';
04412 ++Np->inout_p;
04413 }
04414
04415
04416
04417
04418 else if (Np->last_relevant && *Np->last_relevant == '.')
04419 {
04420 *Np->inout_p = '0';
04421 ++Np->inout_p;
04422 }
04423 }
04424 else
04425 {
04426 *Np->inout_p = *Np->number_p;
04427 ++Np->inout_p;
04428 Np->num_in = TRUE;
04429 }
04430 }
04431 ++Np->number_p;
04432 }
04433
04434 end = Np->num_count + (Np->num_pre ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
04435
04436 if (Np->last_relevant && Np->last_relevant == Np->number_p)
04437 end = Np->num_curr;
04438
04439 if (Np->num_curr + 1 == end)
04440 {
04441 if (Np->sign_wrote == TRUE && IS_BRACKET(Np->Num))
04442 {
04443 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
04444 ++Np->inout_p;
04445 }
04446 else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
04447 {
04448 if (Np->sign == '-')
04449 strcpy(Np->inout_p, Np->L_negative_sign);
04450 else
04451 strcpy(Np->inout_p, Np->L_positive_sign);
04452 Np->inout_p += strlen(Np->inout_p);
04453 }
04454 }
04455 }
04456
04457 ++Np->num_curr;
04458 }
04459
04460
04461
04462
04463
04464 static char *
04465 NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number,
04466 int plen, int sign, bool is_to_char, Oid collid)
04467 {
04468 FormatNode *n;
04469 NUMProc _Np,
04470 *Np = &_Np;
04471
04472 MemSet(Np, 0, sizeof(NUMProc));
04473
04474 Np->Num = Num;
04475 Np->is_to_char = is_to_char;
04476 Np->number = number;
04477 Np->inout = inout;
04478 Np->last_relevant = NULL;
04479 Np->read_post = 0;
04480 Np->read_pre = 0;
04481 Np->read_dec = FALSE;
04482
04483 if (Np->Num->zero_start)
04484 --Np->Num->zero_start;
04485
04486 if (IS_EEEE(Np->Num))
04487 {
04488 if (!Np->is_to_char)
04489 ereport(ERROR,
04490 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04491 errmsg("\"EEEE\" not supported for input")));
04492 return strcpy(inout, number);
04493 }
04494
04495
04496
04497
04498 if (IS_ROMAN(Np->Num))
04499 {
04500 if (!Np->is_to_char)
04501 ereport(ERROR,
04502 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04503 errmsg("\"RN\" not supported for input")));
04504
04505 Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->post =
04506 Np->Num->pre = Np->num_pre = Np->sign = 0;
04507
04508 if (IS_FILLMODE(Np->Num))
04509 {
04510 Np->Num->flag = 0;
04511 Np->Num->flag |= NUM_F_FILLMODE;
04512 }
04513 else
04514 Np->Num->flag = 0;
04515 Np->Num->flag |= NUM_F_ROMAN;
04516 }
04517
04518
04519
04520
04521 if (is_to_char)
04522 {
04523 Np->sign = sign;
04524
04525
04526 if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
04527 {
04528 if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == FALSE)
04529 Np->sign_wrote = FALSE;
04530 else
04531 Np->sign_wrote = TRUE;
04532 }
04533 else
04534 {
04535 if (Np->sign != '-')
04536 {
04537 if (IS_BRACKET(Np->Num) && IS_FILLMODE(Np->Num))
04538 Np->Num->flag &= ~NUM_F_BRACKET;
04539 if (IS_MINUS(Np->Num))
04540 Np->Num->flag &= ~NUM_F_MINUS;
04541 }
04542 else if (Np->sign != '+' && IS_PLUS(Np->Num))
04543 Np->Num->flag &= ~NUM_F_PLUS;
04544
04545 if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == FALSE)
04546 Np->sign_wrote = TRUE;
04547 else
04548 Np->sign_wrote = FALSE;
04549
04550 if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
04551 Np->Num->lsign = NUM_LSIGN_POST;
04552 }
04553 }
04554 else
04555 Np->sign = FALSE;
04556
04557
04558
04559
04560 Np->num_count = Np->Num->post + Np->Num->pre - 1;
04561
04562 if (is_to_char)
04563 {
04564 Np->num_pre = plen;
04565
04566 if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
04567 {
04568 Np->last_relevant = get_last_relevant_decnum(Np->number);
04569
04570
04571
04572
04573
04574 if (Np->last_relevant && Np->Num->zero_end > Np->num_pre)
04575 {
04576 char *last_zero;
04577
04578 last_zero = Np->number + (Np->Num->zero_end - Np->num_pre);
04579 if (Np->last_relevant < last_zero)
04580 Np->last_relevant = last_zero;
04581 }
04582 }
04583
04584 if (Np->sign_wrote == FALSE && Np->num_pre == 0)
04585 ++Np->num_count;
04586 }
04587 else
04588 {
04589 Np->num_pre = 0;
04590 *Np->number = ' ';
04591 *(Np->number + 1) = '\0';
04592 }
04593
04594 Np->num_in = 0;
04595 Np->num_curr = 0;
04596
04597 #ifdef DEBUG_TO_FROM_CHAR
04598 elog(DEBUG_elog_output,
04599 "\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",
04600 Np->sign,
04601 Np->number,
04602 Np->Num->pre,
04603 Np->Num->post,
04604 Np->num_count,
04605 Np->num_pre,
04606 Np->sign_wrote ? "Yes" : "No",
04607 IS_ZERO(Np->Num) ? "Yes" : "No",
04608 Np->Num->zero_start,
04609 Np->Num->zero_end,
04610 Np->last_relevant ? Np->last_relevant : "<not set>",
04611 IS_BRACKET(Np->Num) ? "Yes" : "No",
04612 IS_PLUS(Np->Num) ? "Yes" : "No",
04613 IS_MINUS(Np->Num) ? "Yes" : "No",
04614 IS_FILLMODE(Np->Num) ? "Yes" : "No",
04615 IS_ROMAN(Np->Num) ? "Yes" : "No",
04616 IS_EEEE(Np->Num) ? "Yes" : "No"
04617 );
04618 #endif
04619
04620
04621
04622
04623 NUM_prepare_locale(Np);
04624
04625
04626
04627
04628 if (Np->is_to_char)
04629 Np->number_p = Np->number;
04630 else
04631 Np->number_p = Np->number + 1;
04632
04633 for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
04634 {
04635 if (!Np->is_to_char)
04636 {
04637
04638
04639
04640 if (Np->inout_p >= Np->inout + plen)
04641 break;
04642 }
04643
04644
04645
04646
04647 if (n->type == NODE_TYPE_ACTION)
04648 {
04649
04650
04651
04652
04653
04654
04655
04656
04657 switch (n->key->id)
04658 {
04659 case NUM_9:
04660 case NUM_0:
04661 case NUM_DEC:
04662 case NUM_D:
04663 if (Np->is_to_char)
04664 {
04665 NUM_numpart_to_char(Np, n->key->id);
04666 continue;
04667 }
04668 else
04669 {
04670 NUM_numpart_from_char(Np, n->key->id, plen);
04671 break;
04672 }
04673
04674 case NUM_COMMA:
04675 if (Np->is_to_char)
04676 {
04677 if (!Np->num_in)
04678 {
04679 if (IS_FILLMODE(Np->Num))
04680 continue;
04681 else
04682 *Np->inout_p = ' ';
04683 }
04684 else
04685 *Np->inout_p = ',';
04686 }
04687 else
04688 {
04689 if (!Np->num_in)
04690 {
04691 if (IS_FILLMODE(Np->Num))
04692 continue;
04693 }
04694 }
04695 break;
04696
04697 case NUM_G:
04698 if (Np->is_to_char)
04699 {
04700 if (!Np->num_in)
04701 {
04702 if (IS_FILLMODE(Np->Num))
04703 continue;
04704 else
04705 {
04706 int x = strlen(Np->L_thousands_sep);
04707
04708 memset(Np->inout_p, ' ', x);
04709 Np->inout_p += x - 1;
04710 }
04711 }
04712 else
04713 {
04714 strcpy(Np->inout_p, Np->L_thousands_sep);
04715 Np->inout_p += strlen(Np->inout_p) - 1;
04716 }
04717 }
04718 else
04719 {
04720 if (!Np->num_in)
04721 {
04722 if (IS_FILLMODE(Np->Num))
04723 continue;
04724 }
04725 Np->inout_p += strlen(Np->L_thousands_sep) - 1;
04726 }
04727 break;
04728
04729 case NUM_L:
04730 if (Np->is_to_char)
04731 {
04732 strcpy(Np->inout_p, Np->L_currency_symbol);
04733 Np->inout_p += strlen(Np->inout_p) - 1;
04734 }
04735 else
04736 Np->inout_p += strlen(Np->L_currency_symbol) - 1;
04737 break;
04738
04739 case NUM_RN:
04740 if (IS_FILLMODE(Np->Num))
04741 {
04742 strcpy(Np->inout_p, Np->number_p);
04743 Np->inout_p += strlen(Np->inout_p) - 1;
04744 }
04745 else
04746 {
04747 sprintf(Np->inout_p, "%15s", Np->number_p);
04748 Np->inout_p += strlen(Np->inout_p) - 1;
04749 }
04750 break;
04751
04752 case NUM_rn:
04753 if (IS_FILLMODE(Np->Num))
04754 {
04755 strcpy(Np->inout_p, asc_tolower_z(Np->number_p));
04756 Np->inout_p += strlen(Np->inout_p) - 1;
04757 }
04758 else
04759 {
04760 sprintf(Np->inout_p, "%15s", asc_tolower_z(Np->number_p));
04761 Np->inout_p += strlen(Np->inout_p) - 1;
04762 }
04763 break;
04764
04765 case NUM_th:
04766 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
04767 Np->sign == '-' || IS_DECIMAL(Np->Num))
04768 continue;
04769
04770 if (Np->is_to_char)
04771 strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
04772 Np->inout_p += 1;
04773 break;
04774
04775 case NUM_TH:
04776 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
04777 Np->sign == '-' || IS_DECIMAL(Np->Num))
04778 continue;
04779
04780 if (Np->is_to_char)
04781 strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
04782 Np->inout_p += 1;
04783 break;
04784
04785 case NUM_MI:
04786 if (Np->is_to_char)
04787 {
04788 if (Np->sign == '-')
04789 *Np->inout_p = '-';
04790 else if (IS_FILLMODE(Np->Num))
04791 continue;
04792 else
04793 *Np->inout_p = ' ';
04794 }
04795 else
04796 {
04797 if (*Np->inout_p == '-')
04798 *Np->number = '-';
04799 }
04800 break;
04801
04802 case NUM_PL:
04803 if (Np->is_to_char)
04804 {
04805 if (Np->sign == '+')
04806 *Np->inout_p = '+';
04807 else if (IS_FILLMODE(Np->Num))
04808 continue;
04809 else
04810 *Np->inout_p = ' ';
04811 }
04812 else
04813 {
04814 if (*Np->inout_p == '+')
04815 *Np->number = '+';
04816 }
04817 break;
04818
04819 case NUM_SG:
04820 if (Np->is_to_char)
04821 *Np->inout_p = Np->sign;
04822
04823 else
04824 {
04825 if (*Np->inout_p == '-')
04826 *Np->number = '-';
04827 else if (*Np->inout_p == '+')
04828 *Np->number = '+';
04829 }
04830 break;
04831
04832
04833 default:
04834 continue;
04835 break;
04836 }
04837 }
04838 else
04839 {
04840
04841
04842
04843 if (Np->is_to_char)
04844 *Np->inout_p = n->character;
04845 }
04846 Np->inout_p++;
04847 }
04848
04849 if (Np->is_to_char)
04850 {
04851 *Np->inout_p = '\0';
04852 return Np->inout;
04853 }
04854 else
04855 {
04856 if (*(Np->number_p - 1) == '.')
04857 *(Np->number_p - 1) = '\0';
04858 else
04859 *Np->number_p = '\0';
04860
04861
04862
04863
04864 Np->Num->post = Np->read_post;
04865
04866 #ifdef DEBUG_TO_FROM_CHAR
04867 elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
04868 #endif
04869 return Np->number;
04870 }
04871 }
04872
04873
04874
04875
04876
04877
04878 #define NUM_TOCHAR_prepare \
04879 do { \
04880 len = VARSIZE_ANY_EXHDR(fmt); \
04881 if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
04882 PG_RETURN_TEXT_P(cstring_to_text("")); \
04883 result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
04884 format = NUM_cache(len, &Num, fmt, &shouldFree); \
04885 } while (0)
04886
04887
04888
04889
04890
04891 #define NUM_TOCHAR_finish \
04892 do { \
04893 NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true, PG_GET_COLLATION()); \
04894 \
04895 if (shouldFree) \
04896 pfree(format); \
04897 \
04898
04899
04900
04901
04902 \
04903 len = strlen(VARDATA(result)); \
04904 SET_VARSIZE(result, len + VARHDRSZ); \
04905 } while (0)
04906
04907
04908
04909
04910
04911 Datum
04912 numeric_to_number(PG_FUNCTION_ARGS)
04913 {
04914 text *value = PG_GETARG_TEXT_P(0);
04915 text *fmt = PG_GETARG_TEXT_P(1);
04916 NUMDesc Num;
04917 Datum result;
04918 FormatNode *format;
04919 char *numstr;
04920 bool shouldFree;
04921 int len = 0;
04922 int scale,
04923 precision;
04924
04925 len = VARSIZE(fmt) - VARHDRSZ;
04926
04927 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
04928 PG_RETURN_NULL();
04929
04930 format = NUM_cache(len, &Num, fmt, &shouldFree);
04931
04932 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
04933
04934 NUM_processor(format, &Num, VARDATA(value), numstr,
04935 VARSIZE(value) - VARHDRSZ, 0, false, PG_GET_COLLATION());
04936
04937 scale = Num.post;
04938 precision = Max(0, Num.pre) + scale;
04939
04940 if (shouldFree)
04941 pfree(format);
04942
04943 result = DirectFunctionCall3(numeric_in,
04944 CStringGetDatum(numstr),
04945 ObjectIdGetDatum(InvalidOid),
04946 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
04947 pfree(numstr);
04948 return result;
04949 }
04950
04951
04952
04953
04954
04955 Datum
04956 numeric_to_char(PG_FUNCTION_ARGS)
04957 {
04958 Numeric value = PG_GETARG_NUMERIC(0);
04959 text *fmt = PG_GETARG_TEXT_P(1);
04960 NUMDesc Num;
04961 FormatNode *format;
04962 text *result;
04963 bool shouldFree;
04964 int len = 0,
04965 plen = 0,
04966 sign = 0;
04967 char *numstr,
04968 *orgnum,
04969 *p;
04970 Numeric x;
04971
04972 NUM_TOCHAR_prepare;
04973
04974
04975
04976
04977 if (IS_ROMAN(&Num))
04978 {
04979 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
04980 NumericGetDatum(value),
04981 Int32GetDatum(0)));
04982 numstr = orgnum =
04983 int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4,
04984 NumericGetDatum(x))));
04985 }
04986 else if (IS_EEEE(&Num))
04987 {
04988 orgnum = numeric_out_sci(value, Num.post);
04989
04990
04991
04992
04993
04994
04995 if (strcmp(orgnum, "NaN") == 0)
04996 {
04997
04998
04999
05000
05001 numstr = (char *) palloc(Num.pre + Num.post + 7);
05002 fill_str(numstr, '#', Num.pre + Num.post + 6);
05003 *numstr = ' ';
05004 *(numstr + Num.pre + 1) = '.';
05005 }
05006 else if (*orgnum != '-')
05007 {
05008 numstr = (char *) palloc(strlen(orgnum) + 2);
05009 *numstr = ' ';
05010 strcpy(numstr + 1, orgnum);
05011 len = strlen(numstr);
05012 }
05013 else
05014 {
05015 numstr = orgnum;
05016 len = strlen(orgnum);
05017 }
05018 }
05019 else
05020 {
05021 Numeric val = value;
05022
05023 if (IS_MULTI(&Num))
05024 {
05025 Numeric a = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
05026 Int32GetDatum(10)));
05027 Numeric b = DatumGetNumeric(DirectFunctionCall1(int4_numeric,
05028 Int32GetDatum(Num.multi)));
05029
05030 x = DatumGetNumeric(DirectFunctionCall2(numeric_power,
05031 NumericGetDatum(a),
05032 NumericGetDatum(b)));
05033 val = DatumGetNumeric(DirectFunctionCall2(numeric_mul,
05034 NumericGetDatum(value),
05035 NumericGetDatum(x)));
05036 Num.pre += Num.multi;
05037 }
05038
05039 x = DatumGetNumeric(DirectFunctionCall2(numeric_round,
05040 NumericGetDatum(val),
05041 Int32GetDatum(Num.post)));
05042 orgnum = DatumGetCString(DirectFunctionCall1(numeric_out,
05043 NumericGetDatum(x)));
05044
05045 if (*orgnum == '-')
05046 {
05047 sign = '-';
05048 numstr = orgnum + 1;
05049 }
05050 else
05051 {
05052 sign = '+';
05053 numstr = orgnum;
05054 }
05055 if ((p = strchr(numstr, '.')))
05056 len = p - numstr;
05057 else
05058 len = strlen(numstr);
05059
05060 if (Num.pre > len)
05061 plen = Num.pre - len;
05062 else if (len > Num.pre)
05063 {
05064 numstr = (char *) palloc(Num.pre + Num.post + 2);
05065 fill_str(numstr, '#', Num.pre + Num.post + 1);
05066 *(numstr + Num.pre) = '.';
05067 }
05068 }
05069
05070 NUM_TOCHAR_finish;
05071 PG_RETURN_TEXT_P(result);
05072 }
05073
05074
05075
05076
05077
05078 Datum
05079 int4_to_char(PG_FUNCTION_ARGS)
05080 {
05081 int32 value = PG_GETARG_INT32(0);
05082 text *fmt = PG_GETARG_TEXT_P(1);
05083 NUMDesc Num;
05084 FormatNode *format;
05085 text *result;
05086 bool shouldFree;
05087 int len = 0,
05088 plen = 0,
05089 sign = 0;
05090 char *numstr,
05091 *orgnum;
05092
05093 NUM_TOCHAR_prepare;
05094
05095
05096
05097
05098 if (IS_ROMAN(&Num))
05099 numstr = orgnum = int_to_roman(value);
05100 else if (IS_EEEE(&Num))
05101 {
05102
05103 float8 val = (float8) value;
05104
05105 orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05106 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val);
05107
05108
05109
05110
05111 if (*orgnum == '+')
05112 *orgnum = ' ';
05113
05114 len = strlen(orgnum);
05115 numstr = orgnum;
05116 }
05117 else
05118 {
05119 if (IS_MULTI(&Num))
05120 {
05121 orgnum = DatumGetCString(DirectFunctionCall1(int4out,
05122 Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
05123 Num.pre += Num.multi;
05124 }
05125 else
05126 {
05127 orgnum = DatumGetCString(DirectFunctionCall1(int4out,
05128 Int32GetDatum(value)));
05129 }
05130
05131 if (*orgnum == '-')
05132 {
05133 sign = '-';
05134 orgnum++;
05135 }
05136 else
05137 sign = '+';
05138 len = strlen(orgnum);
05139
05140 if (Num.post)
05141 {
05142 numstr = (char *) palloc(len + Num.post + 2);
05143 strcpy(numstr, orgnum);
05144 *(numstr + len) = '.';
05145 memset(numstr + len + 1, '0', Num.post);
05146 *(numstr + len + Num.post + 1) = '\0';
05147 }
05148 else
05149 numstr = orgnum;
05150
05151 if (Num.pre > len)
05152 plen = Num.pre - len;
05153 else if (len > Num.pre)
05154 {
05155 numstr = (char *) palloc(Num.pre + Num.post + 2);
05156 fill_str(numstr, '#', Num.pre + Num.post + 1);
05157 *(numstr + Num.pre) = '.';
05158 }
05159 }
05160
05161 NUM_TOCHAR_finish;
05162 PG_RETURN_TEXT_P(result);
05163 }
05164
05165
05166
05167
05168
05169 Datum
05170 int8_to_char(PG_FUNCTION_ARGS)
05171 {
05172 int64 value = PG_GETARG_INT64(0);
05173 text *fmt = PG_GETARG_TEXT_P(1);
05174 NUMDesc Num;
05175 FormatNode *format;
05176 text *result;
05177 bool shouldFree;
05178 int len = 0,
05179 plen = 0,
05180 sign = 0;
05181 char *numstr,
05182 *orgnum;
05183
05184 NUM_TOCHAR_prepare;
05185
05186
05187
05188
05189 if (IS_ROMAN(&Num))
05190 {
05191
05192 numstr = orgnum = int_to_roman(DatumGetInt32(
05193 DirectFunctionCall1(int84, Int64GetDatum(value))));
05194 }
05195 else if (IS_EEEE(&Num))
05196 {
05197
05198 Numeric val;
05199
05200 val = DatumGetNumeric(DirectFunctionCall1(int8_numeric,
05201 Int64GetDatum(value)));
05202 orgnum = numeric_out_sci(val, Num.post);
05203
05204
05205
05206
05207
05208
05209 if (*orgnum != '-')
05210 {
05211 numstr = (char *) palloc(strlen(orgnum) + 2);
05212 *numstr = ' ';
05213 strcpy(numstr + 1, orgnum);
05214 len = strlen(numstr);
05215 }
05216 else
05217 {
05218 numstr = orgnum;
05219 len = strlen(orgnum);
05220 }
05221 }
05222 else
05223 {
05224 if (IS_MULTI(&Num))
05225 {
05226 double multi = pow((double) 10, (double) Num.multi);
05227
05228 value = DatumGetInt64(DirectFunctionCall2(int8mul,
05229 Int64GetDatum(value),
05230 DirectFunctionCall1(dtoi8,
05231 Float8GetDatum(multi))));
05232 Num.pre += Num.multi;
05233 }
05234
05235 orgnum = DatumGetCString(DirectFunctionCall1(int8out,
05236 Int64GetDatum(value)));
05237
05238 if (*orgnum == '-')
05239 {
05240 sign = '-';
05241 orgnum++;
05242 }
05243 else
05244 sign = '+';
05245 len = strlen(orgnum);
05246
05247 if (Num.post)
05248 {
05249 numstr = (char *) palloc(len + Num.post + 2);
05250 strcpy(numstr, orgnum);
05251 *(numstr + len) = '.';
05252 memset(numstr + len + 1, '0', Num.post);
05253 *(numstr + len + Num.post + 1) = '\0';
05254 }
05255 else
05256 numstr = orgnum;
05257
05258 if (Num.pre > len)
05259 plen = Num.pre - len;
05260 else if (len > Num.pre)
05261 {
05262 numstr = (char *) palloc(Num.pre + Num.post + 2);
05263 fill_str(numstr, '#', Num.pre + Num.post + 1);
05264 *(numstr + Num.pre) = '.';
05265 }
05266 }
05267
05268 NUM_TOCHAR_finish;
05269 PG_RETURN_TEXT_P(result);
05270 }
05271
05272
05273
05274
05275
05276 Datum
05277 float4_to_char(PG_FUNCTION_ARGS)
05278 {
05279 float4 value = PG_GETARG_FLOAT4(0);
05280 text *fmt = PG_GETARG_TEXT_P(1);
05281 NUMDesc Num;
05282 FormatNode *format;
05283 text *result;
05284 bool shouldFree;
05285 int len = 0,
05286 plen = 0,
05287 sign = 0;
05288 char *numstr,
05289 *orgnum,
05290 *p;
05291
05292 NUM_TOCHAR_prepare;
05293
05294 if (IS_ROMAN(&Num))
05295 numstr = orgnum = int_to_roman((int) rint(value));
05296 else if (IS_EEEE(&Num))
05297 {
05298 numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05299 if (isnan(value) || is_infinite(value))
05300 {
05301
05302
05303
05304
05305 numstr = (char *) palloc(Num.pre + Num.post + 7);
05306 fill_str(numstr, '#', Num.pre + Num.post + 6);
05307 *numstr = ' ';
05308 *(numstr + Num.pre + 1) = '.';
05309 }
05310 else
05311 {
05312 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
05313
05314
05315
05316
05317 if (*orgnum == '+')
05318 *orgnum = ' ';
05319
05320 len = strlen(orgnum);
05321 numstr = orgnum;
05322 }
05323 }
05324 else
05325 {
05326 float4 val = value;
05327
05328 if (IS_MULTI(&Num))
05329 {
05330 float multi = pow((double) 10, (double) Num.multi);
05331
05332 val = value * multi;
05333 Num.pre += Num.multi;
05334 }
05335
05336 orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
05337 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
05338 len = strlen(orgnum);
05339 if (Num.pre > len)
05340 plen = Num.pre - len;
05341 if (len >= FLT_DIG)
05342 Num.post = 0;
05343 else if (Num.post + len > FLT_DIG)
05344 Num.post = FLT_DIG - len;
05345 snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
05346
05347 if (*orgnum == '-')
05348 {
05349 sign = '-';
05350 numstr = orgnum + 1;
05351 }
05352 else
05353 {
05354 sign = '+';
05355 numstr = orgnum;
05356 }
05357 if ((p = strchr(numstr, '.')))
05358 len = p - numstr;
05359 else
05360 len = strlen(numstr);
05361
05362 if (Num.pre > len)
05363 plen = Num.pre - len;
05364 else if (len > Num.pre)
05365 {
05366 numstr = (char *) palloc(Num.pre + Num.post + 2);
05367 fill_str(numstr, '#', Num.pre + Num.post + 1);
05368 *(numstr + Num.pre) = '.';
05369 }
05370 }
05371
05372 NUM_TOCHAR_finish;
05373 PG_RETURN_TEXT_P(result);
05374 }
05375
05376
05377
05378
05379
05380 Datum
05381 float8_to_char(PG_FUNCTION_ARGS)
05382 {
05383 float8 value = PG_GETARG_FLOAT8(0);
05384 text *fmt = PG_GETARG_TEXT_P(1);
05385 NUMDesc Num;
05386 FormatNode *format;
05387 text *result;
05388 bool shouldFree;
05389 int len = 0,
05390 plen = 0,
05391 sign = 0;
05392 char *numstr,
05393 *orgnum,
05394 *p;
05395
05396 NUM_TOCHAR_prepare;
05397
05398 if (IS_ROMAN(&Num))
05399 numstr = orgnum = int_to_roman((int) rint(value));
05400 else if (IS_EEEE(&Num))
05401 {
05402 numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05403 if (isnan(value) || is_infinite(value))
05404 {
05405
05406
05407
05408
05409 numstr = (char *) palloc(Num.pre + Num.post + 7);
05410 fill_str(numstr, '#', Num.pre + Num.post + 6);
05411 *numstr = ' ';
05412 *(numstr + Num.pre + 1) = '.';
05413 }
05414 else
05415 {
05416 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
05417
05418
05419
05420
05421 if (*orgnum == '+')
05422 *orgnum = ' ';
05423
05424 len = strlen(orgnum);
05425 numstr = orgnum;
05426 }
05427 }
05428 else
05429 {
05430 float8 val = value;
05431
05432 if (IS_MULTI(&Num))
05433 {
05434 double multi = pow((double) 10, (double) Num.multi);
05435
05436 val = value * multi;
05437 Num.pre += Num.multi;
05438 }
05439 orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
05440 len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val));
05441 if (Num.pre > len)
05442 plen = Num.pre - len;
05443 if (len >= DBL_DIG)
05444 Num.post = 0;
05445 else if (Num.post + len > DBL_DIG)
05446 Num.post = DBL_DIG - len;
05447 snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
05448
05449 if (*orgnum == '-')
05450 {
05451 sign = '-';
05452 numstr = orgnum + 1;
05453 }
05454 else
05455 {
05456 sign = '+';
05457 numstr = orgnum;
05458 }
05459 if ((p = strchr(numstr, '.')))
05460 len = p - numstr;
05461 else
05462 len = strlen(numstr);
05463
05464 if (Num.pre > len)
05465 plen = Num.pre - len;
05466 else if (len > Num.pre)
05467 {
05468 numstr = (char *) palloc(Num.pre + Num.post + 2);
05469 fill_str(numstr, '#', Num.pre + Num.post + 1);
05470 *(numstr + Num.pre) = '.';
05471 }
05472 }
05473
05474 NUM_TOCHAR_finish;
05475 PG_RETURN_TEXT_P(result);
05476 }