#include "postgres.h"
#include <ctype.h>
#include <unistd.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include "catalog/pg_collation.h"
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/formatting.h"
#include "utils/int8.h"
#include "utils/numeric.h"
#include "utils/pg_locale.h"
Go to the source code of this file.
Data Structures | |
struct | KeySuffix |
struct | KeyWord |
struct | FormatNode |
struct | NUMDesc |
struct | DCHCacheEntry |
struct | NUMCacheEntry |
struct | TmFromChar |
struct | TmToChar |
struct | NUMProc |
Defines | |
#define | DCH_TYPE 1 |
#define | NUM_TYPE 2 |
#define | KeyWord_INDEX_SIZE ('~' - ' ') |
#define | KeyWord_INDEX_FILTER(_c) ((_c) <= ' ' || (_c) >= '~' ? 0 : 1) |
#define | DCH_MAX_ITEM_SIZ 9 |
#define | NUM_MAX_ITEM_SIZ 8 |
#define | MAXFLOATWIDTH 60 |
#define | MAXDOUBLEWIDTH 500 |
#define | NODE_TYPE_END 1 |
#define | NODE_TYPE_ACTION 2 |
#define | NODE_TYPE_CHAR 3 |
#define | SUFFTYPE_PREFIX 1 |
#define | SUFFTYPE_POSTFIX 2 |
#define | CLOCK_24_HOUR 0 |
#define | CLOCK_12_HOUR 1 |
#define | ADJUST_YEAR(year, is_interval) ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year))) |
#define | A_D_STR "A.D." |
#define | a_d_STR "a.d." |
#define | AD_STR "AD" |
#define | ad_STR "ad" |
#define | B_C_STR "B.C." |
#define | b_c_STR "b.c." |
#define | BC_STR "BC" |
#define | bc_STR "bc" |
#define | A_M_STR "A.M." |
#define | a_m_STR "a.m." |
#define | AM_STR "AM" |
#define | am_STR "am" |
#define | P_M_STR "P.M." |
#define | p_m_STR "p.m." |
#define | PM_STR "PM" |
#define | pm_STR "pm" |
#define | ONE_UPPER 1 |
#define | ALL_UPPER 2 |
#define | ALL_LOWER 3 |
#define | FULL_SIZ 0 |
#define | MAX_MONTH_LEN 9 |
#define | MAX_MON_LEN 3 |
#define | MAX_DAY_LEN 9 |
#define | MAX_DY_LEN 3 |
#define | MAX_RM_LEN 4 |
#define | TH_UPPER 1 |
#define | TH_LOWER 2 |
#define | NUM_F_DECIMAL (1 << 1) |
#define | NUM_F_LDECIMAL (1 << 2) |
#define | NUM_F_ZERO (1 << 3) |
#define | NUM_F_BLANK (1 << 4) |
#define | NUM_F_FILLMODE (1 << 5) |
#define | NUM_F_LSIGN (1 << 6) |
#define | NUM_F_BRACKET (1 << 7) |
#define | NUM_F_MINUS (1 << 8) |
#define | NUM_F_PLUS (1 << 9) |
#define | NUM_F_ROMAN (1 << 10) |
#define | NUM_F_MULTI (1 << 11) |
#define | NUM_F_PLUS_POST (1 << 12) |
#define | NUM_F_MINUS_POST (1 << 13) |
#define | NUM_F_EEEE (1 << 14) |
#define | NUM_LSIGN_PRE (-1) |
#define | NUM_LSIGN_POST 1 |
#define | NUM_LSIGN_NONE 0 |
#define | IS_DECIMAL(_f) ((_f)->flag & NUM_F_DECIMAL) |
#define | IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL) |
#define | IS_ZERO(_f) ((_f)->flag & NUM_F_ZERO) |
#define | IS_BLANK(_f) ((_f)->flag & NUM_F_BLANK) |
#define | IS_FILLMODE(_f) ((_f)->flag & NUM_F_FILLMODE) |
#define | IS_BRACKET(_f) ((_f)->flag & NUM_F_BRACKET) |
#define | IS_MINUS(_f) ((_f)->flag & NUM_F_MINUS) |
#define | IS_LSIGN(_f) ((_f)->flag & NUM_F_LSIGN) |
#define | IS_PLUS(_f) ((_f)->flag & NUM_F_PLUS) |
#define | IS_ROMAN(_f) ((_f)->flag & NUM_F_ROMAN) |
#define | IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI) |
#define | IS_EEEE(_f) ((_f)->flag & NUM_F_EEEE) |
#define | NUM_CACHE_SIZE 64 |
#define | NUM_CACHE_FIELDS 16 |
#define | DCH_CACHE_SIZE 128 |
#define | DCH_CACHE_FIELDS 16 |
#define | ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar)) |
#define | DEBUG_TMFC(_X) |
#define | DEBUG_TM(_X) |
#define | tmtcTm(_X) (&(_X)->tm) |
#define | tmtcTzn(_X) ((_X)->tzn) |
#define | tmtcFsec(_X) ((_X)->fsec) |
#define | ZERO_tm(_X) |
#define | ZERO_tmtc(_X) |
#define | INVALID_FOR_INTERVAL |
#define | DCH_S_FM 0x01 |
#define | DCH_S_TH 0x02 |
#define | DCH_S_th 0x04 |
#define | DCH_S_SP 0x08 |
#define | DCH_S_TM 0x10 |
#define | S_THth(_s) ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0) |
#define | S_TH(_s) (((_s) & DCH_S_TH) ? 1 : 0) |
#define | S_th(_s) (((_s) & DCH_S_th) ? 1 : 0) |
#define | S_TH_TYPE(_s) (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER) |
#define | S_FM(_s) (((_s) & DCH_S_FM) ? 1 : 0) |
#define | S_SP(_s) (((_s) & DCH_S_SP) ? 1 : 0) |
#define | S_TM(_s) (((_s) & DCH_S_TM) ? 1 : 0) |
#define | SKIP_THth(_suf) (S_THth(_suf) ? 2 : 0) |
#define | zeroize_NUM(_n) |
#define | OVERLOAD_TEST (Np->inout_p >= Np->inout + plen) |
#define | AMOUNT_TEST(_s) (plen-(Np->inout_p-Np->inout) >= _s) |
#define | IS_PREDEC_SPACE(_n) |
#define | NUM_TOCHAR_prepare |
#define | NUM_TOCHAR_finish |
Typedefs | |
typedef struct FormatNode | FormatNode |
typedef struct TmToChar | TmToChar |
typedef struct NUMProc | NUMProc |
Enumerations | |
enum | FromCharDateMode { FROM_CHAR_DATE_NONE = 0, FROM_CHAR_DATE_GREGORIAN, FROM_CHAR_DATE_ISOWEEK } |
enum | DCH_poz { DCH_A_D, DCH_A_M, DCH_AD, DCH_AM, DCH_B_C, DCH_BC, DCH_CC, DCH_DAY, DCH_DDD, DCH_DD, DCH_DY, DCH_Day, DCH_Dy, DCH_D, DCH_FX, DCH_HH24, DCH_HH12, DCH_HH, DCH_IDDD, DCH_ID, DCH_IW, DCH_IYYY, DCH_IYY, DCH_IY, DCH_I, DCH_J, DCH_MI, DCH_MM, DCH_MONTH, DCH_MON, DCH_MS, DCH_Month, DCH_Mon, DCH_P_M, DCH_PM, DCH_Q, DCH_RM, DCH_SSSS, DCH_SS, DCH_TZ, DCH_US, DCH_WW, DCH_W, DCH_Y_YYY, DCH_YYYY, DCH_YYY, DCH_YY, DCH_Y, DCH_a_d, DCH_a_m, DCH_ad, DCH_am, DCH_b_c, DCH_bc, DCH_cc, DCH_day, DCH_ddd, DCH_dd, DCH_dy, DCH_d, DCH_fx, DCH_hh24, DCH_hh12, DCH_hh, DCH_iddd, DCH_id, DCH_iw, DCH_iyyy, DCH_iyy, DCH_iy, DCH_i, DCH_j, DCH_mi, DCH_mm, DCH_month, DCH_mon, DCH_ms, DCH_p_m, DCH_pm, DCH_q, DCH_rm, DCH_ssss, DCH_ss, DCH_tz, DCH_us, DCH_ww, DCH_w, DCH_y_yyy, DCH_yyyy, DCH_yyy, DCH_yy, DCH_y, _DCH_last_ } |
enum | NUM_poz { NUM_COMMA, NUM_DEC, NUM_0, NUM_9, NUM_B, NUM_C, NUM_D, NUM_E, NUM_FM, NUM_G, NUM_L, NUM_MI, NUM_PL, NUM_PR, NUM_RN, NUM_SG, NUM_SP, NUM_S, NUM_TH, NUM_V, NUM_b, NUM_c, NUM_d, NUM_e, NUM_fm, NUM_g, NUM_l, NUM_mi, NUM_pl, NUM_pr, NUM_rn, NUM_sg, NUM_sp, NUM_s, NUM_th, NUM_v, _NUM_last_ } |
Functions | |
static const KeyWord * | index_seq_search (char *str, const KeyWord *kw, const int *index) |
static KeySuffix * | suff_search (char *str, KeySuffix *suf, int type) |
static void | NUMDesc_prepare (NUMDesc *num, FormatNode *n) |
static void | parse_format (FormatNode *node, char *str, const KeyWord *kw, KeySuffix *suf, const int *index, int ver, NUMDesc *Num) |
static void | DCH_to_char (FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid) |
static void | DCH_from_char (FormatNode *node, char *in, TmFromChar *out) |
static char * | get_th (char *num, int type) |
static char * | str_numth (char *dest, char *num, int type) |
static int | adjust_partial_year_to_2020 (int year) |
static int | strspace_len (char *str) |
static int | strdigits_len (char *str) |
static void | from_char_set_mode (TmFromChar *tmfc, const FromCharDateMode mode) |
static void | from_char_set_int (int *dest, const int value, const FormatNode *node) |
static int | from_char_parse_int_len (int *dest, char **src, const int len, FormatNode *node) |
static int | from_char_parse_int (int *dest, char **src, FormatNode *node) |
static int | seq_search (char *name, char **array, int type, int max, int *len) |
static int | from_char_seq_search (int *dest, char **src, char **array, int type, int max, FormatNode *node) |
static void | do_to_timestamp (text *date_txt, text *fmt, struct pg_tm *tm, fsec_t *fsec) |
static char * | fill_str (char *str, int c, int max) |
static FormatNode * | NUM_cache (int len, NUMDesc *Num, text *pars_str, bool *shouldFree) |
static char * | int_to_roman (int number) |
static void | NUM_prepare_locale (NUMProc *Np) |
static char * | get_last_relevant_decnum (char *num) |
static void | NUM_numpart_from_char (NUMProc *Np, int id, int plen) |
static void | NUM_numpart_to_char (NUMProc *Np, int id) |
static char * | NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, int plen, int sign, bool is_to_char, Oid collid) |
static DCHCacheEntry * | DCH_cache_search (char *str) |
static DCHCacheEntry * | DCH_cache_getnew (char *str) |
static NUMCacheEntry * | NUM_cache_search (char *str) |
static NUMCacheEntry * | NUM_cache_getnew (char *str) |
static void | NUM_cache_remove (NUMCacheEntry *ent) |
char * | str_tolower (const char *buff, size_t nbytes, Oid collid) |
char * | str_toupper (const char *buff, size_t nbytes, Oid collid) |
char * | str_initcap (const char *buff, size_t nbytes, Oid collid) |
char * | asc_tolower (const char *buff, size_t nbytes) |
char * | asc_toupper (const char *buff, size_t nbytes) |
char * | asc_initcap (const char *buff, size_t nbytes) |
static char * | str_tolower_z (const char *buff, Oid collid) |
static char * | str_toupper_z (const char *buff, Oid collid) |
static char * | str_initcap_z (const char *buff, Oid collid) |
static char * | asc_tolower_z (const char *buff) |
static char * | asc_toupper_z (const char *buff) |
static bool | is_next_separator (FormatNode *n) |
static text * | datetime_to_char_body (TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) |
Datum | timestamp_to_char (PG_FUNCTION_ARGS) |
Datum | timestamptz_to_char (PG_FUNCTION_ARGS) |
Datum | interval_to_char (PG_FUNCTION_ARGS) |
Datum | to_timestamp (PG_FUNCTION_ARGS) |
Datum | to_date (PG_FUNCTION_ARGS) |
Datum | numeric_to_number (PG_FUNCTION_ARGS) |
Datum | numeric_to_char (PG_FUNCTION_ARGS) |
Datum | int4_to_char (PG_FUNCTION_ARGS) |
Datum | int8_to_char (PG_FUNCTION_ARGS) |
Datum | float4_to_char (PG_FUNCTION_ARGS) |
Datum | float8_to_char (PG_FUNCTION_ARGS) |
Variables | |
char * | months [] |
char * | days [] |
static char * | months_full [] |
static char * | days_short [] |
static char * | adbc_strings [] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL} |
static char * | adbc_strings_long [] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL} |
static char * | ampm_strings [] = {am_STR, pm_STR, AM_STR, PM_STR, NULL} |
static char * | ampm_strings_long [] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL} |
static char * | rm_months_upper [] |
static char * | rm_months_lower [] |
static char * | rm1 [] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL} |
static char * | rm10 [] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL} |
static char * | rm100 [] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL} |
static char * | numTH [] = {"ST", "ND", "RD", "TH", NULL} |
static char * | numth [] = {"st", "nd", "rd", "th", NULL} |
static DCHCacheEntry | DCHCache [DCH_CACHE_FIELDS+1] |
static int | n_DCHCache = 0 |
static int | DCHCounter = 0 |
static NUMCacheEntry | NUMCache [NUM_CACHE_FIELDS+1] |
static int | n_NUMCache = 0 |
static int | NUMCounter = 0 |
static NUMCacheEntry * | last_NUMCacheEntry = NUMCache + 0 |
static KeySuffix | DCH_suff [] |
static const KeyWord | DCH_keywords [] |
static const KeyWord | NUM_keywords [] |
static const int | DCH_index [KeyWord_INDEX_SIZE] |
static const int | NUM_index [KeyWord_INDEX_SIZE] |
#define A_D_STR "A.D." |
Definition at line 209 of file formatting.c.
Referenced by DCH_to_char().
#define a_d_STR "a.d." |
Definition at line 210 of file formatting.c.
Referenced by DCH_to_char().
#define A_M_STR "A.M." |
Definition at line 236 of file formatting.c.
Referenced by DCH_to_char().
#define a_m_STR "a.m." |
Definition at line 237 of file formatting.c.
Referenced by DCH_to_char().
#define AD_STR "AD" |
Definition at line 211 of file formatting.c.
Referenced by DCH_to_char().
#define ad_STR "ad" |
Definition at line 212 of file formatting.c.
Referenced by DCH_to_char().
#define ADJUST_YEAR | ( | year, | ||
is_interval | ||||
) | ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year))) |
Definition at line 207 of file formatting.c.
Referenced by DCH_to_char().
#define ALL_LOWER 3 |
Definition at line 292 of file formatting.c.
Referenced by DCH_from_char(), and seq_search().
#define ALL_UPPER 2 |
Definition at line 291 of file formatting.c.
Referenced by DCH_from_char(), and seq_search().
#define AM_STR "AM" |
Definition at line 238 of file formatting.c.
Referenced by DCH_to_char().
#define am_STR "am" |
Definition at line 239 of file formatting.c.
Referenced by DCH_to_char().
#define AMOUNT_TEST | ( | _s | ) | (plen-(Np->inout_p-Np->inout) >= _s) |
Referenced by NUM_numpart_from_char().
#define B_C_STR "B.C." |
Definition at line 214 of file formatting.c.
Referenced by DCH_to_char().
#define b_c_STR "b.c." |
Definition at line 215 of file formatting.c.
Referenced by DCH_to_char().
#define BC_STR "BC" |
Definition at line 216 of file formatting.c.
Referenced by DCH_to_char().
#define bc_STR "bc" |
Definition at line 217 of file formatting.c.
Referenced by DCH_to_char().
#define CLOCK_12_HOUR 1 |
Definition at line 184 of file formatting.c.
Referenced by do_to_timestamp().
#define CLOCK_24_HOUR 0 |
Definition at line 183 of file formatting.c.
#define DCH_CACHE_FIELDS 16 |
Definition at line 373 of file formatting.c.
Referenced by DCH_cache_getnew(), and DCH_cache_search().
#define DCH_CACHE_SIZE 128 |
Definition at line 372 of file formatting.c.
Referenced by datetime_to_char_body(), DCH_cache_getnew(), and do_to_timestamp().
#define DCH_MAX_ITEM_SIZ 9 |
Definition at line 113 of file formatting.c.
Referenced by datetime_to_char_body(), from_char_parse_int_len(), from_char_seq_search(), and strdigits_len().
#define DCH_S_FM 0x01 |
Definition at line 504 of file formatting.c.
#define DCH_S_SP 0x08 |
Definition at line 507 of file formatting.c.
#define DCH_S_TH 0x02 |
Definition at line 505 of file formatting.c.
#define DCH_S_th 0x04 |
Definition at line 506 of file formatting.c.
#define DCH_S_TM 0x10 |
Definition at line 508 of file formatting.c.
#define DCH_TYPE 1 |
Definition at line 99 of file formatting.c.
Referenced by datetime_to_char_body(), do_to_timestamp(), and parse_format().
#define DEBUG_TM | ( | _X | ) |
Definition at line 451 of file formatting.c.
Referenced by do_to_timestamp().
#define DEBUG_TMFC | ( | _X | ) |
Definition at line 450 of file formatting.c.
Referenced by do_to_timestamp().
#define FULL_SIZ 0 |
Definition at line 294 of file formatting.c.
#define INVALID_FOR_INTERVAL |
#define IS_BLANK | ( | _f | ) | ((_f)->flag & NUM_F_BLANK) |
Definition at line 352 of file formatting.c.
Referenced by NUMDesc_prepare().
#define IS_BRACKET | ( | _f | ) | ((_f)->flag & NUM_F_BRACKET) |
Definition at line 354 of file formatting.c.
Referenced by NUM_numpart_from_char(), NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().
#define IS_DECIMAL | ( | _f | ) | ((_f)->flag & NUM_F_DECIMAL) |
Definition at line 349 of file formatting.c.
Referenced by NUM_numpart_from_char(), NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().
#define IS_EEEE | ( | _f | ) | ((_f)->flag & NUM_F_EEEE) |
Definition at line 360 of file formatting.c.
Referenced by float4_to_char(), float8_to_char(), int4_to_char(), int8_to_char(), NUM_processor(), NUMDesc_prepare(), and numeric_to_char().
#define IS_FILLMODE | ( | _f | ) | ((_f)->flag & NUM_F_FILLMODE) |
Definition at line 353 of file formatting.c.
Referenced by NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().
#define IS_LDECIMAL | ( | _f | ) | ((_f)->flag & NUM_F_LDECIMAL) |
Definition at line 350 of file formatting.c.
Referenced by NUM_prepare_locale().
#define IS_LSIGN | ( | _f | ) | ((_f)->flag & NUM_F_LSIGN) |
Definition at line 356 of file formatting.c.
Referenced by NUM_numpart_from_char(), NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().
#define IS_MINUS | ( | _f | ) | ((_f)->flag & NUM_F_MINUS) |
Definition at line 355 of file formatting.c.
Referenced by NUM_numpart_from_char(), NUM_processor(), and NUMDesc_prepare().
#define IS_MULTI | ( | _f | ) | ((_f)->flag & NUM_F_MULTI) |
Definition at line 359 of file formatting.c.
Referenced by float4_to_char(), float8_to_char(), int4_to_char(), int8_to_char(), NUMDesc_prepare(), and numeric_to_char().
#define IS_PLUS | ( | _f | ) | ((_f)->flag & NUM_F_PLUS) |
Definition at line 357 of file formatting.c.
Referenced by NUM_numpart_from_char(), NUM_processor(), and NUMDesc_prepare().
#define IS_PREDEC_SPACE | ( | _n | ) |
(IS_ZERO((_n)->Num)==FALSE && \ (_n)->number == (_n)->number_p && \ *(_n)->number == '0' && \ (_n)->Num->post != 0)
Definition at line 4265 of file formatting.c.
Referenced by NUM_numpart_to_char().
#define IS_ROMAN | ( | _f | ) | ((_f)->flag & NUM_F_ROMAN) |
Definition at line 358 of file formatting.c.
Referenced by float4_to_char(), float8_to_char(), int4_to_char(), int8_to_char(), NUM_numpart_to_char(), NUM_processor(), NUMDesc_prepare(), and numeric_to_char().
#define IS_ZERO | ( | _f | ) | ((_f)->flag & NUM_F_ZERO) |
Definition at line 351 of file formatting.c.
Referenced by NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().
#define KeyWord_INDEX_FILTER | ( | _c | ) | ((_c) <= ' ' || (_c) >= '~' ? 0 : 1) |
Definition at line 107 of file formatting.c.
Referenced by index_seq_search().
#define KeyWord_INDEX_SIZE ('~' - ' ') |
Definition at line 106 of file formatting.c.
#define MAX_DAY_LEN 9 |
Definition at line 298 of file formatting.c.
Referenced by DCH_from_char().
#define MAX_DY_LEN 3 |
Definition at line 299 of file formatting.c.
Referenced by DCH_from_char().
#define MAX_MON_LEN 3 |
Definition at line 297 of file formatting.c.
Referenced by DCH_from_char().
#define MAX_MONTH_LEN 9 |
Definition at line 296 of file formatting.c.
Referenced by DCH_from_char().
#define MAX_RM_LEN 4 |
Definition at line 300 of file formatting.c.
Referenced by DCH_from_char().
#define MAXDOUBLEWIDTH 500 |
Definition at line 121 of file formatting.c.
Referenced by float4_to_char(), float8_to_char(), and int4_to_char().
#define MAXFLOATWIDTH 60 |
Definition at line 120 of file formatting.c.
Referenced by float4_to_char().
#define NODE_TYPE_ACTION 2 |
Definition at line 177 of file formatting.c.
Referenced by DCH_from_char(), DCH_to_char(), is_next_separator(), NUM_processor(), NUMDesc_prepare(), and parse_format().
#define NODE_TYPE_CHAR 3 |
Definition at line 178 of file formatting.c.
#define NODE_TYPE_END 1 |
Definition at line 176 of file formatting.c.
Referenced by datetime_to_char_body(), DCH_from_char(), do_to_timestamp(), is_next_separator(), NUM_cache(), and NUM_processor().
#define NUM_CACHE_FIELDS 16 |
Definition at line 371 of file formatting.c.
Referenced by NUM_cache_getnew(), and NUM_cache_search().
#define NUM_CACHE_SIZE 64 |
Definition at line 370 of file formatting.c.
Referenced by NUM_cache(), and NUM_cache_getnew().
#define NUM_F_BLANK (1 << 4) |
Definition at line 329 of file formatting.c.
#define NUM_F_BRACKET (1 << 7) |
Definition at line 332 of file formatting.c.
#define NUM_F_DECIMAL (1 << 1) |
Definition at line 326 of file formatting.c.
#define NUM_F_EEEE (1 << 14) |
Definition at line 339 of file formatting.c.
#define NUM_F_FILLMODE (1 << 5) |
Definition at line 330 of file formatting.c.
#define NUM_F_LDECIMAL (1 << 2) |
Definition at line 327 of file formatting.c.
#define NUM_F_LSIGN (1 << 6) |
Definition at line 331 of file formatting.c.
#define NUM_F_MINUS (1 << 8) |
Definition at line 333 of file formatting.c.
#define NUM_F_MINUS_POST (1 << 13) |
Definition at line 338 of file formatting.c.
#define NUM_F_MULTI (1 << 11) |
Definition at line 336 of file formatting.c.
#define NUM_F_PLUS (1 << 9) |
Definition at line 334 of file formatting.c.
#define NUM_F_PLUS_POST (1 << 12) |
Definition at line 337 of file formatting.c.
#define NUM_F_ROMAN (1 << 10) |
Definition at line 335 of file formatting.c.
#define NUM_F_ZERO (1 << 3) |
Definition at line 328 of file formatting.c.
#define NUM_LSIGN_NONE 0 |
Definition at line 343 of file formatting.c.
Referenced by NUMDesc_prepare().
#define NUM_LSIGN_POST 1 |
Definition at line 342 of file formatting.c.
#define NUM_LSIGN_PRE (-1) |
Definition at line 341 of file formatting.c.
Referenced by NUM_numpart_from_char(), NUM_numpart_to_char(), and NUM_processor().
#define NUM_MAX_ITEM_SIZ 8 |
Definition at line 114 of file formatting.c.
Referenced by numeric_to_number().
#define NUM_TOCHAR_finish |
do { \ NUM_processor(format, &Num, VARDATA(result), numstr, plen, sign, true, PG_GET_COLLATION()); \ \ if (shouldFree) \ pfree(format); \ \ /* \ * Convert null-terminated representation of result to standard text. \ * The result is usually much bigger than it needs to be, but there \ * seems little point in realloc'ing it smaller. \ */ \ len = strlen(VARDATA(result)); \ SET_VARSIZE(result, len + VARHDRSZ); \ } while (0)
Definition at line 4891 of file formatting.c.
#define NUM_TOCHAR_prepare |
do { \ len = VARSIZE_ANY_EXHDR(fmt); \ if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \ PG_RETURN_TEXT_P(cstring_to_text("")); \ result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \ format = NUM_cache(len, &Num, fmt, &shouldFree); \ } while (0)
Definition at line 4878 of file formatting.c.
#define NUM_TYPE 2 |
Definition at line 100 of file formatting.c.
Referenced by NUM_cache(), and parse_format().
#define ONE_UPPER 1 |
Definition at line 290 of file formatting.c.
Referenced by DCH_from_char(), and seq_search().
#define OVERLOAD_TEST (Np->inout_p >= Np->inout + plen) |
Referenced by NUM_numpart_from_char().
#define P_M_STR "P.M." |
Definition at line 241 of file formatting.c.
Referenced by DCH_to_char().
#define p_m_STR "p.m." |
Definition at line 242 of file formatting.c.
Referenced by DCH_to_char().
#define PM_STR "PM" |
Definition at line 243 of file formatting.c.
Referenced by DCH_to_char().
#define pm_STR "pm" |
Definition at line 244 of file formatting.c.
Referenced by DCH_to_char().
#define S_FM | ( | _s | ) | (((_s) & DCH_S_FM) ? 1 : 0) |
Definition at line 520 of file formatting.c.
Referenced by DCH_to_char(), and from_char_parse_int_len().
#define S_SP | ( | _s | ) | (((_s) & DCH_S_SP) ? 1 : 0) |
Definition at line 521 of file formatting.c.
#define S_TH | ( | _s | ) | (((_s) & DCH_S_TH) ? 1 : 0) |
Definition at line 515 of file formatting.c.
#define S_th | ( | _s | ) | (((_s) & DCH_S_th) ? 1 : 0) |
Definition at line 516 of file formatting.c.
#define S_TH_TYPE | ( | _s | ) | (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER) |
Definition at line 517 of file formatting.c.
Referenced by DCH_to_char().
#define S_THth | ( | _s | ) | ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0) |
Definition at line 514 of file formatting.c.
Referenced by DCH_to_char(), and is_next_separator().
#define S_TM | ( | _s | ) | (((_s) & DCH_S_TM) ? 1 : 0) |
Definition at line 522 of file formatting.c.
Referenced by DCH_to_char().
#define SKIP_THth | ( | _suf | ) | (S_THth(_suf) ? 2 : 0) |
Definition at line 1983 of file formatting.c.
Referenced by DCH_from_char().
#define SUFFTYPE_POSTFIX 2 |
Definition at line 181 of file formatting.c.
Referenced by parse_format().
#define SUFFTYPE_PREFIX 1 |
Definition at line 180 of file formatting.c.
Referenced by parse_format().
#define TH_LOWER 2 |
Definition at line 303 of file formatting.c.
Referenced by NUM_processor().
#define TH_UPPER 1 |
Definition at line 302 of file formatting.c.
Referenced by get_th(), and NUM_processor().
#define tmtcFsec | ( | _X | ) | ((_X)->fsec) |
Definition at line 467 of file formatting.c.
Referenced by interval_to_char(), timestamp_to_char(), and timestamptz_to_char().
#define tmtcTm | ( | _X | ) | (&(_X)->tm) |
Definition at line 465 of file formatting.c.
Referenced by interval_to_char(), timestamp_to_char(), and timestamptz_to_char().
#define tmtcTzn | ( | _X | ) | ((_X)->tzn) |
Definition at line 466 of file formatting.c.
Referenced by DCH_to_char(), and timestamptz_to_char().
#define ZERO_tm | ( | _X | ) |
do { \ (_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \ (_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \ (_X)->tm_mday = (_X)->tm_mon = 1; \ } while(0)
Definition at line 469 of file formatting.c.
Referenced by do_to_timestamp().
#define ZERO_tmfc | ( | _X | ) | memset(_X, 0, sizeof(TmFromChar)) |
Definition at line 431 of file formatting.c.
Referenced by do_to_timestamp().
#define ZERO_tmtc | ( | _X | ) |
Definition at line 476 of file formatting.c.
Referenced by interval_to_char(), timestamp_to_char(), and timestamptz_to_char().
#define zeroize_NUM | ( | _n | ) |
do { \ (_n)->flag = 0; \ (_n)->lsign = 0; \ (_n)->pre = 0; \ (_n)->post = 0; \ (_n)->pre_lsign_num = 0; \ (_n)->need_locale = 0; \ (_n)->multi = 0; \ (_n)->zero_start = 0; \ (_n)->zero_end = 0; \ } while(0)
Definition at line 3692 of file formatting.c.
Referenced by NUM_cache(), and NUM_cache_getnew().
typedef struct FormatNode FormatNode |
Definition at line 157 of file formatting.c.
enum DCH_poz |
Definition at line 568 of file formatting.c.
{ DCH_A_D, DCH_A_M, DCH_AD, DCH_AM, DCH_B_C, DCH_BC, DCH_CC, DCH_DAY, DCH_DDD, DCH_DD, DCH_DY, DCH_Day, DCH_Dy, DCH_D, DCH_FX, /* global suffix */ DCH_HH24, DCH_HH12, DCH_HH, DCH_IDDD, DCH_ID, DCH_IW, DCH_IYYY, DCH_IYY, DCH_IY, DCH_I, DCH_J, DCH_MI, DCH_MM, DCH_MONTH, DCH_MON, DCH_MS, DCH_Month, DCH_Mon, DCH_P_M, DCH_PM, DCH_Q, DCH_RM, DCH_SSSS, DCH_SS, DCH_TZ, DCH_US, DCH_WW, DCH_W, DCH_Y_YYY, DCH_YYYY, DCH_YYY, DCH_YY, DCH_Y, DCH_a_d, DCH_a_m, DCH_ad, DCH_am, DCH_b_c, DCH_bc, DCH_cc, DCH_day, DCH_ddd, DCH_dd, DCH_dy, DCH_d, DCH_fx, DCH_hh24, DCH_hh12, DCH_hh, DCH_iddd, DCH_id, DCH_iw, DCH_iyyy, DCH_iyy, DCH_iy, DCH_i, DCH_j, DCH_mi, DCH_mm, DCH_month, DCH_mon, DCH_ms, DCH_p_m, DCH_pm, DCH_q, DCH_rm, DCH_ssss, DCH_ss, DCH_tz, DCH_us, DCH_ww, DCH_w, DCH_y_yyy, DCH_yyyy, DCH_yyy, DCH_yy, DCH_y, /* last */ _DCH_last_ } DCH_poz;
enum FromCharDateMode |
Definition at line 150 of file formatting.c.
{ FROM_CHAR_DATE_NONE = 0, /* Value does not affect date mode. */ FROM_CHAR_DATE_GREGORIAN, /* Gregorian (day, month, year) style date */ FROM_CHAR_DATE_ISOWEEK /* ISO 8601 week date */ } FromCharDateMode;
enum NUM_poz |
Definition at line 667 of file formatting.c.
{ NUM_COMMA, NUM_DEC, NUM_0, NUM_9, NUM_B, NUM_C, NUM_D, NUM_E, NUM_FM, NUM_G, NUM_L, NUM_MI, NUM_PL, NUM_PR, NUM_RN, NUM_SG, NUM_SP, NUM_S, NUM_TH, NUM_V, NUM_b, NUM_c, NUM_d, NUM_e, NUM_fm, NUM_g, NUM_l, NUM_mi, NUM_pl, NUM_pr, NUM_rn, NUM_sg, NUM_sp, NUM_s, NUM_th, NUM_v, /* last */ _NUM_last_ } NUM_poz;
static int adjust_partial_year_to_2020 | ( | int | year | ) | [static] |
Definition at line 2055 of file formatting.c.
Referenced by DCH_from_char().
{ /* * Adjust all dates toward 2020; this is effectively what happens when we * assume '70' is 1970 and '69' is 2069. */ /* Force 0-69 into the 2000's */ if (year < 70) return year + 2000; /* Force 70-99 into the 1900's */ else if (year < 100) return year + 1900; /* Force 100-519 into the 2000's */ else if (year < 520) return year + 2000; /* Force 520-999 into the 1000's */ else if (year < 1000) return year + 1000; else return year; }
char* asc_initcap | ( | const char * | buff, | |
size_t | nbytes | |||
) |
Definition at line 1916 of file formatting.c.
References pg_ascii_tolower(), pg_ascii_toupper(), and pnstrdup().
Referenced by str_initcap().
{ char *result; char *p; int wasalnum = false; if (!buff) return NULL; result = pnstrdup(buff, nbytes); for (p = result; *p; p++) { char c; if (wasalnum) *p = c = pg_ascii_tolower((unsigned char) *p); else *p = c = pg_ascii_toupper((unsigned char) *p); /* we don't trust isalnum() here */ wasalnum = ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')); } return result; }
char* asc_tolower | ( | const char * | buff, | |
size_t | nbytes | |||
) |
Definition at line 1870 of file formatting.c.
References pg_ascii_tolower(), and pnstrdup().
Referenced by asc_tolower_z(), and str_tolower().
{ char *result; char *p; if (!buff) return NULL; result = pnstrdup(buff, nbytes); for (p = result; *p; p++) *p = pg_ascii_tolower((unsigned char) *p); return result; }
static char* asc_tolower_z | ( | const char * | buff | ) | [static] |
Definition at line 1965 of file formatting.c.
References asc_tolower().
Referenced by DCH_to_char(), and NUM_processor().
{ return asc_tolower(buff, strlen(buff)); }
char* asc_toupper | ( | const char * | buff, | |
size_t | nbytes | |||
) |
Definition at line 1893 of file formatting.c.
References pg_ascii_toupper(), and pnstrdup().
Referenced by asc_toupper_z(), and str_toupper().
{ char *result; char *p; if (!buff) return NULL; result = pnstrdup(buff, nbytes); for (p = result; *p; p++) *p = pg_ascii_toupper((unsigned char) *p); return result; }
static char* asc_toupper_z | ( | const char * | buff | ) | [static] |
Definition at line 1971 of file formatting.c.
References asc_toupper().
Referenced by DCH_to_char().
{ return asc_toupper(buff, strlen(buff)); }
static text* datetime_to_char_body | ( | TmToChar * | tmtc, | |
text * | fmt, | |||
bool | is_interval, | |||
Oid | collid | |||
) | [static] |
Definition at line 3169 of file formatting.c.
References cstring_to_text(), DCH_cache_getnew(), DCH_cache_search(), DCH_CACHE_SIZE, DCH_index, DCH_MAX_ITEM_SIZ, DCH_to_char(), DCH_TYPE, DCHCacheEntry::format, format, NODE_TYPE_END, NULL, palloc(), parse_format(), pfree(), and text_to_cstring().
Referenced by interval_to_char(), timestamp_to_char(), and timestamptz_to_char().
{ FormatNode *format; char *fmt_str, *result; bool incache; int fmt_len; text *res; /* * Convert fmt to C string */ fmt_str = text_to_cstring(fmt); fmt_len = strlen(fmt_str); /* * Allocate workspace for result as C string */ result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1); *result = '\0'; /* * Allocate new memory if format picture is bigger than static cache and * not use cache (call parser always) */ if (fmt_len > DCH_CACHE_SIZE) { format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); incache = FALSE; parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_TYPE, NULL); (format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ } else { /* * Use cache buffers */ DCHCacheEntry *ent; incache = TRUE; if ((ent = DCH_cache_search(fmt_str)) == NULL) { ent = DCH_cache_getnew(fmt_str); /* * Not in the cache, must run parser and save a new format-picture * to the cache. */ parse_format(ent->format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_TYPE, NULL); (ent->format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ #ifdef DEBUG_TO_FROM_CHAR /* dump_node(ent->format, fmt_len); */ /* dump_index(DCH_keywords, DCH_index); */ #endif } format = ent->format; } /* The real work is here */ DCH_to_char(format, is_interval, tmtc, result, collid); if (!incache) pfree(format); pfree(fmt_str); /* convert C-string result to TEXT format */ res = cstring_to_text(result); pfree(result); return res; }
static DCHCacheEntry * DCH_cache_getnew | ( | char * | str | ) | [static] |
Definition at line 3086 of file formatting.c.
References DCHCacheEntry::age, DCH_CACHE_FIELDS, DCH_CACHE_SIZE, DCHCounter, elog, n_DCHCache, DCHCacheEntry::str, and StrNCpy.
Referenced by datetime_to_char_body(), and do_to_timestamp().
{ DCHCacheEntry *ent; /* counter overflow check - paranoia? */ if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1)) { DCHCounter = 0; for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) ent->age = (++DCHCounter); } /* * If cache is full, remove oldest entry */ if (n_DCHCache > DCH_CACHE_FIELDS) { DCHCacheEntry *old = DCHCache + 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache); #endif for (ent = DCHCache + 1; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) { if (ent->age < old->age) old = ent; } #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age); #endif StrNCpy(old->str, str, DCH_CACHE_SIZE + 1); /* old->format fill parser */ old->age = (++DCHCounter); return old; } else { #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache); #endif ent = DCHCache + n_DCHCache; StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1); /* ent->format fill parser */ ent->age = (++DCHCounter); ++n_DCHCache; return ent; } }
static DCHCacheEntry * DCH_cache_search | ( | char * | str | ) | [static] |
Definition at line 3137 of file formatting.c.
References DCHCacheEntry::age, DCH_CACHE_FIELDS, DCHCounter, i, n_DCHCache, and DCHCacheEntry::str.
Referenced by datetime_to_char_body(), and do_to_timestamp().
{ int i; DCHCacheEntry *ent; /* counter overflow check - paranoia? */ if (DCHCounter >= (INT_MAX - DCH_CACHE_FIELDS - 1)) { DCHCounter = 0; for (ent = DCHCache; ent <= (DCHCache + DCH_CACHE_FIELDS); ent++) ent->age = (++DCHCounter); } for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++) { if (strcmp(ent->str, str) == 0) { ent->age = (++DCHCounter); return ent; } } return NULL; }
static void DCH_from_char | ( | FormatNode * | node, | |
char * | in, | |||
TmFromChar * | out | |||
) | [static] |
Definition at line 2826 of file formatting.c.
References adbc_strings, adbc_strings_long, adjust_partial_year_to_2020(), ALL_LOWER, ALL_UPPER, ampm_strings, ampm_strings_long, TmFromChar::bc, TmFromChar::cc, FormatNode::character, TmFromChar::clock, TmFromChar::d, KeyWord::date_mode, days, DCH_a_d, DCH_A_D, DCH_a_m, DCH_A_M, DCH_ad, DCH_AD, DCH_am, DCH_AM, DCH_b_c, DCH_B_C, DCH_bc, DCH_BC, DCH_CC, DCH_D, DCH_day, DCH_Day, DCH_DAY, DCH_DD, DCH_DDD, DCH_dy, DCH_Dy, DCH_DY, DCH_FX, DCH_HH, DCH_HH12, DCH_HH24, DCH_I, DCH_ID, DCH_IDDD, DCH_IW, DCH_IY, DCH_IYY, DCH_IYYY, DCH_J, DCH_MI, DCH_MM, DCH_mon, DCH_Mon, DCH_MON, DCH_month, DCH_Month, DCH_MONTH, DCH_MS, DCH_p_m, DCH_P_M, DCH_pm, DCH_PM, DCH_Q, DCH_rm, DCH_RM, DCH_SS, DCH_SSSS, DCH_TZ, DCH_tz, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, TmFromChar::dd, TmFromChar::ddd, ereport, errcode(), errmsg(), ERROR, from_char_parse_int(), from_char_parse_int_len(), from_char_seq_search(), from_char_set_int(), from_char_set_mode(), TmFromChar::hh, KeyWord::id, TmFromChar::j, FormatNode::key, KeyWord::len, MAX_DAY_LEN, MAX_DY_LEN, MAX_MON_LEN, MAX_MONTH_LEN, MAX_RM_LEN, TmFromChar::mi, TmFromChar::mm, months, months_full, MONTHS_PER_YEAR, TmFromChar::ms, NODE_TYPE_ACTION, NODE_TYPE_END, NULL, ONE_UPPER, TmFromChar::pm, rm_months_lower, rm_months_upper, SKIP_THth, TmFromChar::ss, TmFromChar::ssss, strdigits_len(), FormatNode::suffix, FormatNode::type, TmFromChar::us, value, TmFromChar::w, TmFromChar::ww, TmFromChar::year, and TmFromChar::yysz.
Referenced by do_to_timestamp().
{ FormatNode *n; char *s; int len, value; bool fx_mode = false; for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++) { if (n->type != NODE_TYPE_ACTION) { s++; /* Ignore spaces when not in FX (fixed width) mode */ if (isspace((unsigned char) n->character) && !fx_mode) { while (*s != '\0' && isspace((unsigned char) *s)) s++; } continue; } from_char_set_mode(out, n->key->date_mode); switch (n->key->id) { case DCH_FX: fx_mode = true; break; case DCH_A_M: case DCH_P_M: case DCH_a_m: case DCH_p_m: from_char_seq_search(&value, &s, ampm_strings_long, ALL_UPPER, n->key->len, n); from_char_set_int(&out->pm, value % 2, n); out->clock = CLOCK_12_HOUR; break; case DCH_AM: case DCH_PM: case DCH_am: case DCH_pm: from_char_seq_search(&value, &s, ampm_strings, ALL_UPPER, n->key->len, n); from_char_set_int(&out->pm, value % 2, n); out->clock = CLOCK_12_HOUR; break; case DCH_HH: case DCH_HH12: from_char_parse_int_len(&out->hh, &s, 2, n); out->clock = CLOCK_12_HOUR; s += SKIP_THth(n->suffix); break; case DCH_HH24: from_char_parse_int_len(&out->hh, &s, 2, n); s += SKIP_THth(n->suffix); break; case DCH_MI: from_char_parse_int(&out->mi, &s, n); s += SKIP_THth(n->suffix); break; case DCH_SS: from_char_parse_int(&out->ss, &s, n); s += SKIP_THth(n->suffix); break; case DCH_MS: /* millisecond */ len = from_char_parse_int_len(&out->ms, &s, 3, n); /* * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25 */ out->ms *= len == 1 ? 100 : len == 2 ? 10 : 1; s += SKIP_THth(n->suffix); break; case DCH_US: /* microsecond */ len = from_char_parse_int_len(&out->us, &s, 6, n); out->us *= len == 1 ? 100000 : len == 2 ? 10000 : len == 3 ? 1000 : len == 4 ? 100 : len == 5 ? 10 : 1; s += SKIP_THth(n->suffix); break; case DCH_SSSS: from_char_parse_int(&out->ssss, &s, n); s += SKIP_THth(n->suffix); break; case DCH_tz: case DCH_TZ: ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("\"TZ\"/\"tz\" format patterns are not supported in to_date"))); case DCH_A_D: case DCH_B_C: case DCH_a_d: case DCH_b_c: from_char_seq_search(&value, &s, adbc_strings_long, ALL_UPPER, n->key->len, n); from_char_set_int(&out->bc, value % 2, n); break; case DCH_AD: case DCH_BC: case DCH_ad: case DCH_bc: from_char_seq_search(&value, &s, adbc_strings, ALL_UPPER, n->key->len, n); from_char_set_int(&out->bc, value % 2, n); break; case DCH_MONTH: case DCH_Month: case DCH_month: from_char_seq_search(&value, &s, months_full, ONE_UPPER, MAX_MONTH_LEN, n); from_char_set_int(&out->mm, value + 1, n); break; case DCH_MON: case DCH_Mon: case DCH_mon: from_char_seq_search(&value, &s, months, ONE_UPPER, MAX_MON_LEN, n); from_char_set_int(&out->mm, value + 1, n); break; case DCH_MM: from_char_parse_int(&out->mm, &s, n); s += SKIP_THth(n->suffix); break; case DCH_DAY: case DCH_Day: case DCH_day: from_char_seq_search(&value, &s, days, ONE_UPPER, MAX_DAY_LEN, n); from_char_set_int(&out->d, value, n); out->d++; break; case DCH_DY: case DCH_Dy: case DCH_dy: from_char_seq_search(&value, &s, days, ONE_UPPER, MAX_DY_LEN, n); from_char_set_int(&out->d, value, n); out->d++; break; case DCH_DDD: from_char_parse_int(&out->ddd, &s, n); s += SKIP_THth(n->suffix); break; case DCH_IDDD: from_char_parse_int_len(&out->ddd, &s, 3, n); s += SKIP_THth(n->suffix); break; case DCH_DD: from_char_parse_int(&out->dd, &s, n); s += SKIP_THth(n->suffix); break; case DCH_D: from_char_parse_int(&out->d, &s, n); s += SKIP_THth(n->suffix); break; case DCH_ID: from_char_parse_int_len(&out->d, &s, 1, n); /* Shift numbering to match Gregorian where Sunday = 1 */ if (++out->d > 7) out->d = 1; s += SKIP_THth(n->suffix); break; case DCH_WW: case DCH_IW: from_char_parse_int(&out->ww, &s, n); s += SKIP_THth(n->suffix); break; case DCH_Q: /* * We ignore 'Q' when converting to date because it is unclear * which date in the quarter to use, and some people specify * both quarter and month, so if it was honored it might * conflict with the supplied month. That is also why we don't * throw an error. * * We still parse the source string for an integer, but it * isn't stored anywhere in 'out'. */ from_char_parse_int((int *) NULL, &s, n); s += SKIP_THth(n->suffix); break; case DCH_CC: from_char_parse_int(&out->cc, &s, n); s += SKIP_THth(n->suffix); break; case DCH_Y_YYY: { int matched, years, millenia; matched = sscanf(s, "%d,%03d", &millenia, &years); if (matched != 2) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid input string for \"Y,YYY\""))); years += (millenia * 1000); from_char_set_int(&out->year, years, n); out->yysz = 4; s += strdigits_len(s) + 4 + SKIP_THth(n->suffix); } break; case DCH_YYYY: case DCH_IYYY: from_char_parse_int(&out->year, &s, n); out->yysz = 4; s += SKIP_THth(n->suffix); break; case DCH_YYY: case DCH_IYY: if (from_char_parse_int(&out->year, &s, n) < 4) out->year = adjust_partial_year_to_2020(out->year); out->yysz = 3; s += SKIP_THth(n->suffix); break; case DCH_YY: case DCH_IY: if (from_char_parse_int(&out->year, &s, n) < 4) out->year = adjust_partial_year_to_2020(out->year); out->yysz = 2; s += SKIP_THth(n->suffix); break; case DCH_Y: case DCH_I: if (from_char_parse_int(&out->year, &s, n) < 4) out->year = adjust_partial_year_to_2020(out->year); out->yysz = 1; s += SKIP_THth(n->suffix); break; case DCH_RM: from_char_seq_search(&value, &s, rm_months_upper, ALL_UPPER, MAX_RM_LEN, n); from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n); break; case DCH_rm: from_char_seq_search(&value, &s, rm_months_lower, ALL_LOWER, MAX_RM_LEN, n); from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n); break; case DCH_W: from_char_parse_int(&out->w, &s, n); s += SKIP_THth(n->suffix); break; case DCH_J: from_char_parse_int(&out->j, &s, n); s += SKIP_THth(n->suffix); break; } } }
static void DCH_to_char | ( | FormatNode * | node, | |
bool | is_interval, | |||
TmToChar * | in, | |||
char * | out, | |||
Oid | collid | |||
) | [static] |
Definition at line 2378 of file formatting.c.
References a_d_STR, A_D_STR, a_m_STR, A_M_STR, ad_STR, AD_STR, ADJUST_YEAR, am_STR, AM_STR, asc_tolower_z(), asc_toupper_z(), b_c_STR, B_C_STR, bc_STR, BC_STR, cache_locale_time(), FormatNode::character, date2isoweek(), date2isoyear(), date2isoyearday(), date2j(), days, days_short, DCH_a_d, DCH_A_D, DCH_a_m, DCH_A_M, DCH_ad, DCH_AD, DCH_am, DCH_AM, DCH_b_c, DCH_B_C, DCH_bc, DCH_BC, DCH_CC, DCH_D, DCH_day, DCH_Day, DCH_DAY, DCH_DD, DCH_DDD, DCH_dy, DCH_Dy, DCH_DY, DCH_HH, DCH_HH12, DCH_HH24, DCH_I, DCH_ID, DCH_IDDD, DCH_IW, DCH_IY, DCH_IYY, DCH_IYYY, DCH_J, DCH_MI, DCH_MM, DCH_mon, DCH_Mon, DCH_MON, DCH_month, DCH_Month, DCH_MONTH, DCH_MS, DCH_p_m, DCH_P_M, DCH_pm, DCH_PM, DCH_Q, DCH_rm, DCH_RM, DCH_SS, DCH_SSSS, DCH_TZ, DCH_tz, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, TmToChar::fsec, HOURS_PER_DAY, i, KeyWord::id, INT64CONST, FormatNode::key, localized_abbrev_days, localized_abbrev_months, localized_full_days, localized_full_months, months, months_full, MONTHS_PER_YEAR, NODE_TYPE_ACTION, p_m_STR, P_M_STR, pfree(), pm_STR, PM_STR, rm_months_lower, rm_months_upper, S_FM, S_TH_TYPE, S_THth, S_TM, SECS_PER_HOUR, SECS_PER_MINUTE, str_initcap_z(), str_numth(), str_tolower_z(), str_toupper_z(), FormatNode::suffix, TmToChar::tm, tm, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcTzn, and FormatNode::type.
Referenced by datetime_to_char_body().
{ FormatNode *n; char *s; struct pg_tm *tm = &in->tm; int i; /* cache localized days and months */ cache_locale_time(); s = out; for (n = node; n->type != NODE_TYPE_END; n++) { if (n->type != NODE_TYPE_ACTION) { *s = n->character; s++; continue; } switch (n->key->id) { case DCH_A_M: case DCH_P_M: strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2) ? P_M_STR : A_M_STR); s += strlen(s); break; case DCH_AM: case DCH_PM: strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2) ? PM_STR : AM_STR); s += strlen(s); break; case DCH_a_m: case DCH_p_m: strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2) ? p_m_STR : a_m_STR); s += strlen(s); break; case DCH_am: case DCH_pm: strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2) ? pm_STR : am_STR); s += strlen(s); break; case DCH_HH: case DCH_HH12: /* * display time as shown on a 12-hour clock, even for * intervals */ sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? HOURS_PER_DAY / 2 : tm->tm_hour % (HOURS_PER_DAY / 2)); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_HH24: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_hour); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_MI: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_min); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_SS: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_sec); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_MS: /* millisecond */ #ifdef HAVE_INT64_TIMESTAMP sprintf(s, "%03d", (int) (in->fsec / INT64CONST(1000))); #else /* No rint() because we can't overflow and we might print US */ sprintf(s, "%03d", (int) (in->fsec * 1000)); #endif if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_US: /* microsecond */ #ifdef HAVE_INT64_TIMESTAMP sprintf(s, "%06d", (int) in->fsec); #else /* don't use rint() because we can't overflow 1000 */ sprintf(s, "%06d", (int) (in->fsec * 1000000)); #endif if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_SSSS: sprintf(s, "%d", tm->tm_hour * SECS_PER_HOUR + tm->tm_min * SECS_PER_MINUTE + tm->tm_sec); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_tz: INVALID_FOR_INTERVAL; if (tmtcTzn(in)) { /* We assume here that timezone names aren't localized */ char *p = asc_tolower_z(tmtcTzn(in)); strcpy(s, p); pfree(p); s += strlen(s); } break; case DCH_TZ: INVALID_FOR_INTERVAL; if (tmtcTzn(in)) { strcpy(s, tmtcTzn(in)); s += strlen(s); } break; case DCH_A_D: case DCH_B_C: INVALID_FOR_INTERVAL; strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR)); s += strlen(s); break; case DCH_AD: case DCH_BC: INVALID_FOR_INTERVAL; strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR)); s += strlen(s); break; case DCH_a_d: case DCH_b_c: INVALID_FOR_INTERVAL; strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR)); s += strlen(s); break; case DCH_ad: case DCH_bc: INVALID_FOR_INTERVAL; strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR)); s += strlen(s); break; case DCH_MONTH: INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; if (S_TM(n->suffix)) strcpy(s, str_toupper_z(localized_full_months[tm->tm_mon - 1], collid)); else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, asc_toupper_z(months_full[tm->tm_mon - 1])); s += strlen(s); break; case DCH_Month: INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; if (S_TM(n->suffix)) strcpy(s, str_initcap_z(localized_full_months[tm->tm_mon - 1], collid)); else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, months_full[tm->tm_mon - 1]); s += strlen(s); break; case DCH_month: INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; if (S_TM(n->suffix)) strcpy(s, str_tolower_z(localized_full_months[tm->tm_mon - 1], collid)); else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, asc_tolower_z(months_full[tm->tm_mon - 1])); s += strlen(s); break; case DCH_MON: INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; if (S_TM(n->suffix)) strcpy(s, str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid)); else strcpy(s, asc_toupper_z(months[tm->tm_mon - 1])); s += strlen(s); break; case DCH_Mon: INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; if (S_TM(n->suffix)) strcpy(s, str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid)); else strcpy(s, months[tm->tm_mon - 1]); s += strlen(s); break; case DCH_mon: INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; if (S_TM(n->suffix)) strcpy(s, str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid)); else strcpy(s, asc_tolower_z(months[tm->tm_mon - 1])); s += strlen(s); break; case DCH_MM: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mon); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_DAY: INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) strcpy(s, str_toupper_z(localized_full_days[tm->tm_wday], collid)); else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, asc_toupper_z(days[tm->tm_wday])); s += strlen(s); break; case DCH_Day: INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) strcpy(s, str_initcap_z(localized_full_days[tm->tm_wday], collid)); else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, days[tm->tm_wday]); s += strlen(s); break; case DCH_day: INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) strcpy(s, str_tolower_z(localized_full_days[tm->tm_wday], collid)); else sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, asc_tolower_z(days[tm->tm_wday])); s += strlen(s); break; case DCH_DY: INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) strcpy(s, str_toupper_z(localized_abbrev_days[tm->tm_wday], collid)); else strcpy(s, asc_toupper_z(days_short[tm->tm_wday])); s += strlen(s); break; case DCH_Dy: INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) strcpy(s, str_initcap_z(localized_abbrev_days[tm->tm_wday], collid)); else strcpy(s, days_short[tm->tm_wday]); s += strlen(s); break; case DCH_dy: INVALID_FOR_INTERVAL; if (S_TM(n->suffix)) strcpy(s, str_tolower_z(localized_abbrev_days[tm->tm_wday], collid)); else strcpy(s, asc_tolower_z(days_short[tm->tm_wday])); s += strlen(s); break; case DCH_DDD: case DCH_IDDD: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3, (n->key->id == DCH_DDD) ? tm->tm_yday : date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday)); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_DD: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_D: INVALID_FOR_INTERVAL; sprintf(s, "%d", tm->tm_wday + 1); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_ID: INVALID_FOR_INTERVAL; sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_WW: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, (tm->tm_yday - 1) / 7 + 1); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_IW: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday)); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_Q: if (!tm->tm_mon) break; sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_CC: if (is_interval) /* straight calculation */ i = tm->tm_year / 100; else { if (tm->tm_year > 0) /* Century 20 == 1901 - 2000 */ i = (tm->tm_year - 1) / 100 + 1; else /* Century 6BC == 600BC - 501BC */ i = tm->tm_year / 100 - 1; } if (i <= 99 && i >= -99) sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, i); else sprintf(s, "%d", i); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_Y_YYY: i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000; sprintf(s, "%d,%03d", i, ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000)); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_YYYY: case DCH_IYYY: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 4, (n->key->id == DCH_YYYY ? ADJUST_YEAR(tm->tm_year, is_interval) : ADJUST_YEAR(date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday), is_interval))); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_YYY: case DCH_IYY: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3, (n->key->id == DCH_YYY ? ADJUST_YEAR(tm->tm_year, is_interval) : ADJUST_YEAR(date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday), is_interval)) % 1000); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_YY: case DCH_IY: sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, (n->key->id == DCH_YY ? ADJUST_YEAR(tm->tm_year, is_interval) : ADJUST_YEAR(date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday), is_interval)) % 100); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_Y: case DCH_I: sprintf(s, "%1d", (n->key->id == DCH_Y ? ADJUST_YEAR(tm->tm_year, is_interval) : ADJUST_YEAR(date2isoyear(tm->tm_year, tm->tm_mon, tm->tm_mday), is_interval)) % 10); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_RM: if (!tm->tm_mon) break; sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4, rm_months_upper[MONTHS_PER_YEAR - tm->tm_mon]); s += strlen(s); break; case DCH_rm: if (!tm->tm_mon) break; sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4, rm_months_lower[MONTHS_PER_YEAR - tm->tm_mon]); s += strlen(s); break; case DCH_W: sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_J: sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); if (S_THth(n->suffix)) str_numth(s, s, S_TH_TYPE(n->suffix)); s += strlen(s); break; } } *s = '\0'; }
static void do_to_timestamp | ( | text * | date_txt, | |
text * | fmt, | |||
struct pg_tm * | tm, | |||
fsec_t * | fsec | |||
) | [static] |
Definition at line 3425 of file formatting.c.
References TmFromChar::bc, TmFromChar::cc, TmFromChar::clock, CLOCK_12_HOUR, TmFromChar::d, DCH_cache_getnew(), DCH_cache_search(), DCH_CACHE_SIZE, DCH_from_char(), DCH_index, DCH_TYPE, TmFromChar::dd, TmFromChar::ddd, DEBUG_TM, DEBUG_TMFC, ereport, errcode(), errhint(), errmsg(), ERROR, DCHCacheEntry::format, format, FROM_CHAR_DATE_ISOWEEK, TmFromChar::hh, HOURS_PER_DAY, i, isleap, isoweek2date(), isoweek2j(), isoweekdate2date(), TmFromChar::j, j2date(), TmFromChar::mi, TmFromChar::mm, TmFromChar::mode, TmFromChar::ms, NODE_TYPE_END, NULL, palloc(), parse_format(), pfree(), TmFromChar::pm, TmFromChar::ss, TmFromChar::ssss, text_to_cstring(), pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, TmFromChar::us, VARSIZE_ANY_EXHDR, TmFromChar::w, TmFromChar::ww, TmFromChar::year, TmFromChar::yysz, ZERO_tm, and ZERO_tmfc.
Referenced by to_date(), and to_timestamp().
{ FormatNode *format; TmFromChar tmfc; int fmt_len; ZERO_tmfc(&tmfc); ZERO_tm(tm); *fsec = 0; fmt_len = VARSIZE_ANY_EXHDR(fmt); if (fmt_len) { char *fmt_str; char *date_str; bool incache; fmt_str = text_to_cstring(fmt); /* * Allocate new memory if format picture is bigger than static cache * and not use cache (call parser always) */ if (fmt_len > DCH_CACHE_SIZE) { format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode)); incache = FALSE; parse_format(format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_TYPE, NULL); (format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ } else { /* * Use cache buffers */ DCHCacheEntry *ent; incache = TRUE; if ((ent = DCH_cache_search(fmt_str)) == NULL) { ent = DCH_cache_getnew(fmt_str); /* * Not in the cache, must run parser and save a new * format-picture to the cache. */ parse_format(ent->format, fmt_str, DCH_keywords, DCH_suff, DCH_index, DCH_TYPE, NULL); (ent->format + fmt_len)->type = NODE_TYPE_END; /* Paranoia? */ #ifdef DEBUG_TO_FROM_CHAR /* dump_node(ent->format, fmt_len); */ /* dump_index(DCH_keywords, DCH_index); */ #endif } format = ent->format; } #ifdef DEBUG_TO_FROM_CHAR /* dump_node(format, fmt_len); */ #endif date_str = text_to_cstring(date_txt); DCH_from_char(format, date_str, &tmfc); pfree(date_str); pfree(fmt_str); if (!incache) pfree(format); } DEBUG_TMFC(&tmfc); /* * Convert values that user define for FROM_CHAR (to_date/to_timestamp) to * standard 'tm' */ if (tmfc.ssss) { int x = tmfc.ssss; tm->tm_hour = x / SECS_PER_HOUR; x %= SECS_PER_HOUR; tm->tm_min = x / SECS_PER_MINUTE; x %= SECS_PER_MINUTE; tm->tm_sec = x; } if (tmfc.ss) tm->tm_sec = tmfc.ss; if (tmfc.mi) tm->tm_min = tmfc.mi; if (tmfc.hh) tm->tm_hour = tmfc.hh; if (tmfc.clock == CLOCK_12_HOUR) { if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("hour \"%d\" is invalid for the 12-hour clock", tm->tm_hour), errhint("Use the 24-hour clock, or give an hour between 1 and 12."))); if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2) tm->tm_hour += HOURS_PER_DAY / 2; else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2) tm->tm_hour = 0; } if (tmfc.year) { /* * If CC and YY (or Y) are provided, use YY as 2 low-order digits for * the year in the given century. Keep in mind that the 21st century * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from * 600BC to 501BC. */ if (tmfc.cc && tmfc.yysz <= 2) { if (tmfc.bc) tmfc.cc = -tmfc.cc; tm->tm_year = tmfc.year % 100; if (tm->tm_year) { if (tmfc.cc >= 0) tm->tm_year += (tmfc.cc - 1) * 100; else tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1; } else /* find century year for dates ending in "00" */ tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1); } else /* If a 4-digit year is provided, we use that and ignore CC. */ { tm->tm_year = tmfc.year; if (tmfc.bc && tm->tm_year > 0) tm->tm_year = -(tm->tm_year - 1); } } else if (tmfc.cc) /* use first year of century */ { if (tmfc.bc) tmfc.cc = -tmfc.cc; if (tmfc.cc >= 0) /* +1 becuase 21st century started in 2001 */ tm->tm_year = (tmfc.cc - 1) * 100 + 1; else /* +1 because year == 599 is 600 BC */ tm->tm_year = tmfc.cc * 100 + 1; } if (tmfc.j) j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); if (tmfc.ww) { if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK) { /* * If tmfc.d is not set, then the date is left at the beginning of * the ISO week (Monday). */ if (tmfc.d) isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); else isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); } else tmfc.ddd = (tmfc.ww - 1) * 7 + 1; } if (tmfc.w) tmfc.dd = (tmfc.w - 1) * 7 + 1; if (tmfc.d) tm->tm_wday = tmfc.d - 1; /* convert to native numbering */ if (tmfc.dd) tm->tm_mday = tmfc.dd; if (tmfc.ddd) tm->tm_yday = tmfc.ddd; if (tmfc.mm) tm->tm_mon = tmfc.mm; if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1)) { /* * The month and day field have not been set, so we use the * day-of-year field to populate them. Depending on the date mode, * this field may be interpreted as a Gregorian day-of-year, or an ISO * week date day-of-year. */ if (!tm->tm_year && !tmfc.bc) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("cannot calculate day of year without year information"))); if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK) { int j0; /* zeroth day of the ISO year, in Julian */ j0 = isoweek2j(tm->tm_year, 1) - 1; j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday); } else { const int *y; int i; static const int ysum[2][13] = { {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}}; y = ysum[isleap(tm->tm_year)]; for (i = 1; i <= MONTHS_PER_YEAR; i++) { if (tmfc.ddd < y[i]) break; } if (tm->tm_mon <= 1) tm->tm_mon = i; if (tm->tm_mday <= 1) tm->tm_mday = tmfc.ddd - y[i - 1]; } } #ifdef HAVE_INT64_TIMESTAMP if (tmfc.ms) *fsec += tmfc.ms * 1000; if (tmfc.us) *fsec += tmfc.us; #else if (tmfc.ms) *fsec += (double) tmfc.ms / 1000; if (tmfc.us) *fsec += (double) tmfc.us / 1000000; #endif DEBUG_TM(tm); }
static char * fill_str | ( | char * | str, | |
int | c, | |||
int | max | |||
) | [static] |
Definition at line 3685 of file formatting.c.
Referenced by float4_to_char(), float8_to_char(), int4_to_char(), int8_to_char(), int_to_roman(), and numeric_to_char().
{ memset(str, c, max); *(str + max) = '\0'; return str; }
Datum float4_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5273 of file formatting.c.
References fill_str(), format, int_to_roman(), IS_EEEE, is_infinite(), IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, MAXFLOATWIDTH, NUMDesc::multi, palloc(), PG_GETARG_FLOAT4, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, rint(), sign, snprintf(), val, and value.
{ float4 value = PG_GETARG_FLOAT4(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum, *p; NUM_TOCHAR_prepare; if (IS_ROMAN(&Num)) numstr = orgnum = int_to_roman((int) rint(value)); else if (IS_EEEE(&Num)) { numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); if (isnan(value) || is_infinite(value)) { /* * Allow 6 characters for the leading sign, the decimal point, * "e", the exponent's sign and two exponent digits. */ numstr = (char *) palloc(Num.pre + Num.post + 7); fill_str(numstr, '#', Num.pre + Num.post + 6); *numstr = ' '; *(numstr + Num.pre + 1) = '.'; } else { snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ if (*orgnum == '+') *orgnum = ' '; len = strlen(orgnum); numstr = orgnum; } } else { float4 val = value; if (IS_MULTI(&Num)) { float multi = pow((double) 10, (double) Num.multi); val = value * multi; Num.pre += Num.multi; } orgnum = (char *) palloc(MAXFLOATWIDTH + 1); snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val)); len = strlen(orgnum); if (Num.pre > len) plen = Num.pre - len; if (len >= FLT_DIG) Num.post = 0; else if (Num.post + len > FLT_DIG) Num.post = FLT_DIG - len; snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val); if (*orgnum == '-') { /* < 0 */ sign = '-'; numstr = orgnum + 1; } else { sign = '+'; numstr = orgnum; } if ((p = strchr(numstr, '.'))) len = p - numstr; else len = strlen(numstr); if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum float8_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5377 of file formatting.c.
References fill_str(), format, int_to_roman(), IS_EEEE, is_infinite(), IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, NUMDesc::multi, palloc(), PG_GETARG_FLOAT8, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, rint(), sign, snprintf(), val, and value.
{ float8 value = PG_GETARG_FLOAT8(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum, *p; NUM_TOCHAR_prepare; if (IS_ROMAN(&Num)) numstr = orgnum = int_to_roman((int) rint(value)); else if (IS_EEEE(&Num)) { numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); if (isnan(value) || is_infinite(value)) { /* * Allow 6 characters for the leading sign, the decimal point, * "e", the exponent's sign and two exponent digits. */ numstr = (char *) palloc(Num.pre + Num.post + 7); fill_str(numstr, '#', Num.pre + Num.post + 6); *numstr = ' '; *(numstr + Num.pre + 1) = '.'; } else { snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value); /* * Swap a leading positive sign for a space. */ if (*orgnum == '+') *orgnum = ' '; len = strlen(orgnum); numstr = orgnum; } } else { float8 val = value; if (IS_MULTI(&Num)) { double multi = pow((double) 10, (double) Num.multi); val = value * multi; Num.pre += Num.multi; } orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val)); if (Num.pre > len) plen = Num.pre - len; if (len >= DBL_DIG) Num.post = 0; else if (Num.post + len > DBL_DIG) Num.post = DBL_DIG - len; snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val); if (*orgnum == '-') { /* < 0 */ sign = '-'; numstr = orgnum + 1; } else { sign = '+'; numstr = orgnum; } if ((p = strchr(numstr, '.'))) len = p - numstr; else len = strlen(numstr); if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
static int from_char_parse_int | ( | int * | dest, | |
char ** | src, | |||
FormatNode * | node | |||
) | [static] |
Definition at line 2260 of file formatting.c.
References from_char_parse_int_len(), FormatNode::key, and KeyWord::len.
Referenced by DCH_from_char().
{ return from_char_parse_int_len(dest, src, node->key->len, node); }
static int from_char_parse_int_len | ( | int * | dest, | |
char ** | src, | |||
const int | len, | |||
FormatNode * | node | |||
) | [static] |
Definition at line 2170 of file formatting.c.
References Assert, DCH_MAX_ITEM_SIZ, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, from_char_set_int(), init(), is_next_separator(), FormatNode::key, KeyWord::name, NULL, S_FM, strlcpy(), strspace_len(), and FormatNode::suffix.
Referenced by DCH_from_char(), and from_char_parse_int().
{ long result; char copy[DCH_MAX_ITEM_SIZ + 1]; char *init = *src; int used; /* * Skip any whitespace before parsing the integer. */ *src += strspace_len(*src); Assert(len <= DCH_MAX_ITEM_SIZ); used = (int) strlcpy(copy, *src, len + 1); if (S_FM(node->suffix) || is_next_separator(node)) { /* * This node is in Fill Mode, or the next node is known to be a * non-digit value, so we just slurp as many characters as we can get. */ errno = 0; result = strtol(init, src, 10); } else { /* * We need to pull exactly the number of characters given in 'len' out * of the string, and convert those. */ char *last; if (used < len) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("source string too short for \"%s\" formatting field", node->key->name), errdetail("Field requires %d characters, but only %d " "remain.", len, used), errhint("If your source string is not fixed-width, try " "using the \"FM\" modifier."))); errno = 0; result = strtol(copy, &last, 10); used = last - copy; if (used > 0 && used < len) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid value \"%s\" for \"%s\"", copy, node->key->name), errdetail("Field requires %d characters, but only %d " "could be parsed.", len, used), errhint("If your source string is not fixed-width, try " "using the \"FM\" modifier."))); *src += used; } if (*src == init) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid value \"%s\" for \"%s\"", copy, node->key->name), errdetail("Value must be an integer."))); if (errno == ERANGE || result < INT_MIN || result > INT_MAX) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("value for \"%s\" in source string is out of range", node->key->name), errdetail("Value must be in the range %d to %d.", INT_MIN, INT_MAX))); if (dest != NULL) from_char_set_int(dest, (int) result, node); return *src - init; }
static int from_char_seq_search | ( | int * | dest, | |
char ** | src, | |||
char ** | array, | |||
int | type, | |||
int | max, | |||
FormatNode * | node | |||
) | [static] |
Definition at line 2348 of file formatting.c.
References Assert, DCH_MAX_ITEM_SIZ, ereport, errcode(), errdetail(), errmsg(), ERROR, FormatNode::key, KeyWord::name, seq_search(), and strlcpy().
Referenced by DCH_from_char().
{ int len; *dest = seq_search(*src, array, type, max, &len); if (len <= 0) { char copy[DCH_MAX_ITEM_SIZ + 1]; Assert(max <= DCH_MAX_ITEM_SIZ); strlcpy(copy, *src, max + 1); ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid value \"%s\" for \"%s\"", copy, node->key->name), errdetail("The given value did not match any of the allowed " "values for this field."))); } *src += len; return len; }
static void from_char_set_int | ( | int * | dest, | |
const int | value, | |||
const FormatNode * | node | |||
) | [static] |
Definition at line 2137 of file formatting.c.
References ereport, errcode(), errdetail(), errmsg(), ERROR, FormatNode::key, and KeyWord::name.
Referenced by DCH_from_char(), and from_char_parse_int_len().
static void from_char_set_mode | ( | TmFromChar * | tmfc, | |
const FromCharDateMode | mode | |||
) | [static] |
Definition at line 2115 of file formatting.c.
References ereport, errcode(), errhint(), errmsg(), ERROR, FROM_CHAR_DATE_NONE, and TmFromChar::mode.
Referenced by DCH_from_char().
{ if (mode != FROM_CHAR_DATE_NONE) { if (tmfc->mode == FROM_CHAR_DATE_NONE) tmfc->mode = mode; else if (tmfc->mode != mode) ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid combination of date conventions"), errhint("Do not mix Gregorian and ISO week date " "conventions in a formatting template."))); } }
static char * get_last_relevant_decnum | ( | char * | num | ) | [static] |
Definition at line 4018 of file formatting.c.
References elog.
Referenced by NUM_processor().
{ char *result, *p = strchr(num, '.'); #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "get_last_relevant_decnum()"); #endif if (!p) return NULL; result = p; while (*(++p)) { if (*p != '0') result = p; } return result; }
static char * get_th | ( | char * | num, | |
int | type | |||
) | [static] |
Definition at line 1404 of file formatting.c.
References ereport, errcode(), errmsg(), ERROR, numth, numTH, and TH_UPPER.
Referenced by NUM_processor(), and str_numth().
{ int len = strlen(num), last, seclast; last = *(num + (len - 1)); if (!isdigit((unsigned char) last)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("\"%s\" is not a number", num))); /* * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get * 'ST/st', 'ND/nd', 'RD/rd', respectively */ if ((len > 1) && ((seclast = num[len - 2]) == '1')) last = 0; switch (last) { case '1': if (type == TH_UPPER) return numTH[0]; return numth[0]; case '2': if (type == TH_UPPER) return numTH[1]; return numth[1]; case '3': if (type == TH_UPPER) return numTH[2]; return numth[2]; default: if (type == TH_UPPER) return numTH[3]; return numth[3]; } }
static const KeyWord * index_seq_search | ( | char * | str, | |
const KeyWord * | kw, | |||
const int * | index | |||
) | [static] |
Definition at line 1002 of file formatting.c.
References KeyWord_INDEX_FILTER, KeyWord::len, and KeyWord::name.
Referenced by parse_format().
Datum int4_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5075 of file formatting.c.
References DatumGetCString, DirectFunctionCall1, fill_str(), format, Int32GetDatum, int4out(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, NUMDesc::multi, palloc(), PG_GETARG_INT32, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, snprintf(), val, and value.
{ int32 value = PG_GETARG_INT32(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum; NUM_TOCHAR_prepare; /* * On DateType depend part (int32) */ if (IS_ROMAN(&Num)) numstr = orgnum = int_to_roman(value); else if (IS_EEEE(&Num)) { /* we can do it easily because float8 won't lose any precision */ float8 val = (float8) value; orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1); snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val); /* * Swap a leading positive sign for a space. */ if (*orgnum == '+') *orgnum = ' '; len = strlen(orgnum); numstr = orgnum; } else { if (IS_MULTI(&Num)) { orgnum = DatumGetCString(DirectFunctionCall1(int4out, Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi))))); Num.pre += Num.multi; } else { orgnum = DatumGetCString(DirectFunctionCall1(int4out, Int32GetDatum(value))); } if (*orgnum == '-') { sign = '-'; orgnum++; } else sign = '+'; len = strlen(orgnum); if (Num.post) { numstr = (char *) palloc(len + Num.post + 2); strcpy(numstr, orgnum); *(numstr + len) = '.'; memset(numstr + len + 1, '0', Num.post); *(numstr + len + Num.post + 1) = '\0'; } else numstr = orgnum; if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum int8_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 5166 of file formatting.c.
References DatumGetCString, DatumGetInt32, DatumGetInt64, DatumGetNumeric, DirectFunctionCall1, DirectFunctionCall2, dtoi8(), fill_str(), Float8GetDatum(), format, Int64GetDatum(), int84(), int8_numeric(), int8mul(), int8out(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, numeric_out_sci(), palloc(), PG_GETARG_INT64, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, val, and value.
{ int64 value = PG_GETARG_INT64(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum; NUM_TOCHAR_prepare; /* * On DateType depend part (int32) */ if (IS_ROMAN(&Num)) { /* Currently don't support int8 conversion to roman... */ numstr = orgnum = int_to_roman(DatumGetInt32( DirectFunctionCall1(int84, Int64GetDatum(value)))); } else if (IS_EEEE(&Num)) { /* to avoid loss of precision, must go via numeric not float8 */ Numeric val; val = DatumGetNumeric(DirectFunctionCall1(int8_numeric, Int64GetDatum(value))); orgnum = numeric_out_sci(val, Num.post); /* * numeric_out_sci() does not emit a sign for positive numbers. We * need to add a space in this case so that positive and negative * numbers are aligned. We don't have to worry about NaN here. */ if (*orgnum != '-') { numstr = (char *) palloc(strlen(orgnum) + 2); *numstr = ' '; strcpy(numstr + 1, orgnum); len = strlen(numstr); } else { numstr = orgnum; len = strlen(orgnum); } } else { if (IS_MULTI(&Num)) { double multi = pow((double) 10, (double) Num.multi); value = DatumGetInt64(DirectFunctionCall2(int8mul, Int64GetDatum(value), DirectFunctionCall1(dtoi8, Float8GetDatum(multi)))); Num.pre += Num.multi; } orgnum = DatumGetCString(DirectFunctionCall1(int8out, Int64GetDatum(value))); if (*orgnum == '-') { sign = '-'; orgnum++; } else sign = '+'; len = strlen(orgnum); if (Num.post) { numstr = (char *) palloc(len + Num.post + 2); strcpy(numstr, orgnum); *(numstr + len) = '.'; memset(numstr + len + 1, '0', Num.post); *(numstr + len + Num.post + 1) = '\0'; } else numstr = orgnum; if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
static char * int_to_roman | ( | int | number | ) | [static] |
Definition at line 3887 of file formatting.c.
References fill_str(), palloc(), rm1, rm10, rm100, and snprintf().
Referenced by float4_to_char(), float8_to_char(), int4_to_char(), int8_to_char(), and numeric_to_char().
{ int len = 0, num = 0; char *p = NULL, *result, numstr[5]; result = (char *) palloc(16); *result = '\0'; if (number > 3999 || number < 1) { fill_str(result, '#', 15); return result; } len = snprintf(numstr, sizeof(numstr), "%d", number); for (p = numstr; *p != '\0'; p++, --len) { num = *p - 49; /* 48 ascii + 1 */ if (num < 0) continue; if (len > 3) { while (num-- != -1) strcat(result, "M"); } else { if (len == 3) strcat(result, rm100[num]); else if (len == 2) strcat(result, rm10[num]); else if (len == 1) strcat(result, rm1[num]); } } return result; }
Datum interval_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3326 of file formatting.c.
References datetime_to_char_body(), DAYS_PER_MONTH, interval2tm(), MONTHS_PER_YEAR, PG_GET_COLLATION, PG_GETARG_INTERVAL_P, PG_GETARG_TEXT_P, PG_RETURN_NULL, PG_RETURN_TEXT_P, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, VARHDRSZ, VARSIZE, and ZERO_tmtc.
{ Interval *it = PG_GETARG_INTERVAL_P(0); text *fmt = PG_GETARG_TEXT_P(1), *res; TmToChar tmtc; struct pg_tm *tm; if ((VARSIZE(fmt) - VARHDRSZ) <= 0) PG_RETURN_NULL(); ZERO_tmtc(&tmtc); tm = tmtcTm(&tmtc); if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0) PG_RETURN_NULL(); /* wday is meaningless, yday approximates the total span in days */ tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday; if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION()))) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); }
static bool is_next_separator | ( | FormatNode * | n | ) | [static] |
Definition at line 2023 of file formatting.c.
References FormatNode::character, KeyWord::is_digit, FormatNode::key, NODE_TYPE_ACTION, NODE_TYPE_END, S_THth, FormatNode::suffix, and FormatNode::type.
Referenced by from_char_parse_int_len().
{ if (n->type == NODE_TYPE_END) return FALSE; if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix)) return TRUE; /* * Next node */ n++; /* end of format string is treated like a non-digit separator */ if (n->type == NODE_TYPE_END) return TRUE; if (n->type == NODE_TYPE_ACTION) { if (n->key->is_digit) return FALSE; return TRUE; } else if (isdigit((unsigned char) n->character)) return FALSE; return TRUE; /* some non-digit input (separator) */ }
static FormatNode * NUM_cache | ( | int | len, | |
NUMDesc * | Num, | |||
text * | pars_str, | |||
bool * | shouldFree | |||
) | [static] |
Definition at line 3812 of file formatting.c.
References NUMDesc::flag, NUMCacheEntry::format, format, NUMDesc::lsign, NUMDesc::multi, NUMDesc::need_locale, NODE_TYPE_END, NULL, NUMCacheEntry::Num, NUM_cache_getnew(), NUM_cache_search(), NUM_CACHE_SIZE, NUM_index, NUM_TYPE, palloc(), parse_format(), pfree(), NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, text_to_cstring(), NUMDesc::zero_end, NUMDesc::zero_start, and zeroize_NUM.
Referenced by numeric_to_number().
{ FormatNode *format = NULL; char *str; str = text_to_cstring(pars_str); /* * Allocate new memory if format picture is bigger than static cache and * not use cache (call parser always). This branches sets shouldFree to * true, accordingly. */ if (len > NUM_CACHE_SIZE) { format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode)); *shouldFree = true; zeroize_NUM(Num); parse_format(format, str, NUM_keywords, NULL, NUM_index, NUM_TYPE, Num); (format + len)->type = NODE_TYPE_END; /* Paranoia? */ } else { /* * Use cache buffers */ NUMCacheEntry *ent; *shouldFree = false; if ((ent = NUM_cache_search(str)) == NULL) { ent = NUM_cache_getnew(str); /* * Not in the cache, must run parser and save a new format-picture * to the cache. */ parse_format(ent->format, str, NUM_keywords, NULL, NUM_index, NUM_TYPE, &ent->Num); (ent->format + len)->type = NODE_TYPE_END; /* Paranoia? */ } format = ent->format; /* * Copy cache to used struct */ Num->flag = ent->Num.flag; Num->lsign = ent->Num.lsign; Num->pre = ent->Num.pre; Num->post = ent->Num.post; Num->pre_lsign_num = ent->Num.pre_lsign_num; Num->need_locale = ent->Num.need_locale; Num->multi = ent->Num.multi; Num->zero_start = ent->Num.zero_start; Num->zero_end = ent->Num.zero_end; } #ifdef DEBUG_TO_FROM_CHAR /* dump_node(format, len); */ dump_index(NUM_keywords, NUM_index); #endif pfree(str); return format; }
static NUMCacheEntry * NUM_cache_getnew | ( | char * | str | ) | [static] |
Definition at line 3706 of file formatting.c.
References NUMCacheEntry::age, elog, n_NUMCache, NUMCacheEntry::Num, NUM_CACHE_FIELDS, NUM_CACHE_SIZE, NUMCounter, NUMCacheEntry::str, StrNCpy, and zeroize_NUM.
Referenced by NUM_cache().
{ NUMCacheEntry *ent; /* counter overflow check - paranoia? */ if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1)) { NUMCounter = 0; for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) ent->age = (++NUMCounter); } /* * If cache is full, remove oldest entry */ if (n_NUMCache > NUM_CACHE_FIELDS) { NUMCacheEntry *old = NUMCache + 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache); #endif for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) { /* * entry removed via NUM_cache_remove() can be used here, which is * why it's worth scanning first entry again */ if (ent->str[0] == '\0') { old = ent; break; } if (ent->age < old->age) old = ent; } #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age); #endif StrNCpy(old->str, str, NUM_CACHE_SIZE + 1); /* old->format fill parser */ old->age = (++NUMCounter); ent = old; } else { #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache); #endif ent = NUMCache + n_NUMCache; StrNCpy(ent->str, str, NUM_CACHE_SIZE + 1); /* ent->format fill parser */ ent->age = (++NUMCounter); ++n_NUMCache; } zeroize_NUM(&ent->Num); last_NUMCacheEntry = ent; return ent; }
static void NUM_cache_remove | ( | NUMCacheEntry * | ent | ) | [static] |
Definition at line 3798 of file formatting.c.
References NUMCacheEntry::age, elog, and NUMCacheEntry::str.
Referenced by NUMDesc_prepare().
static NUMCacheEntry * NUM_cache_search | ( | char * | str | ) | [static] |
Definition at line 3770 of file formatting.c.
References NUMCacheEntry::age, i, n_NUMCache, NUM_CACHE_FIELDS, NUMCounter, and NUMCacheEntry::str.
Referenced by NUM_cache().
{ int i; NUMCacheEntry *ent; /* counter overflow check - paranoia? */ if (NUMCounter >= (INT_MAX - NUM_CACHE_FIELDS - 1)) { NUMCounter = 0; for (ent = NUMCache; ent <= (NUMCache + NUM_CACHE_FIELDS); ent++) ent->age = (++NUMCounter); } for (i = 0, ent = NUMCache; i < n_NUMCache; i++, ent++) { if (strcmp(ent->str, str) == 0) { ent->age = (++NUMCounter); last_NUMCacheEntry = ent; return ent; } } return NULL; }
static void NUM_numpart_from_char | ( | NUMProc * | Np, | |
int | id, | |||
int | plen | |||
) | [static] |
Definition at line 4046 of file formatting.c.
References AMOUNT_TEST, NUMProc::decimal, elog, FALSE, NUMProc::inout, NUMProc::inout_p, IS_BRACKET, IS_DECIMAL, IS_LSIGN, IS_MINUS, IS_PLUS, NUMProc::L_negative_sign, NUMProc::L_positive_sign, NUMDesc::lsign, NUMProc::Num, NUM_0, NUM_9, NUM_DEC, NUM_LSIGN_PRE, NUMProc::number, NUMProc::number_p, OVERLOAD_TEST, NUMDesc::post, NUMProc::read_dec, NUMProc::read_post, and NUMProc::read_pre.
Referenced by NUM_processor().
{ bool isread = FALSE; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, " --- scan start --- id=%s", (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???"); #endif if (*Np->inout_p == ' ') Np->inout_p++; #define OVERLOAD_TEST (Np->inout_p >= Np->inout + plen) #define AMOUNT_TEST(_s) (plen-(Np->inout_p-Np->inout) >= _s) if (*Np->inout_p == ' ') Np->inout_p++; if (OVERLOAD_TEST) return; /* * read sign before number */ if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) && (Np->read_pre + Np->read_post) == 0) { #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s", *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign); #endif /* * locale sign */ if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE) { int x = 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p); #endif if ((x = strlen(Np->L_negative_sign)) && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->L_negative_sign, x) == 0) { Np->inout_p += x; *Np->number = '-'; } else if ((x = strlen(Np->L_positive_sign)) && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->L_positive_sign, x) == 0) { Np->inout_p += x; *Np->number = '+'; } } else { #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p); #endif /* * simple + - < > */ if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) && *Np->inout_p == '<')) { *Np->number = '-'; /* set - */ Np->inout_p++; } else if (*Np->inout_p == '+') { *Np->number = '+'; /* set + */ Np->inout_p++; } } } if (OVERLOAD_TEST) return; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number); #endif /* * read digit */ if (isdigit((unsigned char) *Np->inout_p)) { if (Np->read_dec && Np->read_post == Np->Num->post) return; *Np->number_p = *Np->inout_p; Np->number_p++; if (Np->read_dec) Np->read_post++; else Np->read_pre++; isread = TRUE; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p); #endif /* * read decimal point */ } else if (IS_DECIMAL(Np->Num) && Np->read_dec == FALSE) { #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read decimal point (%c)", *Np->inout_p); #endif if (*Np->inout_p == '.') { *Np->number_p = '.'; Np->number_p++; Np->read_dec = TRUE; isread = TRUE; } else { int x = strlen(Np->decimal); #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read locale point (%c)", *Np->inout_p); #endif if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0) { Np->inout_p += x - 1; *Np->number_p = '.'; Np->number_p++; Np->read_dec = TRUE; isread = TRUE; } } } if (OVERLOAD_TEST) return; /* * Read sign behind "last" number * * We need sign detection because determine exact position of post-sign is * difficult: * * FM9999.9999999S -> 123.001- 9.9S -> .5- FM9.999999MI -> * 5.01- */ if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0) { /* * locale sign (NUM_S) is always anchored behind a last number, if: - * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and * next char is not digit */ if (IS_LSIGN(Np->Num) && isread && (Np->inout_p + 1) <= Np->inout + plen && !isdigit((unsigned char) *(Np->inout_p + 1))) { int x; char *tmp = Np->inout_p++; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p); #endif if ((x = strlen(Np->L_negative_sign)) && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->L_negative_sign, x) == 0) { Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */ *Np->number = '-'; } else if ((x = strlen(Np->L_positive_sign)) && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->L_positive_sign, x) == 0) { Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */ *Np->number = '+'; } if (*Np->number == ' ') /* no sign read */ Np->inout_p = tmp; } /* * try read non-locale sign, it's happen only if format is not exact * and we cannot determine sign position of MI/PL/SG, an example: * * FM9.999999MI -> 5.01- * * if (.... && IS_LSIGN(Np->Num)==FALSE) prevents read wrong formats * like to_number('1 -', '9S') where sign is not anchored to last * number. */ else if (isread == FALSE && IS_LSIGN(Np->Num) == FALSE && (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))) { #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p); #endif /* * simple + - */ if (*Np->inout_p == '-' || *Np->inout_p == '+') /* NUM_processor() do inout_p++ */ *Np->number = *Np->inout_p; } } }
static void NUM_numpart_to_char | ( | NUMProc * | Np, | |
int | id | |||
) | [static] |
Definition at line 4276 of file formatting.c.
References NUMProc::decimal, elog, FALSE, NUMProc::inout, NUMProc::inout_p, IS_BRACKET, IS_DECIMAL, IS_FILLMODE, IS_LSIGN, IS_PREDEC_SPACE, IS_ROMAN, IS_ZERO, NUMProc::L_negative_sign, NUMProc::L_positive_sign, NUMProc::last_relevant, NUMDesc::lsign, NUMProc::Num, NUM_0, NUM_9, NUMProc::num_count, NUMProc::num_curr, NUM_D, NUM_DEC, NUMProc::num_in, NUM_LSIGN_PRE, NUMProc::num_pre, NUMProc::number_p, NUMProc::sign, NUMProc::sign_wrote, TRUE, and NUMDesc::zero_start.
Referenced by NUM_processor().
{ int end; if (IS_ROMAN(Np->Num)) return; /* Note: in this elog() output not set '\0' in 'inout' */ #ifdef DEBUG_TO_FROM_CHAR /* * Np->num_curr is number of current item in format-picture, it is not * current position in inout! */ elog(DEBUG_elog_output, "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"", Np->sign_wrote, Np->num_curr, Np->number_p, Np->inout); #endif Np->num_in = FALSE; /* * Write sign if real number will write to output Note: IS_PREDEC_SPACE() * handle "9.9" --> " .1" */ if (Np->sign_wrote == FALSE && (Np->num_curr >= Np->num_pre || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) && (IS_PREDEC_SPACE(Np) == FALSE || (Np->last_relevant && *Np->last_relevant == '.'))) { if (IS_LSIGN(Np->Num)) { if (Np->Num->lsign == NUM_LSIGN_PRE) { if (Np->sign == '-') strcpy(Np->inout_p, Np->L_negative_sign); else strcpy(Np->inout_p, Np->L_positive_sign); Np->inout_p += strlen(Np->inout_p); Np->sign_wrote = TRUE; } } else if (IS_BRACKET(Np->Num)) { *Np->inout_p = Np->sign == '+' ? ' ' : '<'; ++Np->inout_p; Np->sign_wrote = TRUE; } else if (Np->sign == '+') { if (!IS_FILLMODE(Np->Num)) { *Np->inout_p = ' '; /* Write + */ ++Np->inout_p; } Np->sign_wrote = TRUE; } else if (Np->sign == '-') { /* Write - */ *Np->inout_p = '-'; ++Np->inout_p; Np->sign_wrote = TRUE; } } /* * digits / FM / Zero / Dec. point */ if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC) { if (Np->num_curr < Np->num_pre && (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num))) { /* * Write blank space */ if (!IS_FILLMODE(Np->Num)) { *Np->inout_p = ' '; /* Write ' ' */ ++Np->inout_p; } } else if (IS_ZERO(Np->Num) && Np->num_curr < Np->num_pre && Np->Num->zero_start <= Np->num_curr) { /* * Write ZERO */ *Np->inout_p = '0'; /* Write '0' */ ++Np->inout_p; Np->num_in = TRUE; } else { /* * Write Decimal point */ if (*Np->number_p == '.') { if (!Np->last_relevant || *Np->last_relevant != '.') { strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */ Np->inout_p += strlen(Np->inout_p); } /* * Ora 'n' -- FM9.9 --> 'n.' */ else if (IS_FILLMODE(Np->Num) && Np->last_relevant && *Np->last_relevant == '.') { strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */ Np->inout_p += strlen(Np->inout_p); } } else { /* * Write Digits */ if (Np->last_relevant && Np->number_p > Np->last_relevant && id != NUM_0) ; /* * '0.1' -- 9.9 --> ' .1' */ else if (IS_PREDEC_SPACE(Np)) { if (!IS_FILLMODE(Np->Num)) { *Np->inout_p = ' '; ++Np->inout_p; } /* * '0' -- FM9.9 --> '0.' */ else if (Np->last_relevant && *Np->last_relevant == '.') { *Np->inout_p = '0'; ++Np->inout_p; } } else { *Np->inout_p = *Np->number_p; /* Write DIGIT */ ++Np->inout_p; Np->num_in = TRUE; } } ++Np->number_p; } end = Np->num_count + (Np->num_pre ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0); if (Np->last_relevant && Np->last_relevant == Np->number_p) end = Np->num_curr; if (Np->num_curr + 1 == end) { if (Np->sign_wrote == TRUE && IS_BRACKET(Np->Num)) { *Np->inout_p = Np->sign == '+' ? ' ' : '>'; ++Np->inout_p; } else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST) { if (Np->sign == '-') strcpy(Np->inout_p, Np->L_negative_sign); else strcpy(Np->inout_p, Np->L_positive_sign); Np->inout_p += strlen(Np->inout_p); } } } ++Np->num_curr; }
static void NUM_prepare_locale | ( | NUMProc * | Np | ) | [static] |
Definition at line 3936 of file formatting.c.
References NUMProc::decimal, IS_LDECIMAL, NUMProc::L_currency_symbol, NUMProc::L_negative_sign, NUMProc::L_positive_sign, NUMProc::L_thousands_sep, NUMDesc::need_locale, NUMProc::Num, and PGLC_localeconv().
Referenced by NUM_processor().
{ if (Np->Num->need_locale) { struct lconv *lconv; /* * Get locales */ lconv = PGLC_localeconv(); /* * Positive / Negative number sign */ if (lconv->negative_sign && *lconv->negative_sign) Np->L_negative_sign = lconv->negative_sign; else Np->L_negative_sign = "-"; if (lconv->positive_sign && *lconv->positive_sign) Np->L_positive_sign = lconv->positive_sign; else Np->L_positive_sign = "+"; /* * Number decimal point */ if (lconv->decimal_point && *lconv->decimal_point) Np->decimal = lconv->decimal_point; else Np->decimal = "."; if (!IS_LDECIMAL(Np->Num)) Np->decimal = "."; /* * Number thousands separator * * Some locales (e.g. broken glibc pt_BR), have a comma for decimal, * but "" for thousands_sep, so we set the thousands_sep too. * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php */ if (lconv->thousands_sep && *lconv->thousands_sep) Np->L_thousands_sep = lconv->thousands_sep; /* Make sure thousands separator doesn't match decimal point symbol. */ else if (strcmp(Np->decimal, ",") !=0) Np->L_thousands_sep = ","; else Np->L_thousands_sep = "."; /* * Currency symbol */ if (lconv->currency_symbol && *lconv->currency_symbol) Np->L_currency_symbol = lconv->currency_symbol; else Np->L_currency_symbol = " "; } else { /* * Default values */ Np->L_negative_sign = "-"; Np->L_positive_sign = "+"; Np->decimal = "."; Np->L_thousands_sep = ","; Np->L_currency_symbol = " "; } }
static char * NUM_processor | ( | FormatNode * | node, | |
NUMDesc * | Num, | |||
char * | inout, | |||
char * | number, | |||
int | plen, | |||
int | sign, | |||
bool | is_to_char, | |||
Oid | collid | |||
) | [static] |
Definition at line 4465 of file formatting.c.
References asc_tolower_z(), FormatNode::character, elog, ereport, errcode(), errmsg(), ERROR, FALSE, NUMDesc::flag, get_last_relevant_decnum(), get_th(), KeyWord::id, NUMProc::inout, NUMProc::inout_p, IS_BRACKET, IS_DECIMAL, IS_EEEE, IS_FILLMODE, IS_LSIGN, IS_MINUS, IS_PLUS, IS_ROMAN, NUMProc::is_to_char, IS_ZERO, FormatNode::key, NUMProc::L_currency_symbol, NUMProc::L_thousands_sep, NUMProc::last_relevant, NUMDesc::lsign, MemSet, NODE_TYPE_ACTION, NODE_TYPE_END, NUMProc::Num, NUM_0, NUM_9, NUM_COMMA, NUMProc::num_count, NUMProc::num_curr, NUM_D, NUM_DEC, NUM_G, NUMProc::num_in, NUM_L, NUM_LSIGN_PRE, NUM_MI, NUM_numpart_from_char(), NUM_numpart_to_char(), NUM_PL, NUMProc::num_pre, NUM_prepare_locale(), NUM_rn, NUM_RN, NUM_SG, NUM_TH, NUM_th, NUMProc::number, NUMProc::number_p, NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, NUMProc::read_dec, NUMProc::read_post, NUMProc::read_pre, NUMProc::sign, NUMProc::sign_wrote, TH_LOWER, TH_UPPER, FormatNode::type, NUMDesc::zero_end, and NUMDesc::zero_start.
Referenced by numeric_to_number().
{ FormatNode *n; NUMProc _Np, *Np = &_Np; MemSet(Np, 0, sizeof(NUMProc)); Np->Num = Num; Np->is_to_char = is_to_char; Np->number = number; Np->inout = inout; Np->last_relevant = NULL; Np->read_post = 0; Np->read_pre = 0; Np->read_dec = FALSE; if (Np->Num->zero_start) --Np->Num->zero_start; if (IS_EEEE(Np->Num)) { if (!Np->is_to_char) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("\"EEEE\" not supported for input"))); return strcpy(inout, number); } /* * Roman correction */ if (IS_ROMAN(Np->Num)) { if (!Np->is_to_char) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("\"RN\" not supported for input"))); Np->Num->lsign = Np->Num->pre_lsign_num = Np->Num->post = Np->Num->pre = Np->num_pre = Np->sign = 0; if (IS_FILLMODE(Np->Num)) { Np->Num->flag = 0; Np->Num->flag |= NUM_F_FILLMODE; } else Np->Num->flag = 0; Np->Num->flag |= NUM_F_ROMAN; } /* * Sign */ if (is_to_char) { Np->sign = sign; /* MI/PL/SG - write sign itself and not in number */ if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)) { if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == FALSE) Np->sign_wrote = FALSE; /* need sign */ else Np->sign_wrote = TRUE; /* needn't sign */ } else { if (Np->sign != '-') { if (IS_BRACKET(Np->Num) && IS_FILLMODE(Np->Num)) Np->Num->flag &= ~NUM_F_BRACKET; if (IS_MINUS(Np->Num)) Np->Num->flag &= ~NUM_F_MINUS; } else if (Np->sign != '+' && IS_PLUS(Np->Num)) Np->Num->flag &= ~NUM_F_PLUS; if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == FALSE) Np->sign_wrote = TRUE; /* needn't sign */ else Np->sign_wrote = FALSE; /* need sign */ if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num) Np->Num->lsign = NUM_LSIGN_POST; } } else Np->sign = FALSE; /* * Count */ Np->num_count = Np->Num->post + Np->Num->pre - 1; if (is_to_char) { Np->num_pre = plen; if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num)) { Np->last_relevant = get_last_relevant_decnum(Np->number); /* * If any '0' specifiers are present, make sure we don't strip * those digits. */ if (Np->last_relevant && Np->Num->zero_end > Np->num_pre) { char *last_zero; last_zero = Np->number + (Np->Num->zero_end - Np->num_pre); if (Np->last_relevant < last_zero) Np->last_relevant = last_zero; } } if (Np->sign_wrote == FALSE && Np->num_pre == 0) ++Np->num_count; } else { Np->num_pre = 0; *Np->number = ' '; /* sign space */ *(Np->number + 1) = '\0'; } Np->num_in = 0; Np->num_curr = 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "\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", Np->sign, Np->number, Np->Num->pre, Np->Num->post, Np->num_count, Np->num_pre, Np->sign_wrote ? "Yes" : "No", IS_ZERO(Np->Num) ? "Yes" : "No", Np->Num->zero_start, Np->Num->zero_end, Np->last_relevant ? Np->last_relevant : "<not set>", IS_BRACKET(Np->Num) ? "Yes" : "No", IS_PLUS(Np->Num) ? "Yes" : "No", IS_MINUS(Np->Num) ? "Yes" : "No", IS_FILLMODE(Np->Num) ? "Yes" : "No", IS_ROMAN(Np->Num) ? "Yes" : "No", IS_EEEE(Np->Num) ? "Yes" : "No" ); #endif /* * Locale */ NUM_prepare_locale(Np); /* * Processor direct cycle */ if (Np->is_to_char) Np->number_p = Np->number; else Np->number_p = Np->number + 1; /* first char is space for sign */ for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++) { if (!Np->is_to_char) { /* * Check non-string inout end */ if (Np->inout_p >= Np->inout + plen) break; } /* * Format pictures actions */ if (n->type == NODE_TYPE_ACTION) { /* * Create/reading digit/zero/blank/sing * * 'NUM_S' note: The locale sign is anchored to number and we * read/write it when we work with first or last number * (NUM_0/NUM_9). This is reason why NUM_S missing in follow * switch(). */ switch (n->key->id) { case NUM_9: case NUM_0: case NUM_DEC: case NUM_D: if (Np->is_to_char) { NUM_numpart_to_char(Np, n->key->id); continue; /* for() */ } else { NUM_numpart_from_char(Np, n->key->id, plen); break; /* switch() case: */ } case NUM_COMMA: if (Np->is_to_char) { if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; else *Np->inout_p = ' '; } else *Np->inout_p = ','; } else { if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; } } break; case NUM_G: if (Np->is_to_char) { if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; else { int x = strlen(Np->L_thousands_sep); memset(Np->inout_p, ' ', x); Np->inout_p += x - 1; } } else { strcpy(Np->inout_p, Np->L_thousands_sep); Np->inout_p += strlen(Np->inout_p) - 1; } } else { if (!Np->num_in) { if (IS_FILLMODE(Np->Num)) continue; } Np->inout_p += strlen(Np->L_thousands_sep) - 1; } break; case NUM_L: if (Np->is_to_char) { strcpy(Np->inout_p, Np->L_currency_symbol); Np->inout_p += strlen(Np->inout_p) - 1; } else Np->inout_p += strlen(Np->L_currency_symbol) - 1; break; case NUM_RN: if (IS_FILLMODE(Np->Num)) { strcpy(Np->inout_p, Np->number_p); Np->inout_p += strlen(Np->inout_p) - 1; } else { sprintf(Np->inout_p, "%15s", Np->number_p); Np->inout_p += strlen(Np->inout_p) - 1; } break; case NUM_rn: if (IS_FILLMODE(Np->Num)) { strcpy(Np->inout_p, asc_tolower_z(Np->number_p)); Np->inout_p += strlen(Np->inout_p) - 1; } else { sprintf(Np->inout_p, "%15s", asc_tolower_z(Np->number_p)); Np->inout_p += strlen(Np->inout_p) - 1; } break; case NUM_th: if (IS_ROMAN(Np->Num) || *Np->number == '#' || Np->sign == '-' || IS_DECIMAL(Np->Num)) continue; if (Np->is_to_char) strcpy(Np->inout_p, get_th(Np->number, TH_LOWER)); Np->inout_p += 1; break; case NUM_TH: if (IS_ROMAN(Np->Num) || *Np->number == '#' || Np->sign == '-' || IS_DECIMAL(Np->Num)) continue; if (Np->is_to_char) strcpy(Np->inout_p, get_th(Np->number, TH_UPPER)); Np->inout_p += 1; break; case NUM_MI: if (Np->is_to_char) { if (Np->sign == '-') *Np->inout_p = '-'; else if (IS_FILLMODE(Np->Num)) continue; else *Np->inout_p = ' '; } else { if (*Np->inout_p == '-') *Np->number = '-'; } break; case NUM_PL: if (Np->is_to_char) { if (Np->sign == '+') *Np->inout_p = '+'; else if (IS_FILLMODE(Np->Num)) continue; else *Np->inout_p = ' '; } else { if (*Np->inout_p == '+') *Np->number = '+'; } break; case NUM_SG: if (Np->is_to_char) *Np->inout_p = Np->sign; else { if (*Np->inout_p == '-') *Np->number = '-'; else if (*Np->inout_p == '+') *Np->number = '+'; } break; default: continue; break; } } else { /* * Remove to output char from input in TO_CHAR */ if (Np->is_to_char) *Np->inout_p = n->character; } Np->inout_p++; } if (Np->is_to_char) { *Np->inout_p = '\0'; return Np->inout; } else { if (*(Np->number_p - 1) == '.') *(Np->number_p - 1) = '\0'; else *Np->number_p = '\0'; /* * Correction - precision of dec. number */ Np->Num->post = Np->read_post; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number); #endif return Np->number; } }
static void NUMDesc_prepare | ( | NUMDesc * | num, | |
FormatNode * | n | |||
) | [static] |
Definition at line 1046 of file formatting.c.
References ereport, errcode(), errdetail(), errmsg(), ERROR, NUMDesc::flag, KeyWord::id, IS_BLANK, IS_BRACKET, IS_DECIMAL, IS_EEEE, IS_FILLMODE, IS_LSIGN, IS_MINUS, IS_MULTI, IS_PLUS, IS_ROMAN, IS_ZERO, FormatNode::key, NUMDesc::lsign, NUMDesc::multi, NUMDesc::need_locale, NODE_TYPE_ACTION, NUM_0, NUM_9, NUM_B, NUM_cache_remove(), NUM_D, NUM_DEC, NUM_E, NUM_FM, NUM_G, NUM_L, NUM_LSIGN_NONE, NUM_MI, NUM_PL, NUM_PR, NUM_RN, NUM_rn, NUM_S, NUM_SG, NUM_V, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, FormatNode::type, NUMDesc::zero_end, and NUMDesc::zero_start.
Referenced by parse_format().
{ if (n->type != NODE_TYPE_ACTION) return; /* * In case of an error, we need to remove the numeric from the cache. Use * a PG_TRY block to ensure that this happens. */ PG_TRY(); { if (IS_EEEE(num) && n->key->id != NUM_E) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"EEEE\" must be the last pattern used"))); switch (n->key->id) { case NUM_9: if (IS_BRACKET(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"9\" must be ahead of \"PR\""))); if (IS_MULTI(num)) { ++num->multi; break; } if (IS_DECIMAL(num)) ++num->post; else ++num->pre; break; case NUM_0: if (IS_BRACKET(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"0\" must be ahead of \"PR\""))); if (!IS_ZERO(num) && !IS_DECIMAL(num)) { num->flag |= NUM_F_ZERO; num->zero_start = num->pre + 1; } if (!IS_DECIMAL(num)) ++num->pre; else ++num->post; num->zero_end = num->pre + num->post; break; case NUM_B: if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num))) num->flag |= NUM_F_BLANK; break; case NUM_D: num->flag |= NUM_F_LDECIMAL; num->need_locale = TRUE; /* FALLTHROUGH */ case NUM_DEC: if (IS_DECIMAL(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("multiple decimal points"))); if (IS_MULTI(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"V\" and decimal point together"))); num->flag |= NUM_F_DECIMAL; break; case NUM_FM: num->flag |= NUM_F_FILLMODE; break; case NUM_S: if (IS_LSIGN(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"S\" twice"))); if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together"))); if (!IS_DECIMAL(num)) { num->lsign = NUM_LSIGN_PRE; num->pre_lsign_num = num->pre; num->need_locale = TRUE; num->flag |= NUM_F_LSIGN; } else if (num->lsign == NUM_LSIGN_NONE) { num->lsign = NUM_LSIGN_POST; num->need_locale = TRUE; num->flag |= NUM_F_LSIGN; } break; case NUM_MI: if (IS_LSIGN(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"S\" and \"MI\" together"))); num->flag |= NUM_F_MINUS; if (IS_DECIMAL(num)) num->flag |= NUM_F_MINUS_POST; break; case NUM_PL: if (IS_LSIGN(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"S\" and \"PL\" together"))); num->flag |= NUM_F_PLUS; if (IS_DECIMAL(num)) num->flag |= NUM_F_PLUS_POST; break; case NUM_SG: if (IS_LSIGN(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"S\" and \"SG\" together"))); num->flag |= NUM_F_MINUS; num->flag |= NUM_F_PLUS; break; case NUM_PR: if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together"))); num->flag |= NUM_F_BRACKET; break; case NUM_rn: case NUM_RN: num->flag |= NUM_F_ROMAN; break; case NUM_L: case NUM_G: num->need_locale = TRUE; break; case NUM_V: if (IS_DECIMAL(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"V\" and decimal point together"))); num->flag |= NUM_F_MULTI; break; case NUM_E: if (IS_EEEE(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot use \"EEEE\" twice"))); if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) || IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) || IS_ROMAN(num) || IS_MULTI(num)) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("\"EEEE\" is incompatible with other formats"), errdetail("\"EEEE\" may only be used together with digit and decimal point patterns."))); num->flag |= NUM_F_EEEE; break; } } PG_CATCH(); { NUM_cache_remove(last_NUMCacheEntry); PG_RE_THROW(); } PG_END_TRY(); return; }
Datum numeric_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 4952 of file formatting.c.
References DatumGetCString, DatumGetInt32, DatumGetNumeric, DirectFunctionCall1, DirectFunctionCall2, fill_str(), format, Int32GetDatum, int4_numeric(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, numeric_int4(), numeric_mul(), numeric_out(), numeric_out_sci(), numeric_power(), numeric_round(), NumericGetDatum, palloc(), PG_GETARG_NUMERIC, PG_GETARG_TEXT_P, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, val, and value.
{ Numeric value = PG_GETARG_NUMERIC(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; FormatNode *format; text *result; bool shouldFree; int len = 0, plen = 0, sign = 0; char *numstr, *orgnum, *p; Numeric x; NUM_TOCHAR_prepare; /* * On DateType depend part (numeric) */ if (IS_ROMAN(&Num)) { x = DatumGetNumeric(DirectFunctionCall2(numeric_round, NumericGetDatum(value), Int32GetDatum(0))); numstr = orgnum = int_to_roman(DatumGetInt32(DirectFunctionCall1(numeric_int4, NumericGetDatum(x)))); } else if (IS_EEEE(&Num)) { orgnum = numeric_out_sci(value, Num.post); /* * numeric_out_sci() does not emit a sign for positive numbers. We * need to add a space in this case so that positive and negative * numbers are aligned. We also have to do the right thing for NaN. */ if (strcmp(orgnum, "NaN") == 0) { /* * Allow 6 characters for the leading sign, the decimal point, * "e", the exponent's sign and two exponent digits. */ numstr = (char *) palloc(Num.pre + Num.post + 7); fill_str(numstr, '#', Num.pre + Num.post + 6); *numstr = ' '; *(numstr + Num.pre + 1) = '.'; } else if (*orgnum != '-') { numstr = (char *) palloc(strlen(orgnum) + 2); *numstr = ' '; strcpy(numstr + 1, orgnum); len = strlen(numstr); } else { numstr = orgnum; len = strlen(orgnum); } } else { Numeric val = value; if (IS_MULTI(&Num)) { Numeric a = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(10))); Numeric b = DatumGetNumeric(DirectFunctionCall1(int4_numeric, Int32GetDatum(Num.multi))); x = DatumGetNumeric(DirectFunctionCall2(numeric_power, NumericGetDatum(a), NumericGetDatum(b))); val = DatumGetNumeric(DirectFunctionCall2(numeric_mul, NumericGetDatum(value), NumericGetDatum(x))); Num.pre += Num.multi; } x = DatumGetNumeric(DirectFunctionCall2(numeric_round, NumericGetDatum(val), Int32GetDatum(Num.post))); orgnum = DatumGetCString(DirectFunctionCall1(numeric_out, NumericGetDatum(x))); if (*orgnum == '-') { sign = '-'; numstr = orgnum + 1; } else { sign = '+'; numstr = orgnum; } if ((p = strchr(numstr, '.'))) len = p - numstr; else len = strlen(numstr); if (Num.pre > len) plen = Num.pre - len; else if (len > Num.pre) { numstr = (char *) palloc(Num.pre + Num.post + 2); fill_str(numstr, '#', Num.pre + Num.post + 1); *(numstr + Num.pre) = '.'; } }
Datum numeric_to_number | ( | PG_FUNCTION_ARGS | ) |
Definition at line 4908 of file formatting.c.
References CStringGetDatum, DirectFunctionCall3, format, Int32GetDatum, InvalidOid, Max, NUM_cache(), NUM_MAX_ITEM_SIZ, NUM_processor(), numeric_in(), ObjectIdGetDatum, palloc(), pfree(), PG_GET_COLLATION, PG_GETARG_TEXT_P, PG_RETURN_NULL, NUMDesc::post, NUMDesc::pre, scale, value, VARDATA, VARHDRSZ, and VARSIZE.
{ text *value = PG_GETARG_TEXT_P(0); text *fmt = PG_GETARG_TEXT_P(1); NUMDesc Num; Datum result; FormatNode *format; char *numstr; bool shouldFree; int len = 0; int scale, precision; len = VARSIZE(fmt) - VARHDRSZ; if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ) PG_RETURN_NULL(); format = NUM_cache(len, &Num, fmt, &shouldFree); numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1); NUM_processor(format, &Num, VARDATA(value), numstr, VARSIZE(value) - VARHDRSZ, 0, false, PG_GET_COLLATION()); scale = Num.post; precision = Max(0, Num.pre) + scale; if (shouldFree) pfree(format); result = DirectFunctionCall3(numeric_in, CStringGetDatum(numstr), ObjectIdGetDatum(InvalidOid),
static void parse_format | ( | FormatNode * | node, | |
char * | str, | |||
const KeyWord * | kw, | |||
KeySuffix * | suf, | |||
const int * | index, | |||
int | ver, | |||
NUMDesc * | Num | |||
) | [static] |
Definition at line 1238 of file formatting.c.
References FormatNode::character, DCH_TYPE, elog, KeySuffix::id, index_seq_search(), FormatNode::key, KeyWord::len, KeySuffix::len, NODE_TYPE_ACTION, NULL, NUM_TYPE, NUMDesc_prepare(), suff_search(), FormatNode::suffix, SUFFTYPE_POSTFIX, SUFFTYPE_PREFIX, and FormatNode::type.
Referenced by datetime_to_char_body(), do_to_timestamp(), and NUM_cache().
{ KeySuffix *s; FormatNode *n; int node_set = 0, suffix, last = 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "to_char/number(): run parser"); #endif n = node; while (*str) { suffix = 0; /* * Prefix */ if (ver == DCH_TYPE && (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL) { suffix |= s->id; if (s->len) str += s->len; } /* * Keyword */ if (*str && (n->key = index_seq_search(str, kw, index)) != NULL) { n->type = NODE_TYPE_ACTION; n->suffix = 0; node_set = 1; if (n->key->len) str += n->key->len; /* * NUM version: Prepare global NUMDesc struct */ if (ver == NUM_TYPE) NUMDesc_prepare(Num, n); /* * Postfix */ if (ver == DCH_TYPE && *str && (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL) { suffix |= s->id; if (s->len) str += s->len; } } else if (*str) { /* * Special characters '\' and '"' */ if (*str == '"' && last != '\\') { int x = 0; while (*(++str)) { if (*str == '"' && x != '\\') { str++; break; } else if (*str == '\\' && x != '\\') { x = '\\'; continue; } n->type = NODE_TYPE_CHAR; n->character = *str; n->key = NULL; n->suffix = 0; ++n; x = *str; } node_set = 0; suffix = 0; last = 0; } else if (*str && *str == '\\' && last != '\\' && *(str + 1) == '"') { last = *str; str++; } else if (*str) { n->type = NODE_TYPE_CHAR; n->character = *str; n->key = NULL; node_set = 1; last = 0; str++; } } /* end */ if (node_set) { if (n->type == NODE_TYPE_ACTION) n->suffix = suffix; ++n; n->suffix = 0; node_set = 0; } } n->type = NODE_TYPE_END; n->suffix = 0; return; }
static int seq_search | ( | char * | name, | |
char ** | array, | |||
int | type, | |||
int | max, | |||
int * | len | |||
) | [static] |
Definition at line 2270 of file formatting.c.
References ALL_LOWER, ALL_UPPER, elog, i, ONE_UPPER, pg_tolower(), and pg_toupper().
Referenced by from_char_seq_search().
{ char *p, *n, **a; int last, i; *len = 0; if (!*name) return -1; /* set first char */ if (type == ONE_UPPER || type == ALL_UPPER) *name = pg_toupper((unsigned char) *name); else if (type == ALL_LOWER) *name = pg_tolower((unsigned char) *name); for (last = 0, a = array; *a != NULL; a++) { /* comperate first chars */ if (*name != **a) continue; for (i = 1, p = *a + 1, n = name + 1;; n++, p++, i++) { /* search fragment (max) only */ if (max && i == max) { *len = i; return a - array; } /* full size */ if (*p == '\0') { *len = i; return a - array; } /* Not found in array 'a' */ if (*n == '\0') break; /* * Convert (but convert new chars only) */ if (i > last) { if (type == ONE_UPPER || type == ALL_LOWER) *n = pg_tolower((unsigned char) *n); else if (type == ALL_UPPER) *n = pg_toupper((unsigned char) *n); last = i; } #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "N: %c, P: %c, A: %s (%s)", *n, *p, *a, name); #endif if (*n != *p) break; } } return -1; }
char* str_initcap | ( | const char * | buff, | |
size_t | nbytes, | |||
Oid | collid | |||
) |
Definition at line 1725 of file formatting.c.
References asc_initcap(), DEFAULT_COLLATION_OID, ereport, errcode(), errhint(), errmsg(), ERROR, isalnum_l, iswalnum_l, lc_ctype_is_c(), OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_tolower(), pg_toupper(), pnstrdup(), tolower_l, toupper_l, towlower_l, and towupper_l.
Referenced by initcap(), and str_initcap_z().
{ char *result; int wasalnum = false; if (!buff) return NULL; /* C/POSIX collations use this path regardless of database encoding */ if (lc_ctype_is_c(collid)) { result = asc_initcap(buff, nbytes); } #ifdef USE_WIDE_UPPER_LOWER else if (pg_database_encoding_max_length() > 1) { pg_locale_t mylocale = 0; wchar_t *workspace; size_t curr_char; size_t result_size; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for initcap() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } mylocale = pg_newlocale_from_collation(collid); } /* Overflow paranoia */ if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T if (mylocale) { if (wasalnum) workspace[curr_char] = towlower_l(workspace[curr_char], mylocale); else workspace[curr_char] = towupper_l(workspace[curr_char], mylocale); wasalnum = iswalnum_l(workspace[curr_char], mylocale); } else #endif { if (wasalnum) workspace[curr_char] = towlower(workspace[curr_char]); else workspace[curr_char] = towupper(workspace[curr_char]); wasalnum = iswalnum(workspace[curr_char]); } } /* Make result large enough; case change might change number of bytes */ result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); wchar2char(result, workspace, result_size, mylocale); pfree(workspace); } #endif /* USE_WIDE_UPPER_LOWER */ else { #ifdef HAVE_LOCALE_T pg_locale_t mylocale = 0; #endif char *p; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for initcap() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } #ifdef HAVE_LOCALE_T mylocale = pg_newlocale_from_collation(collid); #endif } result = pnstrdup(buff, nbytes); /* * Note: we assume that toupper_l()/tolower_l() will not be so broken * as to need guard tests. When using the default collation, we apply * the traditional Postgres behavior that forces ASCII-style treatment * of I/i, but in non-default collations you get exactly what the * collation says. */ for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T if (mylocale) { if (wasalnum) *p = tolower_l((unsigned char) *p, mylocale); else *p = toupper_l((unsigned char) *p, mylocale); wasalnum = isalnum_l((unsigned char) *p, mylocale); } else #endif { if (wasalnum) *p = pg_tolower((unsigned char) *p); else *p = pg_toupper((unsigned char) *p); wasalnum = isalnum((unsigned char) *p); } } } return result; }
static char* str_initcap_z | ( | const char * | buff, | |
Oid | collid | |||
) | [static] |
Definition at line 1959 of file formatting.c.
References str_initcap().
Referenced by DCH_to_char().
{ return str_initcap(buff, strlen(buff), collid); }
static char * str_numth | ( | char * | dest, | |
char * | num, | |||
int | type | |||
) | [static] |
Definition at line 1450 of file formatting.c.
References get_th().
Referenced by DCH_to_char().
{ if (dest != num) strcpy(dest, num); strcat(dest, get_th(num, type)); return dest; }
char* str_tolower | ( | const char * | buff, | |
size_t | nbytes, | |||
Oid | collid | |||
) |
Definition at line 1485 of file formatting.c.
References asc_tolower(), DEFAULT_COLLATION_OID, ereport, errcode(), errhint(), errmsg(), ERROR, lc_ctype_is_c(), OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_tolower(), pnstrdup(), tolower_l, and towlower_l.
Referenced by citext_eq(), citext_hash(), citext_ne(), citextcmp(), lower(), ltree_strncasecmp(), and str_tolower_z().
{ char *result; if (!buff) return NULL; /* C/POSIX collations use this path regardless of database encoding */ if (lc_ctype_is_c(collid)) { result = asc_tolower(buff, nbytes); } #ifdef USE_WIDE_UPPER_LOWER else if (pg_database_encoding_max_length() > 1) { pg_locale_t mylocale = 0; wchar_t *workspace; size_t curr_char; size_t result_size; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for lower() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } mylocale = pg_newlocale_from_collation(collid); } /* Overflow paranoia */ if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T if (mylocale) workspace[curr_char] = towlower_l(workspace[curr_char], mylocale); else #endif workspace[curr_char] = towlower(workspace[curr_char]); } /* Make result large enough; case change might change number of bytes */ result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); wchar2char(result, workspace, result_size, mylocale); pfree(workspace); } #endif /* USE_WIDE_UPPER_LOWER */ else { #ifdef HAVE_LOCALE_T pg_locale_t mylocale = 0; #endif char *p; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for lower() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } #ifdef HAVE_LOCALE_T mylocale = pg_newlocale_from_collation(collid); #endif } result = pnstrdup(buff, nbytes); /* * Note: we assume that tolower_l() will not be so broken as to need * an isupper_l() guard test. When using the default collation, we * apply the traditional Postgres behavior that forces ASCII-style * treatment of I/i, but in non-default collations you get exactly * what the collation says. */ for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T if (mylocale) *p = tolower_l((unsigned char) *p, mylocale); else #endif *p = pg_tolower((unsigned char) *p); } } return result; }
static char* str_tolower_z | ( | const char * | buff, | |
Oid | collid | |||
) | [static] |
Definition at line 1947 of file formatting.c.
References str_tolower().
Referenced by DCH_to_char().
{ return str_tolower(buff, strlen(buff), collid); }
char* str_toupper | ( | const char * | buff, | |
size_t | nbytes, | |||
Oid | collid | |||
) |
Definition at line 1605 of file formatting.c.
References asc_toupper(), DEFAULT_COLLATION_OID, ereport, errcode(), errhint(), errmsg(), ERROR, lc_ctype_is_c(), OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_toupper(), pnstrdup(), toupper_l, and towupper_l.
Referenced by str_toupper_z(), and upper().
{ char *result; if (!buff) return NULL; /* C/POSIX collations use this path regardless of database encoding */ if (lc_ctype_is_c(collid)) { result = asc_toupper(buff, nbytes); } #ifdef USE_WIDE_UPPER_LOWER else if (pg_database_encoding_max_length() > 1) { pg_locale_t mylocale = 0; wchar_t *workspace; size_t curr_char; size_t result_size; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for upper() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } mylocale = pg_newlocale_from_collation(collid); } /* Overflow paranoia */ if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t))) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); /* Output workspace cannot have more codes than input bytes */ workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t)); char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale); for (curr_char = 0; workspace[curr_char] != 0; curr_char++) { #ifdef HAVE_LOCALE_T if (mylocale) workspace[curr_char] = towupper_l(workspace[curr_char], mylocale); else #endif workspace[curr_char] = towupper(workspace[curr_char]); } /* Make result large enough; case change might change number of bytes */ result_size = curr_char * pg_database_encoding_max_length() + 1; result = palloc(result_size); wchar2char(result, workspace, result_size, mylocale); pfree(workspace); } #endif /* USE_WIDE_UPPER_LOWER */ else { #ifdef HAVE_LOCALE_T pg_locale_t mylocale = 0; #endif char *p; if (collid != DEFAULT_COLLATION_OID) { if (!OidIsValid(collid)) { /* * This typically means that the parser could not resolve a * conflict of implicit collations, so report it that way. */ ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("could not determine which collation to use for upper() function"), errhint("Use the COLLATE clause to set the collation explicitly."))); } #ifdef HAVE_LOCALE_T mylocale = pg_newlocale_from_collation(collid); #endif } result = pnstrdup(buff, nbytes); /* * Note: we assume that toupper_l() will not be so broken as to need * an islower_l() guard test. When using the default collation, we * apply the traditional Postgres behavior that forces ASCII-style * treatment of I/i, but in non-default collations you get exactly * what the collation says. */ for (p = result; *p; p++) { #ifdef HAVE_LOCALE_T if (mylocale) *p = toupper_l((unsigned char) *p, mylocale); else #endif *p = pg_toupper((unsigned char) *p); } } return result; }
static char* str_toupper_z | ( | const char * | buff, | |
Oid | collid | |||
) | [static] |
Definition at line 1953 of file formatting.c.
References str_toupper().
Referenced by DCH_to_char().
{ return str_toupper(buff, strlen(buff), collid); }
static int strdigits_len | ( | char * | str | ) | [static] |
Definition at line 2092 of file formatting.c.
References DCH_MAX_ITEM_SIZ, and strspace_len().
Referenced by DCH_from_char().
{ char *p = str; int len; len = strspace_len(str); p += len; while (*p && isdigit((unsigned char) *p) && len <= DCH_MAX_ITEM_SIZ) { len++; p++; } return len; }
static int strspace_len | ( | char * | str | ) | [static] |
Definition at line 2079 of file formatting.c.
Referenced by from_char_parse_int_len(), and strdigits_len().
{ int len = 0; while (*str && isspace((unsigned char) *str)) { str++; len++; } return len; }
Definition at line 1026 of file formatting.c.
References KeySuffix::len, KeySuffix::name, and KeySuffix::type.
Referenced by parse_format().
Datum timestamp_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3258 of file formatting.c.
References date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, NULL, PG_GET_COLLATION, PG_GETARG_TEXT_P, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, VARHDRSZ, VARSIZE, and ZERO_tmtc.
{ Timestamp dt = PG_GETARG_TIMESTAMP(0); text *fmt = PG_GETARG_TEXT_P(1), *res; TmToChar tmtc; struct pg_tm *tm; int thisdate; if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt)) PG_RETURN_NULL(); ZERO_tmtc(&tmtc); tm = tmtcTm(&tmtc); if (timestamp2tm(dt, NULL, tm, &tmtcFsec(&tmtc), NULL, NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); tm->tm_wday = (thisdate + 1) % 7; tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1; if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION()))) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); }
Datum timestamptz_to_char | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3289 of file formatting.c.
References date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, NULL, PG_GET_COLLATION, PG_GETARG_TEXT_P, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, tmtcTzn, VARHDRSZ, VARSIZE, and ZERO_tmtc.
{ TimestampTz dt = PG_GETARG_TIMESTAMP(0); text *fmt = PG_GETARG_TEXT_P(1), *res; TmToChar tmtc; int tz; struct pg_tm *tm; int thisdate; if ((VARSIZE(fmt) - VARHDRSZ) <= 0 || TIMESTAMP_NOT_FINITE(dt)) PG_RETURN_NULL(); ZERO_tmtc(&tmtc); tm = tmtcTm(&tmtc); if (timestamp2tm(dt, &tz, tm, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); thisdate = date2j(tm->tm_year, tm->tm_mon, tm->tm_mday); tm->tm_wday = (thisdate + 1) % 7; tm->tm_yday = thisdate - date2j(tm->tm_year, 1, 1) + 1; if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION()))) PG_RETURN_NULL(); PG_RETURN_TEXT_P(res); }
Datum to_date | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3387 of file formatting.c.
References date2j(), do_to_timestamp(), ereport, errcode(), errmsg(), ERROR, IS_VALID_JULIAN, PG_GETARG_TEXT_P, PG_RETURN_DATEADT, text_to_cstring(), pg_tm::tm_mday, pg_tm::tm_mon, and pg_tm::tm_year.
{ text *date_txt = PG_GETARG_TEXT_P(0); text *fmt = PG_GETARG_TEXT_P(1); DateADT result; struct pg_tm tm; fsec_t fsec; do_to_timestamp(date_txt, fmt, &tm, &fsec); if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("date out of range: \"%s\"", text_to_cstring(date_txt)))); result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE; PG_RETURN_DATEADT(result); }
Datum to_timestamp | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3360 of file formatting.c.
References DetermineTimeZoneOffset(), do_to_timestamp(), ereport, errcode(), errmsg(), ERROR, PG_GETARG_TEXT_P, PG_RETURN_TIMESTAMP, session_timezone, and tm2timestamp().
{ text *date_txt = PG_GETARG_TEXT_P(0); text *fmt = PG_GETARG_TEXT_P(1); Timestamp result; int tz; struct pg_tm tm; fsec_t fsec; do_to_timestamp(date_txt, fmt, &tm, &fsec); tz = DetermineTimeZoneOffset(&tm, session_timezone); if (tm2timestamp(&tm, fsec, &tz, &result) != 0) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), errmsg("timestamp out of range"))); PG_RETURN_TIMESTAMP(result); }
char* adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL} [static] |
Definition at line 229 of file formatting.c.
Referenced by DCH_from_char().
char* adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL} [static] |
Definition at line 230 of file formatting.c.
Referenced by DCH_from_char().
char* ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL} [static] |
Definition at line 256 of file formatting.c.
Referenced by DCH_from_char().
char* ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL} [static] |
Definition at line 257 of file formatting.c.
Referenced by DCH_from_char().
char * days[] |
Definition at line 67 of file datetime.c.
char* days_short[] [static] |
{ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }
Definition at line 196 of file formatting.c.
Referenced by DCH_to_char().
const int DCH_index[KeyWord_INDEX_SIZE] [static] |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1, DCH_FX, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, -1, DCH_P_M, DCH_Q, DCH_RM, DCH_SSSS, DCH_TZ, DCH_US, -1, DCH_WW, -1, DCH_Y_YYY, -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc, DCH_day, -1, DCH_fx, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi, -1, -1, DCH_p_m, DCH_q, DCH_rm, DCH_ssss, DCH_tz, DCH_us, -1, DCH_ww, -1, DCH_y_yyy, -1, -1, -1, -1 }
Definition at line 867 of file formatting.c.
Referenced by datetime_to_char_body(), and do_to_timestamp().
const KeyWord DCH_keywords[] [static] |
Definition at line 714 of file formatting.c.
{ {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX}, {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX}, {"TM", 2, DCH_S_TM, SUFFTYPE_PREFIX}, {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX}, {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX}, {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX}, {"SP", 2, DCH_S_SP, SUFFTYPE_POSTFIX}, {NULL, 0, 0, 0} }
Definition at line 528 of file formatting.c.
DCHCacheEntry DCHCache[DCH_CACHE_FIELDS+1] [static] |
Definition at line 391 of file formatting.c.
int DCHCounter = 0 [static] |
Definition at line 394 of file formatting.c.
Referenced by DCH_cache_getnew(), and DCH_cache_search().
NUMCacheEntry* last_NUMCacheEntry = NUMCache + 0 [static] |
Definition at line 401 of file formatting.c.
char* months[] |
Definition at line 64 of file datetime.c.
char* months_full[] [static] |
{ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December", NULL }
Definition at line 191 of file formatting.c.
Referenced by DCH_from_char(), and DCH_to_char().
int n_DCHCache = 0 [static] |
Definition at line 393 of file formatting.c.
Referenced by DCH_cache_getnew(), and DCH_cache_search().
int n_NUMCache = 0 [static] |
Definition at line 399 of file formatting.c.
Referenced by NUM_cache_getnew(), and NUM_cache_search().
const int NUM_index[KeyWord_INDEX_SIZE] [static] |
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1, -1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1, -1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E, NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1, NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c, NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi, -1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1, -1, -1, -1, -1, -1, -1 }
Definition at line 891 of file formatting.c.
Referenced by NUM_cache().
const KeyWord NUM_keywords[] [static] |
Definition at line 819 of file formatting.c.
NUMCacheEntry NUMCache[NUM_CACHE_FIELDS+1] [static] |
Definition at line 397 of file formatting.c.
int NUMCounter = 0 [static] |
Definition at line 400 of file formatting.c.
Referenced by NUM_cache_getnew(), and NUM_cache_search().
char* numTH[] = {"ST", "ND", "RD", "TH", NULL} [static] |
Definition at line 283 of file formatting.c.
Referenced by get_th().
char* numth[] = {"st", "nd", "rd", "th", NULL} [static] |
Definition at line 284 of file formatting.c.
Referenced by get_th().
char* rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL} [static] |
Definition at line 275 of file formatting.c.
Referenced by int_to_roman().
char* rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL} [static] |
Definition at line 276 of file formatting.c.
Referenced by int_to_roman().
char* rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL} [static] |
Definition at line 277 of file formatting.c.
Referenced by int_to_roman().
char* rm_months_lower[] [static] |
{"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL}
Definition at line 268 of file formatting.c.
Referenced by DCH_from_char(), and DCH_to_char().
char* rm_months_upper[] [static] |
{"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL}
Definition at line 265 of file formatting.c.
Referenced by DCH_from_char(), and DCH_to_char().