Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
formatting.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <unistd.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <wctype.h>
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "common/int.h"
#include "common/unicode_case.h"
#include "common/unicode_category.h"
#include "mb/pg_wchar.h"
#include "nodes/miscnodes.h"
#include "parser/scansup.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/formatting.h"
#include "utils/memutils.h"
#include "utils/numeric.h"
#include "utils/pg_locale.h"
#include "varatt.h"
Include dependency graph for formatting.c:

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  fmt_tz
 
struct  fmt_tm
 
struct  TmToChar
 
struct  NUMProc
 

Macros

#define DCH_FLAG   0x1 /* DATE-TIME flag */
 
#define NUM_FLAG   0x2 /* NUMBER flag */
 
#define STD_FLAG   0x4 /* STANDARD flag */
 
#define KeyWord_INDEX_SIZE   ('~' - ' ')
 
#define KeyWord_INDEX_FILTER(_c)   ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
 
#define DCH_MAX_ITEM_SIZ   12 /* max localized day name */
 
#define NUM_MAX_ITEM_SIZ   8 /* roman number (RN has 15 chars) */
 
#define NODE_TYPE_END   1
 
#define NODE_TYPE_ACTION   2
 
#define NODE_TYPE_CHAR   3
 
#define NODE_TYPE_SEPARATOR   4
 
#define NODE_TYPE_SPACE   5
 
#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 IS_VALID_SUB_COMB(curr, next)
 
#define ROMAN_VAL(r)
 
#define MAX_ROMAN_LEN   15
 
#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 DCH_CACHE_OVERHEAD    MAXALIGN(sizeof(bool) + sizeof(int))
 
#define NUM_CACHE_OVERHEAD    MAXALIGN(sizeof(bool) + sizeof(int) + sizeof(NUMDesc))
 
#define DCH_CACHE_SIZE    ((2048 - DCH_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
 
#define NUM_CACHE_SIZE    ((1024 - NUM_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
 
#define DCH_CACHE_ENTRIES   20
 
#define NUM_CACHE_ENTRIES   20
 
#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 COPY_tm(_DST, _SRC)
 
#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 TM_SUFFIX_LEN   2
 
#define DCH_DATED   0x01
 
#define DCH_TIMED   0x02
 
#define DCH_ZONED   0x04
 
#define OVERLOAD_TEST   (Np->inout_p >= Np->inout + input_len)
 
#define AMOUNT_TEST(s)   (Np->inout_p <= Np->inout + (input_len - (s)))
 
#define SKIP_THth(ptr, _suf)
 
#define DCH_to_char_fsec(frac_fmt, frac_val)
 
#define zeroize_NUM(_n)
 
#define IS_PREDEC_SPACE(_n)
 
#define NUM_TOCHAR_prepare
 
#define NUM_TOCHAR_finish
 

Typedefs

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_FF1 , DCH_FF2 ,
  DCH_FF3 , DCH_FF4 , DCH_FF5 , DCH_FF6 ,
  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_OF ,
  DCH_P_M , DCH_PM , DCH_Q , DCH_RM ,
  DCH_SSSSS , DCH_SSSS , DCH_SS , DCH_TZH ,
  DCH_TZM , 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_ff1 , DCH_ff2 ,
  DCH_ff3 , DCH_ff4 , DCH_ff5 , DCH_ff6 ,
  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_of , DCH_p_m , DCH_pm ,
  DCH_q , DCH_rm , DCH_sssss , DCH_ssss ,
  DCH_ss , DCH_tzh , DCH_tzm , 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 KeyWordindex_seq_search (const char *str, const KeyWord *kw, const int *index)
 
static const KeySuffixsuff_search (const char *str, const KeySuffix *suf, int type)
 
static bool is_separator_char (const char *str)
 
static void NUMDesc_prepare (NUMDesc *num, FormatNode *n)
 
static void parse_format (FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, uint32 flags, 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, const char *in, TmFromChar *out, Oid collid, bool std, Node *escontext)
 
static const 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 (const char *str)
 
static bool from_char_set_mode (TmFromChar *tmfc, const FromCharDateMode mode, Node *escontext)
 
static bool from_char_set_int (int *dest, const int value, const FormatNode *node, Node *escontext)
 
static int from_char_parse_int_len (int *dest, const char **src, const int len, FormatNode *node, Node *escontext)
 
static int from_char_parse_int (int *dest, const char **src, FormatNode *node, Node *escontext)
 
static int seq_search_ascii (const char *name, const char *const *array, int *len)
 
static int seq_search_localized (const char *name, char **array, int *len, Oid collid)
 
static bool from_char_seq_search (int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, Node *escontext)
 
static bool do_to_timestamp (text *date_txt, text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext)
 
static char * fill_str (char *str, int c, int max)
 
static FormatNodeNUM_cache (int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
 
static char * int_to_roman (int number)
 
static int roman_to_int (NUMProc *Np, int input_len)
 
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 input_len)
 
static void NUM_numpart_to_char (NUMProc *Np, int id)
 
static char * NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
 
static DCHCacheEntryDCH_cache_getnew (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_search (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_fetch (const char *str, bool std)
 
static NUMCacheEntryNUM_cache_getnew (const char *str)
 
static NUMCacheEntryNUM_cache_search (const char *str)
 
static NUMCacheEntryNUM_cache_fetch (const char *str)
 
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 * str_casefold (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 void DCH_prevent_counter_overflow (void)
 
static int DCH_datetime_type (FormatNode *node)
 
static textdatetime_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 parse_datetime (text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, Node *escontext)
 
bool datetime_format_has_tz (const char *fmt_str)
 
static void NUM_prevent_counter_overflow (void)
 
static void NUM_eat_non_data_chars (NUMProc *Np, int n, int input_len)
 
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

static const char *const months_full []
 
static const char *const days_short []
 
static const char *const adbc_strings [] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL}
 
static const char *const adbc_strings_long [] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL}
 
static const char *const ampm_strings [] = {am_STR, pm_STR, AM_STR, PM_STR, NULL}
 
static const char *const ampm_strings_long [] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL}
 
static const char *const rm_months_upper []
 
static const char *const rm_months_lower []
 
static const char *const rm1 [] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL}
 
static const char *const rm10 [] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL}
 
static const char *const rm100 [] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL}
 
static const char *const numTH [] = {"ST", "ND", "RD", "TH", NULL}
 
static const char *const numth [] = {"st", "nd", "rd", "th", NULL}
 
static DCHCacheEntryDCHCache [DCH_CACHE_ENTRIES]
 
static int n_DCHCache = 0
 
static int DCHCounter = 0
 
static NUMCacheEntryNUMCache [NUM_CACHE_ENTRIES]
 
static int n_NUMCache = 0
 
static int NUMCounter = 0
 
static const 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]
 

Macro Definition Documentation

◆ A_D_STR

#define A_D_STR   "A.D."

Definition at line 196 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 197 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 223 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 224 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 198 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 199 of file formatting.c.

◆ ADJUST_YEAR

#define ADJUST_YEAR (   year,
  is_interval 
)    ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))

Definition at line 194 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 225 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 226 of file formatting.c.

◆ AMOUNT_TEST

#define AMOUNT_TEST (   s)    (Np->inout_p <= Np->inout + (input_len - (s)))

Definition at line 1062 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 201 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 202 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 203 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

Definition at line 204 of file formatting.c.

◆ CLOCK_12_HOUR

#define CLOCK_12_HOUR   1

Definition at line 171 of file formatting.c.

◆ CLOCK_24_HOUR

#define CLOCK_24_HOUR   0

Definition at line 170 of file formatting.c.

◆ COPY_tm

#define COPY_tm (   _DST,
  _SRC 
)
Value:
do { \
(_DST)->tm_sec = (_SRC)->tm_sec; \
(_DST)->tm_min = (_SRC)->tm_min; \
(_DST)->tm_hour = (_SRC)->tm_hour; \
(_DST)->tm_mday = (_SRC)->tm_mday; \
(_DST)->tm_mon = (_SRC)->tm_mon; \
(_DST)->tm_year = (_SRC)->tm_year; \
(_DST)->tm_wday = (_SRC)->tm_wday; \
(_DST)->tm_yday = (_SRC)->tm_yday; \
(_DST)->tm_gmtoff = (_SRC)->tm_gmtoff; \
} while(0)

Definition at line 520 of file formatting.c.

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 391 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

#define DCH_CACHE_OVERHEAD    MAXALIGN(sizeof(bool) + sizeof(int))

Definition at line 381 of file formatting.c.

◆ DCH_CACHE_SIZE

#define DCH_CACHE_SIZE    ((2048 - DCH_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)

Definition at line 386 of file formatting.c.

◆ DCH_DATED

#define DCH_DATED   0x01

Definition at line 1052 of file formatting.c.

◆ DCH_FLAG

#define DCH_FLAG   0x1 /* DATE-TIME flag */

Definition at line 99 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

#define DCH_MAX_ITEM_SIZ   12 /* max localized day name */

Definition at line 114 of file formatting.c.

◆ DCH_S_FM

#define DCH_S_FM   0x01

Definition at line 568 of file formatting.c.

◆ DCH_S_SP

#define DCH_S_SP   0x08

Definition at line 571 of file formatting.c.

◆ DCH_S_TH

#define DCH_S_TH   0x02

Definition at line 569 of file formatting.c.

◆ DCH_S_th

#define DCH_S_th   0x04

Definition at line 570 of file formatting.c.

◆ DCH_S_TM

#define DCH_S_TM   0x10

Definition at line 572 of file formatting.c.

◆ DCH_TIMED

#define DCH_TIMED   0x02

Definition at line 1053 of file formatting.c.

◆ DCH_to_char_fsec

#define DCH_to_char_fsec (   frac_fmt,
  frac_val 
)
Value:
sprintf(s, frac_fmt, (int) (frac_val)); \
if (S_THth(n->suffix)) \
str_numth(s, s, S_TH_TYPE(n->suffix)); \
s += strlen(s)
#define S_TH_TYPE(_s)
Definition: formatting.c:581
#define S_THth(_s)
Definition: formatting.c:578
#define sprintf
Definition: port.h:241

◆ DCH_ZONED

#define DCH_ZONED   0x04

Definition at line 1054 of file formatting.c.

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 484 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 483 of file formatting.c.

◆ INVALID_FOR_INTERVAL

#define INVALID_FOR_INTERVAL
Value:
do { \
if (is_interval) \
ereport(ERROR, \
(errcode(ERRCODE_INVALID_DATETIME_FORMAT), \
errmsg("invalid format specification for an interval value"), \
errhint("Intervals are not tied to specific calendar dates."))); \
} while(0)
int errhint(const char *fmt,...)
Definition: elog.c:1321
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39

Definition at line 551 of file formatting.c.

◆ IS_BLANK

#define IS_BLANK (   _f)    ((_f)->flag & NUM_F_BLANK)

Definition at line 353 of file formatting.c.

◆ IS_BRACKET

#define IS_BRACKET (   _f)    ((_f)->flag & NUM_F_BRACKET)

Definition at line 355 of file formatting.c.

◆ IS_DECIMAL

#define IS_DECIMAL (   _f)    ((_f)->flag & NUM_F_DECIMAL)

Definition at line 350 of file formatting.c.

◆ IS_EEEE

#define IS_EEEE (   _f)    ((_f)->flag & NUM_F_EEEE)

Definition at line 361 of file formatting.c.

◆ IS_FILLMODE

#define IS_FILLMODE (   _f)    ((_f)->flag & NUM_F_FILLMODE)

Definition at line 354 of file formatting.c.

◆ IS_LDECIMAL

#define IS_LDECIMAL (   _f)    ((_f)->flag & NUM_F_LDECIMAL)

Definition at line 351 of file formatting.c.

◆ IS_LSIGN

#define IS_LSIGN (   _f)    ((_f)->flag & NUM_F_LSIGN)

Definition at line 357 of file formatting.c.

◆ IS_MINUS

#define IS_MINUS (   _f)    ((_f)->flag & NUM_F_MINUS)

Definition at line 356 of file formatting.c.

◆ IS_MULTI

#define IS_MULTI (   _f)    ((_f)->flag & NUM_F_MULTI)

Definition at line 360 of file formatting.c.

◆ IS_PLUS

#define IS_PLUS (   _f)    ((_f)->flag & NUM_F_PLUS)

Definition at line 358 of file formatting.c.

◆ IS_PREDEC_SPACE

#define IS_PREDEC_SPACE (   _n)
Value:
(IS_ZERO((_n)->Num)==false && \
(_n)->number == (_n)->number_p && \
*(_n)->number == '0' && \
(_n)->Num->post != 0)
#define IS_ZERO(_f)
Definition: formatting.c:352

Definition at line 5593 of file formatting.c.

◆ IS_ROMAN

#define IS_ROMAN (   _f)    ((_f)->flag & NUM_F_ROMAN)

Definition at line 359 of file formatting.c.

◆ IS_VALID_SUB_COMB

#define IS_VALID_SUB_COMB (   curr,
  next 
)
Value:
(((curr) == 'I' && ((next) == 'V' || (next) == 'X')) || \
((curr) == 'X' && ((next) == 'L' || (next) == 'C')) || \
((curr) == 'C' && ((next) == 'D' || (next) == 'M')))
static int32 next
Definition: blutils.c:224

Definition at line 270 of file formatting.c.

◆ IS_ZERO

#define IS_ZERO (   _f)    ((_f)->flag & NUM_F_ZERO)

Definition at line 352 of file formatting.c.

◆ KeyWord_INDEX_FILTER

#define KeyWord_INDEX_FILTER (   _c)    ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)

Definition at line 108 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 107 of file formatting.c.

◆ MAX_ROMAN_LEN

#define MAX_ROMAN_LEN   15

Definition at line 290 of file formatting.c.

◆ NODE_TYPE_ACTION

#define NODE_TYPE_ACTION   2

Definition at line 162 of file formatting.c.

◆ NODE_TYPE_CHAR

#define NODE_TYPE_CHAR   3

Definition at line 163 of file formatting.c.

◆ NODE_TYPE_END

#define NODE_TYPE_END   1

Definition at line 161 of file formatting.c.

◆ NODE_TYPE_SEPARATOR

#define NODE_TYPE_SEPARATOR   4

Definition at line 164 of file formatting.c.

◆ NODE_TYPE_SPACE

#define NODE_TYPE_SPACE   5

Definition at line 165 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 392 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

#define NUM_CACHE_OVERHEAD    MAXALIGN(sizeof(bool) + sizeof(int) + sizeof(NUMDesc))

Definition at line 383 of file formatting.c.

◆ NUM_CACHE_SIZE

#define NUM_CACHE_SIZE    ((1024 - NUM_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)

Definition at line 388 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 330 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 333 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 327 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 340 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 331 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 328 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 332 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 334 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 339 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 337 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 335 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 338 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 336 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 329 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 100 of file formatting.c.

◆ NUM_LSIGN_NONE

#define NUM_LSIGN_NONE   0

Definition at line 344 of file formatting.c.

◆ NUM_LSIGN_POST

#define NUM_LSIGN_POST   1

Definition at line 343 of file formatting.c.

◆ NUM_LSIGN_PRE

#define NUM_LSIGN_PRE   (-1)

Definition at line 342 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

#define NUM_MAX_ITEM_SIZ   8 /* roman number (RN has 15 chars) */

Definition at line 115 of file formatting.c.

◆ NUM_TOCHAR_finish

#define NUM_TOCHAR_finish
Value:
do { \
int len; \
NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, 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)
#define VARHDRSZ
Definition: c.h:698
#define PG_GET_COLLATION()
Definition: fmgr.h:198
static char * NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
Definition: formatting.c:5807
char sign
Definition: informix.c:693
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
static char format
const void size_t len
static char * VARDATA(const void *PTR)
Definition: varatt.h:305

Definition at line 6288 of file formatting.c.

◆ NUM_TOCHAR_prepare

#define NUM_TOCHAR_prepare
Value:
do { \
int 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)
#define NUM_MAX_ITEM_SIZ
Definition: formatting.c:115
static FormatNode * NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
Definition: formatting.c:5006
void * palloc0(Size size)
Definition: mcxt.c:1395
Definition: c.h:693
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
text * cstring_to_text(const char *s)
Definition: varlena.c:181

Definition at line 6275 of file formatting.c.

◆ OVERLOAD_TEST

#define OVERLOAD_TEST   (Np->inout_p >= Np->inout + input_len)

Definition at line 1061 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 228 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 229 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 230 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

Definition at line 231 of file formatting.c.

◆ ROMAN_VAL

#define ROMAN_VAL (   r)
Value:
((r) == 'I' ? 1 : \
(r) == 'V' ? 5 : \
(r) == 'X' ? 10 : \
(r) == 'L' ? 50 : \
(r) == 'C' ? 100 : \
(r) == 'D' ? 500 : \
(r) == 'M' ? 1000 : 0)

Definition at line 278 of file formatting.c.

◆ S_FM

#define S_FM (   _s)    (((_s) & DCH_S_FM) ? 1 : 0)

Definition at line 584 of file formatting.c.

◆ S_SP

#define S_SP (   _s)    (((_s) & DCH_S_SP) ? 1 : 0)

Definition at line 585 of file formatting.c.

◆ S_TH

#define S_TH (   _s)    (((_s) & DCH_S_TH) ? 1 : 0)

Definition at line 579 of file formatting.c.

◆ S_th

#define S_th (   _s)    (((_s) & DCH_S_th) ? 1 : 0)

Definition at line 580 of file formatting.c.

◆ S_TH_TYPE

#define S_TH_TYPE (   _s)    (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)

Definition at line 581 of file formatting.c.

◆ S_THth

#define S_THth (   _s)    ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)

Definition at line 578 of file formatting.c.

◆ S_TM

#define S_TM (   _s)    (((_s) & DCH_S_TM) ? 1 : 0)

Definition at line 586 of file formatting.c.

◆ SKIP_THth

#define SKIP_THth (   ptr,
  _suf 
)
Value:
do { \
if (S_THth(_suf)) \
{ \
if (*(ptr)) (ptr) += pg_mblen(ptr); \
if (*(ptr)) (ptr) += pg_mblen(ptr); \
} \
} while (0)
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1024

Definition at line 2015 of file formatting.c.

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 101 of file formatting.c.

◆ SUFFTYPE_POSTFIX

#define SUFFTYPE_POSTFIX   2

Definition at line 168 of file formatting.c.

◆ SUFFTYPE_PREFIX

#define SUFFTYPE_PREFIX   1

Definition at line 167 of file formatting.c.

◆ TH_LOWER

#define TH_LOWER   2

Definition at line 304 of file formatting.c.

◆ TH_UPPER

#define TH_UPPER   1

Definition at line 303 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 592 of file formatting.c.

◆ tmtcFsec

#define tmtcFsec (   _X)    ((_X)->fsec)

Definition at line 517 of file formatting.c.

◆ tmtcTm

#define tmtcTm (   _X)    (&(_X)->tm)

Definition at line 515 of file formatting.c.

◆ tmtcTzn

#define tmtcTzn (   _X)    ((_X)->tzn)

Definition at line 516 of file formatting.c.

◆ ZERO_tm

#define ZERO_tm (   _X)
Value:
do { \
memset(_X, 0, sizeof(*(_X))); \
(_X)->tm_mday = (_X)->tm_mon = 1; \
} while(0)

Definition at line 534 of file formatting.c.

◆ ZERO_tmfc

#define ZERO_tmfc (   _X)    memset(_X, 0, sizeof(TmFromChar))

Definition at line 458 of file formatting.c.

◆ ZERO_tmtc

#define ZERO_tmtc (   _X)
Value:
do { \
ZERO_tm( tmtcTm(_X) ); \
tmtcFsec(_X) = 0; \
tmtcTzn(_X) = NULL; \
} while(0)
#define tmtcTm(_X)
Definition: formatting.c:515

Definition at line 540 of file formatting.c.

◆ zeroize_NUM

#define zeroize_NUM (   _n)
Value:
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)
char * flag(int b)
Definition: test-ctype.c:33

Definition at line 4871 of file formatting.c.

Typedef Documentation

◆ NUMProc

typedef struct NUMProc NUMProc

◆ TmToChar

typedef struct TmToChar TmToChar

Enumeration Type Documentation

◆ DCH_poz

enum DCH_poz
Enumerator
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_FF1 
DCH_FF2 
DCH_FF3 
DCH_FF4 
DCH_FF5 
DCH_FF6 
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_OF 
DCH_P_M 
DCH_PM 
DCH_Q 
DCH_RM 
DCH_SSSSS 
DCH_SSSS 
DCH_SS 
DCH_TZH 
DCH_TZM 
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_ff1 
DCH_ff2 
DCH_ff3 
DCH_ff4 
DCH_ff5 
DCH_ff6 
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_of 
DCH_p_m 
DCH_pm 
DCH_q 
DCH_rm 
DCH_sssss 
DCH_ssss 
DCH_ss 
DCH_tzh 
DCH_tzm 
DCH_tz 
DCH_us 
DCH_ww 
DCH_w 
DCH_y_yyy 
DCH_yyyy 
DCH_yyy 
DCH_yy 
DCH_y 
_DCH_last_ 

Definition at line 635 of file formatting.c.

636{
637 DCH_A_D,
638 DCH_A_M,
639 DCH_AD,
640 DCH_AM,
641 DCH_B_C,
642 DCH_BC,
643 DCH_CC,
644 DCH_DAY,
645 DCH_DDD,
646 DCH_DD,
647 DCH_DY,
648 DCH_Day,
649 DCH_Dy,
650 DCH_D,
651 DCH_FF1, /* FFn codes must be consecutive */
652 DCH_FF2,
653 DCH_FF3,
654 DCH_FF4,
655 DCH_FF5,
656 DCH_FF6,
657 DCH_FX, /* global suffix */
658 DCH_HH24,
659 DCH_HH12,
660 DCH_HH,
661 DCH_IDDD,
662 DCH_ID,
663 DCH_IW,
664 DCH_IYYY,
665 DCH_IYY,
666 DCH_IY,
667 DCH_I,
668 DCH_J,
669 DCH_MI,
670 DCH_MM,
671 DCH_MONTH,
672 DCH_MON,
673 DCH_MS,
674 DCH_Month,
675 DCH_Mon,
676 DCH_OF,
677 DCH_P_M,
678 DCH_PM,
679 DCH_Q,
680 DCH_RM,
681 DCH_SSSSS,
682 DCH_SSSS,
683 DCH_SS,
684 DCH_TZH,
685 DCH_TZM,
686 DCH_TZ,
687 DCH_US,
688 DCH_WW,
689 DCH_W,
690 DCH_Y_YYY,
691 DCH_YYYY,
692 DCH_YYY,
693 DCH_YY,
694 DCH_Y,
695 DCH_a_d,
696 DCH_a_m,
697 DCH_ad,
698 DCH_am,
699 DCH_b_c,
700 DCH_bc,
701 DCH_cc,
702 DCH_day,
703 DCH_ddd,
704 DCH_dd,
705 DCH_dy,
706 DCH_d,
707 DCH_ff1,
708 DCH_ff2,
709 DCH_ff3,
710 DCH_ff4,
711 DCH_ff5,
712 DCH_ff6,
713 DCH_fx,
714 DCH_hh24,
715 DCH_hh12,
716 DCH_hh,
717 DCH_iddd,
718 DCH_id,
719 DCH_iw,
720 DCH_iyyy,
721 DCH_iyy,
722 DCH_iy,
723 DCH_i,
724 DCH_j,
725 DCH_mi,
726 DCH_mm,
727 DCH_month,
728 DCH_mon,
729 DCH_ms,
730 DCH_of,
731 DCH_p_m,
732 DCH_pm,
733 DCH_q,
734 DCH_rm,
735 DCH_sssss,
736 DCH_ssss,
737 DCH_ss,
738 DCH_tzh,
739 DCH_tzm,
740 DCH_tz,
741 DCH_us,
742 DCH_ww,
743 DCH_w,
744 DCH_y_yyy,
745 DCH_yyyy,
746 DCH_yyy,
747 DCH_yy,
748 DCH_y,
749
750 /* last */
752} DCH_poz;
DCH_poz
Definition: formatting.c:636
@ DCH_rm
Definition: formatting.c:734
@ DCH_FF1
Definition: formatting.c:651
@ DCH_p_m
Definition: formatting.c:731
@ DCH_BC
Definition: formatting.c:642
@ DCH_ww
Definition: formatting.c:742
@ DCH_mm
Definition: formatting.c:726
@ DCH_id
Definition: formatting.c:718
@ DCH_WW
Definition: formatting.c:688
@ DCH_y
Definition: formatting.c:748
@ DCH_a_m
Definition: formatting.c:696
@ DCH_bc
Definition: formatting.c:700
@ DCH_ff1
Definition: formatting.c:707
@ DCH_YYYY
Definition: formatting.c:691
@ DCH_i
Definition: formatting.c:723
@ DCH_TZH
Definition: formatting.c:684
@ DCH_P_M
Definition: formatting.c:677
@ DCH_iy
Definition: formatting.c:722
@ DCH_A_D
Definition: formatting.c:637
@ DCH_OF
Definition: formatting.c:676
@ DCH_SS
Definition: formatting.c:683
@ DCH_day
Definition: formatting.c:702
@ DCH_tzm
Definition: formatting.c:739
@ DCH_tz
Definition: formatting.c:740
@ DCH_y_yyy
Definition: formatting.c:744
@ DCH_ff4
Definition: formatting.c:710
@ DCH_b_c
Definition: formatting.c:699
@ DCH_month
Definition: formatting.c:727
@ DCH_HH12
Definition: formatting.c:659
@ DCH_mon
Definition: formatting.c:728
@ DCH_iddd
Definition: formatting.c:717
@ DCH_AM
Definition: formatting.c:640
@ DCH_SSSSS
Definition: formatting.c:681
@ DCH_pm
Definition: formatting.c:732
@ DCH_RM
Definition: formatting.c:680
@ DCH_dd
Definition: formatting.c:704
@ DCH_DY
Definition: formatting.c:647
@ DCH_hh24
Definition: formatting.c:714
@ DCH_HH24
Definition: formatting.c:658
@ DCH_ms
Definition: formatting.c:729
@ DCH_IYY
Definition: formatting.c:665
@ DCH_CC
Definition: formatting.c:643
@ DCH_US
Definition: formatting.c:687
@ DCH_J
Definition: formatting.c:668
@ DCH_FF4
Definition: formatting.c:654
@ DCH_ff2
Definition: formatting.c:708
@ DCH_Month
Definition: formatting.c:674
@ DCH_DDD
Definition: formatting.c:645
@ DCH_fx
Definition: formatting.c:713
@ DCH_DD
Definition: formatting.c:646
@ DCH_Dy
Definition: formatting.c:649
@ DCH_MM
Definition: formatting.c:670
@ DCH_am
Definition: formatting.c:698
@ DCH_FF5
Definition: formatting.c:655
@ DCH_Y_YYY
Definition: formatting.c:690
@ DCH_W
Definition: formatting.c:689
@ DCH_MON
Definition: formatting.c:672
@ DCH_IW
Definition: formatting.c:663
@ DCH_ad
Definition: formatting.c:697
@ DCH_PM
Definition: formatting.c:678
@ DCH_HH
Definition: formatting.c:660
@ DCH_a_d
Definition: formatting.c:695
@ DCH_IY
Definition: formatting.c:666
@ DCH_iw
Definition: formatting.c:719
@ DCH_IDDD
Definition: formatting.c:661
@ DCH_FF2
Definition: formatting.c:652
@ DCH_hh
Definition: formatting.c:716
@ DCH_TZM
Definition: formatting.c:685
@ DCH_FF6
Definition: formatting.c:656
@ DCH_of
Definition: formatting.c:730
@ DCH_YYY
Definition: formatting.c:692
@ DCH_YY
Definition: formatting.c:693
@ DCH_j
Definition: formatting.c:724
@ DCH_MS
Definition: formatting.c:673
@ DCH_TZ
Definition: formatting.c:686
@ DCH_ff6
Definition: formatting.c:712
@ DCH_AD
Definition: formatting.c:639
@ DCH_ddd
Definition: formatting.c:703
@ DCH_FX
Definition: formatting.c:657
@ DCH_IYYY
Definition: formatting.c:664
@ DCH_yyyy
Definition: formatting.c:745
@ DCH_ff3
Definition: formatting.c:709
@ DCH_I
Definition: formatting.c:667
@ _DCH_last_
Definition: formatting.c:751
@ DCH_w
Definition: formatting.c:743
@ DCH_dy
Definition: formatting.c:705
@ DCH_iyy
Definition: formatting.c:721
@ DCH_A_M
Definition: formatting.c:638
@ DCH_Y
Definition: formatting.c:694
@ DCH_iyyy
Definition: formatting.c:720
@ DCH_ff5
Definition: formatting.c:711
@ DCH_Day
Definition: formatting.c:648
@ DCH_tzh
Definition: formatting.c:738
@ DCH_B_C
Definition: formatting.c:641
@ DCH_mi
Definition: formatting.c:725
@ DCH_Mon
Definition: formatting.c:675
@ DCH_FF3
Definition: formatting.c:653
@ DCH_Q
Definition: formatting.c:679
@ DCH_d
Definition: formatting.c:706
@ DCH_ssss
Definition: formatting.c:736
@ DCH_SSSS
Definition: formatting.c:682
@ DCH_ss
Definition: formatting.c:737
@ DCH_us
Definition: formatting.c:741
@ DCH_ID
Definition: formatting.c:662
@ DCH_sssss
Definition: formatting.c:735
@ DCH_yy
Definition: formatting.c:747
@ DCH_q
Definition: formatting.c:733
@ DCH_DAY
Definition: formatting.c:644
@ DCH_MONTH
Definition: formatting.c:671
@ DCH_MI
Definition: formatting.c:669
@ DCH_yyy
Definition: formatting.c:746
@ DCH_D
Definition: formatting.c:650
@ DCH_cc
Definition: formatting.c:701
@ DCH_hh12
Definition: formatting.c:715

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 137 of file formatting.c.

