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