138{
139 FROM_CHAR_DATE_NONE = 0, /* Value does not affect date mode. */
140 FROM_CHAR_DATE_GREGORIAN, /* Gregorian (day, month, year) style date */
141 FROM_CHAR_DATE_ISOWEEK, /* ISO 8601 week date */
FromCharDateMode
Definition: formatting.c:138
@ FROM_CHAR_DATE_ISOWEEK
Definition: formatting.c:141
@ FROM_CHAR_DATE_GREGORIAN
Definition: formatting.c:140
@ FROM_CHAR_DATE_NONE
Definition: formatting.c:139

◆ NUM_poz

enum NUM_poz
Enumerator
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_ 

Definition at line 754 of file formatting.c.

755{
756 NUM_COMMA,
757 NUM_DEC,
758 NUM_0,
759 NUM_9,
760 NUM_B,
761 NUM_C,
762 NUM_D,
763 NUM_E,
764 NUM_FM,
765 NUM_G,
766 NUM_L,
767 NUM_MI,
768 NUM_PL,
769 NUM_PR,
770 NUM_RN,
771 NUM_SG,
772 NUM_SP,
773 NUM_S,
774 NUM_TH,
775 NUM_V,
776 NUM_b,
777 NUM_c,
778 NUM_d,
779 NUM_e,
780 NUM_fm,
781 NUM_g,
782 NUM_l,
783 NUM_mi,
784 NUM_pl,
785 NUM_pr,
786 NUM_rn,
787 NUM_sg,
788 NUM_sp,
789 NUM_s,
790 NUM_th,
791 NUM_v,
792
793 /* last */
795} NUM_poz;
NUM_poz
Definition: formatting.c:755
@ NUM_COMMA
Definition: formatting.c:756
@ NUM_rn
Definition: formatting.c:786
@ NUM_0
Definition: formatting.c:758
@ NUM_g
Definition: formatting.c:781
@ _NUM_last_
Definition: formatting.c:794
@ NUM_pl
Definition: formatting.c:784
@ NUM_sg
Definition: formatting.c:787
@ NUM_D
Definition: formatting.c:762
@ NUM_PL
Definition: formatting.c:768
@ NUM_c
Definition: formatting.c:777
@ NUM_e
Definition: formatting.c:779
@ NUM_S
Definition: formatting.c:773
@ NUM_PR
Definition: formatting.c:769
@ NUM_SP
Definition: formatting.c:772
@ NUM_TH
Definition: formatting.c:774
@ NUM_SG
Definition: formatting.c:771
@ NUM_l
Definition: formatting.c:782
@ NUM_FM
Definition: formatting.c:764
@ NUM_RN
Definition: formatting.c:770
@ NUM_L
Definition: formatting.c:766
@ NUM_th
Definition: formatting.c:790
@ NUM_V
Definition: formatting.c:775
@ NUM_fm
Definition: formatting.c:780
@ NUM_DEC
Definition: formatting.c:757
@ NUM_C
Definition: formatting.c:761
@ NUM_9
Definition: formatting.c:759
@ NUM_mi
Definition: formatting.c:783
@ NUM_b
Definition: formatting.c:776
@ NUM_s
Definition: formatting.c:789
@ NUM_v
Definition: formatting.c:791
@ NUM_MI
Definition: formatting.c:767
@ NUM_G
Definition: formatting.c:765
@ NUM_E
Definition: formatting.c:763
@ NUM_d
Definition: formatting.c:778
@ NUM_sp
Definition: formatting.c:788
@ NUM_pr
Definition: formatting.c:785
@ NUM_B
Definition: formatting.c:760

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2096 of file formatting.c.

2097{
2098 /*
2099 * Adjust all dates toward 2020; this is effectively what happens when we
2100 * assume '70' is 1970 and '69' is 2069.
2101 */
2102 /* Force 0-69 into the 2000's */
2103 if (year < 70)
2104 return year + 2000;
2105 /* Force 70-99 into the 1900's */
2106 else if (year < 100)
2107 return year + 1900;
2108 /* Force 100-519 into the 2000's */
2109 else if (year < 520)
2110 return year + 2000;
2111 /* Force 520-999 into the 1000's */
2112 else if (year < 1000)
2113 return year + 1000;
2114 else
2115 return year;
2116}

Referenced by DCH_from_char().

◆ asc_initcap()

char * asc_initcap ( const char *  buff,
size_t  nbytes 
)

Definition at line 1946 of file formatting.c.

1947{
1948 char *result;
1949 char *p;
1950 int wasalnum = false;
1951
1952 if (!buff)
1953 return NULL;
1954
1955 result = pnstrdup(buff, nbytes);
1956
1957 for (p = result; *p; p++)
1958 {
1959 char c;
1960
1961 if (wasalnum)
1962 *p = c = pg_ascii_tolower((unsigned char) *p);
1963 else
1964 *p = c = pg_ascii_toupper((unsigned char) *p);
1965 /* we don't trust isalnum() here */
1966 wasalnum = ((c >= 'A' && c <= 'Z') ||
1967 (c >= 'a' && c <= 'z') ||
1968 (c >= '0' && c <= '9'));
1969 }
1970
1971 return result;
1972}
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1770
unsigned char pg_ascii_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:146
unsigned char pg_ascii_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:135
char * c

References pg_ascii_tolower(), pg_ascii_toupper(), and pnstrdup().

Referenced by str_initcap().

◆ asc_tolower()

char * asc_tolower ( const char *  buff,
size_t  nbytes 
)

Definition at line 1900 of file formatting.c.

1901{
1902 char *result;
1903 char *p;
1904
1905 if (!buff)
1906 return NULL;
1907
1908 result = pnstrdup(buff, nbytes);
1909
1910 for (p = result; *p; p++)
1911 *p = pg_ascii_tolower((unsigned char) *p);
1912
1913 return result;
1914}

References pg_ascii_tolower(), and pnstrdup().

Referenced by asc_tolower_z(), str_casefold(), and str_tolower().

◆ asc_tolower_z()

static char * asc_tolower_z ( const char *  buff)
static

Definition at line 1995 of file formatting.c.

1996{
1997 return asc_tolower(buff, strlen(buff));
1998}
char * asc_tolower(const char *buff, size_t nbytes)
Definition: formatting.c:1900

References asc_tolower().

Referenced by DCH_to_char(), and NUM_processor().

◆ asc_toupper()

char * asc_toupper ( const char *  buff,
size_t  nbytes 
)

Definition at line 1923 of file formatting.c.

1924{
1925 char *result;
1926 char *p;
1927
1928 if (!buff)
1929 return NULL;
1930
1931 result = pnstrdup(buff, nbytes);
1932
1933 for (p = result; *p; p++)
1934 *p = pg_ascii_toupper((unsigned char) *p);
1935
1936 return result;
1937}

References pg_ascii_toupper(), and pnstrdup().

Referenced by asc_toupper_z(), and str_toupper().

◆ asc_toupper_z()

static char * asc_toupper_z ( const char *  buff)
static

Definition at line 2001 of file formatting.c.

2002{
2003 return asc_toupper(buff, strlen(buff));
2004}
char * asc_toupper(const char *buff, size_t nbytes)
Definition: formatting.c:1923

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char *  fmt_str)

Definition at line 4368 of file formatting.c.

4369{
4370 bool incache;
4371 int fmt_len = strlen(fmt_str);
4372 int result;
4374
4375 if (fmt_len > DCH_CACHE_SIZE)
4376 {
4377 /*
4378 * Allocate new memory if format picture is bigger than static cache
4379 * and do not use cache (call parser always)
4380 */
4381 incache = false;
4382
4383 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4384
4386 DCH_suff, DCH_index, DCH_FLAG, NULL);
4387 }
4388 else
4389 {
4390 /*
4391 * Use cache buffers
4392 */
4393 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4394
4395 incache = true;
4396 format = ent->format;
4397 }
4398
4399 result = DCH_datetime_type(format);
4400
4401 if (!incache)
4402 pfree(format);
4403
4404 return result & DCH_ZONED;
4405}
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:974
static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, uint32 flags, NUMDesc *Num)
Definition: formatting.c:1375
#define DCH_FLAG
Definition: formatting.c:99
static const KeySuffix DCH_suff[]
Definition: formatting.c:594
#define DCH_CACHE_SIZE
Definition: formatting.c:386
#define DCH_ZONED
Definition: formatting.c:1054
static int DCH_datetime_type(FormatNode *node)
Definition: formatting.c:3726
static const KeyWord DCH_keywords[]
Definition: formatting.c:801
static DCHCacheEntry * DCH_cache_fetch(const char *str, bool std)
Definition: formatting.c:3904
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:396

References DCH_cache_fetch(), DCH_CACHE_SIZE, DCH_datetime_type(), DCH_FLAG, DCH_index, DCH_keywords, DCH_suff, DCH_ZONED, DCHCacheEntry::format, format, palloc(), parse_format(), and pfree().

Referenced by jspIsMutableWalker().

◆ datetime_to_char_body()

static text * datetime_to_char_body ( TmToChar tmtc,
text fmt,
bool  is_interval,
Oid  collid 
)
static

Definition at line 3931 of file formatting.c.

3932{
3934 char *fmt_str,
3935 *result;
3936 bool incache;
3937 int fmt_len;
3938 text *res;
3939
3940 /*
3941 * Convert fmt to C string
3942 */
3943 fmt_str = text_to_cstring(fmt);
3944 fmt_len = strlen(fmt_str);
3945
3946 /*
3947 * Allocate workspace for result as C string
3948 */
3949 result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
3950 *result = '\0';
3951
3952 if (fmt_len > DCH_CACHE_SIZE)
3953 {
3954 /*
3955 * Allocate new memory if format picture is bigger than static cache
3956 * and do not use cache (call parser always)
3957 */
3958 incache = false;
3959
3960 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3961
3963 DCH_suff, DCH_index, DCH_FLAG, NULL);
3964 }
3965 else
3966 {
3967 /*
3968 * Use cache buffers
3969 */
3970 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
3971
3972 incache = true;
3973 format = ent->format;
3974 }
3975
3976 /* The real work is here */
3977 DCH_to_char(format, is_interval, tmtc, result, collid);
3978
3979 if (!incache)
3980 pfree(format);
3981
3982 pfree(fmt_str);
3983
3984 /* convert C-string result to TEXT format */
3985 res = cstring_to_text(result);
3986
3987 pfree(result);
3988 return res;
3989}
Oid collid
static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
Definition: formatting.c:2507
#define DCH_MAX_ITEM_SIZ
Definition: formatting.c:114
char * text_to_cstring(const text *t)
Definition: varlena.c:214

References collid, cstring_to_text(), DCH_cache_fetch(), DCH_CACHE_SIZE, DCH_FLAG, DCH_index, DCH_keywords, DCH_MAX_ITEM_SIZ, DCH_suff, DCH_to_char(), DCHCacheEntry::format, format, palloc(), parse_format(), pfree(), and text_to_cstring().

Referenced by interval_to_char(), timestamp_to_char(), and timestamptz_to_char().

◆ DCH_cache_fetch()

static DCHCacheEntry * DCH_cache_fetch ( const char *  str,
bool  std 
)
static

Definition at line 3904 of file formatting.c.

3905{
3906 DCHCacheEntry *ent;
3907
3908 if ((ent = DCH_cache_search(str, std)) == NULL)
3909 {
3910 /*
3911 * Not in the cache, must run parser and save a new format-picture to
3912 * the cache. Do not mark the cache entry valid until parsing
3913 * succeeds.
3914 */
3915 ent = DCH_cache_getnew(str, std);
3916
3918 DCH_FLAG | (std ? STD_FLAG : 0), NULL);
3919
3920 ent->valid = true;
3921 }
3922 return ent;
3923}
#define STD_FLAG
Definition: formatting.c:101
static DCHCacheEntry * DCH_cache_getnew(const char *str, bool std)
Definition: formatting.c:3823
static DCHCacheEntry * DCH_cache_search(const char *str, bool std)
Definition: formatting.c:3883
const char * str

References DCH_cache_getnew(), DCH_cache_search(), DCH_FLAG, DCH_index, DCH_keywords, DCH_suff, DCHCacheEntry::format, parse_format(), STD_FLAG, str, and DCHCacheEntry::valid.

Referenced by datetime_format_has_tz(), datetime_to_char_body(), and do_to_timestamp().

◆ DCH_cache_getnew()

static DCHCacheEntry * DCH_cache_getnew ( const char *  str,
bool  std 
)
static

Definition at line 3823 of file formatting.c.

3824{
3825 DCHCacheEntry *ent;
3826
3827 /* Ensure we can advance DCHCounter below */
3829
3830 /*
3831 * If cache is full, remove oldest entry (or recycle first not-valid one)
3832 */
3834 {
3835 DCHCacheEntry *old = DCHCache[0];
3836
3837#ifdef DEBUG_TO_FROM_CHAR
3838 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3839#endif
3840 if (old->valid)
3841 {
3842 for (int i = 1; i < DCH_CACHE_ENTRIES; i++)
3843 {
3844 ent = DCHCache[i];
3845 if (!ent->valid)
3846 {
3847 old = ent;
3848 break;
3849 }
3850 if (ent->age < old->age)
3851 old = ent;
3852 }
3853 }
3854#ifdef DEBUG_TO_FROM_CHAR
3855 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3856#endif
3857 old->valid = false;
3858 strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
3859 old->age = (++DCHCounter);
3860 /* caller is expected to fill format, then set valid */
3861 return old;
3862 }
3863 else
3864 {
3865#ifdef DEBUG_TO_FROM_CHAR
3866 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3867#endif
3868 Assert(DCHCache[n_DCHCache] == NULL);
3869 DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
3871 ent->valid = false;
3872 strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
3873 ent->std = std;
3874 ent->age = (++DCHCounter);
3875 /* caller is expected to fill format, then set valid */
3876 ++n_DCHCache;
3877 return ent;
3878 }
3879}
#define elog(elevel,...)
Definition: elog.h:226
static void DCH_prevent_counter_overflow(void)
Definition: formatting.c:3712
static int DCHCounter
Definition: formatting.c:415
static int n_DCHCache
Definition: formatting.c:414
static DCHCacheEntry * DCHCache[DCH_CACHE_ENTRIES]
Definition: formatting.c:413
#define DCH_CACHE_ENTRIES
Definition: formatting.c:391
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1263
MemoryContext TopMemoryContext
Definition: mcxt.c:166
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char str[DCH_CACHE_SIZE+1]
Definition: formatting.c:397

References DCHCacheEntry::age, Assert(), DCH_CACHE_ENTRIES, DCH_CACHE_SIZE, DCH_prevent_counter_overflow(), DCHCache, DCHCounter, elog, i, MemoryContextAllocZero(), n_DCHCache, DCHCacheEntry::std, DCHCacheEntry::str, str, strlcpy(), TopMemoryContext, and DCHCacheEntry::valid.

Referenced by DCH_cache_fetch().

◆ DCH_cache_search()

static DCHCacheEntry * DCH_cache_search ( const char *  str,
bool  std 
)
static

Definition at line 3883 of file formatting.c.

3884{
3885 /* Ensure we can advance DCHCounter below */
3887
3888 for (int i = 0; i < n_DCHCache; i++)
3889 {
3890 DCHCacheEntry *ent = DCHCache[i];
3891
3892 if (ent->valid && strcmp(ent->str, str) == 0 && ent->std == std)
3893 {
3894 ent->age = (++DCHCounter);
3895 return ent;
3896 }
3897 }
3898
3899 return NULL;
3900}

References DCHCacheEntry::age, DCH_prevent_counter_overflow(), DCHCache, DCHCounter, i, n_DCHCache, DCHCacheEntry::std, DCHCacheEntry::str, str, and DCHCacheEntry::valid.

Referenced by DCH_cache_fetch().

◆ DCH_datetime_type()

static int DCH_datetime_type ( FormatNode node)
static

Definition at line 3726 of file formatting.c.

3727{
3728 FormatNode *n;
3729 int flags = 0;
3730
3731 for (n = node; n->type != NODE_TYPE_END; n++)
3732 {
3733 if (n->type != NODE_TYPE_ACTION)
3734 continue;
3735
3736 switch (n->key->id)
3737 {
3738 case DCH_FX:
3739 break;
3740 case DCH_A_M:
3741 case DCH_P_M:
3742 case DCH_a_m:
3743 case DCH_p_m:
3744 case DCH_AM:
3745 case DCH_PM:
3746 case DCH_am:
3747 case DCH_pm:
3748 case DCH_HH:
3749 case DCH_HH12:
3750 case DCH_HH24:
3751 case DCH_MI:
3752 case DCH_SS:
3753 case DCH_MS: /* millisecond */
3754 case DCH_US: /* microsecond */
3755 case DCH_FF1:
3756 case DCH_FF2:
3757 case DCH_FF3:
3758 case DCH_FF4:
3759 case DCH_FF5:
3760 case DCH_FF6:
3761 case DCH_SSSS:
3762 flags |= DCH_TIMED;
3763 break;
3764 case DCH_tz:
3765 case DCH_TZ:
3766 case DCH_OF:
3767 case DCH_TZH:
3768 case DCH_TZM:
3769 flags |= DCH_ZONED;
3770 break;
3771 case DCH_A_D:
3772 case DCH_B_C:
3773 case DCH_a_d:
3774 case DCH_b_c:
3775 case DCH_AD:
3776 case DCH_BC:
3777 case DCH_ad:
3778 case DCH_bc:
3779 case DCH_MONTH:
3780 case DCH_Month:
3781 case DCH_month:
3782 case DCH_MON:
3783 case DCH_Mon:
3784 case DCH_mon:
3785 case DCH_MM:
3786 case DCH_DAY:
3787 case DCH_Day:
3788 case DCH_day:
3789 case DCH_DY:
3790 case DCH_Dy:
3791 case DCH_dy:
3792 case DCH_DDD:
3793 case DCH_IDDD:
3794 case DCH_DD:
3795 case DCH_D:
3796 case DCH_ID:
3797 case DCH_WW:
3798 case DCH_Q:
3799 case DCH_CC:
3800 case DCH_Y_YYY:
3801 case DCH_YYYY:
3802 case DCH_IYYY:
3803 case DCH_YYY:
3804 case DCH_IYY:
3805 case DCH_YY:
3806 case DCH_IY:
3807 case DCH_Y:
3808 case DCH_I:
3809 case DCH_RM:
3810 case DCH_rm:
3811 case DCH_W:
3812 case DCH_J:
3813 flags |= DCH_DATED;
3814 break;
3815 }
3816 }
3817
3818 return flags;
3819}
#define DCH_DATED
Definition: formatting.c:1052
#define DCH_TIMED
Definition: formatting.c:1053
#define NODE_TYPE_ACTION
Definition: formatting.c:162
#define NODE_TYPE_END
Definition: formatting.c:161
const KeyWord * key
Definition: formatting.c:158
uint8 type
Definition: formatting.c:155
int id
Definition: formatting.c:148

References 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_DATED, DCH_DAY, DCH_Day, DCH_day, DCH_DD, DCH_DDD, DCH_DY, DCH_Dy, DCH_dy, DCH_FF1, DCH_FF2, DCH_FF3, DCH_FF4, DCH_FF5, DCH_FF6, DCH_FX, DCH_HH, DCH_HH12, DCH_HH24, DCH_I, DCH_ID, DCH_IDDD, 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_OF, DCH_P_M, DCH_p_m, DCH_PM, DCH_pm, DCH_Q, DCH_RM, DCH_rm, DCH_SS, DCH_SSSS, DCH_TIMED, DCH_TZ, DCH_tz, DCH_TZH, DCH_TZM, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, DCH_ZONED, KeyWord::id, FormatNode::key, NODE_TYPE_ACTION, NODE_TYPE_END, and FormatNode::type.

Referenced by datetime_format_has_tz(), and do_to_timestamp().

◆ DCH_from_char()

static void DCH_from_char ( FormatNode node,
const char *  in,
TmFromChar out,
Oid  collid,
bool  std,
Node escontext 
)
static

Definition at line 3154 of file formatting.c.

3156{
3157 FormatNode *n;
3158 const char *s;
3159 int len,
3160 value;
3161 bool fx_mode = std;
3162
3163 /* number of extra skipped characters (more than given in format string) */
3164 int extra_skip = 0;
3165
3166 /* cache localized days and months */
3168
3169 for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
3170 {
3171 /*
3172 * Ignore spaces at the beginning of the string and before fields when
3173 * not in FX (fixed width) mode.
3174 */
3175 if (!fx_mode && (n->type != NODE_TYPE_ACTION || n->key->id != DCH_FX) &&
3176 (n->type == NODE_TYPE_ACTION || n == node))
3177 {
3178 while (*s != '\0' && isspace((unsigned char) *s))
3179 {
3180 s++;
3181 extra_skip++;
3182 }
3183 }
3184
3185 if (n->type == NODE_TYPE_SPACE || n->type == NODE_TYPE_SEPARATOR)
3186 {
3187 if (std)
3188 {
3189 /*
3190 * Standard mode requires strict matching between format
3191 * string separators/spaces and input string.
3192 */
3193 Assert(n->character[0] && !n->character[1]);
3194
3195 if (*s == n->character[0])
3196 s++;
3197 else
3198 ereturn(escontext,,
3199 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3200 errmsg("unmatched format separator \"%c\"",
3201 n->character[0])));
3202 }
3203 else if (!fx_mode)
3204 {
3205 /*
3206 * In non FX (fixed format) mode one format string space or
3207 * separator match to one space or separator in input string.
3208 * Or match nothing if there is no space or separator in the
3209 * current position of input string.
3210 */
3211 extra_skip--;
3212 if (isspace((unsigned char) *s) || is_separator_char(s))
3213 {
3214 s++;
3215 extra_skip++;
3216 }
3217 }
3218 else
3219 {
3220 /*
3221 * In FX mode, on format string space or separator we consume
3222 * exactly one character from input string. Notice we don't
3223 * insist that the consumed character match the format's
3224 * character.
3225 */
3226 s += pg_mblen(s);
3227 }
3228 continue;
3229 }
3230 else if (n->type != NODE_TYPE_ACTION)
3231 {
3232 /*
3233 * Text character, so consume one character from input string.
3234 * Notice we don't insist that the consumed character match the
3235 * format's character.
3236 */
3237 if (!fx_mode)
3238 {
3239 /*
3240 * In non FX mode we might have skipped some extra characters
3241 * (more than specified in format string) before. In this
3242 * case we don't skip input string character, because it might
3243 * be part of field.
3244 */
3245 if (extra_skip > 0)
3246 extra_skip--;
3247 else
3248 s += pg_mblen(s);
3249 }
3250 else
3251 {
3252 int chlen = pg_mblen(s);
3253
3254 /*
3255 * Standard mode requires strict match of format characters.
3256 */
3257 if (std && n->type == NODE_TYPE_CHAR &&
3258 strncmp(s, n->character, chlen) != 0)
3259 ereturn(escontext,,
3260 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3261 errmsg("unmatched format character \"%s\"",
3262 n->character)));
3263
3264 s += chlen;
3265 }
3266 continue;
3267 }
3268
3269 if (!from_char_set_mode(out, n->key->date_mode, escontext))
3270 return;
3271
3272 switch (n->key->id)
3273 {
3274 case DCH_FX:
3275 fx_mode = true;
3276 break;
3277 case DCH_A_M:
3278 case DCH_P_M:
3279 case DCH_a_m:
3280 case DCH_p_m:
3282 NULL, InvalidOid,
3283 n, escontext))
3284 return;
3285 if (!from_char_set_int(&out->pm, value % 2, n, escontext))
3286 return;
3287 out->clock = CLOCK_12_HOUR;
3288 break;
3289 case DCH_AM:
3290 case DCH_PM:
3291 case DCH_am:
3292 case DCH_pm:
3294 NULL, InvalidOid,
3295 n, escontext))
3296 return;
3297 if (!from_char_set_int(&out->pm, value % 2, n, escontext))
3298 return;
3299 out->clock = CLOCK_12_HOUR;
3300 break;
3301 case DCH_HH:
3302 case DCH_HH12:
3303 if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
3304 return;
3305 out->clock = CLOCK_12_HOUR;
3306 SKIP_THth(s, n->suffix);
3307 break;
3308 case DCH_HH24:
3309 if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
3310 return;
3311 SKIP_THth(s, n->suffix);
3312 break;
3313 case DCH_MI:
3314 if (from_char_parse_int(&out->mi, &s, n, escontext) < 0)
3315 return;
3316 SKIP_THth(s, n->suffix);
3317 break;
3318 case DCH_SS:
3319 if (from_char_parse_int(&out->ss, &s, n, escontext) < 0)
3320 return;
3321 SKIP_THth(s, n->suffix);
3322 break;
3323 case DCH_MS: /* millisecond */
3324 len = from_char_parse_int_len(&out->ms, &s, 3, n, escontext);
3325 if (len < 0)
3326 return;
3327
3328 /*
3329 * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
3330 */
3331 out->ms *= len == 1 ? 100 :
3332 len == 2 ? 10 : 1;
3333
3334 SKIP_THth(s, n->suffix);
3335 break;
3336 case DCH_FF1:
3337 case DCH_FF2:
3338 case DCH_FF3:
3339 case DCH_FF4:
3340 case DCH_FF5:
3341 case DCH_FF6:
3342 out->ff = n->key->id - DCH_FF1 + 1;
3343 /* FALLTHROUGH */
3344 case DCH_US: /* microsecond */
3345 len = from_char_parse_int_len(&out->us, &s,
3346 n->key->id == DCH_US ? 6 :
3347 out->ff, n, escontext);
3348 if (len < 0)
3349 return;
3350
3351 out->us *= len == 1 ? 100000 :
3352 len == 2 ? 10000 :
3353 len == 3 ? 1000 :
3354 len == 4 ? 100 :
3355 len == 5 ? 10 : 1;
3356
3357 SKIP_THth(s, n->suffix);
3358 break;
3359 case DCH_SSSS:
3360 if (from_char_parse_int(&out->ssss, &s, n, escontext) < 0)
3361 return;
3362 SKIP_THth(s, n->suffix);
3363 break;
3364 case DCH_tz:
3365 case DCH_TZ:
3366 {
3367 int tzlen;
3368
3370 &out->gmtoffset,
3371 &out->tzp);
3372 if (tzlen > 0)
3373 {
3374 out->has_tz = true;
3375 /* we only need the zone abbrev for DYNTZ case */
3376 if (out->tzp)
3377 out->abbrev = pnstrdup(s, tzlen);
3378 out->tzsign = 0; /* drop any earlier TZH/TZM info */
3379 s += tzlen;
3380 break;
3381 }
3382 else if (isalpha((unsigned char) *s))
3383 {
3384 /*
3385 * It doesn't match any abbreviation, but it starts
3386 * with a letter. OF format certainly won't succeed;
3387 * assume it's a misspelled abbreviation and complain
3388 * accordingly.
3389 */
3390 ereturn(escontext,,
3391 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3392 errmsg("invalid value \"%s\" for \"%s\"",
3393 s, n->key->name),
3394 errdetail("Time zone abbreviation is not recognized.")));
3395 }
3396 /* otherwise parse it like OF */
3397 }
3398 /* FALLTHROUGH */
3399 case DCH_OF:
3400 /* OF is equivalent to TZH or TZH:TZM */
3401 /* see TZH comments below */
3402 if (*s == '+' || *s == '-' || *s == ' ')
3403 {
3404 out->tzsign = *s == '-' ? -1 : +1;
3405 s++;
3406 }
3407 else
3408 {
3409 if (extra_skip > 0 && *(s - 1) == '-')
3410 out->tzsign = -1;
3411 else
3412 out->tzsign = +1;
3413 }
3414 if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
3415 return;
3416 if (*s == ':')
3417 {
3418 s++;
3419 if (from_char_parse_int_len(&out->tzm, &s, 2, n,
3420 escontext) < 0)
3421 return;
3422 }
3423 break;
3424 case DCH_TZH:
3425
3426 /*
3427 * Value of TZH might be negative. And the issue is that we
3428 * might swallow minus sign as the separator. So, if we have
3429 * skipped more characters than specified in the format
3430 * string, then we consider prepending last skipped minus to
3431 * TZH.
3432 */
3433 if (*s == '+' || *s == '-' || *s == ' ')
3434 {
3435 out->tzsign = *s == '-' ? -1 : +1;
3436 s++;
3437 }
3438 else
3439 {
3440 if (extra_skip > 0 && *(s - 1) == '-')
3441 out->tzsign = -1;
3442 else
3443 out->tzsign = +1;
3444 }
3445
3446 if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
3447 return;
3448 break;
3449 case DCH_TZM:
3450 /* assign positive timezone sign if TZH was not seen before */
3451 if (!out->tzsign)
3452 out->tzsign = +1;
3453 if (from_char_parse_int_len(&out->tzm, &s, 2, n, escontext) < 0)
3454 return;
3455 break;
3456 case DCH_A_D:
3457 case DCH_B_C:
3458 case DCH_a_d:
3459 case DCH_b_c:
3461 NULL, InvalidOid,
3462 n, escontext))
3463 return;
3464 if (!from_char_set_int(&out->bc, value % 2, n, escontext))
3465 return;
3466 break;
3467 case DCH_AD:
3468 case DCH_BC:
3469 case DCH_ad:
3470 case DCH_bc:
3472 NULL, InvalidOid,
3473 n, escontext))
3474 return;
3475 if (!from_char_set_int(&out->bc, value % 2, n, escontext))
3476 return;
3477 break;
3478 case DCH_MONTH:
3479 case DCH_Month:
3480 case DCH_month:
3482 S_TM(n->suffix) ? localized_full_months : NULL,
3483 collid,
3484 n, escontext))
3485 return;
3486 if (!from_char_set_int(&out->mm, value + 1, n, escontext))
3487 return;
3488 break;
3489 case DCH_MON:
3490 case DCH_Mon:
3491 case DCH_mon:
3493 S_TM(n->suffix) ? localized_abbrev_months : NULL,
3494 collid,
3495 n, escontext))
3496 return;
3497 if (!from_char_set_int(&out->mm, value + 1, n, escontext))
3498 return;
3499 break;
3500 case DCH_MM:
3501 if (from_char_parse_int(&out->mm, &s, n, escontext) < 0)
3502 return;
3503 SKIP_THth(s, n->suffix);
3504 break;
3505 case DCH_DAY:
3506 case DCH_Day:
3507 case DCH_day:
3508 if (!from_char_seq_search(&value, &s, days,
3509 S_TM(n->suffix) ? localized_full_days : NULL,
3510 collid,
3511 n, escontext))
3512 return;
3513 if (!from_char_set_int(&out->d, value, n, escontext))
3514 return;
3515 out->d++;
3516 break;
3517 case DCH_DY:
3518 case DCH_Dy:
3519 case DCH_dy:
3521 S_TM(n->suffix) ? localized_abbrev_days : NULL,
3522 collid,
3523 n, escontext))
3524 return;
3525 if (!from_char_set_int(&out->d, value, n, escontext))
3526 return;
3527 out->d++;
3528 break;
3529 case DCH_DDD:
3530 if (from_char_parse_int(&out->ddd, &s, n, escontext) < 0)
3531 return;
3532 SKIP_THth(s, n->suffix);
3533 break;
3534 case DCH_IDDD:
3535 if (from_char_parse_int_len(&out->ddd, &s, 3, n, escontext) < 0)
3536 return;
3537 SKIP_THth(s, n->suffix);
3538 break;
3539 case DCH_DD:
3540 if (from_char_parse_int(&out->dd, &s, n, escontext) < 0)
3541 return;
3542 SKIP_THth(s, n->suffix);
3543 break;
3544 case DCH_D:
3545 if (from_char_parse_int(&out->d, &s, n, escontext) < 0)
3546 return;
3547 SKIP_THth(s, n->suffix);
3548 break;
3549 case DCH_ID:
3550 if (from_char_parse_int_len(&out->d, &s, 1, n, escontext) < 0)
3551 return;
3552 /* Shift numbering to match Gregorian where Sunday = 1 */
3553 if (++out->d > 7)
3554 out->d = 1;
3555 SKIP_THth(s, n->suffix);
3556 break;
3557 case DCH_WW:
3558 case DCH_IW:
3559 if (from_char_parse_int(&out->ww, &s, n, escontext) < 0)
3560 return;
3561 SKIP_THth(s, n->suffix);
3562 break;
3563 case DCH_Q:
3564
3565 /*
3566 * We ignore 'Q' when converting to date because it is unclear
3567 * which date in the quarter to use, and some people specify
3568 * both quarter and month, so if it was honored it might
3569 * conflict with the supplied month. That is also why we don't
3570 * throw an error.
3571 *
3572 * We still parse the source string for an integer, but it
3573 * isn't stored anywhere in 'out'.
3574 */
3575 if (from_char_parse_int((int *) NULL, &s, n, escontext) < 0)
3576 return;
3577 SKIP_THth(s, n->suffix);
3578 break;
3579 case DCH_CC:
3580 if (from_char_parse_int(&out->cc, &s, n, escontext) < 0)
3581 return;
3582 SKIP_THth(s, n->suffix);
3583 break;
3584 case DCH_Y_YYY:
3585 {
3586 int matched,
3587 years,
3588 millennia,
3589 nch;
3590
3591 matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch);
3592 if (matched < 2)
3593 ereturn(escontext,,
3594 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3595 errmsg("invalid value \"%s\" for \"%s\"",
3596 s, "Y,YYY")));
3597
3598 /* years += (millennia * 1000); */
3599 if (pg_mul_s32_overflow(millennia, 1000, &millennia) ||
3600 pg_add_s32_overflow(years, millennia, &years))
3601 ereturn(escontext,,
3602 (errcode(ERRCODE_DATETIME_FIELD_OVERFLOW),
3603 errmsg("value for \"%s\" in source string is out of range", "Y,YYY")));
3604
3605 if (!from_char_set_int(&out->year, years, n, escontext))
3606 return;
3607 out->yysz = 4;
3608 s += nch;
3609 SKIP_THth(s, n->suffix);
3610 }
3611 break;
3612 case DCH_YYYY:
3613 case DCH_IYYY:
3614 if (from_char_parse_int(&out->year, &s, n, escontext) < 0)
3615 return;
3616 out->yysz = 4;
3617 SKIP_THth(s, n->suffix);
3618 break;
3619 case DCH_YYY:
3620 case DCH_IYY:
3621 len = from_char_parse_int(&out->year, &s, n, escontext);
3622 if (len < 0)
3623 return;
3624 if (len < 4)
3626 out->yysz = 3;
3627 SKIP_THth(s, n->suffix);
3628 break;
3629 case DCH_YY:
3630 case DCH_IY:
3631 len = from_char_parse_int(&out->year, &s, n, escontext);
3632 if (len < 0)
3633 return;
3634 if (len < 4)
3636 out->yysz = 2;
3637 SKIP_THth(s, n->suffix);
3638 break;
3639 case DCH_Y:
3640 case DCH_I:
3641 len = from_char_parse_int(&out->year, &s, n, escontext);
3642 if (len < 0)
3643 return;
3644 if (len < 4)
3646 out->yysz = 1;
3647 SKIP_THth(s, n->suffix);
3648 break;
3649 case DCH_RM:
3650 case DCH_rm:
3652 NULL, InvalidOid,
3653 n, escontext))
3654 return;
3655 if (!from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n,
3656 escontext))
3657 return;
3658 break;
3659 case DCH_W:
3660 if (from_char_parse_int(&out->w, &s, n, escontext) < 0)
3661 return;
3662 SKIP_THth(s, n->suffix);
3663 break;
3664 case DCH_J:
3665 if (from_char_parse_int(&out->j, &s, n, escontext) < 0)
3666 return;
3667 SKIP_THth(s, n->suffix);
3668 break;
3669 }
3670
3671 /* Ignore all spaces after fields */
3672 if (!fx_mode)
3673 {
3674 extra_skip = 0;
3675 while (*s != '\0' && isspace((unsigned char) *s))
3676 {
3677 s++;
3678 extra_skip++;
3679 }
3680 }
3681 }
3682
3683 /*
3684 * Standard parsing mode doesn't allow unmatched format patterns or
3685 * trailing characters in the input string.
3686 */
3687 if (std)
3688 {
3689 if (n->type != NODE_TYPE_END)
3690 ereturn(escontext,,
3691 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3692 errmsg("input string is too short for datetime format")));
3693
3694 while (*s != '\0' && isspace((unsigned char) *s))
3695 s++;
3696
3697 if (*s != '\0')
3698 ereturn(escontext,,
3699 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3700 errmsg("trailing characters remain in input string after datetime format")));
3701 }
3702}
const char *const months[]
Definition: datetime.c:81
const char *const days[]
Definition: datetime.c:84
int DecodeTimezoneAbbrevPrefix(const char *str, int *offset, pg_tz **tz)
Definition: datetime.c:3371
#define MONTHS_PER_YEAR
Definition: timestamp.h:108
int errdetail(const char *fmt,...)
Definition: elog.c:1207
#define ereturn(context, dummy_value,...)
Definition: elog.h:278
#define CLOCK_12_HOUR
Definition: formatting.c:171
#define SKIP_THth(ptr, _suf)
Definition: formatting.c:2015
static bool from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode, Node *escontext)
Definition: formatting.c:2142
static bool from_char_seq_search(int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, Node *escontext)
Definition: formatting.c:2461
#define S_TM(_s)
Definition: formatting.c:586
#define NODE_TYPE_SPACE
Definition: formatting.c:165
static int from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode *node, Node *escontext)
Definition: formatting.c:2205
static int adjust_partial_year_to_2020(int year)
Definition: formatting.c:2096
static const char *const months_full[]
Definition: formatting.c:178
#define NODE_TYPE_SEPARATOR
Definition: formatting.c:164
static const char *const adbc_strings_long[]
Definition: formatting.c:217
static const char *const days_short[]
Definition: formatting.c:183
static const char *const ampm_strings[]
Definition: formatting.c:243
static bool from_char_set_int(int *dest, const int value, const FormatNode *node, Node *escontext)
Definition: formatting.c:2169
#define NODE_TYPE_CHAR
Definition: formatting.c:163
static const char *const rm_months_lower[]
Definition: formatting.c:255
static const char *const adbc_strings[]
Definition: formatting.c:216
static int from_char_parse_int(int *dest, const char **src, FormatNode *node, Node *escontext)
Definition: formatting.c:2302
static const char *const ampm_strings_long[]
Definition: formatting.c:244
static bool is_separator_char(const char *str)
Definition: formatting.c:1175
static struct @166 value
static bool pg_mul_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:187
static bool pg_add_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:151
void cache_locale_time(void)
Definition: pg_locale.c:695
char * localized_full_months[12+1]
Definition: pg_locale.c:100
char * localized_abbrev_months[12+1]
Definition: pg_locale.c:99
char * localized_full_days[7+1]
Definition: pg_locale.c:98
char * localized_abbrev_days[7+1]
Definition: pg_locale.c:97
#define InvalidOid
Definition: postgres_ext.h:37
uint8 suffix
Definition: formatting.c:157
char character[MAX_MULTIBYTE_CHAR_LEN+1]
Definition: formatting.c:156
FromCharDateMode date_mode
Definition: formatting.c:150
const char * name
Definition: formatting.c:146
int gmtoffset
Definition: formatting.c:453
pg_tz * tzp
Definition: formatting.c:454
bool has_tz
Definition: formatting.c:452
char * abbrev
Definition: formatting.c:455

References TmFromChar::abbrev, adbc_strings, adbc_strings_long, adjust_partial_year_to_2020(), ampm_strings, ampm_strings_long, Assert(), TmFromChar::bc, cache_locale_time(), TmFromChar::cc, FormatNode::character, TmFromChar::clock, CLOCK_12_HOUR, collid, TmFromChar::d, KeyWord::date_mode, 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_FF1, DCH_FF2, DCH_FF3, DCH_FF4, DCH_FF5, DCH_FF6, 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_OF, 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_TZH, DCH_TZM, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, TmFromChar::dd, TmFromChar::ddd, DecodeTimezoneAbbrevPrefix(), ereturn, errcode(), errdetail(), errmsg(), TmFromChar::ff, from_char_parse_int(), from_char_parse_int_len(), from_char_seq_search(), from_char_set_int(), from_char_set_mode(), TmFromChar::gmtoffset, TmFromChar::has_tz, TmFromChar::hh, KeyWord::id, InvalidOid, is_separator_char(), TmFromChar::j, FormatNode::key, len, localized_abbrev_days, localized_abbrev_months, localized_full_days, localized_full_months, TmFromChar::mi, TmFromChar::mm, months, months_full, MONTHS_PER_YEAR, TmFromChar::ms, KeyWord::name, NODE_TYPE_ACTION, NODE_TYPE_CHAR, NODE_TYPE_END, NODE_TYPE_SEPARATOR, NODE_TYPE_SPACE, pg_add_s32_overflow(), pg_mblen(), pg_mul_s32_overflow(), TmFromChar::pm, pnstrdup(), rm_months_lower, S_TM, SKIP_THth, TmFromChar::ss, TmFromChar::ssss, FormatNode::suffix, FormatNode::type, TmFromChar::tzh, TmFromChar::tzm, TmFromChar::tzp, TmFromChar::tzsign, TmFromChar::us, value, TmFromChar::w, TmFromChar::ww, TmFromChar::year, and TmFromChar::yysz.

Referenced by do_to_timestamp().

◆ DCH_prevent_counter_overflow()

static void DCH_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 3712 of file formatting.c.

3713{
3714 if (DCHCounter >= (INT_MAX - 1))
3715 {
3716 for (int i = 0; i < n_DCHCache; i++)
3717 DCHCache[i]->age >>= 1;
3718 DCHCounter >>= 1;
3719 }
3720}

References DCHCache, DCHCounter, i, and n_DCHCache.

Referenced by DCH_cache_getnew(), and DCH_cache_search().

◆ DCH_to_char()

static void DCH_to_char ( FormatNode node,
bool  is_interval,
TmToChar in,
char *  out,
Oid  collid 
)
static

Definition at line 2507 of file formatting.c.

2508{
2509 FormatNode *n;
2510 char *s;
2511 struct fmt_tm *tm = &in->tm;
2512 int i;
2513
2514 /* cache localized days and months */
2516
2517 s = out;
2518 for (n = node; n->type != NODE_TYPE_END; n++)
2519 {
2520 if (n->type != NODE_TYPE_ACTION)
2521 {
2522 strcpy(s, n->character);
2523 s += strlen(s);
2524 continue;
2525 }
2526
2527 switch (n->key->id)
2528 {
2529 case DCH_A_M:
2530 case DCH_P_M:
2531 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2532 ? P_M_STR : A_M_STR);
2533 s += strlen(s);
2534 break;
2535 case DCH_AM:
2536 case DCH_PM:
2537 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2538 ? PM_STR : AM_STR);
2539 s += strlen(s);
2540 break;
2541 case DCH_a_m:
2542 case DCH_p_m:
2543 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2544 ? p_m_STR : a_m_STR);
2545 s += strlen(s);
2546 break;
2547 case DCH_am:
2548 case DCH_pm:
2549 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2550 ? pm_STR : am_STR);
2551 s += strlen(s);
2552 break;
2553 case DCH_HH:
2554 case DCH_HH12:
2555
2556 /*
2557 * display time as shown on a 12-hour clock, even for
2558 * intervals
2559 */
2560 sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2561 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ?
2562 (long long) (HOURS_PER_DAY / 2) :
2563 (long long) (tm->tm_hour % (HOURS_PER_DAY / 2)));
2564 if (S_THth(n->suffix))
2565 str_numth(s, s, S_TH_TYPE(n->suffix));
2566 s += strlen(s);
2567 break;
2568 case DCH_HH24:
2569 sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2570 (long long) tm->tm_hour);
2571 if (S_THth(n->suffix))
2572 str_numth(s, s, S_TH_TYPE(n->suffix));
2573 s += strlen(s);
2574 break;
2575 case DCH_MI:
2576 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2577 tm->tm_min);
2578 if (S_THth(n->suffix))
2579 str_numth(s, s, S_TH_TYPE(n->suffix));
2580 s += strlen(s);
2581 break;
2582 case DCH_SS:
2583 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2584 tm->tm_sec);
2585 if (S_THth(n->suffix))
2586 str_numth(s, s, S_TH_TYPE(n->suffix));
2587 s += strlen(s);
2588 break;
2589
2590#define DCH_to_char_fsec(frac_fmt, frac_val) \
2591 sprintf(s, frac_fmt, (int) (frac_val)); \
2592 if (S_THth(n->suffix)) \
2593 str_numth(s, s, S_TH_TYPE(n->suffix)); \
2594 s += strlen(s)
2595
2596 case DCH_FF1: /* tenth of second */
2597 DCH_to_char_fsec("%01d", in->fsec / 100000);
2598 break;
2599 case DCH_FF2: /* hundredth of second */
2600 DCH_to_char_fsec("%02d", in->fsec / 10000);
2601 break;
2602 case DCH_FF3:
2603 case DCH_MS: /* millisecond */
2604 DCH_to_char_fsec("%03d", in->fsec / 1000);
2605 break;
2606 case DCH_FF4: /* tenth of a millisecond */
2607 DCH_to_char_fsec("%04d", in->fsec / 100);
2608 break;
2609 case DCH_FF5: /* hundredth of a millisecond */
2610 DCH_to_char_fsec("%05d", in->fsec / 10);
2611 break;
2612 case DCH_FF6:
2613 case DCH_US: /* microsecond */
2614 DCH_to_char_fsec("%06d", in->fsec);
2615 break;
2616#undef DCH_to_char_fsec
2617 case DCH_SSSS:
2618 sprintf(s, "%lld",
2619 (long long) (tm->tm_hour * SECS_PER_HOUR +
2621 tm->tm_sec));
2622 if (S_THth(n->suffix))
2623 str_numth(s, s, S_TH_TYPE(n->suffix));
2624 s += strlen(s);
2625 break;
2626 case DCH_tz:
2628 if (tmtcTzn(in))
2629 {
2630 /* We assume here that timezone names aren't localized */
2631 char *p = asc_tolower_z(tmtcTzn(in));
2632
2633 strcpy(s, p);
2634 pfree(p);
2635 s += strlen(s);
2636 }
2637 break;
2638 case DCH_TZ:
2640 if (tmtcTzn(in))
2641 {
2642 strcpy(s, tmtcTzn(in));
2643 s += strlen(s);
2644 }
2645 break;
2646 case DCH_TZH:
2648 sprintf(s, "%c%02d",
2649 (tm->tm_gmtoff >= 0) ? '+' : '-',
2650 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2651 s += strlen(s);
2652 break;
2653 case DCH_TZM:
2655 sprintf(s, "%02d",
2656 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2657 s += strlen(s);
2658 break;
2659 case DCH_OF:
2661 sprintf(s, "%c%0*d",
2662 (tm->tm_gmtoff >= 0) ? '+' : '-',
2663 S_FM(n->suffix) ? 0 : 2,
2664 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2665 s += strlen(s);
2666 if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2667 {
2668 sprintf(s, ":%02d",
2669 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2670 s += strlen(s);
2671 }
2672 break;
2673 case DCH_A_D:
2674 case DCH_B_C:
2676 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2677 s += strlen(s);
2678 break;
2679 case DCH_AD:
2680 case DCH_BC:
2682 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2683 s += strlen(s);
2684 break;
2685 case DCH_a_d:
2686 case DCH_b_c:
2688 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2689 s += strlen(s);
2690 break;
2691 case DCH_ad:
2692 case DCH_bc:
2694 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2695 s += strlen(s);
2696 break;
2697 case DCH_MONTH:
2699 if (!tm->tm_mon)
2700 break;
2701 if (S_TM(n->suffix))
2702 {
2704
2705 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2706 strcpy(s, str);
2707 else
2708 ereport(ERROR,
2709 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2710 errmsg("localized string format value too long")));
2711 }
2712 else
2713 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2715 s += strlen(s);
2716 break;
2717 case DCH_Month:
2719 if (!tm->tm_mon)
2720 break;
2721 if (S_TM(n->suffix))
2722 {
2724
2725 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2726 strcpy(s, str);
2727 else
2728 ereport(ERROR,
2729 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2730 errmsg("localized string format value too long")));
2731 }
2732 else
2733 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2734 months_full[tm->tm_mon - 1]);
2735 s += strlen(s);
2736 break;
2737 case DCH_month:
2739 if (!tm->tm_mon)
2740 break;
2741 if (S_TM(n->suffix))
2742 {
2744
2745 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2746 strcpy(s, str);
2747 else
2748 ereport(ERROR,
2749 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2750 errmsg("localized string format value too long")));
2751 }
2752 else
2753 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2755 s += strlen(s);
2756 break;
2757 case DCH_MON:
2759 if (!tm->tm_mon)
2760 break;
2761 if (S_TM(n->suffix))
2762 {
2764
2765 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2766 strcpy(s, str);
2767 else
2768 ereport(ERROR,
2769 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2770 errmsg("localized string format value too long")));
2771 }
2772 else
2773 strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2774 s += strlen(s);
2775 break;
2776 case DCH_Mon:
2778 if (!tm->tm_mon)
2779 break;
2780 if (S_TM(n->suffix))
2781 {
2783
2784 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2785 strcpy(s, str);
2786 else
2787 ereport(ERROR,
2788 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2789 errmsg("localized string format value too long")));
2790 }
2791 else
2792 strcpy(s, months[tm->tm_mon - 1]);
2793 s += strlen(s);
2794 break;
2795 case DCH_mon:
2797 if (!tm->tm_mon)
2798 break;
2799 if (S_TM(n->suffix))
2800 {
2802
2803 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2804 strcpy(s, str);
2805 else
2806 ereport(ERROR,
2807 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2808 errmsg("localized string format value too long")));
2809 }
2810 else
2811 strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
2812 s += strlen(s);
2813 break;
2814 case DCH_MM:
2815 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
2816 tm->tm_mon);
2817 if (S_THth(n->suffix))
2818 str_numth(s, s, S_TH_TYPE(n->suffix));
2819 s += strlen(s);
2820 break;
2821 case DCH_DAY:
2823 if (S_TM(n->suffix))
2824 {
2826
2827 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2828 strcpy(s, str);
2829 else
2830 ereport(ERROR,
2831 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2832 errmsg("localized string format value too long")));
2833 }
2834 else
2835 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2837 s += strlen(s);
2838 break;
2839 case DCH_Day:
2841 if (S_TM(n->suffix))
2842 {
2844
2845 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2846 strcpy(s, str);
2847 else
2848 ereport(ERROR,
2849 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2850 errmsg("localized string format value too long")));
2851 }
2852 else
2853 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2854 days[tm->tm_wday]);
2855 s += strlen(s);
2856 break;
2857 case DCH_day:
2859 if (S_TM(n->suffix))
2860 {
2862
2863 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2864 strcpy(s, str);
2865 else
2866 ereport(ERROR,
2867 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2868 errmsg("localized string format value too long")));
2869 }
2870 else
2871 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2873 s += strlen(s);
2874 break;
2875 case DCH_DY:
2877 if (S_TM(n->suffix))
2878 {
2880
2881 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2882 strcpy(s, str);
2883 else
2884 ereport(ERROR,
2885 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2886 errmsg("localized string format value too long")));
2887 }
2888 else
2889 strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
2890 s += strlen(s);
2891 break;
2892 case DCH_Dy:
2894 if (S_TM(n->suffix))
2895 {
2897
2898 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2899 strcpy(s, str);
2900 else
2901 ereport(ERROR,
2902 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2903 errmsg("localized string format value too long")));
2904 }
2905 else
2906 strcpy(s, days_short[tm->tm_wday]);
2907 s += strlen(s);
2908 break;
2909 case DCH_dy:
2911 if (S_TM(n->suffix))
2912 {
2914
2915 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2916 strcpy(s, str);
2917 else
2918 ereport(ERROR,
2919 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2920 errmsg("localized string format value too long")));
2921 }
2922 else
2923 strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
2924 s += strlen(s);
2925 break;
2926 case DCH_DDD:
2927 case DCH_IDDD:
2928 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
2929 (n->key->id == DCH_DDD) ?
2930 tm->tm_yday :
2932 if (S_THth(n->suffix))
2933 str_numth(s, s, S_TH_TYPE(n->suffix));
2934 s += strlen(s);
2935 break;
2936 case DCH_DD:
2937 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
2938 if (S_THth(n->suffix))
2939 str_numth(s, s, S_TH_TYPE(n->suffix));
2940 s += strlen(s);
2941 break;
2942 case DCH_D:
2944 sprintf(s, "%d", tm->tm_wday + 1);
2945 if (S_THth(n->suffix))
2946 str_numth(s, s, S_TH_TYPE(n->suffix));
2947 s += strlen(s);
2948 break;
2949 case DCH_ID:
2951 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
2952 if (S_THth(n->suffix))
2953 str_numth(s, s, S_TH_TYPE(n->suffix));
2954 s += strlen(s);
2955 break;
2956 case DCH_WW:
2957 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2958 (tm->tm_yday - 1) / 7 + 1);
2959 if (S_THth(n->suffix))
2960 str_numth(s, s, S_TH_TYPE(n->suffix));
2961 s += strlen(s);
2962 break;
2963 case DCH_IW:
2964 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2966 if (S_THth(n->suffix))
2967 str_numth(s, s, S_TH_TYPE(n->suffix));
2968 s += strlen(s);
2969 break;
2970 case DCH_Q:
2971 if (!tm->tm_mon)
2972 break;
2973 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
2974 if (S_THth(n->suffix))
2975 str_numth(s, s, S_TH_TYPE(n->suffix));
2976 s += strlen(s);
2977 break;
2978 case DCH_CC:
2979 if (is_interval) /* straight calculation */
2980 i = tm->tm_year / 100;
2981 else
2982 {
2983 if (tm->tm_year > 0)
2984 /* Century 20 == 1901 - 2000 */
2985 i = (tm->tm_year - 1) / 100 + 1;
2986 else
2987 /* Century 6BC == 600BC - 501BC */
2988 i = tm->tm_year / 100 - 1;
2989 }
2990 if (i <= 99 && i >= -99)
2991 sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
2992 else
2993 sprintf(s, "%d", i);
2994 if (S_THth(n->suffix))
2995 str_numth(s, s, S_TH_TYPE(n->suffix));
2996 s += strlen(s);
2997 break;
2998 case DCH_Y_YYY:
2999 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
3000 sprintf(s, "%d,%03d", i,
3001 ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
3002 if (S_THth(n->suffix))
3003 str_numth(s, s, S_TH_TYPE(n->suffix));
3004 s += strlen(s);
3005 break;
3006 case DCH_YYYY:
3007 case DCH_IYYY:
3008 sprintf(s, "%0*d",
3009 S_FM(n->suffix) ? 0 :
3010 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
3011 (n->key->id == DCH_YYYY ?
3012 ADJUST_YEAR(tm->tm_year, is_interval) :
3014 tm->tm_mon,
3015 tm->tm_mday),
3016 is_interval)));
3017 if (S_THth(n->suffix))
3018 str_numth(s, s, S_TH_TYPE(n->suffix));
3019 s += strlen(s);
3020 break;
3021 case DCH_YYY:
3022 case DCH_IYY:
3023 sprintf(s, "%0*d",
3024 S_FM(n->suffix) ? 0 :
3025 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
3026 (n->key->id == DCH_YYY ?
3027 ADJUST_YEAR(tm->tm_year, is_interval) :
3029 tm->tm_mon,
3030 tm->tm_mday),
3031 is_interval)) % 1000);
3032 if (S_THth(n->suffix))
3033 str_numth(s, s, S_TH_TYPE(n->suffix));
3034 s += strlen(s);
3035 break;
3036 case DCH_YY:
3037 case DCH_IY:
3038 sprintf(s, "%0*d",
3039 S_FM(n->suffix) ? 0 :
3040 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
3041 (n->key->id == DCH_YY ?
3042 ADJUST_YEAR(tm->tm_year, is_interval) :
3044 tm->tm_mon,
3045 tm->tm_mday),
3046 is_interval)) % 100);
3047 if (S_THth(n->suffix))
3048 str_numth(s, s, S_TH_TYPE(n->suffix));
3049 s += strlen(s);
3050 break;
3051 case DCH_Y:
3052 case DCH_I:
3053 sprintf(s, "%1d",
3054 (n->key->id == DCH_Y ?
3055 ADJUST_YEAR(tm->tm_year, is_interval) :
3057 tm->tm_mon,
3058 tm->tm_mday),
3059 is_interval)) % 10);
3060 if (S_THth(n->suffix))
3061 str_numth(s, s, S_TH_TYPE(n->suffix));
3062 s += strlen(s);
3063 break;
3064 case DCH_RM:
3065 /* FALLTHROUGH */
3066 case DCH_rm:
3067
3068 /*
3069 * For intervals, values like '12 month' will be reduced to 0
3070 * month and some years. These should be processed.
3071 */
3072 if (!tm->tm_mon && !tm->tm_year)
3073 break;
3074 else
3075 {
3076 int mon = 0;
3077 const char *const *months;
3078
3079 if (n->key->id == DCH_RM)
3081 else
3083
3084 /*
3085 * Compute the position in the roman-numeral array. Note
3086 * that the contents of the array are reversed, December
3087 * being first and January last.
3088 */
3089 if (tm->tm_mon == 0)
3090 {
3091 /*
3092 * This case is special, and tracks the case of full
3093 * interval years.
3094 */
3095 mon = tm->tm_year >= 0 ? 0 : MONTHS_PER_YEAR - 1;
3096 }
3097 else if (tm->tm_mon < 0)
3098 {
3099 /*
3100 * Negative case. In this case, the calculation is
3101 * reversed, where -1 means December, -2 November,
3102 * etc.
3103 */
3104 mon = -1 * (tm->tm_mon + 1);
3105 }
3106 else
3107 {
3108 /*
3109 * Common case, with a strictly positive value. The
3110 * position in the array matches with the value of
3111 * tm_mon.
3112 */
3113 mon = MONTHS_PER_YEAR - tm->tm_mon;
3114 }
3115
3116 sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
3117 months[mon]);
3118 s += strlen(s);
3119 }
3120 break;
3121 case DCH_W:
3122 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
3123 if (S_THth(n->suffix))
3124 str_numth(s, s, S_TH_TYPE(n->suffix));
3125 s += strlen(s);
3126 break;
3127 case DCH_J:
3128 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
3129 if (S_THth(n->suffix))
3130 str_numth(s, s, S_TH_TYPE(n->suffix));
3131 s += strlen(s);
3132 break;
3133 }
3134 }
3135
3136 *s = '\0';
3137}
int date2j(int year, int month, int day)
Definition: datetime.c:296
int date2isoweek(int year, int mon, int mday)
Definition: timestamp.c:5292
int date2isoyearday(int year, int mon, int mday)
Definition: timestamp.c:5404
int date2isoyear(int year, int mon, int mday)
Definition: timestamp.c:5347
#define SECS_PER_HOUR
Definition: timestamp.h:127
#define SECS_PER_MINUTE
Definition: timestamp.h:128
#define HOURS_PER_DAY
Definition: timestamp.h:118
#define ereport(elevel,...)
Definition: elog.h:150
#define ad_STR
Definition: formatting.c:199
#define bc_STR
Definition: formatting.c:204
#define AD_STR
Definition: formatting.c:198
static char * str_numth(char *dest, char *num, int type)
Definition: formatting.c:1610
#define a_d_STR
Definition: formatting.c:197
#define DCH_to_char_fsec(frac_fmt, frac_val)
#define PM_STR
Definition: formatting.c:230
#define BC_STR
Definition: formatting.c:203
#define a_m_STR
Definition: formatting.c:224
#define A_D_STR
Definition: formatting.c:196
#define pm_STR
Definition: formatting.c:231
#define B_C_STR
Definition: formatting.c:201
#define ADJUST_YEAR(year, is_interval)
Definition: formatting.c:194
static char * str_tolower_z(const char *buff, Oid collid)
Definition: formatting.c:1977
static char * asc_toupper_z(const char *buff)
Definition: formatting.c:2001
#define TM_SUFFIX_LEN
Definition: formatting.c:592
static char * str_toupper_z(const char *buff, Oid collid)
Definition: formatting.c:1983
#define b_c_STR
Definition: formatting.c:202
#define INVALID_FOR_INTERVAL
Definition: formatting.c:551
#define S_FM(_s)
Definition: formatting.c:584
static char * str_initcap_z(const char *buff, Oid collid)
Definition: formatting.c:1989
#define tmtcTzn(_X)
Definition: formatting.c:516
#define P_M_STR
Definition: formatting.c:228
#define p_m_STR
Definition: formatting.c:229
#define A_M_STR
Definition: formatting.c:223
#define am_STR
Definition: formatting.c:226
static char * asc_tolower_z(const char *buff)
Definition: formatting.c:1995
#define AM_STR
Definition: formatting.c:225
static const char *const rm_months_upper[]
Definition: formatting.c:252
static struct pg_tm tm
Definition: localtime.c:104
int len
Definition: formatting.c:147
struct fmt_tm tm
Definition: formatting.c:510
fsec_t fsec
Definition: formatting.c:511
int tm_hour
Definition: pgtime.h:38
int tm_mday
Definition: pgtime.h:39
int tm_mon
Definition: pgtime.h:40
int tm_min
Definition: pgtime.h:37
int tm_yday
Definition: pgtime.h:43
int tm_wday
Definition: pgtime.h:42
int tm_sec
Definition: pgtime.h:36
long int tm_gmtoff
Definition: pgtime.h:45
int tm_year
Definition: pgtime.h:41

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, collid, 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_FF1, DCH_FF2, DCH_FF3, DCH_FF4, DCH_FF5, DCH_FF6, DCH_HH, DCH_HH12, DCH_HH24, DCH_I, DCH_ID, DCH_IDDD, DCH_IW, DCH_IY, DCH_IYY, DCH_IYYY, DCH_J, DCH_MAX_ITEM_SIZ, DCH_MI, DCH_MM, DCH_MON, DCH_Mon, DCH_mon, DCH_MONTH, DCH_Month, DCH_month, DCH_MS, DCH_OF, DCH_P_M, DCH_p_m, DCH_PM, DCH_pm, DCH_Q, DCH_RM, DCH_rm, DCH_SS, DCH_SSSS, DCH_to_char_fsec, DCH_TZ, DCH_tz, DCH_TZH, DCH_TZM, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, ereport, errcode(), errmsg(), ERROR, TmToChar::fsec, HOURS_PER_DAY, i, KeyWord::id, INVALID_FOR_INTERVAL, FormatNode::key, KeyWord::len, localized_abbrev_days, localized_abbrev_months, localized_full_days, localized_full_months, months, months_full, MONTHS_PER_YEAR, NODE_TYPE_ACTION, NODE_TYPE_END, 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, sprintf, str, str_initcap_z(), str_numth(), str_tolower_z(), str_toupper_z(), FormatNode::suffix, TmToChar::tm, tm, pg_tm::tm_gmtoff, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, TM_SUFFIX_LEN, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcTzn, and FormatNode::type.

Referenced by datetime_to_char_body().

◆ do_to_timestamp()

static bool do_to_timestamp ( text date_txt,
text fmt,
Oid  collid,
bool  std,
struct pg_tm tm,
fsec_t fsec,
struct fmt_tz tz,
int *  fprec,
uint32 flags,
Node escontext 
)
static

Definition at line 4431 of file formatting.c.

4434{
4435 FormatNode *format = NULL;
4436 TmFromChar tmfc;
4437 int fmt_len;
4438 char *date_str;
4439 int fmask;
4440 bool incache = false;
4441
4442 Assert(tm != NULL);
4443 Assert(fsec != NULL);
4444
4445 date_str = text_to_cstring(date_txt);
4446
4447 ZERO_tmfc(&tmfc);
4448 ZERO_tm(tm);
4449 *fsec = 0;
4450 tz->has_tz = false;
4451 if (fprec)
4452 *fprec = 0;
4453 if (flags)
4454 *flags = 0;
4455 fmask = 0; /* bit mask for ValidateDate() */
4456
4457 fmt_len = VARSIZE_ANY_EXHDR(fmt);
4458
4459 if (fmt_len)
4460 {
4461 char *fmt_str;
4462
4463 fmt_str = text_to_cstring(fmt);
4464
4465 if (fmt_len > DCH_CACHE_SIZE)
4466 {
4467 /*
4468 * Allocate new memory if format picture is bigger than static
4469 * cache and do not use cache (call parser always)
4470 */
4471 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4472
4474 DCH_FLAG | (std ? STD_FLAG : 0), NULL);
4475 }
4476 else
4477 {
4478 /*
4479 * Use cache buffers
4480 */
4481 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, std);
4482
4483 incache = true;
4484 format = ent->format;
4485 }
4486
4487#ifdef DEBUG_TO_FROM_CHAR
4488 /* dump_node(format, fmt_len); */
4489 /* dump_index(DCH_keywords, DCH_index); */
4490#endif
4491
4492 DCH_from_char(format, date_str, &tmfc, collid, std, escontext);
4493 pfree(fmt_str);
4494 if (SOFT_ERROR_OCCURRED(escontext))
4495 goto fail;
4496
4497 if (flags)
4498 *flags = DCH_datetime_type(format);
4499
4500 if (!incache)
4501 {
4502 pfree(format);
4503 format = NULL;
4504 }
4505 }
4506
4507 DEBUG_TMFC(&tmfc);
4508
4509 /*
4510 * Convert to_date/to_timestamp input fields to standard 'tm'
4511 */
4512 if (tmfc.ssss)
4513 {
4514 int x = tmfc.ssss;
4515
4517 x %= SECS_PER_HOUR;
4519 x %= SECS_PER_MINUTE;
4520 tm->tm_sec = x;
4521 }
4522
4523 if (tmfc.ss)
4524 tm->tm_sec = tmfc.ss;
4525 if (tmfc.mi)
4526 tm->tm_min = tmfc.mi;
4527 if (tmfc.hh)
4528 tm->tm_hour = tmfc.hh;
4529
4530 if (tmfc.clock == CLOCK_12_HOUR)
4531 {
4532 if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
4533 {
4534 errsave(escontext,
4535 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4536 errmsg("hour \"%d\" is invalid for the 12-hour clock",
4537 tm->tm_hour),
4538 errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
4539 goto fail;
4540 }
4541
4542 if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
4543 tm->tm_hour += HOURS_PER_DAY / 2;
4544 else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
4545 tm->tm_hour = 0;
4546 }
4547
4548 if (tmfc.year)
4549 {
4550 /*
4551 * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
4552 * the year in the given century. Keep in mind that the 21st century
4553 * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
4554 * 600BC to 501BC.
4555 */
4556 if (tmfc.cc && tmfc.yysz <= 2)
4557 {
4558 if (tmfc.bc)
4559 tmfc.cc = -tmfc.cc;
4560 tm->tm_year = tmfc.year % 100;
4561 if (tm->tm_year)
4562 {
4563 int tmp;
4564
4565 if (tmfc.cc >= 0)
4566 {
4567 /* tm->tm_year += (tmfc.cc - 1) * 100; */
4568 tmp = tmfc.cc - 1;
4569 if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
4571 {
4573 text_to_cstring(date_txt), "timestamp",
4574 escontext);
4575 goto fail;
4576 }
4577 }
4578 else
4579 {
4580 /* tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1; */
4581 tmp = tmfc.cc + 1;
4582 if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
4583 pg_sub_s32_overflow(tmp, tm->tm_year, &tmp) ||
4584 pg_add_s32_overflow(tmp, 1, &tm->tm_year))
4585 {
4587 text_to_cstring(date_txt), "timestamp",
4588 escontext);
4589 goto fail;
4590 }
4591 }
4592 }
4593 else
4594 {
4595 /* find century year for dates ending in "00" */
4596 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
4597 }
4598 }
4599 else
4600 {
4601 /* If a 4-digit year is provided, we use that and ignore CC. */
4602 tm->tm_year = tmfc.year;
4603 if (tmfc.bc)
4604 tm->tm_year = -tm->tm_year;
4605 /* correct for our representation of BC years */
4606 if (tm->tm_year < 0)
4607 tm->tm_year++;
4608 }
4609 fmask |= DTK_M(YEAR);
4610 }
4611 else if (tmfc.cc)
4612 {
4613 /* use first year of century */
4614 if (tmfc.bc)
4615 tmfc.cc = -tmfc.cc;
4616 if (tmfc.cc >= 0)
4617 {
4618 /* +1 because 21st century started in 2001 */
4619 /* tm->tm_year = (tmfc.cc - 1) * 100 + 1; */
4620 if (pg_mul_s32_overflow(tmfc.cc - 1, 100, &tm->tm_year) ||
4622 {
4624 text_to_cstring(date_txt), "timestamp",
4625 escontext);
4626 goto fail;
4627 }
4628 }
4629 else
4630 {
4631 /* +1 because year == 599 is 600 BC */
4632 /* tm->tm_year = tmfc.cc * 100 + 1; */
4633 if (pg_mul_s32_overflow(tmfc.cc, 100, &tm->tm_year) ||
4635 {
4637 text_to_cstring(date_txt), "timestamp",
4638 escontext);
4639 goto fail;
4640 }
4641 }
4642 fmask |= DTK_M(YEAR);
4643 }
4644
4645 if (tmfc.j)
4646 {
4647 j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4648 fmask |= DTK_DATE_M;
4649 }
4650
4651 if (tmfc.ww)
4652 {
4653 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4654 {
4655 /*
4656 * If tmfc.d is not set, then the date is left at the beginning of
4657 * the ISO week (Monday).
4658 */
4659 if (tmfc.d)
4660 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4661 else
4662 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4663 fmask |= DTK_DATE_M;
4664 }
4665 else
4666 {
4667 /* tmfc.ddd = (tmfc.ww - 1) * 7 + 1; */
4668 if (pg_sub_s32_overflow(tmfc.ww, 1, &tmfc.ddd) ||
4669 pg_mul_s32_overflow(tmfc.ddd, 7, &tmfc.ddd) ||
4670 pg_add_s32_overflow(tmfc.ddd, 1, &tmfc.ddd))
4671 {
4673 date_str, "timestamp", escontext);
4674 goto fail;
4675 }
4676 }
4677 }
4678
4679 if (tmfc.w)
4680 {
4681 /* tmfc.dd = (tmfc.w - 1) * 7 + 1; */
4682 if (pg_sub_s32_overflow(tmfc.w, 1, &tmfc.dd) ||
4683 pg_mul_s32_overflow(tmfc.dd, 7, &tmfc.dd) ||
4684 pg_add_s32_overflow(tmfc.dd, 1, &tmfc.dd))
4685 {
4687 date_str, "timestamp", escontext);
4688 goto fail;
4689 }
4690 }
4691 if (tmfc.dd)
4692 {
4693 tm->tm_mday = tmfc.dd;
4694 fmask |= DTK_M(DAY);
4695 }
4696 if (tmfc.mm)
4697 {
4698 tm->tm_mon = tmfc.mm;
4699 fmask |= DTK_M(MONTH);
4700 }
4701
4702 if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
4703 {
4704 /*
4705 * The month and day field have not been set, so we use the
4706 * day-of-year field to populate them. Depending on the date mode,
4707 * this field may be interpreted as a Gregorian day-of-year, or an ISO
4708 * week date day-of-year.
4709 */
4710
4711 if (!tm->tm_year && !tmfc.bc)
4712 {
4713 errsave(escontext,
4714 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4715 errmsg("cannot calculate day of year without year information")));
4716 goto fail;
4717 }
4718
4719 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4720 {
4721 int j0; /* zeroth day of the ISO year, in Julian */
4722
4723 j0 = isoweek2j(tm->tm_year, 1) - 1;
4724
4725 j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4726 fmask |= DTK_DATE_M;
4727 }
4728 else
4729 {
4730 const int *y;
4731 int i;
4732
4733 static const int ysum[2][13] = {
4734 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
4735 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
4736
4737 y = ysum[isleap(tm->tm_year)];
4738
4739 for (i = 1; i <= MONTHS_PER_YEAR; i++)
4740 {
4741 if (tmfc.ddd <= y[i])
4742 break;
4743 }
4744 if (tm->tm_mon <= 1)
4745 tm->tm_mon = i;
4746
4747 if (tm->tm_mday <= 1)
4748 tm->tm_mday = tmfc.ddd - y[i - 1];
4749
4750 fmask |= DTK_M(MONTH) | DTK_M(DAY);
4751 }
4752 }
4753
4754 if (tmfc.ms)
4755 {
4756 int tmp = 0;
4757
4758 /* *fsec += tmfc.ms * 1000; */
4759 if (pg_mul_s32_overflow(tmfc.ms, 1000, &tmp) ||
4760 pg_add_s32_overflow(*fsec, tmp, fsec))
4761 {
4763 date_str, "timestamp", escontext);
4764 goto fail;
4765 }
4766 }
4767 if (tmfc.us)
4768 *fsec += tmfc.us;
4769 if (fprec)
4770 *fprec = tmfc.ff; /* fractional precision, if specified */
4771
4772 /* Range-check date fields according to bit mask computed above */
4773 if (fmask != 0)
4774 {
4775 /* We already dealt with AD/BC, so pass isjulian = true */
4776 int dterr = ValidateDate(fmask, true, false, false, tm);
4777
4778 if (dterr != 0)
4779 {
4780 /*
4781 * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
4782 * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
4783 * irrelevant hint about datestyle.
4784 */
4786 date_str, "timestamp", escontext);
4787 goto fail;
4788 }
4789 }
4790
4791 /* Range-check time fields too */
4792 if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY ||
4793 tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR ||
4794 tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
4795 *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
4796 {
4798 date_str, "timestamp", escontext);
4799 goto fail;
4800 }
4801
4802 /*
4803 * If timezone info was present, reduce it to a GMT offset. (We cannot do
4804 * this until we've filled all of the tm struct, since the zone's offset
4805 * might be time-varying.)
4806 */
4807 if (tmfc.tzsign)
4808 {
4809 /* TZH and/or TZM fields */
4810 if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
4811 tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
4812 {
4814 date_str, "timestamp", escontext);
4815 goto fail;
4816 }
4817
4818 tz->has_tz = true;
4819 tz->gmtoffset = (tmfc.tzh * MINS_PER_HOUR + tmfc.tzm) * SECS_PER_MINUTE;
4820 /* note we are flipping the sign convention here */
4821 if (tmfc.tzsign > 0)
4822 tz->gmtoffset = -tz->gmtoffset;
4823 }
4824 else if (tmfc.has_tz)
4825 {
4826 /* TZ field */
4827 tz->has_tz = true;
4828 if (tmfc.tzp == NULL)
4829 {
4830 /* fixed-offset abbreviation; flip the sign convention */
4831 tz->gmtoffset = -tmfc.gmtoffset;
4832 }
4833 else
4834 {
4835 /* dynamic-offset abbreviation, resolve using specified time */
4837 tmfc.tzp);
4838 }
4839 }
4840
4841 DEBUG_TM(tm);
4842
4843 if (format && !incache)
4844 pfree(format);
4845 pfree(date_str);
4846
4847 return true;
4848
4849fail:
4850 if (format && !incache)
4851 pfree(format);
4852 pfree(date_str);
4853
4854 return false;
4855}
void DateTimeParseError(int dterr, DateTimeErrorExtra *extra, const char *str, const char *datatype, Node *escontext)
Definition: datetime.c:4214
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2561
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:321
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1765
void isoweek2date(int woy, int *year, int *mon, int *mday)
Definition: timestamp.c:5261
int isoweek2j(int year, int week)
Definition: timestamp.c:5241
void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
Definition: timestamp.c:5274
#define INT64CONST(x)
Definition: c.h:553
#define MAX_TZDISP_HOUR
Definition: timestamp.h:143
#define MINS_PER_HOUR
Definition: timestamp.h:129
#define USECS_PER_SEC
Definition: timestamp.h:134
#define errsave(context,...)
Definition: elog.h:262
static void DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, Oid collid, bool std, Node *escontext)
Definition: formatting.c:3154
#define DEBUG_TM(_X)
Definition: formatting.c:484
#define ZERO_tmfc(_X)
Definition: formatting.c:458
#define DEBUG_TMFC(_X)
Definition: formatting.c:483
#define ZERO_tm(_X)
Definition: formatting.c:534
#define MONTH
Definition: datetime.h:91
#define DTK_M(t)
Definition: datetime.h:187
#define DAY
Definition: datetime.h:93
#define YEAR
Definition: datetime.h:92
#define DTK_DATE_M
Definition: datetime.h:191
#define isleap(y)
Definition: datetime.h:271
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:286
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
static bool pg_sub_s32_overflow(int32 a, int32 b, int32 *result)
Definition: int.h:169
int y
Definition: isn.c:76
int x
Definition: isn.c:75
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:53
FromCharDateMode mode
Definition: formatting.c:428
bool has_tz
Definition: formatting.c:462
int gmtoffset
Definition: formatting.c:463

References TmFromChar::abbrev, Assert(), TmFromChar::bc, TmFromChar::cc, TmFromChar::clock, CLOCK_12_HOUR, collid, TmFromChar::d, DateTimeParseError(), DAY, DCH_cache_fetch(), DCH_CACHE_SIZE, DCH_datetime_type(), DCH_FLAG, DCH_from_char(), DCH_index, DCH_keywords, DCH_suff, TmFromChar::dd, TmFromChar::ddd, DEBUG_TM, DEBUG_TMFC, DetermineTimeZoneAbbrevOffset(), DTERR_FIELD_OVERFLOW, DTERR_TZDISP_OVERFLOW, DTK_DATE_M, DTK_M, errcode(), errhint(), errmsg(), errsave, TmFromChar::ff, DCHCacheEntry::format, format, FROM_CHAR_DATE_ISOWEEK, TmFromChar::gmtoffset, fmt_tz::gmtoffset, TmFromChar::has_tz, fmt_tz::has_tz, TmFromChar::hh, HOURS_PER_DAY, i, INT64CONST, isleap, isoweek2date(), isoweek2j(), isoweekdate2date(), TmFromChar::j, j2date(), MAX_TZDISP_HOUR, TmFromChar::mi, MINS_PER_HOUR, TmFromChar::mm, TmFromChar::mode, MONTH, MONTHS_PER_YEAR, TmFromChar::ms, palloc(), parse_format(), pfree(), pg_add_s32_overflow(), pg_mul_s32_overflow(), pg_sub_s32_overflow(), TmFromChar::pm, SECS_PER_HOUR, SECS_PER_MINUTE, SOFT_ERROR_OCCURRED, TmFromChar::ss, TmFromChar::ssss, STD_FLAG, text_to_cstring(), tm, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, TmFromChar::tzh, TmFromChar::tzm, TmFromChar::tzp, TmFromChar::tzsign, TmFromChar::us, USECS_PER_SEC, ValidateDate(), VARSIZE_ANY_EXHDR(), TmFromChar::w, TmFromChar::ww, x, y, TmFromChar::year, YEAR, TmFromChar::yysz, ZERO_tm, and ZERO_tmfc.

Referenced by parse_datetime(), to_date(), and to_timestamp().

◆ fill_str()

static char * fill_str ( char *  str,
int  c,
int  max 
)
static

Definition at line 4864 of file formatting.c.

4865{
4866 memset(str, c, max);
4867 *(str + max) = '\0';
4868 return str;
4869}

References str.

Referenced by float4_to_char(), float8_to_char(), int4_to_char(), int8_to_char(), int_to_roman(), and numeric_to_char().

◆ float4_to_char()

Datum float4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6700 of file formatting.c.

6705{
6707 text *fmt = PG_GETARG_TEXT_PP(1);
6708 NUMDesc Num;
6710 text *result;
6711 bool shouldFree;
6712 int out_pre_spaces = 0,
6713 sign = 0;
6714 char *numstr,
6715 *p;
6716
6718
6719 if (IS_ROMAN(&Num))
6720 {
6721 int32 intvalue;
6722
6723 /* See notes in ftoi4() */
6724 value = rint(value);
6725 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6726 if (!isnan(value) && FLOAT4_FITS_IN_INT32(value))
6727 intvalue = (int32) value;
6728 else
6729 intvalue = PG_INT32_MAX;
6730 numstr = int_to_roman(intvalue);
6731 }
6732 else if (IS_EEEE(&Num))
6733 {
6734 if (isnan(value) || isinf(value))
6735 {
6736 /*
6737 * Allow 6 characters for the leading sign, the decimal point,
6738 * "e", the exponent's sign and two exponent digits.
6739 */
6740 numstr = (char *) palloc(Num.pre + Num.post + 7);
6741 fill_str(numstr, '#', Num.pre + Num.post + 6);
6742 *numstr = ' ';
6743 *(numstr + Num.pre + 1) = '.';
6744 }
6745 else
6746 {
6747 numstr = psprintf("%+.*e", Num.post, value);
6748
6749 /*
6750 * Swap a leading positive sign for a space.
6751 */
6752 if (*numstr == '+')
6753 *numstr = ' ';
6754 }
6755 }
6756 else
6757 {
6758 float4 val = value;
6759 char *orgnum;
6760 int numstr_pre_len;
6761
6762 if (IS_MULTI(&Num))
6763 {
6764 float multi = pow((double) 10, (double) Num.multi);
6765
6766 val = value * multi;
6767 Num.pre += Num.multi;
6768 }
6769
6770 orgnum = psprintf("%.0f", fabs(val));
6771 numstr_pre_len = strlen(orgnum);
6772
6773 /* adjust post digits to fit max float digits */
6774 if (numstr_pre_len >= FLT_DIG)
6775 Num.post = 0;
6776 else if (numstr_pre_len + Num.post > FLT_DIG)
6777 Num.post = FLT_DIG - numstr_pre_len;
6778 orgnum = psprintf("%.*f", Num.post, val);
6779
6780 if (*orgnum == '-')
6781 { /* < 0 */
6782 sign = '-';
6783 numstr = orgnum + 1;
6784 }
6785 else
6786 {
6787 sign = '+';
6788 numstr = orgnum;
6789 }
6790
6791 if ((p = strchr(numstr, '.')))
6792 numstr_pre_len = p - numstr;
6793 else
6794 numstr_pre_len = strlen(numstr);
6795
6796 /* needs padding? */
6797 if (numstr_pre_len < Num.pre)
6798 out_pre_spaces = Num.pre - numstr_pre_len;
6799 /* overflowed prefix digit format? */
6800 else if (numstr_pre_len > Num.pre)
6801 {
6802 numstr = (char *) palloc(Num.pre + Num.post + 2);
6803 fill_str(numstr, '#', Num.pre + Num.post + 1);
6804 *(numstr + Num.pre) = '.';
6805 }
6806 }
#define FLOAT4_FITS_IN_INT32(num)
Definition: c.h:1084
#define PG_INT32_MAX
Definition: c.h:595
int32_t int32
Definition: c.h:535
float float4
Definition: c.h:635
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GETARG_FLOAT4(n)
Definition: fmgr.h:281
#define NUM_TOCHAR_prepare
Definition: formatting.c:6275
#define IS_MULTI(_f)
Definition: formatting.c:360
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:4864
#define IS_ROMAN(_f)
Definition: formatting.c:359
#define IS_EEEE(_f)
Definition: formatting.c:361
static char * int_to_roman(int number)
Definition: formatting.c:5069
long val
Definition: informix.c:689
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
int pre
Definition: formatting.c:312
int multi
Definition: formatting.c:317
int post
Definition: formatting.c:313

References fill_str(), FLOAT4_FITS_IN_INT32, format, int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, palloc(), PG_GETARG_FLOAT4, PG_GETARG_TEXT_PP, PG_INT32_MAX, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, psprintf(), sign, val, and value.

◆ float8_to_char()

Datum float8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6813 of file formatting.c.

6818{
6820 text *fmt = PG_GETARG_TEXT_PP(1);
6821 NUMDesc Num;
6823 text *result;
6824 bool shouldFree;
6825 int out_pre_spaces = 0,
6826 sign = 0;
6827 char *numstr,
6828 *p;
6829
6831
6832 if (IS_ROMAN(&Num))
6833 {
6834 int32 intvalue;
6835
6836 /* See notes in dtoi4() */
6837 value = rint(value);
6838 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6839 if (!isnan(value) && FLOAT8_FITS_IN_INT32(value))
6840 intvalue = (int32) value;
6841 else
6842 intvalue = PG_INT32_MAX;
6843 numstr = int_to_roman(intvalue);
6844 }
6845 else if (IS_EEEE(&Num))
6846 {
6847 if (isnan(value) || isinf(value))
6848 {
6849 /*
6850 * Allow 6 characters for the leading sign, the decimal point,
6851 * "e", the exponent's sign and two exponent digits.
6852 */
6853 numstr = (char *) palloc(Num.pre + Num.post + 7);
6854 fill_str(numstr, '#', Num.pre + Num.post + 6);
6855 *numstr = ' ';
6856 *(numstr + Num.pre + 1) = '.';
6857 }
6858 else
6859 {
6860 numstr = psprintf("%+.*e", Num.post, value);
6861
6862 /*
6863 * Swap a leading positive sign for a space.
6864 */
6865 if (*numstr == '+')
6866 *numstr = ' ';
6867 }
6868 }
6869 else
6870 {
6871 float8 val = value;
6872 char *orgnum;
6873 int numstr_pre_len;
6874
6875 if (IS_MULTI(&Num))
6876 {
6877 double multi = pow((double) 10, (double) Num.multi);
6878
6879 val = value * multi;
6880 Num.pre += Num.multi;
6881 }
6882
6883 orgnum = psprintf("%.0f", fabs(val));
6884 numstr_pre_len = strlen(orgnum);
6885
6886 /* adjust post digits to fit max double digits */
6887 if (numstr_pre_len >= DBL_DIG)
6888 Num.post = 0;
6889 else if (numstr_pre_len + Num.post > DBL_DIG)
6890 Num.post = DBL_DIG - numstr_pre_len;
6891 orgnum = psprintf("%.*f", Num.post, val);
6892
6893 if (*orgnum == '-')
6894 { /* < 0 */
6895 sign = '-';
6896 numstr = orgnum + 1;
6897 }
6898 else
6899 {
6900 sign = '+';
6901 numstr = orgnum;
6902 }
6903
6904 if ((p = strchr(numstr, '.')))
6905 numstr_pre_len = p - numstr;
6906 else
6907 numstr_pre_len = strlen(numstr);
6908
6909 /* needs padding? */
6910 if (numstr_pre_len < Num.pre)
6911 out_pre_spaces = Num.pre - numstr_pre_len;
6912 /* overflowed prefix digit format? */
6913 else if (numstr_pre_len > Num.pre)
6914 {
6915 numstr = (char *) palloc(Num.pre + Num.post + 2);
6916 fill_str(numstr, '#', Num.pre + Num.post + 1);
6917 *(numstr + Num.pre) = '.';
6918 }
6919 }
#define FLOAT8_FITS_IN_INT32(num)
Definition: c.h:1090
double float8
Definition: c.h:636
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282

References fill_str(), FLOAT8_FITS_IN_INT32, format, int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, palloc(), PG_GETARG_FLOAT8, PG_GETARG_TEXT_PP, PG_INT32_MAX, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, psprintf(), sign, val, and value.

◆ from_char_parse_int()

static int from_char_parse_int ( int *  dest,
const char **  src,
FormatNode node,
Node escontext 
)
static

Definition at line 2302 of file formatting.c.

2304{
2305 return from_char_parse_int_len(dest, src, node->key->len, node, escontext);
2306}

References generate_unaccent_rules::dest, from_char_parse_int_len(), FormatNode::key, and KeyWord::len.

Referenced by DCH_from_char().

◆ from_char_parse_int_len()

static int from_char_parse_int_len ( int *  dest,
const char **  src,
const int  len,
FormatNode node,
Node escontext 
)
static

Definition at line 2205 of file formatting.c.

2207{
2208 long result;
2209 char copy[DCH_MAX_ITEM_SIZ + 1];
2210 const char *init = *src;
2211 int used;
2212
2213 /*
2214 * Skip any whitespace before parsing the integer.
2215 */
2216 *src += strspace_len(*src);
2217
2219 used = (int) strlcpy(copy, *src, len + 1);
2220
2221 if (S_FM(node->suffix) || is_next_separator(node))
2222 {
2223 /*
2224 * This node is in Fill Mode, or the next node is known to be a
2225 * non-digit value, so we just slurp as many characters as we can get.
2226 */
2227 char *endptr;
2228
2229 errno = 0;
2230 result = strtol(init, &endptr, 10);
2231 *src = endptr;
2232 }
2233 else
2234 {
2235 /*
2236 * We need to pull exactly the number of characters given in 'len' out
2237 * of the string, and convert those.
2238 */
2239 char *last;
2240
2241 if (used < len)
2242 ereturn(escontext, -1,
2243 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2244 errmsg("source string too short for \"%s\" formatting field",
2245 node->key->name),
2246 errdetail("Field requires %d characters, but only %d remain.",
2247 len, used),
2248 errhint("If your source string is not fixed-width, "
2249 "try using the \"FM\" modifier.")));
2250
2251 errno = 0;
2252 result = strtol(copy, &last, 10);
2253 used = last - copy;
2254
2255 if (used > 0 && used < len)
2256 ereturn(escontext, -1,
2257 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2258 errmsg("invalid value \"%s\" for \"%s\"",
2259 copy, node->key->name),
2260 errdetail("Field requires %d characters, but only %d could be parsed.",
2261 len, used),
2262 errhint("If your source string is not fixed-width, "
2263 "try using the \"FM\" modifier.")));
2264
2265 *src += used;
2266 }
2267
2268 if (*src == init)
2269 ereturn(escontext, -1,
2270 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2271 errmsg("invalid value \"%s\" for \"%s\"",
2272 copy, node->key->name),
2273 errdetail("Value must be an integer.")));
2274
2275 if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
2276 ereturn(escontext, -1,
2277 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2278 errmsg("value for \"%s\" in source string is out of range",
2279 node->key->name),
2280 errdetail("Value must be in the range %d to %d.",
2281 INT_MIN, INT_MAX)));
2282
2283 if (dest != NULL)
2284 {
2285 if (!from_char_set_int(dest, (int) result, node, escontext))
2286 return -1;
2287 }
2288
2289 return *src - init;
2290}
static bool is_next_separator(FormatNode *n)
Definition: formatting.c:2063
static int strspace_len(const char *str)
Definition: formatting.c:2120
int init
Definition: isn.c:79

References Assert(), DCH_MAX_ITEM_SIZ, generate_unaccent_rules::dest, ereturn, errcode(), errdetail(), errhint(), errmsg(), from_char_set_int(), init, is_next_separator(), FormatNode::key, len, KeyWord::name, S_FM, strlcpy(), strspace_len(), and FormatNode::suffix.

Referenced by DCH_from_char(), and from_char_parse_int().

◆ from_char_seq_search()

static bool from_char_seq_search ( int *  dest,
const char **  src,
const char *const *  array,
char **  localized_array,
Oid  collid,
FormatNode node,
Node escontext 
)
static

Definition at line 2461 of file formatting.c.

2464{
2465 int len;
2466
2467 if (localized_array == NULL)
2468 *dest = seq_search_ascii(*src, array, &len);
2469 else
2470 *dest = seq_search_localized(*src, localized_array, &len, collid);
2471
2472 if (len <= 0)
2473 {
2474 /*
2475 * In the error report, truncate the string at the next whitespace (if
2476 * any) to avoid including irrelevant data.
2477 */
2478 char *copy = pstrdup(*src);
2479 char *c;
2480
2481 for (c = copy; *c; c++)
2482 {
2483 if (scanner_isspace(*c))
2484 {
2485 *c = '\0';
2486 break;
2487 }
2488 }
2489
2490 ereturn(escontext, false,
2491 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2492 errmsg("invalid value \"%s\" for \"%s\"",
2493 copy, node->key->name),
2494 errdetail("The given value did not match any of "
2495 "the allowed values for this field.")));
2496 }
2497 *src += len;
2498 return true;
2499}
static int seq_search_localized(const char *name, char **array, int *len, Oid collid)
Definition: formatting.c:2377
static int seq_search_ascii(const char *name, const char *const *array, int *len)
Definition: formatting.c:2320
char * pstrdup(const char *in)
Definition: mcxt.c:1759
bool scanner_isspace(char ch)
Definition: scansup.c:117

References collid, generate_unaccent_rules::dest, ereturn, errcode(), errdetail(), errmsg(), FormatNode::key, len, KeyWord::name, pstrdup(), scanner_isspace(), seq_search_ascii(), and seq_search_localized().

Referenced by DCH_from_char().

◆ from_char_set_int()

static bool from_char_set_int ( int *  dest,
const int  value,
const FormatNode node,
Node escontext 
)
static

Definition at line 2169 of file formatting.c.

2171{
2172 if (*dest != 0 && *dest != value)
2173 ereturn(escontext, false,
2174 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2175 errmsg("conflicting values for \"%s\" field in formatting string",
2176 node->key->name),
2177 errdetail("This value contradicts a previous setting "
2178 "for the same field type.")));
2179 *dest = value;
2180 return true;
2181}

References generate_unaccent_rules::dest, ereturn, errcode(), errdetail(), errmsg(), FormatNode::key, KeyWord::name, and value.

Referenced by DCH_from_char(), and from_char_parse_int_len().

◆ from_char_set_mode()

static bool from_char_set_mode ( TmFromChar tmfc,
const FromCharDateMode  mode,
Node escontext 
)
static

Definition at line 2142 of file formatting.c.

2144{
2146 {
2147 if (tmfc->mode == FROM_CHAR_DATE_NONE)
2148 tmfc->mode = mode;
2149 else if (tmfc->mode != mode)
2150 ereturn(escontext, false,
2151 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2152 errmsg("invalid combination of date conventions"),
2153 errhint("Do not mix Gregorian and ISO week date "
2154 "conventions in a formatting template.")));
2155 }
2156 return true;
2157}
static PgChecksumMode mode
Definition: pg_checksums.c:55

References ereturn, errcode(), errhint(), errmsg(), FROM_CHAR_DATE_NONE, TmFromChar::mode, and mode.

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

static char * get_last_relevant_decnum ( char *  num)
static

Definition at line 5361 of file formatting.c.

5362{
5363 char *result,
5364 *p = strchr(num, '.');
5365
5366#ifdef DEBUG_TO_FROM_CHAR
5367 elog(DEBUG_elog_output, "get_last_relevant_decnum()");
5368#endif
5369
5370 if (!p)
5371 return NULL;
5372
5373 result = p;
5374
5375 while (*(++p))
5376 {
5377 if (*p != '0')
5378 result = p;
5379 }
5380
5381 return result;
5382}

References elog.

Referenced by NUM_processor().

◆ get_th()

static const char * get_th ( char *  num,
int  type 
)
static

Definition at line 1563 of file formatting.c.

1564{
1565 int len = strlen(num),
1566 last;
1567
1568 Assert(len > 0);
1569
1570 last = *(num + (len - 1));
1571 if (!isdigit((unsigned char) last))
1572 ereport(ERROR,
1573 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1574 errmsg("\"%s\" is not a number", num)));
1575
1576 /*
1577 * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1578 * 'ST/st', 'ND/nd', 'RD/rd', respectively
1579 */
1580 if ((len > 1) && (num[len - 2] == '1'))
1581 last = 0;
1582
1583 switch (last)
1584 {
1585 case '1':
1586 if (type == TH_UPPER)
1587 return numTH[0];
1588 return numth[0];
1589 case '2':
1590 if (type == TH_UPPER)
1591 return numTH[1];
1592 return numth[1];
1593 case '3':
1594 if (type == TH_UPPER)
1595 return numTH[2];
1596 return numth[2];
1597 default:
1598 if (type == TH_UPPER)
1599 return numTH[3];
1600 return numth[3];
1601 }
1602}
static const char *const numth[]
Definition: formatting.c:297
static const char *const numTH[]
Definition: formatting.c:296
#define TH_UPPER
Definition: formatting.c:303
const char * type

References Assert(), ereport, errcode(), errmsg(), ERROR, len, numTH, numth, TH_UPPER, and type.

Referenced by NUM_processor(), and str_numth().

◆ index_seq_search()

static const KeyWord * index_seq_search ( const char *  str,
const KeyWord kw,
const int *  index 
)
static

Definition at line 1135 of file formatting.c.

1136{
1137 int poz;
1138
1140 return NULL;
1141
1142 if ((poz = *(index + (*str - ' '))) > -1)
1143 {
1144 const KeyWord *k = kw + poz;
1145
1146 do
1147 {
1148 if (strncmp(str, k->name, k->len) == 0)
1149 return k;
1150 k++;
1151 if (!k->name)
1152 return NULL;
1153 } while (*str == *k->name);
1154 }
1155 return NULL;
1156}
#define KeyWord_INDEX_FILTER(_c)
Definition: formatting.c:108
Definition: type.h:96

References KeyWord_INDEX_FILTER, KeyWord::len, KeyWord::name, and str.

Referenced by parse_format().

◆ int4_to_char()

Datum int4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6494 of file formatting.c.

6499{
6501 text *fmt = PG_GETARG_TEXT_PP(1);
6502 NUMDesc Num;
6504 text *result;
6505 bool shouldFree;
6506 int out_pre_spaces = 0,
6507 sign = 0;
6508 char *numstr,
6509 *orgnum;
6510
6512
6513 /*
6514 * On DateType depend part (int32)
6515 */
6516 if (IS_ROMAN(&Num))
6517 numstr = int_to_roman(value);
6518 else if (IS_EEEE(&Num))
6519 {
6520 /* we can do it easily because float8 won't lose any precision */
6521 float8 val = (float8) value;
6522
6523 orgnum = (char *) psprintf("%+.*e", Num.post, val);
6524
6525 /*
6526 * Swap a leading positive sign for a space.
6527 */
6528 if (*orgnum == '+')
6529 *orgnum = ' ';
6530
6531 numstr = orgnum;
6532 }
6533 else
6534 {
6535 int numstr_pre_len;
6536
6537 if (IS_MULTI(&Num))
6538 {
6540 Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
6541 Num.pre += Num.multi;
6542 }
6543 else
6544 {
6547 }
6548
6549 if (*orgnum == '-')
6550 {
6551 sign = '-';
6552 orgnum++;
6553 }
6554 else
6555 sign = '+';
6556
6557 numstr_pre_len = strlen(orgnum);
6558
6559 /* post-decimal digits? Pad out with zeros. */
6560 if (Num.post)
6561 {
6562 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6563 strcpy(numstr, orgnum);
6564 *(numstr + numstr_pre_len) = '.';
6565 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6566 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6567 }
6568 else
6569 numstr = orgnum;
6570
6571 /* needs padding? */
6572 if (numstr_pre_len < Num.pre)
6573 out_pre_spaces = Num.pre - numstr_pre_len;
6574 /* overflowed prefix digit format? */
6575 else if (numstr_pre_len > Num.pre)
6576 {
6577 numstr = (char *) palloc(Num.pre + Num.post + 2);
6578 fill_str(numstr, '#', Num.pre + Num.post + 1);
6579 *(numstr + Num.pre) = '.';
6580 }
6581 }
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
Datum int4out(PG_FUNCTION_ARGS)
Definition: int.c:298
static char * DatumGetCString(Datum X)
Definition: postgres.h:345
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222

References DatumGetCString(), DirectFunctionCall1, fill_str(), format, Int32GetDatum(), int4out(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, palloc(), PG_GETARG_INT32, PG_GETARG_TEXT_PP, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, psprintf(), sign, val, and value.

◆ int8_to_char()

Datum int8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6588 of file formatting.c.

6593{
6595 text *fmt = PG_GETARG_TEXT_PP(1);
6596 NUMDesc Num;
6598 text *result;
6599 bool shouldFree;
6600 int out_pre_spaces = 0,
6601 sign = 0;
6602 char *numstr,
6603 *orgnum;
6604
6606
6607 /*
6608 * On DateType depend part (int64)
6609 */
6610 if (IS_ROMAN(&Num))
6611 {
6612 int32 intvalue;
6613
6614 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6615 if (value <= PG_INT32_MAX && value >= PG_INT32_MIN)
6616 intvalue = (int32) value;
6617 else
6618 intvalue = PG_INT32_MAX;
6619 numstr = int_to_roman(intvalue);
6620 }
6621 else if (IS_EEEE(&Num))
6622 {
6623 /* to avoid loss of precision, must go via numeric not float8 */
6625 Num.post);
6626
6627 /*
6628 * numeric_out_sci() does not emit a sign for positive numbers. We
6629 * need to add a space in this case so that positive and negative
6630 * numbers are aligned. We don't have to worry about NaN/inf here.
6631 */
6632 if (*orgnum != '-')
6633 {
6634 numstr = (char *) palloc(strlen(orgnum) + 2);
6635 *numstr = ' ';
6636 strcpy(numstr + 1, orgnum);
6637 }
6638 else
6639 {
6640 numstr = orgnum;
6641 }
6642 }
6643 else
6644 {
6645 int numstr_pre_len;
6646
6647 if (IS_MULTI(&Num))
6648 {
6649 double multi = pow((double) 10, (double) Num.multi);
6650
6654 Float8GetDatum(multi))));
6655 Num.pre += Num.multi;
6656 }
6657
6660
6661 if (*orgnum == '-')
6662 {
6663 sign = '-';
6664 orgnum++;
6665 }
6666 else
6667 sign = '+';
6668
6669 numstr_pre_len = strlen(orgnum);
6670
6671 /* post-decimal digits? Pad out with zeros. */
6672 if (Num.post)
6673 {
6674 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6675 strcpy(numstr, orgnum);
6676 *(numstr + numstr_pre_len) = '.';
6677 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6678 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6679 }
6680 else
6681 numstr = orgnum;
6682
6683 /* needs padding? */
6684 if (numstr_pre_len < Num.pre)
6685 out_pre_spaces = Num.pre - numstr_pre_len;
6686 /* overflowed prefix digit format? */
6687 else if (numstr_pre_len > Num.pre)
6688 {
6689 numstr = (char *) palloc(Num.pre + Num.post + 2);
6690 fill_str(numstr, '#', Num.pre + Num.post + 1);
6691 *(numstr + Num.pre) = '.';
6692 }
6693 }
char * numeric_out_sci(Numeric num, int scale)
Definition: numeric.c:975
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4260
int64_t int64
Definition: c.h:536
#define PG_INT32_MIN
Definition: c.h:594
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:684
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
Datum int8out(PG_FUNCTION_ARGS)
Definition: int8.c:61
Datum int8mul(PG_FUNCTION_ARGS)
Definition: int8.c:490
Datum dtoi8(PG_FUNCTION_ARGS)
Definition: int8.c:1250
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:393
static Datum Float8GetDatum(float8 X)
Definition: postgres.h:492

References DatumGetCString(), DatumGetInt64(), DirectFunctionCall1, DirectFunctionCall2, dtoi8(), fill_str(), Float8GetDatum(), format, int64_to_numeric(), Int64GetDatum(), int8mul(), int8out(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, numeric_out_sci(), palloc(), PG_GETARG_INT64, PG_GETARG_TEXT_PP, PG_INT32_MAX, PG_INT32_MIN, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, and value.

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 5069 of file formatting.c.

5070{
5071 int len,
5072 num;
5073 char *p,
5074 *result,
5075 numstr[12];
5076
5077 result = (char *) palloc(MAX_ROMAN_LEN + 1);
5078 *result = '\0';
5079
5080 /*
5081 * This range limit is the same as in Oracle(TM). The difficulty with
5082 * handling 4000 or more is that we'd need to use more than 3 "M"'s, and
5083 * more than 3 of the same digit isn't considered a valid Roman string.
5084 */
5085 if (number > 3999 || number < 1)
5086 {
5087 fill_str(result, '#', MAX_ROMAN_LEN);
5088 return result;
5089 }
5090
5091 /* Convert to decimal, then examine each digit */
5092 len = snprintf(numstr, sizeof(numstr), "%d", number);
5093 Assert(len > 0 && len <= 4);
5094
5095 for (p = numstr; *p != '\0'; p++, --len)
5096 {
5097 num = *p - ('0' + 1);
5098 if (num < 0)
5099 continue; /* ignore zeroes */
5100 /* switch on current column position */
5101 switch (len)
5102 {
5103 case 4:
5104 while (num-- >= 0)
5105 strcat(result, "M");
5106 break;
5107 case 3:
5108 strcat(result, rm100[num]);
5109 break;
5110 case 2:
5111 strcat(result, rm10[num]);
5112 break;
5113 case 1:
5114 strcat(result, rm1[num]);
5115 break;
5116 }
5117 }
5118 return result;
5119}
#define MAX_ROMAN_LEN
Definition: formatting.c:290
static const char *const rm100[]
Definition: formatting.c:264
static const char *const rm10[]
Definition: formatting.c:263
static const char *const rm1[]
Definition: formatting.c:262
#define snprintf
Definition: port.h:239

References Assert(), fill_str(), len, MAX_ROMAN_LEN, palloc(), rm1, rm10, rm100, and snprintf.

Referenced by float4_to_char(), float8_to_char(), int4_to_char(), int8_to_char(), and numeric_to_char().

◆ interval_to_char()

Datum interval_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4076 of file formatting.c.

4077{
4079 text *fmt = PG_GETARG_TEXT_PP(1),
4080 *res;
4081 TmToChar tmtc;
4082 struct fmt_tm *tm;
4083 struct pg_itm tt,
4084 *itm = &tt;
4085
4086 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || INTERVAL_NOT_FINITE(it))
4088
4089 ZERO_tmtc(&tmtc);
4090 tm = tmtcTm(&tmtc);
4091
4092 interval2itm(*it, itm);
4093 tmtc.fsec = itm->tm_usec;
4094 tm->tm_sec = itm->tm_sec;
4095 tm->tm_min = itm->tm_min;
4096 tm->tm_hour = itm->tm_hour;
4097 tm->tm_mday = itm->tm_mday;
4098 tm->tm_mon = itm->tm_mon;
4099 tm->tm_year = itm->tm_year;
4100
4101 /* wday is meaningless, yday approximates the total span in days */
4103
4104 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4106
4107 PG_RETURN_TEXT_P(res);
4108}
void interval2itm(Interval span, struct pg_itm *itm)
Definition: timestamp.c:2047
#define INTERVAL_NOT_FINITE(i)
Definition: timestamp.h:195
#define DAYS_PER_MONTH
Definition: timestamp.h:116
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define ZERO_tmtc(_X)
Definition: formatting.c:540
static text * datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
Definition: formatting.c:3931
int64 tm_hour
Definition: timestamp.h:70
int tm_year
Definition: timestamp.h:73
int tm_mon
Definition: timestamp.h:72
int tm_mday
Definition: timestamp.h:71
int tm_sec
Definition: timestamp.h:68
int tm_min
Definition: timestamp.h:69
int tm_usec
Definition: timestamp.h:67
#define PG_GETARG_INTERVAL_P(n)
Definition: timestamp.h:65

References datetime_to_char_body(), DAYS_PER_MONTH, TmToChar::fsec, if(), interval2itm(), INTERVAL_NOT_FINITE, MONTHS_PER_YEAR, PG_GET_COLLATION, PG_GETARG_INTERVAL_P, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, tm, pg_itm::tm_hour, pg_tm::tm_hour, pg_itm::tm_mday, pg_tm::tm_mday, pg_itm::tm_min, pg_tm::tm_min, pg_itm::tm_mon, pg_tm::tm_mon, pg_itm::tm_sec, pg_tm::tm_sec, pg_itm::tm_usec, pg_tm::tm_yday, pg_itm::tm_year, pg_tm::tm_year, tmtcTm, VARSIZE_ANY_EXHDR(), and ZERO_tmtc.

◆ is_next_separator()

static bool is_next_separator ( FormatNode n)
static

Definition at line 2063 of file formatting.c.

2064{
2065 if (n->type == NODE_TYPE_END)
2066 return false;
2067
2068 if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
2069 return true;
2070
2071 /*
2072 * Next node
2073 */
2074 n++;
2075
2076 /* end of format string is treated like a non-digit separator */
2077 if (n->type == NODE_TYPE_END)
2078 return true;
2079
2080 if (n->type == NODE_TYPE_ACTION)
2081 {
2082 if (n->key->is_digit)
2083 return false;
2084
2085 return true;
2086 }
2087 else if (n->character[1] == '\0' &&
2088 isdigit((unsigned char) n->character[0]))
2089 return false;
2090
2091 return true; /* some non-digit input (separator) */
2092}
bool is_digit
Definition: formatting.c:149

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().

◆ is_separator_char()

static bool is_separator_char ( const char *  str)
static

Definition at line 1175 of file formatting.c.

1176{
1177 /* ASCII printable character, but not letter or digit */
1178 return (*str > 0x20 && *str < 0x7F &&
1179 !(*str >= 'A' && *str <= 'Z') &&
1180 !(*str >= 'a' && *str <= 'z') &&
1181 !(*str >= '0' && *str <= '9'));
1182}

References str.

Referenced by DCH_from_char(), and parse_format().

◆ NUM_cache()

static FormatNode * NUM_cache ( int  len,
NUMDesc Num,
text pars_str,
bool *  shouldFree 
)
static

Definition at line 5006 of file formatting.c.

5007{
5008 FormatNode *format = NULL;
5009 char *str;
5010
5011 str = text_to_cstring(pars_str);
5012
5013 if (len > NUM_CACHE_SIZE)
5014 {
5015 /*
5016 * Allocate new memory if format picture is bigger than static cache
5017 * and do not use cache (call parser always)
5018 */
5019 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
5020
5021 *shouldFree = true;
5022
5023 zeroize_NUM(Num);
5024
5026 NULL, NUM_index, NUM_FLAG, Num);
5027 }
5028 else
5029 {
5030 /*
5031 * Use cache buffers
5032 */
5034
5035 *shouldFree = false;
5036
5037 format = ent->format;
5038
5039 /*
5040 * Copy cache to used struct
5041 */
5042 Num->flag = ent->Num.flag;
5043 Num->lsign = ent->Num.lsign;
5044 Num->pre = ent->Num.pre;
5045 Num->post = ent->Num.post;
5046 Num->pre_lsign_num = ent->Num.pre_lsign_num;
5047 Num->need_locale = ent->Num.need_locale;
5048 Num->multi = ent->Num.multi;
5049 Num->zero_start = ent->Num.zero_start;
5050 Num->zero_end = ent->Num.zero_end;
5051 }
5052
5053#ifdef DEBUG_TO_FROM_CHAR
5054 /* dump_node(format, len); */
5055 dump_index(NUM_keywords, NUM_index);
5056#endif
5057
5058 pfree(str);
5059 return format;
5060}
static const KeyWord NUM_keywords[]
Definition: formatting.c:926
#define NUM_CACHE_SIZE
Definition: formatting.c:388
static NUMCacheEntry * NUM_cache_fetch(const char *str)
Definition: formatting.c:4978
#define NUM_FLAG
Definition: formatting.c:100
#define zeroize_NUM(_n)
Definition: formatting.c:4871
static const int NUM_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:998
NUMDesc Num
Definition: formatting.c:409
FormatNode format[NUM_CACHE_SIZE+1]
Definition: formatting.c:405
int pre_lsign_num
Definition: formatting.c:316
int need_locale
Definition: formatting.c:320
int zero_end
Definition: formatting.c:319
int flag
Definition: formatting.c:315
int lsign
Definition: formatting.c:314
int zero_start
Definition: formatting.c:318

References NUMDesc::flag, NUMCacheEntry::format, format, len, NUMDesc::lsign, NUMDesc::multi, NUMDesc::need_locale, NUMCacheEntry::Num, NUM_cache_fetch(), NUM_CACHE_SIZE, NUM_FLAG, NUM_index, NUM_keywords, palloc(), parse_format(), pfree(), NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, str, text_to_cstring(), NUMDesc::zero_end, NUMDesc::zero_start, and zeroize_NUM.

Referenced by numeric_to_number().

◆ NUM_cache_fetch()

static NUMCacheEntry * NUM_cache_fetch ( const char *  str)
static

Definition at line 4978 of file formatting.c.

4979{
4980 NUMCacheEntry *ent;
4981
4982 if ((ent = NUM_cache_search(str)) == NULL)
4983 {
4984 /*
4985 * Not in the cache, must run parser and save a new format-picture to
4986 * the cache. Do not mark the cache entry valid until parsing
4987 * succeeds.
4988 */
4989 ent = NUM_cache_getnew(str);
4990
4991 zeroize_NUM(&ent->Num);
4992
4994 NULL, NUM_index, NUM_FLAG, &ent->Num);
4995
4996 ent->valid = true;
4997 }
4998 return ent;
4999}
static NUMCacheEntry * NUM_cache_getnew(const char *str)
Definition: formatting.c:4898
static NUMCacheEntry * NUM_cache_search(const char *str)
Definition: formatting.c:4957

References NUMCacheEntry::format, NUMCacheEntry::Num, NUM_cache_getnew(), NUM_cache_search(), NUM_FLAG, NUM_index, NUM_keywords, parse_format(), str, NUMCacheEntry::valid, and zeroize_NUM.

Referenced by NUM_cache().

◆ NUM_cache_getnew()

static NUMCacheEntry * NUM_cache_getnew ( const char *  str)
static

Definition at line 4898 of file formatting.c.

4899{
4900 NUMCacheEntry *ent;
4901
4902 /* Ensure we can advance NUMCounter below */
4904
4905 /*
4906 * If cache is full, remove oldest entry (or recycle first not-valid one)
4907 */
4909 {
4910 NUMCacheEntry *old = NUMCache[0];
4911
4912#ifdef DEBUG_TO_FROM_CHAR
4913 elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
4914#endif
4915 if (old->valid)
4916 {
4917 for (int i = 1; i < NUM_CACHE_ENTRIES; i++)
4918 {
4919 ent = NUMCache[i];
4920 if (!ent->valid)
4921 {
4922 old = ent;
4923 break;
4924 }
4925 if (ent->age < old->age)
4926 old = ent;
4927 }
4928 }
4929#ifdef DEBUG_TO_FROM_CHAR
4930 elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
4931#endif
4932 old->valid = false;
4933 strlcpy(old->str, str, NUM_CACHE_SIZE + 1);
4934 old->age = (++NUMCounter);
4935 /* caller is expected to fill format and Num, then set valid */
4936 return old;
4937 }
4938 else
4939 {
4940#ifdef DEBUG_TO_FROM_CHAR
4941 elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
4942#endif
4943 Assert(NUMCache[n_NUMCache] == NULL);
4944 NUMCache[n_NUMCache] = ent = (NUMCacheEntry *)
4946 ent->valid = false;
4947 strlcpy(ent->str, str, NUM_CACHE_SIZE + 1);
4948 ent->age = (++NUMCounter);
4949 /* caller is expected to fill format and Num, then set valid */
4950 ++n_NUMCache;
4951 return ent;
4952 }
4953}
static NUMCacheEntry * NUMCache[NUM_CACHE_ENTRIES]
Definition: formatting.c:418
#define NUM_CACHE_ENTRIES
Definition: formatting.c:392
static void NUM_prevent_counter_overflow(void)
Definition: formatting.c:4886
static int NUMCounter
Definition: formatting.c:420
static int n_NUMCache
Definition: formatting.c:419
char str[NUM_CACHE_SIZE+1]
Definition: formatting.c:406

References NUMCacheEntry::age, Assert(), elog, i, MemoryContextAllocZero(), n_NUMCache, NUM_CACHE_ENTRIES, NUM_CACHE_SIZE, NUM_prevent_counter_overflow(), NUMCache, NUMCounter, NUMCacheEntry::str, str, strlcpy(), TopMemoryContext, and NUMCacheEntry::valid.

Referenced by NUM_cache_fetch().

◆ NUM_cache_search()

static NUMCacheEntry * NUM_cache_search ( const char *  str)
static

Definition at line 4957 of file formatting.c.

4958{
4959 /* Ensure we can advance NUMCounter below */
4961
4962 for (int i = 0; i < n_NUMCache; i++)
4963 {
4964 NUMCacheEntry *ent = NUMCache[i];
4965
4966 if (ent->valid && strcmp(ent->str, str) == 0)
4967 {
4968 ent->age = (++NUMCounter);
4969 return ent;
4970 }
4971 }
4972
4973 return NULL;
4974}

References NUMCacheEntry::age, i, n_NUMCache, NUM_prevent_counter_overflow(), NUMCache, NUMCounter, NUMCacheEntry::str, str, and NUMCacheEntry::valid.

Referenced by NUM_cache_fetch().

◆ NUM_eat_non_data_chars()

static void NUM_eat_non_data_chars ( NUMProc Np,
int  n,
int  input_len 
)
static

Definition at line 5794 of file formatting.c.

5795{
5796 while (n-- > 0)
5797 {
5798 if (OVERLOAD_TEST)
5799 break; /* end of input */
5800 if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
5801 break; /* it's a data character */
5802 Np->inout_p += pg_mblen(Np->inout_p);
5803 }
5804}
#define OVERLOAD_TEST
Definition: formatting.c:1061
char * inout_p
Definition: formatting.c:1041

References NUMProc::inout_p, OVERLOAD_TEST, and pg_mblen().

Referenced by NUM_processor().

◆ NUM_numpart_from_char()

static void NUM_numpart_from_char ( NUMProc Np,
int  id,
int  input_len 
)
static

Definition at line 5389 of file formatting.c.

5390{
5391 bool isread = false;
5392
5393#ifdef DEBUG_TO_FROM_CHAR
5394 elog(DEBUG_elog_output, " --- scan start --- id=%s",
5395 (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
5396#endif
5397
5398 if (OVERLOAD_TEST)
5399 return;
5400
5401 if (*Np->inout_p == ' ')
5402 Np->inout_p++;
5403
5404 if (OVERLOAD_TEST)
5405 return;
5406
5407 /*
5408 * read sign before number
5409 */
5410 if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
5411 (Np->read_pre + Np->read_post) == 0)
5412 {
5413#ifdef DEBUG_TO_FROM_CHAR
5414 elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
5415 *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
5416#endif
5417
5418 /*
5419 * locale sign
5420 */
5421 if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
5422 {
5423 int x = 0;
5424
5425#ifdef DEBUG_TO_FROM_CHAR
5426 elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
5427#endif
5428 if ((x = strlen(Np->L_negative_sign)) &&
5429 AMOUNT_TEST(x) &&
5430 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
5431 {
5432 Np->inout_p += x;
5433 *Np->number = '-';
5434 }
5435 else if ((x = strlen(Np->L_positive_sign)) &&
5436 AMOUNT_TEST(x) &&
5437 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
5438 {
5439 Np->inout_p += x;
5440 *Np->number = '+';
5441 }
5442 }
5443 else
5444 {
5445#ifdef DEBUG_TO_FROM_CHAR
5446 elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
5447#endif
5448
5449 /*
5450 * simple + - < >
5451 */
5452 if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
5453 *Np->inout_p == '<'))
5454 {
5455 *Np->number = '-'; /* set - */
5456 Np->inout_p++;
5457 }
5458 else if (*Np->inout_p == '+')
5459 {
5460 *Np->number = '+'; /* set + */
5461 Np->inout_p++;
5462 }
5463 }
5464 }
5465
5466 if (OVERLOAD_TEST)
5467 return;
5468
5469#ifdef DEBUG_TO_FROM_CHAR
5470 elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
5471#endif
5472
5473 /*
5474 * read digit or decimal point
5475 */
5476 if (isdigit((unsigned char) *Np->inout_p))
5477 {
5478 if (Np->read_dec && Np->read_post == Np->Num->post)
5479 return;
5480
5481 *Np->number_p = *Np->inout_p;
5482 Np->number_p++;
5483
5484 if (Np->read_dec)
5485 Np->read_post++;
5486 else
5487 Np->read_pre++;
5488
5489 isread = true;
5490
5491#ifdef DEBUG_TO_FROM_CHAR
5492 elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
5493#endif
5494 }
5495 else if (IS_DECIMAL(Np->Num) && Np->read_dec == false)
5496 {
5497 /*
5498 * We need not test IS_LDECIMAL(Np->Num) explicitly here, because
5499 * Np->decimal is always just "." if we don't have a D format token.
5500 * So we just unconditionally match to Np->decimal.
5501 */
5502 int x = strlen(Np->decimal);
5503
5504#ifdef DEBUG_TO_FROM_CHAR
5505 elog(DEBUG_elog_output, "Try read decimal point (%c)",
5506 *Np->inout_p);
5507#endif
5508 if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
5509 {
5510 Np->inout_p += x - 1;
5511 *Np->number_p = '.';
5512 Np->number_p++;
5513 Np->read_dec = true;
5514 isread = true;
5515 }
5516 }
5517
5518 if (OVERLOAD_TEST)
5519 return;
5520
5521 /*
5522 * Read sign behind "last" number
5523 *
5524 * We need sign detection because determine exact position of post-sign is
5525 * difficult:
5526 *
5527 * FM9999.9999999S -> 123.001- 9.9S -> .5- FM9.999999MI ->
5528 * 5.01-
5529 */
5530 if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
5531 {
5532 /*
5533 * locale sign (NUM_S) is always anchored behind a last number, if: -
5534 * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
5535 * next char is not digit
5536 */
5537 if (IS_LSIGN(Np->Num) && isread &&
5538 (Np->inout_p + 1) < Np->inout + input_len &&
5539 !isdigit((unsigned char) *(Np->inout_p + 1)))
5540 {
5541 int x;
5542 char *tmp = Np->inout_p++;
5543
5544#ifdef DEBUG_TO_FROM_CHAR
5545 elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
5546#endif
5547 if ((x = strlen(Np->L_negative_sign)) &&
5548 AMOUNT_TEST(x) &&
5549 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
5550 {
5551 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
5552 *Np->number = '-';
5553 }
5554 else if ((x = strlen(Np->L_positive_sign)) &&
5555 AMOUNT_TEST(x) &&
5556 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
5557 {
5558 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
5559 *Np->number = '+';
5560 }
5561 if (*Np->number == ' ')
5562 /* no sign read */
5563 Np->inout_p = tmp;
5564 }
5565
5566 /*
5567 * try read non-locale sign, which happens only if format is not exact
5568 * and we cannot determine sign position of MI/PL/SG, an example:
5569 *
5570 * FM9.999999MI -> 5.01-
5571 *
5572 * if (.... && IS_LSIGN(Np->Num)==false) prevents read wrong formats
5573 * like to_number('1 -', '9S') where sign is not anchored to last
5574 * number.
5575 */
5576 else if (isread == false && IS_LSIGN(Np->Num) == false &&
5577 (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
5578 {
5579#ifdef DEBUG_TO_FROM_CHAR
5580 elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
5581#endif
5582
5583 /*
5584 * simple + -
5585 */
5586 if (*Np->inout_p == '-' || *Np->inout_p == '+')
5587 /* NUM_processor() do inout_p++ */
5588 *Np->number = *Np->inout_p;
5589 }
5590 }
5591}
#define NUM_LSIGN_PRE
Definition: formatting.c:342
#define IS_LSIGN(_f)
Definition: formatting.c:357
#define IS_BRACKET(_f)
Definition: formatting.c:355
#define AMOUNT_TEST(s)
Definition: formatting.c:1062
#define IS_MINUS(_f)
Definition: formatting.c:356
#define IS_DECIMAL(_f)
Definition: formatting.c:350
#define IS_PLUS(_f)
Definition: formatting.c:358
char * L_negative_sign
Definition: formatting.c:1044
char * L_positive_sign
Definition: formatting.c:1045
int read_post
Definition: formatting.c:1035
char * number_p
Definition: formatting.c:1039
char * decimal
Definition: formatting.c:1046
NUMDesc * Num
Definition: formatting.c:1025
char * number
Definition: formatting.c:1038
int read_pre
Definition: formatting.c:1036
int read_dec
Definition: formatting.c:1034
char * inout
Definition: formatting.c:1040

References AMOUNT_TEST, NUMProc::decimal, elog, 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, NUMProc::read_pre, and x.

Referenced by NUM_processor().

◆ NUM_numpart_to_char()

static void NUM_numpart_to_char ( NUMProc Np,
int  id 
)
static

Definition at line 5604 of file formatting.c.

5605{
5606 int end;
5607
5608 if (IS_ROMAN(Np->Num))
5609 return;
5610
5611 /* Note: in this elog() output not set '\0' in 'inout' */
5612
5613#ifdef DEBUG_TO_FROM_CHAR
5614
5615 /*
5616 * Np->num_curr is number of current item in format-picture, it is not
5617 * current position in inout!
5618 */
5619 elog(DEBUG_elog_output,
5620 "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
5621 Np->sign_wrote,
5622 Np->num_curr,
5623 Np->number_p,
5624 Np->inout);
5625#endif
5626 Np->num_in = false;
5627
5628 /*
5629 * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
5630 * handle "9.9" --> " .1"
5631 */
5632 if (Np->sign_wrote == false &&
5633 (Np->num_curr >= Np->out_pre_spaces || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
5634 (IS_PREDEC_SPACE(Np) == false || (Np->last_relevant && *Np->last_relevant == '.')))
5635 {
5636 if (IS_LSIGN(Np->Num))
5637 {
5638 if (Np->Num->lsign == NUM_LSIGN_PRE)
5639 {
5640 if (Np->sign == '-')
5641 strcpy(Np->inout_p, Np->L_negative_sign);
5642 else
5643 strcpy(Np->inout_p, Np->L_positive_sign);
5644 Np->inout_p += strlen(Np->inout_p);
5645 Np->sign_wrote = true;
5646 }
5647 }
5648 else if (IS_BRACKET(Np->Num))
5649 {
5650 *Np->inout_p = Np->sign == '+' ? ' ' : '<';
5651 ++Np->inout_p;
5652 Np->sign_wrote = true;
5653 }
5654 else if (Np->sign == '+')
5655 {
5656 if (!IS_FILLMODE(Np->Num))
5657 {
5658 *Np->inout_p = ' '; /* Write + */
5659 ++Np->inout_p;
5660 }
5661 Np->sign_wrote = true;
5662 }
5663 else if (Np->sign == '-')
5664 { /* Write - */
5665 *Np->inout_p = '-';
5666 ++Np->inout_p;
5667 Np->sign_wrote = true;
5668 }
5669 }
5670
5671
5672 /*
5673 * digits / FM / Zero / Dec. point
5674 */
5675 if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
5676 {
5677 if (Np->num_curr < Np->out_pre_spaces &&
5678 (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
5679 {
5680 /*
5681 * Write blank space
5682 */
5683 if (!IS_FILLMODE(Np->Num))
5684 {
5685 *Np->inout_p = ' '; /* Write ' ' */
5686 ++Np->inout_p;
5687 }
5688 }
5689 else if (IS_ZERO(Np->Num) &&
5690 Np->num_curr < Np->out_pre_spaces &&
5691 Np->Num->zero_start <= Np->num_curr)
5692 {
5693 /*
5694 * Write ZERO
5695 */
5696 *Np->inout_p = '0'; /* Write '0' */
5697 ++Np->inout_p;
5698 Np->num_in = true;
5699 }
5700 else
5701 {
5702 /*
5703 * Write Decimal point
5704 */
5705 if (*Np->number_p == '.')
5706 {
5707 if (!Np->last_relevant || *Np->last_relevant != '.')
5708 {
5709 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
5710 Np->inout_p += strlen(Np->inout_p);
5711 }
5712
5713 /*
5714 * Ora 'n' -- FM9.9 --> 'n.'
5715 */
5716 else if (IS_FILLMODE(Np->Num) &&
5717 Np->last_relevant && *Np->last_relevant == '.')
5718 {
5719 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
5720 Np->inout_p += strlen(Np->inout_p);
5721 }
5722 }
5723 else
5724 {
5725 /*
5726 * Write Digits
5727 */
5728 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
5729 id != NUM_0)
5730 ;
5731
5732 /*
5733 * '0.1' -- 9.9 --> ' .1'
5734 */
5735 else if (IS_PREDEC_SPACE(Np))
5736 {
5737 if (!IS_FILLMODE(Np->Num))
5738 {
5739 *Np->inout_p = ' ';
5740 ++Np->inout_p;
5741 }
5742
5743 /*
5744 * '0' -- FM9.9 --> '0.'
5745 */
5746 else if (Np->last_relevant && *Np->last_relevant == '.')
5747 {
5748 *Np->inout_p = '0';
5749 ++Np->inout_p;
5750 }
5751 }
5752 else
5753 {
5754 *Np->inout_p = *Np->number_p; /* Write DIGIT */
5755 ++Np->inout_p;
5756 Np->num_in = true;
5757 }
5758 }
5759 /* do no exceed string length */
5760 if (*Np->number_p)
5761 ++Np->number_p;
5762 }
5763
5764 end = Np->num_count + (Np->out_pre_spaces ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
5765
5766 if (Np->last_relevant && Np->last_relevant == Np->number_p)
5767 end = Np->num_curr;
5768
5769 if (Np->num_curr + 1 == end)
5770 {
5771 if (Np->sign_wrote == true && IS_BRACKET(Np->Num))
5772 {
5773 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
5774 ++Np->inout_p;
5775 }
5776 else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
5777 {
5778 if (Np->sign == '-')
5779 strcpy(Np->inout_p, Np->L_negative_sign);
5780 else
5781 strcpy(Np->inout_p, Np->L_positive_sign);
5782 Np->inout_p += strlen(Np->inout_p);
5783 }
5784 }
5785 }
5786
5787 ++Np->num_curr;
5788}
#define IS_FILLMODE(_f)
Definition: formatting.c:354
#define NUM_LSIGN_POST
Definition: formatting.c:343
#define IS_PREDEC_SPACE(_n)
Definition: formatting.c:5593
int num_curr
Definition: formatting.c:1031
int num_in
Definition: formatting.c:1030
int out_pre_spaces
Definition: formatting.c:1032
int sign
Definition: formatting.c:1027
char * last_relevant
Definition: formatting.c:1042
int sign_wrote
Definition: formatting.c:1028
int num_count
Definition: formatting.c:1029

References NUMProc::decimal, elog, 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_POST, NUM_LSIGN_PRE, NUMProc::number_p, NUMProc::out_pre_spaces, NUMProc::sign, NUMProc::sign_wrote, and NUMDesc::zero_start.

Referenced by NUM_processor().

◆ NUM_prepare_locale()

static void NUM_prepare_locale ( NUMProc Np)
static

Definition at line 5279 of file formatting.c.

5280{
5281 if (Np->Num->need_locale)
5282 {
5283 struct lconv *lconv;
5284
5285 /*
5286 * Get locales
5287 */
5288 lconv = PGLC_localeconv();
5289
5290 /*
5291 * Positive / Negative number sign
5292 */
5293 if (lconv->negative_sign && *lconv->negative_sign)
5294 Np->L_negative_sign = lconv->negative_sign;
5295 else
5296 Np->L_negative_sign = "-";
5297
5298 if (lconv->positive_sign && *lconv->positive_sign)
5299 Np->L_positive_sign = lconv->positive_sign;
5300 else
5301 Np->L_positive_sign = "+";
5302
5303 /*
5304 * Number decimal point
5305 */
5306 if (lconv->decimal_point && *lconv->decimal_point)
5307 Np->decimal = lconv->decimal_point;
5308
5309 else
5310 Np->decimal = ".";
5311
5312 if (!IS_LDECIMAL(Np->Num))
5313 Np->decimal = ".";
5314
5315 /*
5316 * Number thousands separator
5317 *
5318 * Some locales (e.g. broken glibc pt_BR), have a comma for decimal,
5319 * but "" for thousands_sep, so we set the thousands_sep too.
5320 * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php
5321 */
5322 if (lconv->thousands_sep && *lconv->thousands_sep)
5323 Np->L_thousands_sep = lconv->thousands_sep;
5324 /* Make sure thousands separator doesn't match decimal point symbol. */
5325 else if (strcmp(Np->decimal, ",") != 0)
5326 Np->L_thousands_sep = ",";
5327 else
5328 Np->L_thousands_sep = ".";
5329
5330 /*
5331 * Currency symbol
5332 */
5333 if (lconv->currency_symbol && *lconv->currency_symbol)
5334 Np->L_currency_symbol = lconv->currency_symbol;
5335 else
5336 Np->L_currency_symbol = " ";
5337 }
5338 else
5339 {
5340 /*
5341 * Default values
5342 */
5343 Np->L_negative_sign = "-";
5344 Np->L_positive_sign = "+";
5345 Np->decimal = ".";
5346
5347 Np->L_thousands_sep = ",";
5348 Np->L_currency_symbol = " ";
5349 }
5350}
#define IS_LDECIMAL(_f)
Definition: formatting.c:351
struct lconv * PGLC_localeconv(void)
Definition: pg_locale.c:499
char * L_currency_symbol
Definition: formatting.c:1048
char * L_thousands_sep
Definition: formatting.c:1047

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().

◆ NUM_prevent_counter_overflow()

static void NUM_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 4886 of file formatting.c.

4887{
4888 if (NUMCounter >= (INT_MAX - 1))
4889 {
4890 for (int i = 0; i < n_NUMCache; i++)
4891 NUMCache[i]->age >>= 1;
4892 NUMCounter >>= 1;
4893 }
4894}

References i, n_NUMCache, NUMCache, and NUMCounter.

Referenced by NUM_cache_getnew(), and NUM_cache_search().

◆ NUM_processor()

static char * NUM_processor ( FormatNode node,
NUMDesc Num,
char *  inout,
char *  number,
int  input_len,
int  to_char_out_pre_spaces,
int  sign,
bool  is_to_char,
Oid  collid 
)
static

Definition at line 5807 of file formatting.c.

5810{
5811 FormatNode *n;
5812 NUMProc _Np,
5813 *Np = &_Np;
5814 const char *pattern;
5815 int pattern_len;
5816
5817 MemSet(Np, 0, sizeof(NUMProc));
5818
5819 Np->Num = Num;
5820 Np->is_to_char = is_to_char;
5821 Np->number = number;
5822 Np->inout = inout;
5823 Np->last_relevant = NULL;
5824 Np->read_post = 0;
5825 Np->read_pre = 0;
5826 Np->read_dec = false;
5827
5828 if (Np->Num->zero_start)
5829 --Np->Num->zero_start;
5830
5831 if (IS_EEEE(Np->Num))
5832 {
5833 if (!Np->is_to_char)
5834 ereport(ERROR,
5835 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5836 errmsg("\"EEEE\" not supported for input")));
5837 return strcpy(inout, number);
5838 }
5839
5840 /*
5841 * Sign
5842 */
5843 if (is_to_char)
5844 {
5845 Np->sign = sign;
5846
5847 /* MI/PL/SG - write sign itself and not in number */
5848 if (IS_PLUS(Np->Num) || IS_MINUS(Np->Num))
5849 {
5850 if (IS_PLUS(Np->Num) && IS_MINUS(Np->Num) == false)
5851 Np->sign_wrote = false; /* need sign */
5852 else
5853 Np->sign_wrote = true; /* needn't sign */
5854 }
5855 else
5856 {
5857 if (Np->sign != '-')
5858 {
5859 if (IS_FILLMODE(Np->Num))
5860 Np->Num->flag &= ~NUM_F_BRACKET;
5861 }
5862
5863 if (Np->sign == '+' && IS_FILLMODE(Np->Num) && IS_LSIGN(Np->Num) == false)
5864 Np->sign_wrote = true; /* needn't sign */
5865 else
5866 Np->sign_wrote = false; /* need sign */
5867
5868 if (Np->Num->lsign == NUM_LSIGN_PRE && Np->Num->pre == Np->Num->pre_lsign_num)
5869 Np->Num->lsign = NUM_LSIGN_POST;
5870 }
5871 }
5872 else
5873 Np->sign = false;
5874
5875 /*
5876 * Count
5877 */
5878 Np->num_count = Np->Num->post + Np->Num->pre - 1;
5879
5880 if (is_to_char)
5881 {
5882 Np->out_pre_spaces = to_char_out_pre_spaces;
5883
5884 if (IS_FILLMODE(Np->Num) && IS_DECIMAL(Np->Num))
5885 {
5887
5888 /*
5889 * If any '0' specifiers are present, make sure we don't strip
5890 * those digits. But don't advance last_relevant beyond the last
5891 * character of the Np->number string, which is a hazard if the
5892 * number got shortened due to precision limitations.
5893 */
5894 if (Np->last_relevant && Np->Num->zero_end > Np->out_pre_spaces)
5895 {
5896 int last_zero_pos;
5897 char *last_zero;
5898
5899 /* note that Np->number cannot be zero-length here */
5900 last_zero_pos = strlen(Np->number) - 1;
5901 last_zero_pos = Min(last_zero_pos,
5902 Np->Num->zero_end - Np->out_pre_spaces);
5903 last_zero = Np->number + last_zero_pos;
5904 if (Np->last_relevant < last_zero)
5905 Np->last_relevant = last_zero;
5906 }
5907 }
5908
5909 if (Np->sign_wrote == false && Np->out_pre_spaces == 0)
5910 ++Np->num_count;
5911 }
5912 else
5913 {
5914 Np->out_pre_spaces = 0;
5915 *Np->number = ' '; /* sign space */
5916 *(Np->number + 1) = '\0';
5917 }
5918
5919 Np->num_in = 0;
5920 Np->num_curr = 0;
5921
5922#ifdef DEBUG_TO_FROM_CHAR
5923 elog(DEBUG_elog_output,
5924 "\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",
5925 Np->sign,
5926 Np->number,
5927 Np->Num->pre,
5928 Np->Num->post,
5929 Np->num_count,
5930 Np->out_pre_spaces,
5931 Np->sign_wrote ? "Yes" : "No",
5932 IS_ZERO(Np->Num) ? "Yes" : "No",
5933 Np->Num->zero_start,
5934 Np->Num->zero_end,
5935 Np->last_relevant ? Np->last_relevant : "<not set>",
5936 IS_BRACKET(Np->Num) ? "Yes" : "No",
5937 IS_PLUS(Np->Num) ? "Yes" : "No",
5938 IS_MINUS(Np->Num) ? "Yes" : "No",
5939 IS_FILLMODE(Np->Num) ? "Yes" : "No",
5940 IS_ROMAN(Np->Num) ? "Yes" : "No",
5941 IS_EEEE(Np->Num) ? "Yes" : "No"
5942 );
5943#endif
5944
5945 /*
5946 * Locale
5947 */
5949
5950 /*
5951 * Processor direct cycle
5952 */
5953 if (Np->is_to_char)
5954 Np->number_p = Np->number;
5955 else
5956 Np->number_p = Np->number + 1; /* first char is space for sign */
5957
5958 for (n = node, Np->inout_p = Np->inout; n->type != NODE_TYPE_END; n++)
5959 {
5960 if (!Np->is_to_char)
5961 {
5962 /*
5963 * Check at least one byte remains to be scanned. (In actions
5964 * below, must use AMOUNT_TEST if we want to read more bytes than
5965 * that.)
5966 */
5967 if (OVERLOAD_TEST)
5968 break;
5969 }
5970
5971 /*
5972 * Format pictures actions
5973 */
5974 if (n->type == NODE_TYPE_ACTION)
5975 {
5976 /*
5977 * Create/read digit/zero/blank/sign/special-case
5978 *
5979 * 'NUM_S' note: The locale sign is anchored to number and we
5980 * read/write it when we work with first or last number
5981 * (NUM_0/NUM_9). This is why NUM_S is missing in switch().
5982 *
5983 * Notice the "Np->inout_p++" at the bottom of the loop. This is
5984 * why most of the actions advance inout_p one less than you might
5985 * expect. In cases where we don't want that increment to happen,
5986 * a switch case ends with "continue" not "break".
5987 */
5988 switch (n->key->id)
5989 {
5990 case NUM_9:
5991 case NUM_0:
5992 case NUM_DEC:
5993 case NUM_D:
5994 if (Np->is_to_char)
5995 {
5996 NUM_numpart_to_char(Np, n->key->id);
5997 continue; /* for() */
5998 }
5999 else
6000 {
6001 NUM_numpart_from_char(Np, n->key->id, input_len);
6002 break; /* switch() case: */
6003 }
6004
6005 case NUM_COMMA:
6006 if (Np->is_to_char)
6007 {
6008 if (!Np->num_in)
6009 {
6010 if (IS_FILLMODE(Np->Num))
6011 continue;
6012 else
6013 *Np->inout_p = ' ';
6014 }
6015 else
6016 *Np->inout_p = ',';
6017 }
6018 else
6019 {
6020 if (!Np->num_in)
6021 {
6022 if (IS_FILLMODE(Np->Num))
6023 continue;
6024 }
6025 if (*Np->inout_p != ',')
6026 continue;
6027 }
6028 break;
6029
6030 case NUM_G:
6031 pattern = Np->L_thousands_sep;
6032 pattern_len = strlen(pattern);
6033 if (Np->is_to_char)
6034 {
6035 if (!Np->num_in)
6036 {
6037 if (IS_FILLMODE(Np->Num))
6038 continue;
6039 else
6040 {
6041 /* just in case there are MB chars */
6042 pattern_len = pg_mbstrlen(pattern);
6043 memset(Np->inout_p, ' ', pattern_len);
6044 Np->inout_p += pattern_len - 1;
6045 }
6046 }
6047 else
6048 {
6049 strcpy(Np->inout_p, pattern);
6050 Np->inout_p += pattern_len - 1;
6051 }
6052 }
6053 else
6054 {
6055 if (!Np->num_in)
6056 {
6057 if (IS_FILLMODE(Np->Num))
6058 continue;
6059 }
6060
6061 /*
6062 * Because L_thousands_sep typically contains data
6063 * characters (either '.' or ','), we can't use
6064 * NUM_eat_non_data_chars here. Instead skip only if
6065 * the input matches L_thousands_sep.
6066 */
6067 if (AMOUNT_TEST(pattern_len) &&
6068 strncmp(Np->inout_p, pattern, pattern_len) == 0)
6069 Np->inout_p += pattern_len - 1;
6070 else
6071 continue;
6072 }
6073 break;
6074
6075 case NUM_L:
6076 pattern = Np->L_currency_symbol;
6077 if (Np->is_to_char)
6078 {
6079 strcpy(Np->inout_p, pattern);
6080 Np->inout_p += strlen(pattern) - 1;
6081 }
6082 else
6083 {
6084 NUM_eat_non_data_chars(Np, pg_mbstrlen(pattern), input_len);
6085 continue;
6086 }
6087 break;
6088
6089 case NUM_RN:
6090 case NUM_rn:
6091 if (Np->is_to_char)
6092 {
6093 const char *number_p;
6094
6095 if (n->key->id == NUM_rn)
6096 number_p = asc_tolower_z(Np->number_p);
6097 else
6098 number_p = Np->number_p;
6099 if (IS_FILLMODE(Np->Num))
6100 strcpy(Np->inout_p, number_p);
6101 else
6102 sprintf(Np->inout_p, "%15s", number_p);
6103 Np->inout_p += strlen(Np->inout_p) - 1;
6104 }
6105 else
6106 {
6107 int roman_result = roman_to_int(Np, input_len);
6108 int numlen;
6109
6110 if (roman_result < 0)
6111 ereport(ERROR,
6112 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
6113 errmsg("invalid Roman numeral")));
6114 numlen = sprintf(Np->number_p, "%d", roman_result);
6115 Np->number_p += numlen;
6116 Np->Num->pre = numlen;
6117 Np->Num->post = 0;
6118 continue; /* roman_to_int ate all the chars */
6119 }
6120 break;
6121
6122 case NUM_th:
6123 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
6124 Np->sign == '-' || IS_DECIMAL(Np->Num))
6125 continue;
6126
6127 if (Np->is_to_char)
6128 {
6129 strcpy(Np->inout_p, get_th(Np->number, TH_LOWER));
6130 Np->inout_p += 1;
6131 }
6132 else
6133 {
6134 /* All variants of 'th' occupy 2 characters */
6135 NUM_eat_non_data_chars(Np, 2, input_len);
6136 continue;
6137 }
6138 break;
6139
6140 case NUM_TH:
6141 if (IS_ROMAN(Np->Num) || *Np->number == '#' ||
6142 Np->sign == '-' || IS_DECIMAL(Np->Num))
6143 continue;
6144
6145 if (Np->is_to_char)
6146 {
6147 strcpy(Np->inout_p, get_th(Np->number, TH_UPPER));
6148 Np->inout_p += 1;
6149 }
6150 else
6151 {
6152 /* All variants of 'TH' occupy 2 characters */
6153 NUM_eat_non_data_chars(Np, 2, input_len);
6154 continue;
6155 }
6156 break;
6157
6158 case NUM_MI:
6159 if (Np->is_to_char)
6160 {
6161 if (Np->sign == '-')
6162 *Np->inout_p = '-';
6163 else if (IS_FILLMODE(Np->Num))
6164 continue;
6165 else
6166 *Np->inout_p = ' ';
6167 }
6168 else
6169 {
6170 if (*Np->inout_p == '-')
6171 *Np->number = '-';
6172 else
6173 {
6174 NUM_eat_non_data_chars(Np, 1, input_len);
6175 continue;
6176 }
6177 }
6178 break;
6179
6180 case NUM_PL:
6181 if (Np->is_to_char)
6182 {
6183 if (Np->sign == '+')
6184 *Np->inout_p = '+';
6185 else if (IS_FILLMODE(Np->Num))
6186 continue;
6187 else
6188 *Np->inout_p = ' ';
6189 }
6190 else
6191 {
6192 if (*Np->inout_p == '+')
6193 *Np->number = '+';
6194 else
6195 {
6196 NUM_eat_non_data_chars(Np, 1, input_len);
6197 continue;
6198 }
6199 }
6200 break;
6201
6202 case NUM_SG:
6203 if (Np->is_to_char)
6204 *Np->inout_p = Np->sign;
6205 else
6206 {
6207 if (*Np->inout_p == '-')
6208 *Np->number = '-';
6209 else if (*Np->inout_p == '+')
6210 *Np->number = '+';
6211 else
6212 {
6213 NUM_eat_non_data_chars(Np, 1, input_len);
6214 continue;
6215 }
6216 }
6217 break;
6218
6219 default:
6220 continue;
6221 break;
6222 }
6223 }
6224 else
6225 {
6226 /*
6227 * In TO_CHAR, non-pattern characters in the format are copied to
6228 * the output. In TO_NUMBER, we skip one input character for each
6229 * non-pattern format character, whether or not it matches the
6230 * format character.
6231 */
6232 if (Np->is_to_char)
6233 {
6234 strcpy(Np->inout_p, n->character);
6235 Np->inout_p += strlen(Np->inout_p);
6236 }
6237 else
6238 {
6239 Np->inout_p += pg_mblen(Np->inout_p);
6240 }
6241 continue;
6242 }
6243 Np->inout_p++;
6244 }
6245
6246 if (Np->is_to_char)
6247 {
6248 *Np->inout_p = '\0';
6249 return Np->inout;
6250 }
6251 else
6252 {
6253 if (*(Np->number_p - 1) == '.')
6254 *(Np->number_p - 1) = '\0';
6255 else
6256 *Np->number_p = '\0';
6257
6258 /*
6259 * Correction - precision of dec. number
6260 */
6261 Np->Num->post = Np->read_post;
6262
6263#ifdef DEBUG_TO_FROM_CHAR
6264 elog(DEBUG_elog_output, "TO_NUMBER (number): '%s'", Np->number);
6265#endif
6266 return Np->number;
6267 }
6268}
#define Min(x, y)
Definition: c.h:1004
#define MemSet(start, val, len)
Definition: c.h:1020
#define TH_LOWER
Definition: formatting.c:304
static void NUM_numpart_to_char(NUMProc *Np, int id)
Definition: formatting.c:5604
static void NUM_numpart_from_char(NUMProc *Np, int id, int input_len)
Definition: formatting.c:5389
static char * get_last_relevant_decnum(char *num)
Definition: formatting.c:5361
static int roman_to_int(NUMProc *Np, int input_len)
Definition: formatting.c:5129
static void NUM_prepare_locale(NUMProc *Np)
Definition: formatting.c:5279
static void NUM_eat_non_data_chars(NUMProc *Np, int n, int input_len)
Definition: formatting.c:5794
static const char * get_th(char *num, int type)
Definition: formatting.c:1563
int pg_mbstrlen(const char *mbstr)
Definition: mbutils.c:1038
bool is_to_char
Definition: formatting.c:1024

References AMOUNT_TEST, asc_tolower_z(), FormatNode::character, elog, ereport, errcode(), errmsg(), ERROR, 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, Min, 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_eat_non_data_chars(), NUM_G, NUMProc::num_in, NUM_L, NUM_LSIGN_POST, NUM_LSIGN_PRE, NUM_MI, NUM_numpart_from_char(), NUM_numpart_to_char(), NUM_PL, NUM_prepare_locale(), NUM_RN, NUM_rn, NUM_SG, NUM_TH, NUM_th, NUMProc::number, NUMProc::number_p, NUMProc::out_pre_spaces, OVERLOAD_TEST, pg_mblen(), pg_mbstrlen(), NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, NUMProc::read_dec, NUMProc::read_post, NUMProc::read_pre, roman_to_int(), NUMProc::sign, sign, NUMProc::sign_wrote, sprintf, TH_LOWER, TH_UPPER, FormatNode::type, NUMDesc::zero_end, and NUMDesc::zero_start.

Referenced by numeric_to_number().

◆ NUMDesc_prepare()

static void NUMDesc_prepare ( NUMDesc num,
FormatNode n 
)
static

Definition at line 1189 of file formatting.c.

1190{
1191 if (n->type != NODE_TYPE_ACTION)
1192 return;
1193
1194 if (IS_EEEE(num) && n->key->id != NUM_E)
1195 ereport(ERROR,
1196 (errcode(ERRCODE_SYNTAX_ERROR),
1197 errmsg("\"EEEE\" must be the last pattern used")));
1198
1199 switch (n->key->id)
1200 {
1201 case NUM_9:
1202 if (IS_BRACKET(num))
1203 ereport(ERROR,
1204 (errcode(ERRCODE_SYNTAX_ERROR),
1205 errmsg("\"9\" must be ahead of \"PR\"")));
1206 if (IS_MULTI(num))
1207 {
1208 ++num->multi;
1209 break;
1210 }
1211 if (IS_DECIMAL(num))
1212 ++num->post;
1213 else
1214 ++num->pre;
1215 break;
1216
1217 case NUM_0:
1218 if (IS_BRACKET(num))
1219 ereport(ERROR,
1220 (errcode(ERRCODE_SYNTAX_ERROR),
1221 errmsg("\"0\" must be ahead of \"PR\"")));
1222 if (!IS_ZERO(num) && !IS_DECIMAL(num))
1223 {
1224 num->flag |= NUM_F_ZERO;
1225 num->zero_start = num->pre + 1;
1226 }
1227 if (!IS_DECIMAL(num))
1228 ++num->pre;
1229 else
1230 ++num->post;
1231
1232 num->zero_end = num->pre + num->post;
1233 break;
1234
1235 case NUM_B:
1236 if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num)))
1237 num->flag |= NUM_F_BLANK;
1238 break;
1239
1240 case NUM_D:
1241 num->flag |= NUM_F_LDECIMAL;
1242 num->need_locale = true;
1243 /* FALLTHROUGH */
1244 case NUM_DEC:
1245 if (IS_DECIMAL(num))
1246 ereport(ERROR,
1247 (errcode(ERRCODE_SYNTAX_ERROR),
1248 errmsg("multiple decimal points")));
1249 if (IS_MULTI(num))
1250 ereport(ERROR,
1251 (errcode(ERRCODE_SYNTAX_ERROR),
1252 errmsg("cannot use \"V\" and decimal point together")));
1253 num->flag |= NUM_F_DECIMAL;
1254 break;
1255
1256 case NUM_FM:
1257 num->flag |= NUM_F_FILLMODE;
1258 break;
1259
1260 case NUM_S:
1261 if (IS_LSIGN(num))
1262 ereport(ERROR,
1263 (errcode(ERRCODE_SYNTAX_ERROR),
1264 errmsg("cannot use \"S\" twice")));
1265 if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
1266 ereport(ERROR,
1267 (errcode(ERRCODE_SYNTAX_ERROR),
1268 errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
1269 if (!IS_DECIMAL(num))
1270 {
1271 num->lsign = NUM_LSIGN_PRE;
1272 num->pre_lsign_num = num->pre;
1273 num->need_locale = true;
1274 num->flag |= NUM_F_LSIGN;
1275 }
1276 else if (num->lsign == NUM_LSIGN_NONE)
1277 {
1278 num->lsign = NUM_LSIGN_POST;
1279 num->need_locale = true;
1280 num->flag |= NUM_F_LSIGN;
1281 }
1282 break;
1283
1284 case NUM_MI:
1285 if (IS_LSIGN(num))
1286 ereport(ERROR,
1287 (errcode(ERRCODE_SYNTAX_ERROR),
1288 errmsg("cannot use \"S\" and \"MI\" together")));
1289 num->flag |= NUM_F_MINUS;
1290 if (IS_DECIMAL(num))
1291 num->flag |= NUM_F_MINUS_POST;
1292 break;
1293
1294 case NUM_PL:
1295 if (IS_LSIGN(num))
1296 ereport(ERROR,
1297 (errcode(ERRCODE_SYNTAX_ERROR),
1298 errmsg("cannot use \"S\" and \"PL\" together")));
1299 num->flag |= NUM_F_PLUS;
1300 if (IS_DECIMAL(num))
1301 num->flag |= NUM_F_PLUS_POST;
1302 break;
1303
1304 case NUM_SG:
1305 if (IS_LSIGN(num))
1306 ereport(ERROR,
1307 (errcode(ERRCODE_SYNTAX_ERROR),
1308 errmsg("cannot use \"S\" and \"SG\" together")));
1309 num->flag |= NUM_F_MINUS;
1310 num->flag |= NUM_F_PLUS;
1311 break;
1312
1313 case NUM_PR:
1314 if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
1315 ereport(ERROR,
1316 (errcode(ERRCODE_SYNTAX_ERROR),
1317 errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
1318 num->flag |= NUM_F_BRACKET;
1319 break;
1320
1321 case NUM_rn:
1322 case NUM_RN:
1323 if (IS_ROMAN(num))
1324 ereport(ERROR,
1325 (errcode(ERRCODE_SYNTAX_ERROR),
1326 errmsg("cannot use \"RN\" twice")));
1327 num->flag |= NUM_F_ROMAN;
1328 break;
1329
1330 case NUM_L:
1331 case NUM_G:
1332 num->need_locale = true;
1333 break;
1334
1335 case NUM_V:
1336 if (IS_DECIMAL(num))
1337 ereport(ERROR,
1338 (errcode(ERRCODE_SYNTAX_ERROR),
1339 errmsg("cannot use \"V\" and decimal point together")));
1340 num->flag |= NUM_F_MULTI;
1341 break;
1342
1343 case NUM_E:
1344 if (IS_EEEE(num))
1345 ereport(ERROR,
1346 (errcode(ERRCODE_SYNTAX_ERROR),
1347 errmsg("cannot use \"EEEE\" twice")));
1348 if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) ||
1349 IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) ||
1350 IS_ROMAN(num) || IS_MULTI(num))
1351 ereport(ERROR,
1352 (errcode(ERRCODE_SYNTAX_ERROR),
1353 errmsg("\"EEEE\" is incompatible with other formats"),
1354 errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
1355 num->flag |= NUM_F_EEEE;
1356 break;
1357 }
1358
1359 if (IS_ROMAN(num) &&
1360 (num->flag & ~(NUM_F_ROMAN | NUM_F_FILLMODE)) != 0)
1361 ereport(ERROR,
1362 (errcode(ERRCODE_SYNTAX_ERROR),
1363 errmsg("\"RN\" is incompatible with other formats"),
1364 errdetail("\"RN\" may only be used together with \"FM\".")));
1365}
#define NUM_F_MINUS
Definition: formatting.c:334
#define NUM_F_DECIMAL
Definition: formatting.c:327
#define NUM_F_BLANK
Definition: formatting.c:330
#define NUM_LSIGN_NONE
Definition: formatting.c:344
#define IS_BLANK(_f)
Definition: formatting.c:353
#define NUM_F_ROMAN
Definition: formatting.c:336
#define NUM_F_MINUS_POST
Definition: formatting.c:339
#define NUM_F_LDECIMAL
Definition: formatting.c:328
#define NUM_F_PLUS_POST
Definition: formatting.c:338
#define NUM_F_MULTI
Definition: formatting.c:337
#define NUM_F_FILLMODE
Definition: formatting.c:331
#define NUM_F_EEEE
Definition: formatting.c:340
#define NUM_F_ZERO
Definition: formatting.c:329
#define NUM_F_LSIGN
Definition: formatting.c:332
#define NUM_F_PLUS
Definition: formatting.c:335
#define NUM_F_BRACKET
Definition: formatting.c:333

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_D, NUM_DEC, NUM_E, NUM_F_BLANK, NUM_F_BRACKET, NUM_F_DECIMAL, NUM_F_EEEE, NUM_F_FILLMODE, NUM_F_LDECIMAL, NUM_F_LSIGN, NUM_F_MINUS, NUM_F_MINUS_POST, NUM_F_MULTI, NUM_F_PLUS, NUM_F_PLUS_POST, NUM_F_ROMAN, NUM_F_ZERO, NUM_FM, NUM_G, NUM_L, NUM_LSIGN_NONE, NUM_LSIGN_POST, NUM_LSIGN_PRE, NUM_MI, NUM_PL, NUM_PR, NUM_RN, NUM_rn, NUM_S, NUM_SG, NUM_V, NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, FormatNode::type, NUMDesc::zero_end, and NUMDesc::zero_start.

Referenced by parse_format().

◆ numeric_to_char()

Datum numeric_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6366 of file formatting.c.

6371{
6373 text *fmt = PG_GETARG_TEXT_PP(1);
6374 NUMDesc Num;
6376 text *result;
6377 bool shouldFree;
6378 int out_pre_spaces = 0,
6379 sign = 0;
6380 char *numstr,
6381 *orgnum,
6382 *p;
6383
6385
6386 /*
6387 * On DateType depend part (numeric)
6388 */
6389 if (IS_ROMAN(&Num))
6390 {
6391 int32 intvalue;
6392 ErrorSaveContext escontext = {T_ErrorSaveContext};
6393
6394 /* Round and convert to int */
6395 intvalue = numeric_int4_safe(value, (Node *) &escontext);
6396 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6397 if (escontext.error_occurred)
6398 intvalue = PG_INT32_MAX;
6399 numstr = int_to_roman(intvalue);
6400 }
6401 else if (IS_EEEE(&Num))
6402 {
6403 orgnum = numeric_out_sci(value, Num.post);
6404
6405 /*
6406 * numeric_out_sci() does not emit a sign for positive numbers. We
6407 * need to add a space in this case so that positive and negative
6408 * numbers are aligned. Also must check for NaN/infinity cases, which
6409 * we handle the same way as in float8_to_char.
6410 */
6411 if (strcmp(orgnum, "NaN") == 0 ||
6412 strcmp(orgnum, "Infinity") == 0 ||
6413 strcmp(orgnum, "-Infinity") == 0)
6414 {
6415 /*
6416 * Allow 6 characters for the leading sign, the decimal point,
6417 * "e", the exponent's sign and two exponent digits.
6418 */
6419 numstr = (char *) palloc(Num.pre + Num.post + 7);
6420 fill_str(numstr, '#', Num.pre + Num.post + 6);
6421 *numstr = ' ';
6422 *(numstr + Num.pre + 1) = '.';
6423 }
6424 else if (*orgnum != '-')
6425 {
6426 numstr = (char *) palloc(strlen(orgnum) + 2);
6427 *numstr = ' ';
6428 strcpy(numstr + 1, orgnum);
6429 }
6430 else
6431 {
6432 numstr = orgnum;
6433 }
6434 }
6435 else
6436 {
6437 int numstr_pre_len;
6438 Numeric val = value;
6439 Numeric x;
6440
6441 if (IS_MULTI(&Num))
6442 {
6445
6448 NumericGetDatum(b)));
6451 NumericGetDatum(x)));
6452 Num.pre += Num.multi;
6453 }
6454
6457 Int32GetDatum(Num.post)));
6459 NumericGetDatum(x)));
6460
6461 if (*orgnum == '-')
6462 {
6463 sign = '-';
6464 numstr = orgnum + 1;
6465 }
6466 else
6467 {
6468 sign = '+';
6469 numstr = orgnum;
6470 }
6471
6472 if ((p = strchr(numstr, '.')))
6473 numstr_pre_len = p - numstr;
6474 else
6475 numstr_pre_len = strlen(numstr);
6476
6477 /* needs padding? */
6478 if (numstr_pre_len < Num.pre)
6479 out_pre_spaces = Num.pre - numstr_pre_len;
6480 /* overflowed prefix digit format? */
6481 else if (numstr_pre_len > Num.pre)
6482 {
6483 numstr = (char *) palloc(Num.pre + Num.post + 2);
6484 fill_str(numstr, '#', Num.pre + Num.post + 1);
6485 *(numstr + Num.pre) = '.';
6486 }
6487 }
Datum numeric_round(PG_FUNCTION_ARGS)
Definition: numeric.c:1526
int32 numeric_int4_safe(Numeric num, Node *escontext)
Definition: numeric.c:4365
Datum numeric_power(PG_FUNCTION_ARGS)
Definition: numeric.c:3912
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:799
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3016
int b
Definition: isn.c:74
int a
Definition: isn.c:73
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:64
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:81
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:76
bool error_occurred
Definition: miscnodes.h:47
Definition: nodes.h:135

References a, b, DatumGetCString(), DatumGetNumeric(), DirectFunctionCall1, DirectFunctionCall2, ErrorSaveContext::error_occurred, fill_str(), format, Int32GetDatum(), int64_to_numeric(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, numeric_int4_safe(), numeric_mul(), numeric_out(), numeric_out_sci(), numeric_power(), numeric_round(), NumericGetDatum(), palloc(), PG_GETARG_NUMERIC, PG_GETARG_TEXT_PP, PG_INT32_MAX, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, val, value, and x.

◆ numeric_to_number()

Datum numeric_to_number ( PG_FUNCTION_ARGS  )

Definition at line 6307 of file formatting.c.

6312{
6314 text *fmt = PG_GETARG_TEXT_PP(1);
6315 NUMDesc Num;
6316 Datum result;
6318 char *numstr;
6319 bool shouldFree;
6320 int len = 0;
6321 int scale,
6322 precision;
6323
6324 len = VARSIZE_ANY_EXHDR(fmt);
6325
6326 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
6328
6329 format = NUM_cache(len, &Num, fmt, &shouldFree);
6330
6331 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
6332
6333 NUM_processor(format, &Num, VARDATA_ANY(value), numstr,
6334 VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
6335
6336 scale = Num.post;
6337 precision = Num.pre + Num.multi + scale;
6338
6339 if (shouldFree)
6340 pfree(format);
6341
6343 CStringGetDatum(numstr),
6345 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
6346
6347 if (IS_MULTI(&Num))
6348 {
6349 Numeric x;
6352
6355 NumericGetDatum(b)));
6357 result,
6359 }
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:626
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:686
static int scale
Definition: pgbench.c:182
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486

References a, b, CStringGetDatum(), DatumGetNumeric(), DirectFunctionCall2, DirectFunctionCall3, format, Int32GetDatum(), int64_to_numeric(), InvalidOid, IS_MULTI, len, NUMDesc::multi, NUM_cache(), NUM_MAX_ITEM_SIZ, NUM_processor(), numeric_in(), numeric_mul(), numeric_power(), NumericGetDatum(), ObjectIdGetDatum(), palloc(), pfree(), PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_NULL, NUMDesc::post, NUMDesc::pre, scale, value, VARDATA_ANY(), VARHDRSZ, VARSIZE_ANY_EXHDR(), and x.

◆ parse_datetime()

Datum parse_datetime ( text date_txt,
text fmt,
Oid  collid,
bool  strict,
Oid typid,
int32 typmod,
int *  tz,
Node escontext 
)

Definition at line 4205 of file formatting.c.

4208{
4209 struct pg_tm tm;
4210 struct fmt_tz ftz;
4211 fsec_t fsec;
4212 int fprec;
4213 uint32 flags;
4214
4215 if (!do_to_timestamp(date_txt, fmt, collid, strict,
4216 &tm, &fsec, &ftz, &fprec, &flags, escontext))
4217 return (Datum) 0;
4218
4219 *typmod = fprec ? fprec : -1; /* fractional part precision */
4220
4221 if (flags & DCH_DATED)
4222 {
4223 if (flags & DCH_TIMED)
4224 {
4225 if (flags & DCH_ZONED)
4226 {
4227 TimestampTz result;
4228
4229 if (ftz.has_tz)
4230 {
4231 *tz = ftz.gmtoffset;
4232 }
4233 else
4234 {
4235 /*
4236 * Time zone is present in format string, but not in input
4237 * string. Assuming do_to_timestamp() triggers no error
4238 * this should be possible only in non-strict case.
4239 */
4240 Assert(!strict);
4241
4242 ereturn(escontext, (Datum) 0,
4243 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4244 errmsg("missing time zone in input string for type timestamptz")));
4245 }
4246
4247 if (tm2timestamp(&tm, fsec, tz, &result) != 0)
4248 ereturn(escontext, (Datum) 0,
4249 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4250 errmsg("timestamptz out of range")));
4251
4252 AdjustTimestampForTypmod(&result, *typmod, escontext);
4253
4254 *typid = TIMESTAMPTZOID;
4255 return TimestampTzGetDatum(result);
4256 }
4257 else
4258 {
4259 Timestamp result;
4260
4261 if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
4262 ereturn(escontext, (Datum) 0,
4263 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4264 errmsg("timestamp out of range")));
4265
4266 AdjustTimestampForTypmod(&result, *typmod, escontext);
4267
4268 *typid = TIMESTAMPOID;
4269 return TimestampGetDatum(result);
4270 }
4271 }
4272 else
4273 {
4274 if (flags & DCH_ZONED)
4275 {
4276 ereturn(escontext, (Datum) 0,
4277 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4278 errmsg("datetime format is zoned but not timed")));
4279 }
4280 else
4281 {
4282 DateADT result;
4283
4284 /* Prevent overflow in Julian-day routines */
4286 ereturn(escontext, (Datum) 0,
4287 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4288 errmsg("date out of range: \"%s\"",
4289 text_to_cstring(date_txt))));
4290
4291 result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) -
4293
4294 /* Now check for just-out-of-range dates */
4295 if (!IS_VALID_DATE(result))
4296 ereturn(escontext, (Datum) 0,
4297 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4298 errmsg("date out of range: \"%s\"",
4299 text_to_cstring(date_txt))));
4300
4301 *typid = DATEOID;
4302 return DateADTGetDatum(result);
4303 }
4304 }
4305 }
4306 else if (flags & DCH_TIMED)
4307 {
4308 if (flags & DCH_ZONED)
4309 {
4310 TimeTzADT *result = palloc(sizeof(TimeTzADT));
4311
4312 if (ftz.has_tz)
4313 {
4314 *tz = ftz.gmtoffset;
4315 }
4316 else
4317 {
4318 /*
4319 * Time zone is present in format string, but not in input
4320 * string. Assuming do_to_timestamp() triggers no error this
4321 * should be possible only in non-strict case.
4322 */
4323 Assert(!strict);
4324
4325 ereturn(escontext, (Datum) 0,
4326 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4327 errmsg("missing time zone in input string for type timetz")));
4328 }
4329
4330 if (tm2timetz(&tm, fsec, *tz, result) != 0)
4331 ereturn(escontext, (Datum) 0,
4332 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4333 errmsg("timetz out of range")));
4334
4335 AdjustTimeForTypmod(&result->time, *typmod);
4336
4337 *typid = TIMETZOID;
4338 return TimeTzADTPGetDatum(result);
4339 }
4340 else
4341 {
4342 TimeADT result;
4343
4344 if (tm2time(&tm, fsec, &result) != 0)
4345 ereturn(escontext, (Datum) 0,
4346 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4347 errmsg("time out of range")));
4348
4349 AdjustTimeForTypmod(&result, *typmod);
4350
4351 *typid = TIMEOID;
4352 return TimeADTGetDatum(result);
4353 }
4354 }
4355 else
4356 {
4357 ereturn(escontext, (Datum) 0,
4358 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4359 errmsg("datetime format is not dated and not timed")));
4360 }
4361}
bool AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
Definition: timestamp.c:368
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:2006
uint32_t uint32
Definition: c.h:539
int64 Timestamp
Definition: timestamp.h:38
int64 TimestampTz
Definition: timestamp.h:39
#define IS_VALID_DATE(d)
Definition: timestamp.h:262
int32 fsec_t
Definition: timestamp.h:41
#define IS_VALID_JULIAN(y, m, d)
Definition: timestamp.h:227
#define POSTGRES_EPOCH_JDATE
Definition: timestamp.h:235
int tm2time(struct pg_tm *tm, fsec_t fsec, TimeADT *result)
Definition: date.c:1563
int tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
Definition: date.c:2410
void AdjustTimeForTypmod(TimeADT *time, int32 typmod)
Definition: date.c:1792
static Datum DateADTGetDatum(DateADT X)
Definition: date.h:72
int32 DateADT
Definition: date.h:23
static Datum TimeTzADTPGetDatum(const TimeTzADT *X)
Definition: date.h:84
int64 TimeADT
Definition: date.h:25
static Datum TimeADTGetDatum(TimeADT X)
Definition: date.h:78
static bool do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext)
Definition: formatting.c:4431
Definition: date.h:28
TimeADT time
Definition: date.h:29
Definition: pgtime.h:35
static Datum TimestampTzGetDatum(TimestampTz X)
Definition: timestamp.h:52
static Datum TimestampGetDatum(Timestamp X)
Definition: timestamp.h:46

References AdjustTimeForTypmod(), AdjustTimestampForTypmod(), Assert(), collid, date2j(), DateADTGetDatum(), DCH_DATED, DCH_TIMED, DCH_ZONED, do_to_timestamp(), ereturn, errcode(), errmsg(), fmt_tz::gmtoffset, fmt_tz::has_tz, IS_VALID_DATE, IS_VALID_JULIAN, palloc(), POSTGRES_EPOCH_JDATE, text_to_cstring(), TimeTzADT::time, TimeADTGetDatum(), TimestampGetDatum(), TimestampTzGetDatum(), TimeTzADTPGetDatum(), tm, tm2time(), tm2timestamp(), tm2timetz(), pg_tm::tm_mday, pg_tm::tm_mon, and pg_tm::tm_year.

Referenced by executeDateTimeMethod().

◆ parse_format()

static void parse_format ( FormatNode node,
const char *  str,
const KeyWord kw,
const KeySuffix suf,
const int *  index,
uint32  flags,
NUMDesc Num 
)
static

Definition at line 1375 of file formatting.c.

1377{
1378 FormatNode *n;
1379
1380#ifdef DEBUG_TO_FROM_CHAR
1381 elog(DEBUG_elog_output, "to_char/number(): run parser");
1382#endif
1383
1384 n = node;
1385
1386 while (*str)
1387 {
1388 int suffix = 0;
1389 const KeySuffix *s;
1390
1391 /*
1392 * Prefix
1393 */
1394 if ((flags & DCH_FLAG) &&
1395 (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
1396 {
1397 suffix |= s->id;
1398 if (s->len)
1399 str += s->len;
1400 }
1401
1402 /*
1403 * Keyword
1404 */
1405 if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
1406 {
1408 n->suffix = suffix;
1409 if (n->key->len)
1410 str += n->key->len;
1411
1412 /*
1413 * NUM version: Prepare global NUMDesc struct
1414 */
1415 if (flags & NUM_FLAG)
1416 NUMDesc_prepare(Num, n);
1417
1418 /*
1419 * Postfix
1420 */
1421 if ((flags & DCH_FLAG) && *str &&
1422 (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
1423 {
1424 n->suffix |= s->id;
1425 if (s->len)
1426 str += s->len;
1427 }
1428
1429 n++;
1430 }
1431 else if (*str)
1432 {
1433 int chlen;
1434
1435 if ((flags & STD_FLAG) && *str != '"')
1436 {
1437 /*
1438 * Standard mode, allow only following separators: "-./,':; ".
1439 * However, we support double quotes even in standard mode
1440 * (see below). This is our extension of standard mode.
1441 */
1442 if (strchr("-./,':; ", *str) == NULL)
1443 ereport(ERROR,
1444 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
1445 errmsg("invalid datetime format separator: \"%s\"",
1446 pnstrdup(str, pg_mblen(str)))));
1447
1448 if (*str == ' ')
1449 n->type = NODE_TYPE_SPACE;
1450 else
1452
1453 n->character[0] = *str;
1454 n->character[1] = '\0';
1455 n->key = NULL;
1456 n->suffix = 0;
1457 n++;
1458 str++;
1459 }
1460 else if (*str == '"')
1461 {
1462 /*
1463 * Process double-quoted literal string, if any
1464 */
1465 str++;
1466 while (*str)
1467 {
1468 if (*str == '"')
1469 {
1470 str++;
1471 break;
1472 }
1473 /* backslash quotes the next character, if any */
1474 if (*str == '\\' && *(str + 1))
1475 str++;
1476 chlen = pg_mblen(str);
1477 n->type = NODE_TYPE_CHAR;
1478 memcpy(n->character, str, chlen);
1479 n->character[chlen] = '\0';
1480 n->key = NULL;
1481 n->suffix = 0;
1482 n++;
1483 str += chlen;
1484 }
1485 }
1486 else
1487 {
1488 /*
1489 * Outside double-quoted strings, backslash is only special if
1490 * it immediately precedes a double quote.
1491 */
1492 if (*str == '\\' && *(str + 1) == '"')
1493 str++;
1494 chlen = pg_mblen(str);
1495
1496 if ((flags & DCH_FLAG) && is_separator_char(str))
1498 else if (isspace((unsigned char) *str))
1499 n->type = NODE_TYPE_SPACE;
1500 else
1501 n->type = NODE_TYPE_CHAR;
1502
1503 memcpy(n->character, str, chlen);
1504 n->character[chlen] = '\0';
1505 n->key = NULL;
1506 n->suffix = 0;
1507 n++;
1508 str += chlen;
1509 }
1510 }
1511 }
1512
1513 n->type = NODE_TYPE_END;
1514 n->suffix = 0;
1515}
static void NUMDesc_prepare(NUMDesc *num, FormatNode *n)
Definition: formatting.c:1189
static const KeySuffix * suff_search(const char *str, const KeySuffix *suf, int type)
Definition: formatting.c:1159
static const KeyWord * index_seq_search(const char *str, const KeyWord *kw, const int *index)
Definition: formatting.c:1135
#define SUFFTYPE_PREFIX
Definition: formatting.c:167
#define SUFFTYPE_POSTFIX
Definition: formatting.c:168

References FormatNode::character, DCH_FLAG, elog, ereport, errcode(), errmsg(), ERROR, KeySuffix::id, index_seq_search(), is_separator_char(), FormatNode::key, KeySuffix::len, KeyWord::len, NODE_TYPE_ACTION, NODE_TYPE_CHAR, NODE_TYPE_END, NODE_TYPE_SEPARATOR, NODE_TYPE_SPACE, NUM_FLAG, NUMDesc_prepare(), pg_mblen(), pnstrdup(), STD_FLAG, str, suff_search(), FormatNode::suffix, SUFFTYPE_POSTFIX, SUFFTYPE_PREFIX, and FormatNode::type.

Referenced by datetime_format_has_tz(), datetime_to_char_body(), DCH_cache_fetch(), do_to_timestamp(), NUM_cache(), and NUM_cache_fetch().

◆ roman_to_int()

static int roman_to_int ( NUMProc Np,
int  input_len 
)
static

Definition at line 5129 of file formatting.c.

5130{
5131 int result = 0;
5132 int len;
5133 char romanChars[MAX_ROMAN_LEN];
5134 int romanValues[MAX_ROMAN_LEN];
5135 int repeatCount = 1;
5136 int vCount = 0,
5137 lCount = 0,
5138 dCount = 0;
5139 bool subtractionEncountered = false;
5140 int lastSubtractedValue = 0;
5141
5142 /*
5143 * Skip any leading whitespace. Perhaps we should limit the amount of
5144 * space skipped to MAX_ROMAN_LEN, but that seems unnecessarily picky.
5145 */
5146 while (!OVERLOAD_TEST && isspace((unsigned char) *Np->inout_p))
5147 Np->inout_p++;
5148
5149 /*
5150 * Collect and decode valid roman numerals, consuming at most
5151 * MAX_ROMAN_LEN characters. We do this in a separate loop to avoid
5152 * repeated decoding and because the main loop needs to know when it's at
5153 * the last numeral.
5154 */
5155 for (len = 0; len < MAX_ROMAN_LEN && !OVERLOAD_TEST; len++)
5156 {
5157 char currChar = pg_ascii_toupper(*Np->inout_p);
5158 int currValue = ROMAN_VAL(currChar);
5159
5160 if (currValue == 0)
5161 break; /* Not a valid roman numeral. */
5162 romanChars[len] = currChar;
5163 romanValues[len] = currValue;
5164 Np->inout_p++;
5165 }
5166
5167 if (len == 0)
5168 return -1; /* No valid roman numerals. */
5169
5170 /* Check for valid combinations and compute the represented value. */
5171 for (int i = 0; i < len; i++)
5172 {
5173 char currChar = romanChars[i];
5174 int currValue = romanValues[i];
5175
5176 /*
5177 * Ensure no numeral greater than or equal to the subtracted numeral
5178 * appears after a subtraction.
5179 */
5180 if (subtractionEncountered && currValue >= lastSubtractedValue)
5181 return -1;
5182
5183 /*
5184 * V, L, and D should not appear before a larger numeral, nor should
5185 * they be repeated.
5186 */
5187 if ((vCount && currValue >= ROMAN_VAL('V')) ||
5188 (lCount && currValue >= ROMAN_VAL('L')) ||
5189 (dCount && currValue >= ROMAN_VAL('D')))
5190 return -1;
5191 if (currChar == 'V')
5192 vCount++;
5193 else if (currChar == 'L')
5194 lCount++;
5195 else if (currChar == 'D')
5196 dCount++;
5197
5198 if (i < len - 1)
5199 {
5200 /* Compare current numeral to next numeral. */
5201 char nextChar = romanChars[i + 1];
5202 int nextValue = romanValues[i + 1];
5203
5204 /*
5205 * If the current value is less than the next value, handle
5206 * subtraction. Verify valid subtractive combinations and update
5207 * the result accordingly.
5208 */
5209 if (currValue < nextValue)
5210 {
5211 if (!IS_VALID_SUB_COMB(currChar, nextChar))
5212 return -1;
5213
5214 /*
5215 * Reject cases where same numeral is repeated with
5216 * subtraction (e.g. 'MCCM' or 'DCCCD').
5217 */
5218 if (repeatCount > 1)
5219 return -1;
5220
5221 /*
5222 * We are going to skip nextChar, so first make checks needed
5223 * for V, L, and D. These are the same as we'd have applied
5224 * if we reached nextChar without a subtraction.
5225 */
5226 if ((vCount && nextValue >= ROMAN_VAL('V')) ||
5227 (lCount && nextValue >= ROMAN_VAL('L')) ||
5228 (dCount && nextValue >= ROMAN_VAL('D')))
5229 return -1;
5230 if (nextChar == 'V')
5231 vCount++;
5232 else if (nextChar == 'L')
5233 lCount++;
5234 else if (nextChar == 'D')
5235 dCount++;
5236
5237 /*
5238 * Skip the next numeral as it is part of the subtractive
5239 * combination.
5240 */
5241 i++;
5242
5243 /* Update state. */
5244 repeatCount = 1;
5245 subtractionEncountered = true;
5246 lastSubtractedValue = currValue;
5247 result += (nextValue - currValue);
5248 }
5249 else
5250 {
5251 /* For same numerals, check for repetition. */
5252 if (currChar == nextChar)
5253 {
5254 repeatCount++;
5255 if (repeatCount > 3)
5256 return -1;
5257 }
5258 else
5259 repeatCount = 1;
5260 result += currValue;
5261 }
5262 }
5263 else
5264 {
5265 /* This is the last numeral; just add it to the result. */
5266 result += currValue;
5267 }
5268 }
5269
5270 return result;
5271}
#define IS_VALID_SUB_COMB(curr, next)
Definition: formatting.c:270
#define ROMAN_VAL(r)
Definition: formatting.c:278

References i, NUMProc::inout_p, IS_VALID_SUB_COMB, len, MAX_ROMAN_LEN, OVERLOAD_TEST, pg_ascii_toupper(), and ROMAN_VAL.

Referenced by NUM_processor().

◆ seq_search_ascii()

static int seq_search_ascii ( const char *  name,
const char *const *  array,
int *  len 
)
static

Definition at line 2320 of file formatting.c.

2321{
2322 unsigned char firstc;
2323 const char *const *a;
2324
2325 *len = 0;
2326
2327 /* empty string can't match anything */
2328 if (!*name)
2329 return -1;
2330
2331 /* we handle first char specially to gain some speed */
2332 firstc = pg_ascii_tolower((unsigned char) *name);
2333
2334 for (a = array; *a != NULL; a++)
2335 {
2336 const char *p;
2337 const char *n;
2338
2339 /* compare first chars */
2340 if (pg_ascii_tolower((unsigned char) **a) != firstc)
2341 continue;
2342
2343 /* compare rest of string */
2344 for (p = *a + 1, n = name + 1;; p++, n++)
2345 {
2346 /* return success if we matched whole array entry */
2347 if (*p == '\0')
2348 {
2349 *len = n - name;
2350 return a - array;
2351 }
2352 /* else, must have another character in "name" ... */
2353 if (*n == '\0')
2354 break;
2355 /* ... and it must match */
2356 if (pg_ascii_tolower((unsigned char) *p) !=
2357 pg_ascii_tolower((unsigned char) *n))
2358 break;
2359 }
2360 }
2361
2362 return -1;
2363}
const char * name

References a, len, name, and pg_ascii_tolower().

Referenced by from_char_seq_search().

◆ seq_search_localized()

static int seq_search_localized ( const char *  name,
char **  array,
int *  len,
Oid  collid 
)
static

Definition at line 2377 of file formatting.c.

2378{
2379 char **a;
2380 char *upper_name;
2381 char *lower_name;
2382
2383 *len = 0;
2384
2385 /* empty string can't match anything */
2386 if (!*name)
2387 return -1;
2388
2389 /*
2390 * The case-folding processing done below is fairly expensive, so before
2391 * doing that, make a quick pass to see if there is an exact match.
2392 */
2393 for (a = array; *a != NULL; a++)
2394 {
2395 int element_len = strlen(*a);
2396
2397 if (strncmp(name, *a, element_len) == 0)
2398 {
2399 *len = element_len;
2400 return a - array;
2401 }
2402 }
2403
2404 /*
2405 * Fold to upper case, then to lower case, so that we can match reliably
2406 * even in languages in which case conversions are not injective.
2407 */
2408 upper_name = str_toupper(name, strlen(name), collid);
2409 lower_name = str_tolower(upper_name, strlen(upper_name), collid);
2410 pfree(upper_name);
2411
2412 for (a = array; *a != NULL; a++)
2413 {
2414 char *upper_element;
2415 char *lower_element;
2416 int element_len;
2417
2418 /* Likewise upper/lower-case array element */
2419 upper_element = str_toupper(*a, strlen(*a), collid);
2420 lower_element = str_tolower(upper_element, strlen(upper_element),
2421 collid);
2422 pfree(upper_element);
2423 element_len = strlen(lower_element);
2424
2425 /* Match? */
2426 if (strncmp(lower_name, lower_element, element_len) == 0)
2427 {
2428 *len = element_len;
2429 pfree(lower_element);
2430 pfree(lower_name);
2431 return a - array;
2432 }
2433 pfree(lower_element);
2434 }
2435
2436 pfree(lower_name);
2437 return -1;
2438}
char * str_toupper(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1703
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1639

References a, collid, len, name, pfree(), str_tolower(), and str_toupper().

Referenced by from_char_seq_search().

◆ str_casefold()

char * str_casefold ( const char *  buff,
size_t  nbytes,
Oid  collid 
)

Definition at line 1831 of file formatting.c.

1832{
1833 char *result;
1834 pg_locale_t mylocale;
1835
1836 if (!buff)
1837 return NULL;
1838
1839 if (!OidIsValid(collid))
1840 {
1841 /*
1842 * This typically means that the parser could not resolve a conflict
1843 * of implicit collations, so report it that way.
1844 */
1845 ereport(ERROR,
1846 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1847 errmsg("could not determine which collation to use for %s function",
1848 "lower()"),
1849 errhint("Use the COLLATE clause to set the collation explicitly.")));
1850 }
1851
1853 ereport(ERROR,
1854 (errcode(ERRCODE_SYNTAX_ERROR),
1855 errmsg("Unicode case folding can only be performed if server encoding is UTF8")));
1856
1858
1859 /* C/POSIX collations use this path regardless of database encoding */
1860 if (mylocale->ctype_is_c)
1861 {
1862 result = asc_tolower(buff, nbytes);
1863 }
1864 else
1865 {
1866 const char *src = buff;
1867 size_t srclen = nbytes;
1868 size_t dstsize;
1869 char *dst;
1870 size_t needed;
1871
1872 /* first try buffer of equal size plus terminating NUL */
1873 dstsize = srclen + 1;
1874 dst = palloc(dstsize);
1875
1876 needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
1877 if (needed + 1 > dstsize)
1878 {
1879 /* grow buffer if needed and retry */
1880 dstsize = needed + 1;
1881 dst = repalloc(dst, dstsize);
1882 needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
1883 Assert(needed + 1 <= dstsize);
1884 }
1885
1886 Assert(dst[needed] == '\0');
1887 result = dst;
1888 }
1889
1890 return result;
1891}
#define OidIsValid(objectId)
Definition: c.h:775
int GetDatabaseEncoding(void)
Definition: mbutils.c:1262
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1610
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1166
size_t pg_strfold(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1255
@ PG_UTF8
Definition: pg_wchar.h:232

References asc_tolower(), Assert(), collid, pg_locale_struct::ctype_is_c, ereport, errcode(), errhint(), errmsg(), ERROR, GetDatabaseEncoding(), OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strfold(), PG_UTF8, and repalloc().

Referenced by casefold().

◆ str_initcap()

char * str_initcap ( const char *  buff,
size_t  nbytes,
Oid  collid 
)

Definition at line 1767 of file formatting.c.

1768{
1769 char *result;
1770 pg_locale_t mylocale;
1771
1772 if (!buff)
1773 return NULL;
1774
1775 if (!OidIsValid(collid))
1776 {
1777 /*
1778 * This typically means that the parser could not resolve a conflict
1779 * of implicit collations, so report it that way.
1780 */
1781 ereport(ERROR,
1782 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1783 errmsg("could not determine which collation to use for %s function",
1784 "initcap()"),
1785 errhint("Use the COLLATE clause to set the collation explicitly.")));
1786 }
1787
1789
1790 /* C/POSIX collations use this path regardless of database encoding */
1791 if (mylocale->ctype_is_c)
1792 {
1793 result = asc_initcap(buff, nbytes);
1794 }
1795 else
1796 {
1797 const char *src = buff;
1798 size_t srclen = nbytes;
1799 size_t dstsize;
1800 char *dst;
1801 size_t needed;
1802
1803 /* first try buffer of equal size plus terminating NUL */
1804 dstsize = srclen + 1;
1805 dst = palloc(dstsize);
1806
1807 needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
1808 if (needed + 1 > dstsize)
1809 {
1810 /* grow buffer if needed and retry */
1811 dstsize = needed + 1;
1812 dst = repalloc(dst, dstsize);
1813 needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
1814 Assert(needed + 1 <= dstsize);
1815 }
1816
1817 Assert(dst[needed] == '\0');
1818 result = dst;
1819 }
1820
1821 return result;
1822}
char * asc_initcap(const char *buff, size_t nbytes)
Definition: formatting.c:1946
size_t pg_strtitle(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1241

References asc_initcap(), Assert(), collid, pg_locale_struct::ctype_is_c, ereport, errcode(), errhint(), errmsg(), ERROR, OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strtitle(), and repalloc().

Referenced by initcap(), and str_initcap_z().

◆ str_initcap_z()

static char * str_initcap_z ( const char *  buff,
Oid  collid 
)
static

Definition at line 1989 of file formatting.c.

1990{
1991 return str_initcap(buff, strlen(buff), collid);
1992}
char * str_initcap(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1767

References collid, and str_initcap().

Referenced by DCH_to_char().

◆ str_numth()

static char * str_numth ( char *  dest,
char *  num,
int  type 
)
static

Definition at line 1610 of file formatting.c.

1611{
1612 if (dest != num)
1613 strcpy(dest, num);
1614 strcat(dest, get_th(num, type));
1615 return dest;
1616}

References generate_unaccent_rules::dest, get_th(), and type.

Referenced by DCH_to_char().

◆ str_tolower()

char * str_tolower ( const char *  buff,
size_t  nbytes,
Oid  collid 
)

Definition at line 1639 of file formatting.c.

1640{
1641 char *result;
1642 pg_locale_t mylocale;
1643
1644 if (!buff)
1645 return NULL;
1646
1647 if (!OidIsValid(collid))
1648 {
1649 /*
1650 * This typically means that the parser could not resolve a conflict
1651 * of implicit collations, so report it that way.
1652 */
1653 ereport(ERROR,
1654 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1655 errmsg("could not determine which collation to use for %s function",
1656 "lower()"),
1657 errhint("Use the COLLATE clause to set the collation explicitly.")));
1658 }
1659
1661
1662 /* C/POSIX collations use this path regardless of database encoding */
1663 if (mylocale->ctype_is_c)
1664 {
1665 result = asc_tolower(buff, nbytes);
1666 }
1667 else
1668 {
1669 const char *src = buff;
1670 size_t srclen = nbytes;
1671 size_t dstsize;
1672 char *dst;
1673 size_t needed;
1674
1675 /* first try buffer of equal size plus terminating NUL */
1676 dstsize = srclen + 1;
1677 dst = palloc(dstsize);
1678
1679 needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
1680 if (needed + 1 > dstsize)
1681 {
1682 /* grow buffer if needed and retry */
1683 dstsize = needed + 1;
1684 dst = repalloc(dst, dstsize);
1685 needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
1686 Assert(needed + 1 <= dstsize);
1687 }
1688
1689 Assert(dst[needed] == '\0');
1690 result = dst;
1691 }
1692
1693 return result;
1694}
size_t pg_strlower(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1234

References asc_tolower(), Assert(), collid, pg_locale_struct::ctype_is_c, ereport, errcode(), errhint(), errmsg(), ERROR, OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strlower(), and repalloc().

Referenced by citext_eq(), citext_hash(), citext_hash_extended(), citext_ne(), citextcmp(), convertPgWchar(), dispell_init(), dispell_lexize(), dsimple_init(), dsimple_lexize(), dsnowball_init(), dsnowball_lexize(), dsynonym_init(), dsynonym_lexize(), dxsyn_lexize(), generate_trgm_only(), generate_wildcard_trgm(), internal_citext_pattern_cmp(), lower(), lowerstr_ctx(), ltree_strncasecmp(), NIImportAffixes(), read_dictionary(), seq_search_localized(), and str_tolower_z().

◆ str_tolower_z()

static char * str_tolower_z ( const char *  buff,
Oid  collid 
)
static

Definition at line 1977 of file formatting.c.

1978{
1979 return str_tolower(buff, strlen(buff), collid);
1980}

References collid, and str_tolower().

Referenced by DCH_to_char().

◆ str_toupper()

char * str_toupper ( const char *  buff,
size_t  nbytes,
Oid  collid 
)

Definition at line 1703 of file formatting.c.

1704{
1705 char *result;
1706 pg_locale_t mylocale;
1707
1708 if (!buff)
1709 return NULL;
1710
1711 if (!OidIsValid(collid))
1712 {
1713 /*
1714 * This typically means that the parser could not resolve a conflict
1715 * of implicit collations, so report it that way.
1716 */
1717 ereport(ERROR,
1718 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1719 errmsg("could not determine which collation to use for %s function",
1720 "upper()"),
1721 errhint("Use the COLLATE clause to set the collation explicitly.")));
1722 }
1723
1725
1726 /* C/POSIX collations use this path regardless of database encoding */
1727 if (mylocale->ctype_is_c)
1728 {
1729 result = asc_toupper(buff, nbytes);
1730 }
1731 else
1732 {
1733 const char *src = buff;
1734 size_t srclen = nbytes;
1735 size_t dstsize;
1736 char *dst;
1737 size_t needed;
1738
1739 /* first try buffer of equal size plus terminating NUL */
1740 dstsize = srclen + 1;
1741 dst = palloc(dstsize);
1742
1743 needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
1744 if (needed + 1 > dstsize)
1745 {
1746 /* grow buffer if needed and retry */
1747 dstsize = needed + 1;
1748 dst = repalloc(dst, dstsize);
1749 needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
1750 Assert(needed + 1 <= dstsize);
1751 }
1752
1753 Assert(dst[needed] == '\0');
1754 result = dst;
1755 }
1756
1757 return result;
1758}
size_t pg_strupper(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1248

References asc_toupper(), Assert(), collid, pg_locale_struct::ctype_is_c, ereport, errcode(), errhint(), errmsg(), ERROR, OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strupper(), and repalloc().

Referenced by seq_search_localized(), str_toupper_z(), and upper().

◆ str_toupper_z()

static char * str_toupper_z ( const char *  buff,
Oid  collid 
)
static

Definition at line 1983 of file formatting.c.

1984{
1985 return str_toupper(buff, strlen(buff), collid);
1986}

References collid, and str_toupper().

Referenced by DCH_to_char().

◆ strspace_len()

static int strspace_len ( const char *  str)
static

Definition at line 2120 of file formatting.c.

2121{
2122 int len = 0;
2123
2124 while (*str && isspace((unsigned char) *str))
2125 {
2126 str++;
2127 len++;
2128 }
2129 return len;
2130}

References len, and str.

Referenced by from_char_parse_int_len().

◆ suff_search()

static const KeySuffix * suff_search ( const char *  str,
const KeySuffix suf,
int  type 
)
static

Definition at line 1159 of file formatting.c.

1160{
1161 const KeySuffix *s;
1162
1163 for (s = suf; s->name != NULL; s++)
1164 {
1165 if (s->type != type)
1166 continue;
1167
1168 if (strncmp(str, s->name, s->len) == 0)
1169 return s;
1170 }
1171 return NULL;
1172}
const char * name
Definition: formatting.c:124

References KeySuffix::len, KeySuffix::name, str, type, and KeySuffix::type.

Referenced by parse_format().

◆ timestamp_to_char()

Datum timestamp_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4000 of file formatting.c.

4001{
4003 text *fmt = PG_GETARG_TEXT_PP(1),
4004 *res;
4005 TmToChar tmtc;
4006 struct pg_tm tt;
4007 struct fmt_tm *tm;
4008 int thisdate;
4009
4010 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
4012
4013 ZERO_tmtc(&tmtc);
4014 tm = tmtcTm(&tmtc);
4015
4016 if (timestamp2tm(dt, NULL, &tt, &tmtcFsec(&tmtc), NULL, NULL) != 0)
4017 ereport(ERROR,
4018 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4019 errmsg("timestamp out of range")));
4020
4021 /* calculate wday and yday, because timestamp2tm doesn't */
4022 thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
4023 tt.tm_wday = (thisdate + 1) % 7;
4024 tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
4025
4026 COPY_tm(tm, &tt);
4027
4028 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
4030
4031 PG_RETURN_TEXT_P(res);
4032}
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1910
#define TIMESTAMP_NOT_FINITE(j)
Definition: timestamp.h:169
#define tmtcFsec(_X)
Definition: formatting.c:517
#define COPY_tm(_DST, _SRC)
Definition: formatting.c:520
#define PG_GETARG_TIMESTAMP(n)
Definition: timestamp.h:63

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, PG_GET_COLLATION, PG_GETARG_TEXT_PP, 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, VARSIZE_ANY_EXHDR(), and ZERO_tmtc.

◆ timestamptz_to_char()

Datum timestamptz_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4035 of file formatting.c.

4036{
4038 text *fmt = PG_GETARG_TEXT_PP(1),
4039 *res;
4040 TmToChar tmtc;
4041 int tz;
4042 struct pg_tm tt;
4043 struct fmt_tm *tm;
4044 int thisdate;
4045
4046 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
4048
4049 ZERO_tmtc(&tmtc);
4050 tm = tmtcTm(&tmtc);
4051
4052 if (timestamp2tm(dt, &tz, &tt, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
4053 ereport(ERROR,
4054 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4055 errmsg("timestamp out of range")));
4056
4057 /* calculate wday and yday, because timestamp2tm doesn't */
4058 thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
4059 tt.tm_wday = (thisdate + 1) % 7;
4060 tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
4061
4062 COPY_tm(tm, &tt);
4063
4064 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
4066
4067 PG_RETURN_TEXT_P(res);
4068}

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, PG_GET_COLLATION, PG_GETARG_TEXT_PP, 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, VARSIZE_ANY_EXHDR(), and ZERO_tmtc.

◆ to_date()

Datum to_date ( PG_FUNCTION_ARGS  )

Definition at line 4157 of file formatting.c.

4158{
4159 text *date_txt = PG_GETARG_TEXT_PP(0);
4160 text *fmt = PG_GETARG_TEXT_PP(1);
4162 DateADT result;
4163 struct pg_tm tm;
4164 struct fmt_tz ftz;
4165 fsec_t fsec;
4166
4167 do_to_timestamp(date_txt, fmt, collid, false,
4168 &tm, &fsec, &ftz, NULL, NULL, NULL);
4169
4170 /* Prevent overflow in Julian-day routines */
4172 ereport(ERROR,
4173 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4174 errmsg("date out of range: \"%s\"",
4175 text_to_cstring(date_txt))));
4176
4178
4179 /* Now check for just-out-of-range dates */
4180 if (!IS_VALID_DATE(result))
4181 ereport(ERROR,
4182 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4183 errmsg("date out of range: \"%s\"",
4184 text_to_cstring(date_txt))));
4185
4186 PG_RETURN_DATEADT(result);
4187}
#define PG_RETURN_DATEADT(x)
Definition: date.h:93
unsigned int Oid
Definition: postgres_ext.h:32

References collid, date2j(), do_to_timestamp(), ereport, errcode(), errmsg(), ERROR, IS_VALID_DATE, IS_VALID_JULIAN, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_DATEADT, POSTGRES_EPOCH_JDATE, text_to_cstring(), tm, pg_tm::tm_mday, pg_tm::tm_mon, and pg_tm::tm_year.

◆ to_timestamp()

Datum to_timestamp ( PG_FUNCTION_ARGS  )

Definition at line 4118 of file formatting.c.

4119{
4120 text *date_txt = PG_GETARG_TEXT_PP(0);
4121 text *fmt = PG_GETARG_TEXT_PP(1);
4123 Timestamp result;
4124 int tz;
4125 struct pg_tm tm;
4126 struct fmt_tz ftz;
4127 fsec_t fsec;
4128 int fprec;
4129
4130 do_to_timestamp(date_txt, fmt, collid, false,
4131 &tm, &fsec, &ftz, &fprec, NULL, NULL);
4132
4133 /* Use the specified time zone, if any. */
4134 if (ftz.has_tz)
4135 tz = ftz.gmtoffset;
4136 else
4138
4139 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
4140 ereport(ERROR,
4141 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4142 errmsg("timestamp out of range")));
4143
4144 /* Use the specified fractional precision, if any. */
4145 if (fprec)
4146 AdjustTimestampForTypmod(&result, fprec, NULL);
4147
4148 PG_RETURN_TIMESTAMP(result);
4149}
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1604
PGDLLIMPORT pg_tz * session_timezone
Definition: pgtz.c:28
#define PG_RETURN_TIMESTAMP(x)
Definition: timestamp.h:67

References AdjustTimestampForTypmod(), collid, DetermineTimeZoneOffset(), do_to_timestamp(), ereport, errcode(), errmsg(), ERROR, fmt_tz::gmtoffset, fmt_tz::has_tz, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_TIMESTAMP, session_timezone, tm, and tm2timestamp().

Variable Documentation

◆ adbc_strings

const char* const adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL}
static

Definition at line 216 of file formatting.c.

Referenced by DCH_from_char().

◆ adbc_strings_long

const char* const adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL}
static

Definition at line 217 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings

const char* const ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL}
static

Definition at line 243 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings_long

const char* const ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL}
static

Definition at line 244 of file formatting.c.

Referenced by DCH_from_char().

◆ days_short

const char* const days_short[]
static
Initial value:
= {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
}

Definition at line 183 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ DCH_index

const int DCH_index[KeyWord_INDEX_SIZE]
static
Initial value:
= {
-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_FF1, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, DCH_OF,
-1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
DCH_day, -1, DCH_ff1, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
-1, DCH_y_yyy, -1, -1, -1, -1
}

Definition at line 974 of file formatting.c.

Referenced by datetime_format_has_tz(), datetime_to_char_body(), DCH_cache_fetch(), and do_to_timestamp().

◆ DCH_keywords

const KeyWord DCH_keywords[]
static

◆ DCH_suff

const KeySuffix DCH_suff[]
static
Initial value:
= {
{NULL, 0, 0, 0}
}
#define DCH_S_FM
Definition: formatting.c:568
#define DCH_S_th
Definition: formatting.c:570
#define DCH_S_TH
Definition: formatting.c:569
#define DCH_S_SP
Definition: formatting.c:571
#define DCH_S_TM
Definition: formatting.c:572

Definition at line 594 of file formatting.c.

Referenced by datetime_format_has_tz(), datetime_to_char_body(), DCH_cache_fetch(), and do_to_timestamp().

◆ DCHCache

DCHCacheEntry* DCHCache[DCH_CACHE_ENTRIES]
static

Definition at line 413 of file formatting.c.

Referenced by DCH_cache_getnew(), DCH_cache_search(), and DCH_prevent_counter_overflow().

◆ DCHCounter

int DCHCounter = 0
static

Definition at line 415 of file formatting.c.

Referenced by DCH_cache_getnew(), DCH_cache_search(), and DCH_prevent_counter_overflow().

◆ months_full

const char* const months_full[]
static
Initial value:
= {
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December", NULL
}

Definition at line 178 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ n_DCHCache

int n_DCHCache = 0
static

Definition at line 414 of file formatting.c.

Referenced by DCH_cache_getnew(), DCH_cache_search(), and DCH_prevent_counter_overflow().

◆ n_NUMCache

int n_NUMCache = 0
static

Definition at line 419 of file formatting.c.

Referenced by NUM_cache_getnew(), NUM_cache_search(), and NUM_prevent_counter_overflow().

◆ NUM_index

const int NUM_index[KeyWord_INDEX_SIZE]
static
Initial value:
= {
-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 998 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUM_keywords

const KeyWord NUM_keywords[]
static

Definition at line 926 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUMCache

NUMCacheEntry* NUMCache[NUM_CACHE_ENTRIES]
static

Definition at line 418 of file formatting.c.

Referenced by NUM_cache_getnew(), NUM_cache_search(), and NUM_prevent_counter_overflow().

◆ NUMCounter

int NUMCounter = 0
static

Definition at line 420 of file formatting.c.

Referenced by NUM_cache_getnew(), NUM_cache_search(), and NUM_prevent_counter_overflow().

◆ numTH

const char* const numTH[] = {"ST", "ND", "RD", "TH", NULL}
static

Definition at line 296 of file formatting.c.

Referenced by get_th().

◆ numth

const char* const numth[] = {"st", "nd", "rd", "th", NULL}
static

Definition at line 297 of file formatting.c.

Referenced by get_th().

◆ rm1

const char* const rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL}
static

Definition at line 262 of file formatting.c.

Referenced by int_to_roman().

◆ rm10

const char* const rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL}
static

Definition at line 263 of file formatting.c.

Referenced by int_to_roman().

◆ rm100

const char* const rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL}
static

Definition at line 264 of file formatting.c.

Referenced by int_to_roman().

◆ rm_months_lower

const char* const rm_months_lower[]
static
Initial value:
=
{"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL}

Definition at line 255 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ rm_months_upper

const char* const rm_months_upper[]
static
Initial value:
=
{"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL}

Definition at line 252 of file formatting.c.

Referenced by DCH_to_char().