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 <wchar.h>
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.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 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_tm
 
struct  TmToChar
 
struct  NUMProc
 

Macros

#define RETURN_ERROR(throw_error)
 
#define CHECK_ERROR
 
#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 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 SKIP_THth(ptr, _suf)
 
#define DCH_to_char_fsec(frac_fmt, frac_val)
 
#define zeroize_NUM(_n)
 
#define OVERLOAD_TEST   (Np->inout_p >= Np->inout + input_len)
 
#define AMOUNT_TEST(s)   (Np->inout_p <= Np->inout + (input_len - (s)))
 
#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, bool *have_error)
 
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 void from_char_set_mode (TmFromChar *tmfc, const FromCharDateMode mode, bool *have_error)
 
static void from_char_set_int (int *dest, const int value, const FormatNode *node, bool *have_error)
 
static int from_char_parse_int_len (int *dest, const char **src, const int len, FormatNode *node, bool *have_error)
 
static int from_char_parse_int (int *dest, const char **src, FormatNode *node, bool *have_error)
 
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 int from_char_seq_search (int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, bool *have_error)
 
static void do_to_timestamp (text *date_txt, text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, int *fprec, uint32 *flags, bool *have_error)
 
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 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 * 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, bool *have_error)
 
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, bool *have_error)
 
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)
 
int datetime_format_flags (const char *fmt_str, bool *have_error)
 

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 237 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 238 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 264 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 265 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 239 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 240 of file formatting.c.

◆ ADJUST_YEAR

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

Definition at line 235 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 266 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 267 of file formatting.c.

◆ AMOUNT_TEST

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

Definition at line 5194 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 242 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 243 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 244 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

Definition at line 245 of file formatting.c.

◆ CHECK_ERROR

#define CHECK_ERROR
Value:
do { \
if (have_error && *have_error) \
goto on_error; \
} while (0)

Definition at line 130 of file formatting.c.

◆ CLOCK_12_HOUR

#define CLOCK_12_HOUR   1

Definition at line 212 of file formatting.c.

◆ CLOCK_24_HOUR

#define CLOCK_24_HOUR   0

Definition at line 211 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 525 of file formatting.c.

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 406 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

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

Definition at line 396 of file formatting.c.

◆ DCH_CACHE_SIZE

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

Definition at line 401 of file formatting.c.

◆ DCH_FLAG

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

Definition at line 140 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

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

Definition at line 155 of file formatting.c.

◆ DCH_S_FM

#define DCH_S_FM   0x01

Definition at line 573 of file formatting.c.

◆ DCH_S_SP

#define DCH_S_SP   0x08

Definition at line 576 of file formatting.c.

◆ DCH_S_TH

#define DCH_S_TH   0x02

Definition at line 574 of file formatting.c.

◆ DCH_S_th

#define DCH_S_th   0x04

Definition at line 575 of file formatting.c.

◆ DCH_S_TM

#define DCH_S_TM   0x10

Definition at line 577 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:586
#define S_THth(_s)
Definition: formatting.c:583
#define sprintf
Definition: port.h:227

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 489 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 488 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:1151
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33

Definition at line 556 of file formatting.c.

◆ IS_BLANK

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

Definition at line 368 of file formatting.c.

◆ IS_BRACKET

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

Definition at line 370 of file formatting.c.

◆ IS_DECIMAL

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

Definition at line 365 of file formatting.c.

◆ IS_EEEE

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

Definition at line 376 of file formatting.c.

◆ IS_FILLMODE

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

Definition at line 369 of file formatting.c.

◆ IS_LDECIMAL

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

Definition at line 366 of file formatting.c.

◆ IS_LSIGN

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

Definition at line 372 of file formatting.c.

◆ IS_MINUS

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

Definition at line 371 of file formatting.c.

◆ IS_MULTI

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

Definition at line 375 of file formatting.c.

◆ IS_PLUS

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

Definition at line 373 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:367

Definition at line 5405 of file formatting.c.

◆ IS_ROMAN

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

Definition at line 374 of file formatting.c.

◆ IS_ZERO

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

Definition at line 367 of file formatting.c.

◆ KeyWord_INDEX_FILTER

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

Definition at line 149 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 148 of file formatting.c.

◆ NODE_TYPE_ACTION

#define NODE_TYPE_ACTION   2

Definition at line 203 of file formatting.c.

◆ NODE_TYPE_CHAR

#define NODE_TYPE_CHAR   3

Definition at line 204 of file formatting.c.

◆ NODE_TYPE_END

#define NODE_TYPE_END   1

Definition at line 202 of file formatting.c.

◆ NODE_TYPE_SEPARATOR

#define NODE_TYPE_SEPARATOR   4

Definition at line 205 of file formatting.c.

◆ NODE_TYPE_SPACE

#define NODE_TYPE_SPACE   5

Definition at line 206 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 407 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

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

Definition at line 398 of file formatting.c.

◆ NUM_CACHE_SIZE

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

Definition at line 403 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 345 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 348 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 342 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 355 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 346 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 343 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 347 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 349 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 354 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 352 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 350 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 353 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 351 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 344 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 141 of file formatting.c.

◆ NUM_LSIGN_NONE

#define NUM_LSIGN_NONE   0

Definition at line 359 of file formatting.c.

◆ NUM_LSIGN_POST

#define NUM_LSIGN_POST   1

Definition at line 358 of file formatting.c.

◆ NUM_LSIGN_PRE

#define NUM_LSIGN_PRE   (-1)

Definition at line 357 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 156 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:627
#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:5619
char sign
Definition: informix.c:668
static char format
const void size_t len
#define VARDATA(PTR)
Definition: postgres.h:315

Definition at line 6113 of file formatting.c.

◆ NUM_TOCHAR_prepare

#define NUM_TOCHAR_prepare
Value:
do { \
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:156
static FormatNode * NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
Definition: formatting.c:4976
static void const char * fmt
void * palloc0(Size size)
Definition: mcxt.c:1099
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:354
Definition: c.h:622
text * cstring_to_text(const char *s)
Definition: varlena.c:188

Definition at line 6100 of file formatting.c.

◆ OVERLOAD_TEST

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

Definition at line 5193 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 269 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 270 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 271 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

Definition at line 272 of file formatting.c.

◆ RETURN_ERROR

#define RETURN_ERROR (   throw_error)
Value:
do { \
if (have_error) \
{ \
*have_error = true; \
goto on_error; \
} \
else \
{ \
throw_error; \
} \
} while (0)

Definition at line 117 of file formatting.c.

◆ S_FM

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

Definition at line 589 of file formatting.c.

◆ S_SP

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

Definition at line 590 of file formatting.c.

◆ S_TH

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

Definition at line 584 of file formatting.c.

◆ S_th

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

Definition at line 585 of file formatting.c.

◆ S_TH_TYPE

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

Definition at line 586 of file formatting.c.

◆ S_THth

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

Definition at line 583 of file formatting.c.

◆ S_TM

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

Definition at line 591 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:966

Definition at line 2174 of file formatting.c.

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 142 of file formatting.c.

◆ SUFFTYPE_POSTFIX

#define SUFFTYPE_POSTFIX   2

Definition at line 209 of file formatting.c.

◆ SUFFTYPE_PREFIX

#define SUFFTYPE_PREFIX   1

Definition at line 208 of file formatting.c.

◆ TH_LOWER

#define TH_LOWER   2

Definition at line 319 of file formatting.c.

◆ TH_UPPER

#define TH_UPPER   1

Definition at line 318 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 597 of file formatting.c.

◆ tmtcFsec

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

Definition at line 522 of file formatting.c.

◆ tmtcTm

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

Definition at line 520 of file formatting.c.

◆ tmtcTzn

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

Definition at line 521 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 539 of file formatting.c.

◆ ZERO_tmfc

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

Definition at line 469 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:520

Definition at line 545 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 4841 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 640 of file formatting.c.

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

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 178 of file formatting.c.

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

◆ 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 759 of file formatting.c.

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

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2255 of file formatting.c.

2256 {
2257  /*
2258  * Adjust all dates toward 2020; this is effectively what happens when we
2259  * assume '70' is 1970 and '69' is 2069.
2260  */
2261  /* Force 0-69 into the 2000's */
2262  if (year < 70)
2263  return year + 2000;
2264  /* Force 70-99 into the 1900's */
2265  else if (year < 100)
2266  return year + 1900;
2267  /* Force 100-519 into the 2000's */
2268  else if (year < 520)
2269  return year + 2000;
2270  /* Force 520-999 into the 1000's */
2271  else if (year < 1000)
2272  return year + 1000;
2273  else
2274  return year;
2275 }

Referenced by DCH_from_char().

◆ asc_initcap()

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

Definition at line 2105 of file formatting.c.

2106 {
2107  char *result;
2108  char *p;
2109  int wasalnum = false;
2110 
2111  if (!buff)
2112  return NULL;
2113 
2114  result = pnstrdup(buff, nbytes);
2115 
2116  for (p = result; *p; p++)
2117  {
2118  char c;
2119 
2120  if (wasalnum)
2121  *p = c = pg_ascii_tolower((unsigned char) *p);
2122  else
2123  *p = c = pg_ascii_toupper((unsigned char) *p);
2124  /* we don't trust isalnum() here */
2125  wasalnum = ((c >= 'A' && c <= 'Z') ||
2126  (c >= 'a' && c <= 'z') ||
2127  (c >= '0' && c <= '9'));
2128  }
2129 
2130  return result;
2131 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1316
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 2059 of file formatting.c.

2060 {
2061  char *result;
2062  char *p;
2063 
2064  if (!buff)
2065  return NULL;
2066 
2067  result = pnstrdup(buff, nbytes);
2068 
2069  for (p = result; *p; p++)
2070  *p = pg_ascii_tolower((unsigned char) *p);
2071 
2072  return result;
2073 }

References pg_ascii_tolower(), and pnstrdup().

Referenced by asc_tolower_z(), and str_tolower().

◆ asc_tolower_z()

static char* asc_tolower_z ( const char *  buff)
static

Definition at line 2154 of file formatting.c.

2155 {
2156  return asc_tolower(buff, strlen(buff));
2157 }
char * asc_tolower(const char *buff, size_t nbytes)
Definition: formatting.c:2059

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 2082 of file formatting.c.

2083 {
2084  char *result;
2085  char *p;
2086 
2087  if (!buff)
2088  return NULL;
2089 
2090  result = pnstrdup(buff, nbytes);
2091 
2092  for (p = result; *p; p++)
2093  *p = pg_ascii_toupper((unsigned char) *p);
2094 
2095  return result;
2096 }

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 2160 of file formatting.c.

2161 {
2162  return asc_toupper(buff, strlen(buff));
2163 }
char * asc_toupper(const char *buff, size_t nbytes)
Definition: formatting.c:2082

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_flags()

int datetime_format_flags ( const char *  fmt_str,
bool have_error 
)

Definition at line 6716 of file formatting.c.

6721 {
6722  bool incache;
6723  int fmt_len = strlen(fmt_str);
6724  int result;
6725  FormatNode *format;
6726 
6727  if (fmt_len > DCH_CACHE_SIZE)
6728  {
6729  /*
6730  * Allocate new memory if format picture is bigger than static cache
6731  * and do not use cache (call parser always)
6732  */
6733  incache = false;
6734 
6735  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
6736 
6737  parse_format(format, fmt_str, DCH_keywords,
6738  DCH_suff, DCH_index, DCH_FLAG, NULL);
6739  }
6740  else
6741  {
6742  /*
6743  * Use cache buffers
6744  */
6745  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
6746 
6747  incache = true;
6748  format = ent->format;
6749  }
6750 
6751  result = DCH_datetime_type(format, have_error);
6752 
6753  if (!incache)
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:979
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:1354
#define DCH_FLAG
Definition: formatting.c:140
static int DCH_datetime_type(FormatNode *node, bool *have_error)
Definition: formatting.c:3836
static const KeySuffix DCH_suff[]
Definition: formatting.c:599
#define DCH_CACHE_SIZE
Definition: formatting.c:401
static const KeyWord DCH_keywords[]
Definition: formatting.c:806
static DCHCacheEntry * DCH_cache_fetch(const char *str, bool std)
Definition: formatting.c:4021
void * palloc(Size size)
Definition: mcxt.c:1068
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:411

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 4048 of file formatting.c.

4049 {
4050  FormatNode *format;
4051  char *fmt_str,
4052  *result;
4053  bool incache;
4054  int fmt_len;
4055  text *res;
4056 
4057  /*
4058  * Convert fmt to C string
4059  */
4060  fmt_str = text_to_cstring(fmt);
4061  fmt_len = strlen(fmt_str);
4062 
4063  /*
4064  * Allocate workspace for result as C string
4065  */
4066  result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
4067  *result = '\0';
4068 
4069  if (fmt_len > DCH_CACHE_SIZE)
4070  {
4071  /*
4072  * Allocate new memory if format picture is bigger than static cache
4073  * and do not use cache (call parser always)
4074  */
4075  incache = false;
4076 
4077  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4078 
4079  parse_format(format, fmt_str, DCH_keywords,
4080  DCH_suff, DCH_index, DCH_FLAG, NULL);
4081  }
4082  else
4083  {
4084  /*
4085  * Use cache buffers
4086  */
4087  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4088 
4089  incache = true;
4090  format = ent->format;
4091  }
4092 
4093  /* The real work is here */
4094  DCH_to_char(format, is_interval, tmtc, result, collid);
4095 
4096  if (!incache)
4097  pfree(format);
4098 
4099  pfree(fmt_str);
4100 
4101  /* convert C-string result to TEXT format */
4102  res = cstring_to_text(result);
4103 
4104  pfree(result);
4105  return res;
4106 }
static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
Definition: formatting.c:2678
#define DCH_MAX_ITEM_SIZ
Definition: formatting.c:155
void pfree(void *pointer)
Definition: mcxt.c:1175
char * text_to_cstring(const text *t)
Definition: varlena.c:221

References cstring_to_text(), DCH_cache_fetch(), DCH_CACHE_SIZE, DCH_FLAG, DCH_index, DCH_keywords, DCH_MAX_ITEM_SIZ, DCH_suff, DCH_to_char(), fmt, DCHCacheEntry::format, format, palloc(), parse_format(), pfree(), res, 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 4021 of file formatting.c.

4022 {
4023  DCHCacheEntry *ent;
4024 
4025  if ((ent = DCH_cache_search(str, std)) == NULL)
4026  {
4027  /*
4028  * Not in the cache, must run parser and save a new format-picture to
4029  * the cache. Do not mark the cache entry valid until parsing
4030  * succeeds.
4031  */
4032  ent = DCH_cache_getnew(str, std);
4033 
4035  DCH_FLAG | (std ? STD_FLAG : 0), NULL);
4036 
4037  ent->valid = true;
4038  }
4039  return ent;
4040 }
#define STD_FLAG
Definition: formatting.c:142
static DCHCacheEntry * DCH_cache_getnew(const char *str, bool std)
Definition: formatting.c:3940
static DCHCacheEntry * DCH_cache_search(const char *str, bool std)
Definition: formatting.c:4000

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

Referenced by 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 3940 of file formatting.c.

3941 {
3942  DCHCacheEntry *ent;
3943 
3944  /* Ensure we can advance DCHCounter below */
3946 
3947  /*
3948  * If cache is full, remove oldest entry (or recycle first not-valid one)
3949  */
3951  {
3952  DCHCacheEntry *old = DCHCache[0];
3953 
3954 #ifdef DEBUG_TO_FROM_CHAR
3955  elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3956 #endif
3957  if (old->valid)
3958  {
3959  for (int i = 1; i < DCH_CACHE_ENTRIES; i++)
3960  {
3961  ent = DCHCache[i];
3962  if (!ent->valid)
3963  {
3964  old = ent;
3965  break;
3966  }
3967  if (ent->age < old->age)
3968  old = ent;
3969  }
3970  }
3971 #ifdef DEBUG_TO_FROM_CHAR
3972  elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3973 #endif
3974  old->valid = false;
3975  strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
3976  old->age = (++DCHCounter);
3977  /* caller is expected to fill format, then set valid */
3978  return old;
3979  }
3980  else
3981  {
3982 #ifdef DEBUG_TO_FROM_CHAR
3983  elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3984 #endif
3985  Assert(DCHCache[n_DCHCache] == NULL);
3986  DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
3988  ent->valid = false;
3989  strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
3990  ent->std = std;
3991  ent->age = (++DCHCounter);
3992  /* caller is expected to fill format, then set valid */
3993  ++n_DCHCache;
3994  return ent;
3995  }
3996 }
#define elog(elevel,...)
Definition: elog.h:218
static void DCH_prevent_counter_overflow(void)
Definition: formatting.c:3820
static int DCHCounter
Definition: formatting.c:430
static int n_DCHCache
Definition: formatting.c:429
static DCHCacheEntry * DCHCache[DCH_CACHE_ENTRIES]
Definition: formatting.c:428
#define DCH_CACHE_ENTRIES
Definition: formatting.c:406
int i
Definition: isn.c:73
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext TopMemoryContext
Definition: mcxt.c:48
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char str[DCH_CACHE_SIZE+1]
Definition: formatting.c:412

References DCHCacheEntry::age, Assert(), DCH_CACHE_ENTRIES, DCH_CACHE_SIZE, DCH_prevent_counter_overflow(), DCHCache, DCHCounter, elog, i, MemoryContextAllocZero(), n_DCHCache, DCHCacheEntry::std, generate_unaccent_rules::str, DCHCacheEntry::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 4000 of file formatting.c.

4001 {
4002  /* Ensure we can advance DCHCounter below */
4004 
4005  for (int i = 0; i < n_DCHCache; i++)
4006  {
4007  DCHCacheEntry *ent = DCHCache[i];
4008 
4009  if (ent->valid && strcmp(ent->str, str) == 0 && ent->std == std)
4010  {
4011  ent->age = (++DCHCounter);
4012  return ent;
4013  }
4014  }
4015 
4016  return NULL;
4017 }

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

Referenced by DCH_cache_fetch().

◆ DCH_datetime_type()

static int DCH_datetime_type ( FormatNode node,
bool have_error 
)
static

Definition at line 3836 of file formatting.c.

3837 {
3838  FormatNode *n;
3839  int flags = 0;
3840 
3841  for (n = node; n->type != NODE_TYPE_END; n++)
3842  {
3843  if (n->type != NODE_TYPE_ACTION)
3844  continue;
3845 
3846  switch (n->key->id)
3847  {
3848  case DCH_FX:
3849  break;
3850  case DCH_A_M:
3851  case DCH_P_M:
3852  case DCH_a_m:
3853  case DCH_p_m:
3854  case DCH_AM:
3855  case DCH_PM:
3856  case DCH_am:
3857  case DCH_pm:
3858  case DCH_HH:
3859  case DCH_HH12:
3860  case DCH_HH24:
3861  case DCH_MI:
3862  case DCH_SS:
3863  case DCH_MS: /* millisecond */
3864  case DCH_US: /* microsecond */
3865  case DCH_FF1:
3866  case DCH_FF2:
3867  case DCH_FF3:
3868  case DCH_FF4:
3869  case DCH_FF5:
3870  case DCH_FF6:
3871  case DCH_SSSS:
3872  flags |= DCH_TIMED;
3873  break;
3874  case DCH_tz:
3875  case DCH_TZ:
3876  case DCH_OF:
3878  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3879  errmsg("formatting field \"%s\" is only supported in to_char",
3880  n->key->name))));
3881  flags |= DCH_ZONED;
3882  break;
3883  case DCH_TZH:
3884  case DCH_TZM:
3885  flags |= DCH_ZONED;
3886  break;
3887  case DCH_A_D:
3888  case DCH_B_C:
3889  case DCH_a_d:
3890  case DCH_b_c:
3891  case DCH_AD:
3892  case DCH_BC:
3893  case DCH_ad:
3894  case DCH_bc:
3895  case DCH_MONTH:
3896  case DCH_Month:
3897  case DCH_month:
3898  case DCH_MON:
3899  case DCH_Mon:
3900  case DCH_mon:
3901  case DCH_MM:
3902  case DCH_DAY:
3903  case DCH_Day:
3904  case DCH_day:
3905  case DCH_DY:
3906  case DCH_Dy:
3907  case DCH_dy:
3908  case DCH_DDD:
3909  case DCH_IDDD:
3910  case DCH_DD:
3911  case DCH_D:
3912  case DCH_ID:
3913  case DCH_WW:
3914  case DCH_Q:
3915  case DCH_CC:
3916  case DCH_Y_YYY:
3917  case DCH_YYYY:
3918  case DCH_IYYY:
3919  case DCH_YYY:
3920  case DCH_IYY:
3921  case DCH_YY:
3922  case DCH_IY:
3923  case DCH_Y:
3924  case DCH_I:
3925  case DCH_RM:
3926  case DCH_rm:
3927  case DCH_W:
3928  case DCH_J:
3929  flags |= DCH_DATED;
3930  break;
3931  }
3932  }
3933 
3934 on_error:
3935  return flags;
3936 }
#define ereport(elevel,...)
Definition: elog.h:143
#define RETURN_ERROR(throw_error)
Definition: formatting.c:117
#define NODE_TYPE_ACTION
Definition: formatting.c:203
#define NODE_TYPE_END
Definition: formatting.c:202
#define DCH_DATED
Definition: formatting.h:20
#define DCH_TIMED
Definition: formatting.h:21
#define DCH_ZONED
Definition: formatting.h:22
const KeyWord * key
Definition: formatting.c:199
uint8 type
Definition: formatting.c:196
int id
Definition: formatting.c:189
const char * name
Definition: formatting.c:187

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, ereport, errcode(), errmsg(), ERROR, KeyWord::id, FormatNode::key, KeyWord::name, NODE_TYPE_ACTION, NODE_TYPE_END, RETURN_ERROR, and FormatNode::type.

Referenced by do_to_timestamp().

◆ DCH_from_char()

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

Definition at line 3322 of file formatting.c.

3324 {
3325  FormatNode *n;
3326  const char *s;
3327  int len,
3328  value;
3329  bool fx_mode = std;
3330 
3331  /* number of extra skipped characters (more than given in format string) */
3332  int extra_skip = 0;
3333 
3334  /* cache localized days and months */
3336 
3337  for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
3338  {
3339  /*
3340  * Ignore spaces at the beginning of the string and before fields when
3341  * not in FX (fixed width) mode.
3342  */
3343  if (!fx_mode && (n->type != NODE_TYPE_ACTION || n->key->id != DCH_FX) &&
3344  (n->type == NODE_TYPE_ACTION || n == node))
3345  {
3346  while (*s != '\0' && isspace((unsigned char) *s))
3347  {
3348  s++;
3349  extra_skip++;
3350  }
3351  }
3352 
3353  if (n->type == NODE_TYPE_SPACE || n->type == NODE_TYPE_SEPARATOR)
3354  {
3355  if (std)
3356  {
3357  /*
3358  * Standard mode requires strict matching between format
3359  * string separators/spaces and input string.
3360  */
3361  Assert(n->character[0] && !n->character[1]);
3362 
3363  if (*s == n->character[0])
3364  s++;
3365  else
3367  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3368  errmsg("unmatched format separator \"%c\"",
3369  n->character[0]))));
3370  }
3371  else if (!fx_mode)
3372  {
3373  /*
3374  * In non FX (fixed format) mode one format string space or
3375  * separator match to one space or separator in input string.
3376  * Or match nothing if there is no space or separator in the
3377  * current position of input string.
3378  */
3379  extra_skip--;
3380  if (isspace((unsigned char) *s) || is_separator_char(s))
3381  {
3382  s++;
3383  extra_skip++;
3384  }
3385  }
3386  else
3387  {
3388  /*
3389  * In FX mode, on format string space or separator we consume
3390  * exactly one character from input string. Notice we don't
3391  * insist that the consumed character match the format's
3392  * character.
3393  */
3394  s += pg_mblen(s);
3395  }
3396  continue;
3397  }
3398  else if (n->type != NODE_TYPE_ACTION)
3399  {
3400  /*
3401  * Text character, so consume one character from input string.
3402  * Notice we don't insist that the consumed character match the
3403  * format's character.
3404  */
3405  if (!fx_mode)
3406  {
3407  /*
3408  * In non FX mode we might have skipped some extra characters
3409  * (more than specified in format string) before. In this
3410  * case we don't skip input string character, because it might
3411  * be part of field.
3412  */
3413  if (extra_skip > 0)
3414  extra_skip--;
3415  else
3416  s += pg_mblen(s);
3417  }
3418  else
3419  {
3420  int chlen = pg_mblen(s);
3421 
3422  /*
3423  * Standard mode requires strict match of format characters.
3424  */
3425  if (std && n->type == NODE_TYPE_CHAR &&
3426  strncmp(s, n->character, chlen) != 0)
3428  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3429  errmsg("unmatched format character \"%s\"",
3430  n->character))));
3431 
3432  s += chlen;
3433  }
3434  continue;
3435  }
3436 
3437  from_char_set_mode(out, n->key->date_mode, have_error);
3438  CHECK_ERROR;
3439 
3440  switch (n->key->id)
3441  {
3442  case DCH_FX:
3443  fx_mode = true;
3444  break;
3445  case DCH_A_M:
3446  case DCH_P_M:
3447  case DCH_a_m:
3448  case DCH_p_m:
3450  NULL, InvalidOid,
3451  n, have_error);
3452  CHECK_ERROR;
3453  from_char_set_int(&out->pm, value % 2, n, have_error);
3454  CHECK_ERROR;
3455  out->clock = CLOCK_12_HOUR;
3456  break;
3457  case DCH_AM:
3458  case DCH_PM:
3459  case DCH_am:
3460  case DCH_pm:
3462  NULL, InvalidOid,
3463  n, have_error);
3464  CHECK_ERROR;
3465  from_char_set_int(&out->pm, value % 2, n, have_error);
3466  CHECK_ERROR;
3467  out->clock = CLOCK_12_HOUR;
3468  break;
3469  case DCH_HH:
3470  case DCH_HH12:
3471  from_char_parse_int_len(&out->hh, &s, 2, n, have_error);
3472  CHECK_ERROR;
3473  out->clock = CLOCK_12_HOUR;
3474  SKIP_THth(s, n->suffix);
3475  break;
3476  case DCH_HH24:
3477  from_char_parse_int_len(&out->hh, &s, 2, n, have_error);
3478  CHECK_ERROR;
3479  SKIP_THth(s, n->suffix);
3480  break;
3481  case DCH_MI:
3482  from_char_parse_int(&out->mi, &s, n, have_error);
3483  CHECK_ERROR;
3484  SKIP_THth(s, n->suffix);
3485  break;
3486  case DCH_SS:
3487  from_char_parse_int(&out->ss, &s, n, have_error);
3488  CHECK_ERROR;
3489  SKIP_THth(s, n->suffix);
3490  break;
3491  case DCH_MS: /* millisecond */
3492  len = from_char_parse_int_len(&out->ms, &s, 3, n, have_error);
3493  CHECK_ERROR;
3494 
3495  /*
3496  * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
3497  */
3498  out->ms *= len == 1 ? 100 :
3499  len == 2 ? 10 : 1;
3500 
3501  SKIP_THth(s, n->suffix);
3502  break;
3503  case DCH_FF1:
3504  case DCH_FF2:
3505  case DCH_FF3:
3506  case DCH_FF4:
3507  case DCH_FF5:
3508  case DCH_FF6:
3509  out->ff = n->key->id - DCH_FF1 + 1;
3510  /* fall through */
3511  case DCH_US: /* microsecond */
3512  len = from_char_parse_int_len(&out->us, &s,
3513  n->key->id == DCH_US ? 6 :
3514  out->ff, n, have_error);
3515  CHECK_ERROR;
3516 
3517  out->us *= len == 1 ? 100000 :
3518  len == 2 ? 10000 :
3519  len == 3 ? 1000 :
3520  len == 4 ? 100 :
3521  len == 5 ? 10 : 1;
3522 
3523  SKIP_THth(s, n->suffix);
3524  break;
3525  case DCH_SSSS:
3526  from_char_parse_int(&out->ssss, &s, n, have_error);
3527  CHECK_ERROR;
3528  SKIP_THth(s, n->suffix);
3529  break;
3530  case DCH_tz:
3531  case DCH_TZ:
3532  case DCH_OF:
3534  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3535  errmsg("formatting field \"%s\" is only supported in to_char",
3536  n->key->name))));
3537  CHECK_ERROR;
3538  break;
3539  case DCH_TZH:
3540 
3541  /*
3542  * Value of TZH might be negative. And the issue is that we
3543  * might swallow minus sign as the separator. So, if we have
3544  * skipped more characters than specified in the format
3545  * string, then we consider prepending last skipped minus to
3546  * TZH.
3547  */
3548  if (*s == '+' || *s == '-' || *s == ' ')
3549  {
3550  out->tzsign = *s == '-' ? -1 : +1;
3551  s++;
3552  }
3553  else
3554  {
3555  if (extra_skip > 0 && *(s - 1) == '-')
3556  out->tzsign = -1;
3557  else
3558  out->tzsign = +1;
3559  }
3560 
3561  from_char_parse_int_len(&out->tzh, &s, 2, n, have_error);
3562  CHECK_ERROR;
3563  break;
3564  case DCH_TZM:
3565  /* assign positive timezone sign if TZH was not seen before */
3566  if (!out->tzsign)
3567  out->tzsign = +1;
3568  from_char_parse_int_len(&out->tzm, &s, 2, n, have_error);
3569  CHECK_ERROR;
3570  break;
3571  case DCH_A_D:
3572  case DCH_B_C:
3573  case DCH_a_d:
3574  case DCH_b_c:
3576  NULL, InvalidOid,
3577  n, have_error);
3578  CHECK_ERROR;
3579  from_char_set_int(&out->bc, value % 2, n, have_error);
3580  CHECK_ERROR;
3581  break;
3582  case DCH_AD:
3583  case DCH_BC:
3584  case DCH_ad:
3585  case DCH_bc:
3587  NULL, InvalidOid,
3588  n, have_error);
3589  CHECK_ERROR;
3590  from_char_set_int(&out->bc, value % 2, n, have_error);
3591  CHECK_ERROR;
3592  break;
3593  case DCH_MONTH:
3594  case DCH_Month:
3595  case DCH_month:
3597  S_TM(n->suffix) ? localized_full_months : NULL,
3598  collid,
3599  n, have_error);
3600  CHECK_ERROR;
3601  from_char_set_int(&out->mm, value + 1, n, have_error);
3602  CHECK_ERROR;
3603  break;
3604  case DCH_MON:
3605  case DCH_Mon:
3606  case DCH_mon:
3608  S_TM(n->suffix) ? localized_abbrev_months : NULL,
3609  collid,
3610  n, have_error);
3611  CHECK_ERROR;
3612  from_char_set_int(&out->mm, value + 1, n, have_error);
3613  CHECK_ERROR;
3614  break;
3615  case DCH_MM:
3616  from_char_parse_int(&out->mm, &s, n, have_error);
3617  CHECK_ERROR;
3618  SKIP_THth(s, n->suffix);
3619  break;
3620  case DCH_DAY:
3621  case DCH_Day:
3622  case DCH_day:
3624  S_TM(n->suffix) ? localized_full_days : NULL,
3625  collid,
3626  n, have_error);
3627  CHECK_ERROR;
3628  from_char_set_int(&out->d, value, n, have_error);
3629  CHECK_ERROR;
3630  out->d++;
3631  break;
3632  case DCH_DY:
3633  case DCH_Dy:
3634  case DCH_dy:
3636  S_TM(n->suffix) ? localized_abbrev_days : NULL,
3637  collid,
3638  n, have_error);
3639  CHECK_ERROR;
3640  from_char_set_int(&out->d, value, n, have_error);
3641  CHECK_ERROR;
3642  out->d++;
3643  break;
3644  case DCH_DDD:
3645  from_char_parse_int(&out->ddd, &s, n, have_error);
3646  CHECK_ERROR;
3647  SKIP_THth(s, n->suffix);
3648  break;
3649  case DCH_IDDD:
3650  from_char_parse_int_len(&out->ddd, &s, 3, n, have_error);
3651  CHECK_ERROR;
3652  SKIP_THth(s, n->suffix);
3653  break;
3654  case DCH_DD:
3655  from_char_parse_int(&out->dd, &s, n, have_error);
3656  CHECK_ERROR;
3657  SKIP_THth(s, n->suffix);
3658  break;
3659  case DCH_D:
3660  from_char_parse_int(&out->d, &s, n, have_error);
3661  CHECK_ERROR;
3662  SKIP_THth(s, n->suffix);
3663  break;
3664  case DCH_ID:
3665  from_char_parse_int_len(&out->d, &s, 1, n, have_error);
3666  CHECK_ERROR;
3667  /* Shift numbering to match Gregorian where Sunday = 1 */
3668  if (++out->d > 7)
3669  out->d = 1;
3670  SKIP_THth(s, n->suffix);
3671  break;
3672  case DCH_WW:
3673  case DCH_IW:
3674  from_char_parse_int(&out->ww, &s, n, have_error);
3675  CHECK_ERROR;
3676  SKIP_THth(s, n->suffix);
3677  break;
3678  case DCH_Q:
3679 
3680  /*
3681  * We ignore 'Q' when converting to date because it is unclear
3682  * which date in the quarter to use, and some people specify
3683  * both quarter and month, so if it was honored it might
3684  * conflict with the supplied month. That is also why we don't
3685  * throw an error.
3686  *
3687  * We still parse the source string for an integer, but it
3688  * isn't stored anywhere in 'out'.
3689  */
3690  from_char_parse_int((int *) NULL, &s, n, have_error);
3691  CHECK_ERROR;
3692  SKIP_THth(s, n->suffix);
3693  break;
3694  case DCH_CC:
3695  from_char_parse_int(&out->cc, &s, n, have_error);
3696  CHECK_ERROR;
3697  SKIP_THth(s, n->suffix);
3698  break;
3699  case DCH_Y_YYY:
3700  {
3701  int matched,
3702  years,
3703  millennia,
3704  nch;
3705 
3706  matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch);
3707  if (matched < 2)
3709  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3710  errmsg("invalid input string for \"Y,YYY\""))));
3711  years += (millennia * 1000);
3712  from_char_set_int(&out->year, years, n, have_error);
3713  CHECK_ERROR;
3714  out->yysz = 4;
3715  s += nch;
3716  SKIP_THth(s, n->suffix);
3717  }
3718  break;
3719  case DCH_YYYY:
3720  case DCH_IYYY:
3721  from_char_parse_int(&out->year, &s, n, have_error);
3722  CHECK_ERROR;
3723  out->yysz = 4;
3724  SKIP_THth(s, n->suffix);
3725  break;
3726  case DCH_YYY:
3727  case DCH_IYY:
3728  len = from_char_parse_int(&out->year, &s, n, have_error);
3729  CHECK_ERROR;
3730  if (len < 4)
3731  out->year = adjust_partial_year_to_2020(out->year);
3732  out->yysz = 3;
3733  SKIP_THth(s, n->suffix);
3734  break;
3735  case DCH_YY:
3736  case DCH_IY:
3737  len = from_char_parse_int(&out->year, &s, n, have_error);
3738  CHECK_ERROR;
3739  if (len < 4)
3740  out->year = adjust_partial_year_to_2020(out->year);
3741  out->yysz = 2;
3742  SKIP_THth(s, n->suffix);
3743  break;
3744  case DCH_Y:
3745  case DCH_I:
3746  len = from_char_parse_int(&out->year, &s, n, have_error);
3747  CHECK_ERROR;
3748  if (len < 4)
3749  out->year = adjust_partial_year_to_2020(out->year);
3750  out->yysz = 1;
3751  SKIP_THth(s, n->suffix);
3752  break;
3753  case DCH_RM:
3754  case DCH_rm:
3756  NULL, InvalidOid,
3757  n, have_error);
3758  CHECK_ERROR;
3760  n, have_error);
3761  CHECK_ERROR;
3762  break;
3763  case DCH_W:
3764  from_char_parse_int(&out->w, &s, n, have_error);
3765  CHECK_ERROR;
3766  SKIP_THth(s, n->suffix);
3767  break;
3768  case DCH_J:
3769  from_char_parse_int(&out->j, &s, n, have_error);
3770  CHECK_ERROR;
3771  SKIP_THth(s, n->suffix);
3772  break;
3773  }
3774 
3775  /* Ignore all spaces after fields */
3776  if (!fx_mode)
3777  {
3778  extra_skip = 0;
3779  while (*s != '\0' && isspace((unsigned char) *s))
3780  {
3781  s++;
3782  extra_skip++;
3783  }
3784  }
3785  }
3786 
3787  /*
3788  * Standard parsing mode doesn't allow unmatched format patterns or
3789  * trailing characters in the input string.
3790  */
3791  if (std)
3792  {
3793  if (n->type != NODE_TYPE_END)
3795  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3796  errmsg("input string is too short for datetime format"))));
3797 
3798  while (*s != '\0' && isspace((unsigned char) *s))
3799  s++;
3800 
3801  if (*s != '\0')
3803  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3804  errmsg("trailing characters remain in input string "
3805  "after datetime format"))));
3806  }
3807 
3808 on_error:
3809  return;
3810 }
const char *const months[]
Definition: datetime.c:80
const char *const days[]
Definition: datetime.c:83
#define MONTHS_PER_YEAR
Definition: timestamp.h:108
#define CHECK_ERROR
Definition: formatting.c:130
#define CLOCK_12_HOUR
Definition: formatting.c:212
#define SKIP_THth(ptr, _suf)
Definition: formatting.c:2174
#define S_TM(_s)
Definition: formatting.c:591
#define NODE_TYPE_SPACE
Definition: formatting.c:206
static int from_char_seq_search(int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, bool *have_error)
Definition: formatting.c:2629
static int adjust_partial_year_to_2020(int year)
Definition: formatting.c:2255
static const char *const months_full[]
Definition: formatting.c:219
#define NODE_TYPE_SEPARATOR
Definition: formatting.c:205
static const char *const adbc_strings_long[]
Definition: formatting.c:258
static int from_char_parse_int(int *dest, const char **src, FormatNode *node, bool *have_error)
Definition: formatting.c:2471
static const char *const days_short[]
Definition: formatting.c:224
static const char *const ampm_strings[]
Definition: formatting.c:284
static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode, bool *have_error)
Definition: formatting.c:2300
#define NODE_TYPE_CHAR
Definition: formatting.c:204
static int from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode *node, bool *have_error)
Definition: formatting.c:2368
static void from_char_set_int(int *dest, const int value, const FormatNode *node, bool *have_error)
Definition: formatting.c:2327
static const char *const rm_months_lower[]
Definition: formatting.c:296
static const char *const adbc_strings[]
Definition: formatting.c:257
static const char *const ampm_strings_long[]
Definition: formatting.c:285
static bool is_separator_char(const char *str)
Definition: formatting.c:1165
static struct @151 value
void cache_locale_time(void)
Definition: pg_locale.c:747
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:36
uint8 suffix
Definition: formatting.c:198
char character[MAX_MULTIBYTE_CHAR_LEN+1]
Definition: formatting.c:197
FromCharDateMode date_mode
Definition: formatting.c:191

References 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, CHECK_ERROR, TmFromChar::clock, CLOCK_12_HOUR, 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, ereport, errcode(), errmsg(), ERROR, TmFromChar::ff, from_char_parse_int(), from_char_parse_int_len(), from_char_seq_search(), from_char_set_int(), from_char_set_mode(), TmFromChar::hh, KeyWord::id, 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_mblen(), TmFromChar::pm, RETURN_ERROR, rm_months_lower, S_TM, SKIP_THth, TmFromChar::ss, TmFromChar::ssss, FormatNode::suffix, FormatNode::type, TmFromChar::tzh, TmFromChar::tzm, 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 3820 of file formatting.c.

3821 {
3822  if (DCHCounter >= (INT_MAX - 1))
3823  {
3824  for (int i = 0; i < n_DCHCache; i++)
3825  DCHCache[i]->age >>= 1;
3826  DCHCounter >>= 1;
3827  }
3828 }

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 2678 of file formatting.c.

2679 {
2680  FormatNode *n;
2681  char *s;
2682  struct fmt_tm *tm = &in->tm;
2683  int i;
2684 
2685  /* cache localized days and months */
2687 
2688  s = out;
2689  for (n = node; n->type != NODE_TYPE_END; n++)
2690  {
2691  if (n->type != NODE_TYPE_ACTION)
2692  {
2693  strcpy(s, n->character);
2694  s += strlen(s);
2695  continue;
2696  }
2697 
2698  switch (n->key->id)
2699  {
2700  case DCH_A_M:
2701  case DCH_P_M:
2702  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2703  ? P_M_STR : A_M_STR);
2704  s += strlen(s);
2705  break;
2706  case DCH_AM:
2707  case DCH_PM:
2708  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2709  ? PM_STR : AM_STR);
2710  s += strlen(s);
2711  break;
2712  case DCH_a_m:
2713  case DCH_p_m:
2714  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2715  ? p_m_STR : a_m_STR);
2716  s += strlen(s);
2717  break;
2718  case DCH_am:
2719  case DCH_pm:
2720  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2721  ? pm_STR : am_STR);
2722  s += strlen(s);
2723  break;
2724  case DCH_HH:
2725  case DCH_HH12:
2726 
2727  /*
2728  * display time as shown on a 12-hour clock, even for
2729  * intervals
2730  */
2731  sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2732  tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ?
2733  (long long) (HOURS_PER_DAY / 2) :
2734  (long long) (tm->tm_hour % (HOURS_PER_DAY / 2)));
2735  if (S_THth(n->suffix))
2736  str_numth(s, s, S_TH_TYPE(n->suffix));
2737  s += strlen(s);
2738  break;
2739  case DCH_HH24:
2740  sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2741  (long long) tm->tm_hour);
2742  if (S_THth(n->suffix))
2743  str_numth(s, s, S_TH_TYPE(n->suffix));
2744  s += strlen(s);
2745  break;
2746  case DCH_MI:
2747  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2748  tm->tm_min);
2749  if (S_THth(n->suffix))
2750  str_numth(s, s, S_TH_TYPE(n->suffix));
2751  s += strlen(s);
2752  break;
2753  case DCH_SS:
2754  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2755  tm->tm_sec);
2756  if (S_THth(n->suffix))
2757  str_numth(s, s, S_TH_TYPE(n->suffix));
2758  s += strlen(s);
2759  break;
2760 
2761 #define DCH_to_char_fsec(frac_fmt, frac_val) \
2762  sprintf(s, frac_fmt, (int) (frac_val)); \
2763  if (S_THth(n->suffix)) \
2764  str_numth(s, s, S_TH_TYPE(n->suffix)); \
2765  s += strlen(s)
2766 
2767  case DCH_FF1: /* tenth of second */
2768  DCH_to_char_fsec("%01d", in->fsec / 100000);
2769  break;
2770  case DCH_FF2: /* hundredth of second */
2771  DCH_to_char_fsec("%02d", in->fsec / 10000);
2772  break;
2773  case DCH_FF3:
2774  case DCH_MS: /* millisecond */
2775  DCH_to_char_fsec("%03d", in->fsec / 1000);
2776  break;
2777  case DCH_FF4: /* tenth of a millisecond */
2778  DCH_to_char_fsec("%04d", in->fsec / 100);
2779  break;
2780  case DCH_FF5: /* hundredth of a millisecond */
2781  DCH_to_char_fsec("%05d", in->fsec / 10);
2782  break;
2783  case DCH_FF6:
2784  case DCH_US: /* microsecond */
2785  DCH_to_char_fsec("%06d", in->fsec);
2786  break;
2787 #undef DCH_to_char_fsec
2788  case DCH_SSSS:
2789  sprintf(s, "%lld",
2790  (long long) (tm->tm_hour * SECS_PER_HOUR +
2792  tm->tm_sec));
2793  if (S_THth(n->suffix))
2794  str_numth(s, s, S_TH_TYPE(n->suffix));
2795  s += strlen(s);
2796  break;
2797  case DCH_tz:
2799  if (tmtcTzn(in))
2800  {
2801  /* We assume here that timezone names aren't localized */
2802  char *p = asc_tolower_z(tmtcTzn(in));
2803 
2804  strcpy(s, p);
2805  pfree(p);
2806  s += strlen(s);
2807  }
2808  break;
2809  case DCH_TZ:
2811  if (tmtcTzn(in))
2812  {
2813  strcpy(s, tmtcTzn(in));
2814  s += strlen(s);
2815  }
2816  break;
2817  case DCH_TZH:
2819  sprintf(s, "%c%02d",
2820  (tm->tm_gmtoff >= 0) ? '+' : '-',
2821  abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2822  s += strlen(s);
2823  break;
2824  case DCH_TZM:
2826  sprintf(s, "%02d",
2827  (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2828  s += strlen(s);
2829  break;
2830  case DCH_OF:
2832  sprintf(s, "%c%0*d",
2833  (tm->tm_gmtoff >= 0) ? '+' : '-',
2834  S_FM(n->suffix) ? 0 : 2,
2835  abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2836  s += strlen(s);
2837  if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2838  {
2839  sprintf(s, ":%02d",
2840  (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2841  s += strlen(s);
2842  }
2843  break;
2844  case DCH_A_D:
2845  case DCH_B_C:
2847  strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2848  s += strlen(s);
2849  break;
2850  case DCH_AD:
2851  case DCH_BC:
2853  strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2854  s += strlen(s);
2855  break;
2856  case DCH_a_d:
2857  case DCH_b_c:
2859  strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2860  s += strlen(s);
2861  break;
2862  case DCH_ad:
2863  case DCH_bc:
2865  strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2866  s += strlen(s);
2867  break;
2868  case DCH_MONTH:
2870  if (!tm->tm_mon)
2871  break;
2872  if (S_TM(n->suffix))
2873  {
2874  char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid);
2875 
2876  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2877  strcpy(s, str);
2878  else
2879  ereport(ERROR,
2880  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2881  errmsg("localized string format value too long")));
2882  }
2883  else
2884  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2886  s += strlen(s);
2887  break;
2888  case DCH_Month:
2890  if (!tm->tm_mon)
2891  break;
2892  if (S_TM(n->suffix))
2893  {
2894  char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid);
2895 
2896  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2897  strcpy(s, str);
2898  else
2899  ereport(ERROR,
2900  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2901  errmsg("localized string format value too long")));
2902  }
2903  else
2904  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2905  months_full[tm->tm_mon - 1]);
2906  s += strlen(s);
2907  break;
2908  case DCH_month:
2910  if (!tm->tm_mon)
2911  break;
2912  if (S_TM(n->suffix))
2913  {
2914  char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid);
2915 
2916  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2917  strcpy(s, str);
2918  else
2919  ereport(ERROR,
2920  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2921  errmsg("localized string format value too long")));
2922  }
2923  else
2924  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2926  s += strlen(s);
2927  break;
2928  case DCH_MON:
2930  if (!tm->tm_mon)
2931  break;
2932  if (S_TM(n->suffix))
2933  {
2934  char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2935 
2936  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2937  strcpy(s, str);
2938  else
2939  ereport(ERROR,
2940  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2941  errmsg("localized string format value too long")));
2942  }
2943  else
2944  strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2945  s += strlen(s);
2946  break;
2947  case DCH_Mon:
2949  if (!tm->tm_mon)
2950  break;
2951  if (S_TM(n->suffix))
2952  {
2953  char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2954 
2955  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2956  strcpy(s, str);
2957  else
2958  ereport(ERROR,
2959  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2960  errmsg("localized string format value too long")));
2961  }
2962  else
2963  strcpy(s, months[tm->tm_mon - 1]);
2964  s += strlen(s);
2965  break;
2966  case DCH_mon:
2968  if (!tm->tm_mon)
2969  break;
2970  if (S_TM(n->suffix))
2971  {
2972  char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2973 
2974  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2975  strcpy(s, str);
2976  else
2977  ereport(ERROR,
2978  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2979  errmsg("localized string format value too long")));
2980  }
2981  else
2982  strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
2983  s += strlen(s);
2984  break;
2985  case DCH_MM:
2986  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
2987  tm->tm_mon);
2988  if (S_THth(n->suffix))
2989  str_numth(s, s, S_TH_TYPE(n->suffix));
2990  s += strlen(s);
2991  break;
2992  case DCH_DAY:
2994  if (S_TM(n->suffix))
2995  {
2996  char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid);
2997 
2998  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2999  strcpy(s, str);
3000  else
3001  ereport(ERROR,
3002  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3003  errmsg("localized string format value too long")));
3004  }
3005  else
3006  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
3008  s += strlen(s);
3009  break;
3010  case DCH_Day:
3012  if (S_TM(n->suffix))
3013  {
3014  char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid);
3015 
3016  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3017  strcpy(s, str);
3018  else
3019  ereport(ERROR,
3020  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3021  errmsg("localized string format value too long")));
3022  }
3023  else
3024  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
3025  days[tm->tm_wday]);
3026  s += strlen(s);
3027  break;
3028  case DCH_day:
3030  if (S_TM(n->suffix))
3031  {
3032  char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid);
3033 
3034  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3035  strcpy(s, str);
3036  else
3037  ereport(ERROR,
3038  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3039  errmsg("localized string format value too long")));
3040  }
3041  else
3042  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
3044  s += strlen(s);
3045  break;
3046  case DCH_DY:
3048  if (S_TM(n->suffix))
3049  {
3050  char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid);
3051 
3052  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3053  strcpy(s, str);
3054  else
3055  ereport(ERROR,
3056  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3057  errmsg("localized string format value too long")));
3058  }
3059  else
3060  strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
3061  s += strlen(s);
3062  break;
3063  case DCH_Dy:
3065  if (S_TM(n->suffix))
3066  {
3067  char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid);
3068 
3069  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3070  strcpy(s, str);
3071  else
3072  ereport(ERROR,
3073  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3074  errmsg("localized string format value too long")));
3075  }
3076  else
3077  strcpy(s, days_short[tm->tm_wday]);
3078  s += strlen(s);
3079  break;
3080  case DCH_dy:
3082  if (S_TM(n->suffix))
3083  {
3084  char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid);
3085 
3086  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3087  strcpy(s, str);
3088  else
3089  ereport(ERROR,
3090  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3091  errmsg("localized string format value too long")));
3092  }
3093  else
3094  strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
3095  s += strlen(s);
3096  break;
3097  case DCH_DDD:
3098  case DCH_IDDD:
3099  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
3100  (n->key->id == DCH_DDD) ?
3101  tm->tm_yday :
3103  if (S_THth(n->suffix))
3104  str_numth(s, s, S_TH_TYPE(n->suffix));
3105  s += strlen(s);
3106  break;
3107  case DCH_DD:
3108  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
3109  if (S_THth(n->suffix))
3110  str_numth(s, s, S_TH_TYPE(n->suffix));
3111  s += strlen(s);
3112  break;
3113  case DCH_D:
3115  sprintf(s, "%d", tm->tm_wday + 1);
3116  if (S_THth(n->suffix))
3117  str_numth(s, s, S_TH_TYPE(n->suffix));
3118  s += strlen(s);
3119  break;
3120  case DCH_ID:
3122  sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
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_WW:
3128  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
3129  (tm->tm_yday - 1) / 7 + 1);
3130  if (S_THth(n->suffix))
3131  str_numth(s, s, S_TH_TYPE(n->suffix));
3132  s += strlen(s);
3133  break;
3134  case DCH_IW:
3135  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
3137  if (S_THth(n->suffix))
3138  str_numth(s, s, S_TH_TYPE(n->suffix));
3139  s += strlen(s);
3140  break;
3141  case DCH_Q:
3142  if (!tm->tm_mon)
3143  break;
3144  sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
3145  if (S_THth(n->suffix))
3146  str_numth(s, s, S_TH_TYPE(n->suffix));
3147  s += strlen(s);
3148  break;
3149  case DCH_CC:
3150  if (is_interval) /* straight calculation */
3151  i = tm->tm_year / 100;
3152  else
3153  {
3154  if (tm->tm_year > 0)
3155  /* Century 20 == 1901 - 2000 */
3156  i = (tm->tm_year - 1) / 100 + 1;
3157  else
3158  /* Century 6BC == 600BC - 501BC */
3159  i = tm->tm_year / 100 - 1;
3160  }
3161  if (i <= 99 && i >= -99)
3162  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
3163  else
3164  sprintf(s, "%d", i);
3165  if (S_THth(n->suffix))
3166  str_numth(s, s, S_TH_TYPE(n->suffix));
3167  s += strlen(s);
3168  break;
3169  case DCH_Y_YYY:
3170  i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
3171  sprintf(s, "%d,%03d", i,
3172  ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
3173  if (S_THth(n->suffix))
3174  str_numth(s, s, S_TH_TYPE(n->suffix));
3175  s += strlen(s);
3176  break;
3177  case DCH_YYYY:
3178  case DCH_IYYY:
3179  sprintf(s, "%0*d",
3180  S_FM(n->suffix) ? 0 :
3181  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
3182  (n->key->id == DCH_YYYY ?
3183  ADJUST_YEAR(tm->tm_year, is_interval) :
3185  tm->tm_mon,
3186  tm->tm_mday),
3187  is_interval)));
3188  if (S_THth(n->suffix))
3189  str_numth(s, s, S_TH_TYPE(n->suffix));
3190  s += strlen(s);
3191  break;
3192  case DCH_YYY:
3193  case DCH_IYY:
3194  sprintf(s, "%0*d",
3195  S_FM(n->suffix) ? 0 :
3196  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
3197  (n->key->id == DCH_YYY ?
3198  ADJUST_YEAR(tm->tm_year, is_interval) :
3200  tm->tm_mon,
3201  tm->tm_mday),
3202  is_interval)) % 1000);
3203  if (S_THth(n->suffix))
3204  str_numth(s, s, S_TH_TYPE(n->suffix));
3205  s += strlen(s);
3206  break;
3207  case DCH_YY:
3208  case DCH_IY:
3209  sprintf(s, "%0*d",
3210  S_FM(n->suffix) ? 0 :
3211  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
3212  (n->key->id == DCH_YY ?
3213  ADJUST_YEAR(tm->tm_year, is_interval) :
3215  tm->tm_mon,
3216  tm->tm_mday),
3217  is_interval)) % 100);
3218  if (S_THth(n->suffix))
3219  str_numth(s, s, S_TH_TYPE(n->suffix));
3220  s += strlen(s);
3221  break;
3222  case DCH_Y:
3223  case DCH_I:
3224  sprintf(s, "%1d",
3225  (n->key->id == DCH_Y ?
3226  ADJUST_YEAR(tm->tm_year, is_interval) :
3228  tm->tm_mon,
3229  tm->tm_mday),
3230  is_interval)) % 10);
3231  if (S_THth(n->suffix))
3232  str_numth(s, s, S_TH_TYPE(n->suffix));
3233  s += strlen(s);
3234  break;
3235  case DCH_RM:
3236  /* FALLTHROUGH */
3237  case DCH_rm:
3238 
3239  /*
3240  * For intervals, values like '12 month' will be reduced to 0
3241  * month and some years. These should be processed.
3242  */
3243  if (!tm->tm_mon && !tm->tm_year)
3244  break;
3245  else
3246  {
3247  int mon = 0;
3248  const char *const *months;
3249 
3250  if (n->key->id == DCH_RM)
3252  else
3254 
3255  /*
3256  * Compute the position in the roman-numeral array. Note
3257  * that the contents of the array are reversed, December
3258  * being first and January last.
3259  */
3260  if (tm->tm_mon == 0)
3261  {
3262  /*
3263  * This case is special, and tracks the case of full
3264  * interval years.
3265  */
3266  mon = tm->tm_year >= 0 ? 0 : MONTHS_PER_YEAR - 1;
3267  }
3268  else if (tm->tm_mon < 0)
3269  {
3270  /*
3271  * Negative case. In this case, the calculation is
3272  * reversed, where -1 means December, -2 November,
3273  * etc.
3274  */
3275  mon = -1 * (tm->tm_mon + 1);
3276  }
3277  else
3278  {
3279  /*
3280  * Common case, with a strictly positive value. The
3281  * position in the array matches with the value of
3282  * tm_mon.
3283  */
3284  mon = MONTHS_PER_YEAR - tm->tm_mon;
3285  }
3286 
3287  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
3288  months[mon]);
3289  s += strlen(s);
3290  }
3291  break;
3292  case DCH_W:
3293  sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
3294  if (S_THth(n->suffix))
3295  str_numth(s, s, S_TH_TYPE(n->suffix));
3296  s += strlen(s);
3297  break;
3298  case DCH_J:
3299  sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
3300  if (S_THth(n->suffix))
3301  str_numth(s, s, S_TH_TYPE(n->suffix));
3302  s += strlen(s);
3303  break;
3304  }
3305  }
3306 
3307  *s = '\0';
3308 }
int date2j(int y, int m, int d)
Definition: datetime.c:284
int date2isoweek(int year, int mon, int mday)
Definition: timestamp.c:4475
int date2isoyearday(int year, int mon, int mday)
Definition: timestamp.c:4587
int date2isoyear(int year, int mon, int mday)
Definition: timestamp.c:4530
#define SECS_PER_HOUR
Definition: timestamp.h:126
#define SECS_PER_MINUTE
Definition: timestamp.h:127
#define HOURS_PER_DAY
Definition: timestamp.h:117
#define ad_STR
Definition: formatting.c:240
#define bc_STR
Definition: formatting.c:245
#define AD_STR
Definition: formatting.c:239
static char * asc_tolower_z(const char *buff)
Definition: formatting.c:2154
static char * str_numth(char *dest, char *num, int type)
Definition: formatting.c:1587
#define a_d_STR
Definition: formatting.c:238
#define DCH_to_char_fsec(frac_fmt, frac_val)
#define PM_STR
Definition: formatting.c:271
#define BC_STR
Definition: formatting.c:244
#define a_m_STR
Definition: formatting.c:265
#define A_D_STR
Definition: formatting.c:237
static char * str_initcap_z(const char *buff, Oid collid)
Definition: formatting.c:2148
#define pm_STR
Definition: formatting.c:272
static char * str_tolower_z(const char *buff, Oid collid)
Definition: formatting.c:2136
#define B_C_STR
Definition: formatting.c:242
#define ADJUST_YEAR(year, is_interval)
Definition: formatting.c:235
static char * str_toupper_z(const char *buff, Oid collid)
Definition: formatting.c:2142
#define TM_SUFFIX_LEN
Definition: formatting.c:597
#define b_c_STR
Definition: formatting.c:243
#define INVALID_FOR_INTERVAL
Definition: formatting.c:556
#define S_FM(_s)
Definition: formatting.c:589
#define tmtcTzn(_X)
Definition: formatting.c:521
static char * asc_toupper_z(const char *buff)
Definition: formatting.c:2160
#define P_M_STR
Definition: formatting.c:269
#define p_m_STR
Definition: formatting.c:270
#define A_M_STR
Definition: formatting.c:264
#define am_STR
Definition: formatting.c:267
#define AM_STR
Definition: formatting.c:266
static const char *const rm_months_upper[]
Definition: formatting.c:293
static struct pg_tm tm
Definition: localtime.c:102
int len
Definition: formatting.c:188
struct fmt_tm tm
Definition: formatting.c:515
fsec_t fsec
Definition: formatting.c:516
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, 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, generate_unaccent_rules::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 void do_to_timestamp ( text date_txt,
text fmt,
Oid  collid,
bool  std,
struct pg_tm tm,
fsec_t fsec,
int *  fprec,
uint32 flags,
bool have_error 
)
static

Definition at line 4510 of file formatting.c.

4513 {
4514  FormatNode *format = NULL;
4515  TmFromChar tmfc;
4516  int fmt_len;
4517  char *date_str;
4518  int fmask;
4519  bool incache = false;
4520 
4521  Assert(tm != NULL);
4522  Assert(fsec != NULL);
4523 
4524  date_str = text_to_cstring(date_txt);
4525 
4526  ZERO_tmfc(&tmfc);
4527  ZERO_tm(tm);
4528  *fsec = 0;
4529  if (fprec)
4530  *fprec = 0;
4531  if (flags)
4532  *flags = 0;
4533  fmask = 0; /* bit mask for ValidateDate() */
4534 
4535  fmt_len = VARSIZE_ANY_EXHDR(fmt);
4536 
4537  if (fmt_len)
4538  {
4539  char *fmt_str;
4540 
4541  fmt_str = text_to_cstring(fmt);
4542 
4543  if (fmt_len > DCH_CACHE_SIZE)
4544  {
4545  /*
4546  * Allocate new memory if format picture is bigger than static
4547  * cache and do not use cache (call parser always)
4548  */
4549  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4550 
4552  DCH_FLAG | (std ? STD_FLAG : 0), NULL);
4553  }
4554  else
4555  {
4556  /*
4557  * Use cache buffers
4558  */
4559  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, std);
4560 
4561  incache = true;
4562  format = ent->format;
4563  }
4564 
4565 #ifdef DEBUG_TO_FROM_CHAR
4566  /* dump_node(format, fmt_len); */
4567  /* dump_index(DCH_keywords, DCH_index); */
4568 #endif
4569 
4570  DCH_from_char(format, date_str, &tmfc, collid, std, have_error);
4571  CHECK_ERROR;
4572 
4573  pfree(fmt_str);
4574 
4575  if (flags)
4576  *flags = DCH_datetime_type(format, have_error);
4577 
4578  if (!incache)
4579  {
4580  pfree(format);
4581  format = NULL;
4582  }
4583 
4584  CHECK_ERROR;
4585  }
4586 
4587  DEBUG_TMFC(&tmfc);
4588 
4589  /*
4590  * Convert to_date/to_timestamp input fields to standard 'tm'
4591  */
4592  if (tmfc.ssss)
4593  {
4594  int x = tmfc.ssss;
4595 
4596  tm->tm_hour = x / SECS_PER_HOUR;
4597  x %= SECS_PER_HOUR;
4598  tm->tm_min = x / SECS_PER_MINUTE;
4599  x %= SECS_PER_MINUTE;
4600  tm->tm_sec = x;
4601  }
4602 
4603  if (tmfc.ss)
4604  tm->tm_sec = tmfc.ss;
4605  if (tmfc.mi)
4606  tm->tm_min = tmfc.mi;
4607  if (tmfc.hh)
4608  tm->tm_hour = tmfc.hh;
4609 
4610  if (tmfc.clock == CLOCK_12_HOUR)
4611  {
4612  if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
4613  {
4615  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4616  errmsg("hour \"%d\" is invalid for the 12-hour clock",
4617  tm->tm_hour),
4618  errhint("Use the 24-hour clock, or give an hour between 1 and 12."))));
4619  }
4620 
4621  if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
4622  tm->tm_hour += HOURS_PER_DAY / 2;
4623  else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
4624  tm->tm_hour = 0;
4625  }
4626 
4627  if (tmfc.year)
4628  {
4629  /*
4630  * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
4631  * the year in the given century. Keep in mind that the 21st century
4632  * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
4633  * 600BC to 501BC.
4634  */
4635  if (tmfc.cc && tmfc.yysz <= 2)
4636  {
4637  if (tmfc.bc)
4638  tmfc.cc = -tmfc.cc;
4639  tm->tm_year = tmfc.year % 100;
4640  if (tm->tm_year)
4641  {
4642  if (tmfc.cc >= 0)
4643  tm->tm_year += (tmfc.cc - 1) * 100;
4644  else
4645  tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1;
4646  }
4647  else
4648  {
4649  /* find century year for dates ending in "00" */
4650  tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
4651  }
4652  }
4653  else
4654  {
4655  /* If a 4-digit year is provided, we use that and ignore CC. */
4656  tm->tm_year = tmfc.year;
4657  if (tmfc.bc)
4658  tm->tm_year = -tm->tm_year;
4659  /* correct for our representation of BC years */
4660  if (tm->tm_year < 0)
4661  tm->tm_year++;
4662  }
4663  fmask |= DTK_M(YEAR);
4664  }
4665  else if (tmfc.cc)
4666  {
4667  /* use first year of century */
4668  if (tmfc.bc)
4669  tmfc.cc = -tmfc.cc;
4670  if (tmfc.cc >= 0)
4671  /* +1 because 21st century started in 2001 */
4672  tm->tm_year = (tmfc.cc - 1) * 100 + 1;
4673  else
4674  /* +1 because year == 599 is 600 BC */
4675  tm->tm_year = tmfc.cc * 100 + 1;
4676  fmask |= DTK_M(YEAR);
4677  }
4678 
4679  if (tmfc.j)
4680  {
4681  j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4682  fmask |= DTK_DATE_M;
4683  }
4684 
4685  if (tmfc.ww)
4686  {
4687  if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4688  {
4689  /*
4690  * If tmfc.d is not set, then the date is left at the beginning of
4691  * the ISO week (Monday).
4692  */
4693  if (tmfc.d)
4694  isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4695  else
4696  isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4697  fmask |= DTK_DATE_M;
4698  }
4699  else
4700  tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
4701  }
4702 
4703  if (tmfc.w)
4704  tmfc.dd = (tmfc.w - 1) * 7 + 1;
4705  if (tmfc.dd)
4706  {
4707  tm->tm_mday = tmfc.dd;
4708  fmask |= DTK_M(DAY);
4709  }
4710  if (tmfc.mm)
4711  {
4712  tm->tm_mon = tmfc.mm;
4713  fmask |= DTK_M(MONTH);
4714  }
4715 
4716  if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
4717  {
4718  /*
4719  * The month and day field have not been set, so we use the
4720  * day-of-year field to populate them. Depending on the date mode,
4721  * this field may be interpreted as a Gregorian day-of-year, or an ISO
4722  * week date day-of-year.
4723  */
4724 
4725  if (!tm->tm_year && !tmfc.bc)
4726  {
4728  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4729  errmsg("cannot calculate day of year without year information"))));
4730  }
4731 
4732  if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4733  {
4734  int j0; /* zeroth day of the ISO year, in Julian */
4735 
4736  j0 = isoweek2j(tm->tm_year, 1) - 1;
4737 
4738  j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4739  fmask |= DTK_DATE_M;
4740  }
4741  else
4742  {
4743  const int *y;
4744  int i;
4745 
4746  static const int ysum[2][13] = {
4747  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
4748  {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
4749 
4750  y = ysum[isleap(tm->tm_year)];
4751 
4752  for (i = 1; i <= MONTHS_PER_YEAR; i++)
4753  {
4754  if (tmfc.ddd <= y[i])
4755  break;
4756  }
4757  if (tm->tm_mon <= 1)
4758  tm->tm_mon = i;
4759 
4760  if (tm->tm_mday <= 1)
4761  tm->tm_mday = tmfc.ddd - y[i - 1];
4762 
4763  fmask |= DTK_M(MONTH) | DTK_M(DAY);
4764  }
4765  }
4766 
4767  if (tmfc.ms)
4768  *fsec += tmfc.ms * 1000;
4769  if (tmfc.us)
4770  *fsec += tmfc.us;
4771  if (fprec)
4772  *fprec = tmfc.ff; /* fractional precision, if specified */
4773 
4774  /* Range-check date fields according to bit mask computed above */
4775  if (fmask != 0)
4776  {
4777  /* We already dealt with AD/BC, so pass isjulian = true */
4778  int dterr = ValidateDate(fmask, true, false, false, tm);
4779 
4780  if (dterr != 0)
4781  {
4782  /*
4783  * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
4784  * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
4785  * irrelevant hint about datestyle.
4786  */
4787  RETURN_ERROR(DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"));
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  {
4797  RETURN_ERROR(DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp"));
4798  }
4799 
4800  /* Save parsed time-zone into tm->tm_zone if it was specified */
4801  if (tmfc.tzsign)
4802  {
4803  char *tz;
4804 
4805  if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
4806  tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
4807  {
4808  RETURN_ERROR(DateTimeParseError(DTERR_TZDISP_OVERFLOW, date_str, "timestamp"));
4809  }
4810 
4811  tz = psprintf("%c%02d:%02d",
4812  tmfc.tzsign > 0 ? '+' : '-', tmfc.tzh, tmfc.tzm);
4813 
4814  tm->tm_zone = tz;
4815  }
4816 
4817  DEBUG_TM(tm);
4818 
4819 on_error:
4820 
4821  if (format && !incache)
4822  pfree(format);
4823 
4824  pfree(date_str);
4825 }
void DateTimeParseError(int dterr, const char *str, const char *datatype)
Definition: datetime.c:4024
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2648
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:309
void isoweek2date(int woy, int *year, int *mon, int *mday)
Definition: timestamp.c:4444
int isoweek2j(int year, int week)
Definition: timestamp.c:4424
void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
Definition: timestamp.c:4457
#define MAX_TZDISP_HOUR
Definition: timestamp.h:142
#define MINS_PER_HOUR
Definition: timestamp.h:128
#define USECS_PER_SEC
Definition: timestamp.h:133
#define DEBUG_TM(_X)
Definition: formatting.c:489
#define ZERO_tmfc(_X)
Definition: formatting.c:469
#define DEBUG_TMFC(_X)
Definition: formatting.c:488
static void DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, Oid collid, bool std, bool *have_error)
Definition: formatting.c:3322
#define ZERO_tm(_X)
Definition: formatting.c:539
#define MONTH
Definition: datetime.h:92
#define DTK_M(t)
Definition: datetime.h:188
#define DAY
Definition: datetime.h:94
#define YEAR
Definition: datetime.h:93
#define DTK_DATE_M
Definition: datetime.h:192
#define isleap(y)
Definition: datetime.h:272
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:285
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:282
int y
Definition: isn.c:72
int x
Definition: isn.c:71
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
FromCharDateMode mode
Definition: formatting.c:443
const char * tm_zone
Definition: pgtime.h:46

References Assert(), TmFromChar::bc, TmFromChar::cc, CHECK_ERROR, TmFromChar::clock, CLOCK_12_HOUR, 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, DTERR_FIELD_OVERFLOW, DTERR_TZDISP_OVERFLOW, DTK_DATE_M, DTK_M, ereport, errcode(), errhint(), errmsg(), ERROR, TmFromChar::ff, fmt, DCHCacheEntry::format, format, FROM_CHAR_DATE_ISOWEEK, TmFromChar::hh, HOURS_PER_DAY, i, 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(), TmFromChar::pm, psprintf(), RETURN_ERROR, SECS_PER_HOUR, SECS_PER_MINUTE, 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, pg_tm::tm_zone, TmFromChar::tzh, TmFromChar::tzm, 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 4834 of file formatting.c.

4835 {
4836  memset(str, c, max);
4837  *(str + max) = '\0';
4838  return str;
4839 }

References generate_unaccent_rules::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 6516 of file formatting.c.

6521 {
6523  text *fmt = PG_GETARG_TEXT_PP(1);
6524  NUMDesc Num;
6525  FormatNode *format;
6526  text *result;
6527  bool shouldFree;
6528  int out_pre_spaces = 0,
6529  sign = 0;
6530  char *numstr,
6531  *p;
6532 
6534 
6535  if (IS_ROMAN(&Num))
6536  numstr = int_to_roman((int) rint(value));
6537  else if (IS_EEEE(&Num))
6538  {
6539  if (isnan(value) || isinf(value))
6540  {
6541  /*
6542  * Allow 6 characters for the leading sign, the decimal point,
6543  * "e", the exponent's sign and two exponent digits.
6544  */
6545  numstr = (char *) palloc(Num.pre + Num.post + 7);
6546  fill_str(numstr, '#', Num.pre + Num.post + 6);
6547  *numstr = ' ';
6548  *(numstr + Num.pre + 1) = '.';
6549  }
6550  else
6551  {
6552  numstr = psprintf("%+.*e", Num.post, value);
6553 
6554  /*
6555  * Swap a leading positive sign for a space.
6556  */
6557  if (*numstr == '+')
6558  *numstr = ' ';
6559  }
6560  }
6561  else
6562  {
6563  float4 val = value;
6564  char *orgnum;
6565  int numstr_pre_len;
6566 
6567  if (IS_MULTI(&Num))
6568  {
6569  float multi = pow((double) 10, (double) Num.multi);
6570 
6571  val = value * multi;
6572  Num.pre += Num.multi;
6573  }
6574 
6575  orgnum = psprintf("%.0f", fabs(val));
6576  numstr_pre_len = strlen(orgnum);
6577 
6578  /* adjust post digits to fit max float digits */
6579  if (numstr_pre_len >= FLT_DIG)
6580  Num.post = 0;
6581  else if (numstr_pre_len + Num.post > FLT_DIG)
6582  Num.post = FLT_DIG - numstr_pre_len;
6583  orgnum = psprintf("%.*f", Num.post, val);
6584 
6585  if (*orgnum == '-')
6586  { /* < 0 */
6587  sign = '-';
6588  numstr = orgnum + 1;
6589  }
6590  else
6591  {
6592  sign = '+';
6593  numstr = orgnum;
6594  }
6595 
6596  if ((p = strchr(numstr, '.')))
6597  numstr_pre_len = p - numstr;
6598  else
6599  numstr_pre_len = strlen(numstr);
6600 
6601  /* needs padding? */
6602  if (numstr_pre_len < Num.pre)
6603  out_pre_spaces = Num.pre - numstr_pre_len;
6604  /* overflowed prefix digit format? */
6605  else if (numstr_pre_len > Num.pre)
6606  {
6607  numstr = (char *) palloc(Num.pre + Num.post + 2);
6608  fill_str(numstr, '#', Num.pre + Num.post + 1);
6609  *(numstr + Num.pre) = '.';
6610  }
6611  }
float float4
Definition: c.h:564
#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:6100
#define IS_MULTI(_f)
Definition: formatting.c:375
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:4834
#define IS_ROMAN(_f)
Definition: formatting.c:374
#define IS_EEEE(_f)
Definition: formatting.c:376
static char * int_to_roman(int number)
Definition: formatting.c:5034
long val
Definition: informix.c:664
int pre
Definition: formatting.c:327
int multi
Definition: formatting.c:332
int post
Definition: formatting.c:328

References fill_str(), fmt, 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_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 6618 of file formatting.c.

6623 {
6625  text *fmt = PG_GETARG_TEXT_PP(1);
6626  NUMDesc Num;
6627  FormatNode *format;
6628  text *result;
6629  bool shouldFree;
6630  int out_pre_spaces = 0,
6631  sign = 0;
6632  char *numstr,
6633  *p;
6634 
6636 
6637  if (IS_ROMAN(&Num))
6638  numstr = int_to_roman((int) rint(value));
6639  else if (IS_EEEE(&Num))
6640  {
6641  if (isnan(value) || isinf(value))
6642  {
6643  /*
6644  * Allow 6 characters for the leading sign, the decimal point,
6645  * "e", the exponent's sign and two exponent digits.
6646  */
6647  numstr = (char *) palloc(Num.pre + Num.post + 7);
6648  fill_str(numstr, '#', Num.pre + Num.post + 6);
6649  *numstr = ' ';
6650  *(numstr + Num.pre + 1) = '.';
6651  }
6652  else
6653  {
6654  numstr = psprintf("%+.*e", Num.post, value);
6655 
6656  /*
6657  * Swap a leading positive sign for a space.
6658  */
6659  if (*numstr == '+')
6660  *numstr = ' ';
6661  }
6662  }
6663  else
6664  {
6665  float8 val = value;
6666  char *orgnum;
6667  int numstr_pre_len;
6668 
6669  if (IS_MULTI(&Num))
6670  {
6671  double multi = pow((double) 10, (double) Num.multi);
6672 
6673  val = value * multi;
6674  Num.pre += Num.multi;
6675  }
6676 
6677  orgnum = psprintf("%.0f", fabs(val));
6678  numstr_pre_len = strlen(orgnum);
6679 
6680  /* adjust post digits to fit max double digits */
6681  if (numstr_pre_len >= DBL_DIG)
6682  Num.post = 0;
6683  else if (numstr_pre_len + Num.post > DBL_DIG)
6684  Num.post = DBL_DIG - numstr_pre_len;
6685  orgnum = psprintf("%.*f", Num.post, val);
6686 
6687  if (*orgnum == '-')
6688  { /* < 0 */
6689  sign = '-';
6690  numstr = orgnum + 1;
6691  }
6692  else
6693  {
6694  sign = '+';
6695  numstr = orgnum;
6696  }
6697 
6698  if ((p = strchr(numstr, '.')))
6699  numstr_pre_len = p - numstr;
6700  else
6701  numstr_pre_len = strlen(numstr);
6702 
6703  /* needs padding? */
6704  if (numstr_pre_len < Num.pre)
6705  out_pre_spaces = Num.pre - numstr_pre_len;
6706  /* overflowed prefix digit format? */
6707  else if (numstr_pre_len > Num.pre)
6708  {
6709  numstr = (char *) palloc(Num.pre + Num.post + 2);
6710  fill_str(numstr, '#', Num.pre + Num.post + 1);
6711  *(numstr + Num.pre) = '.';
6712  }
6713  }
double float8
Definition: c.h:565
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282

References fill_str(), fmt, 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, 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,
bool have_error 
)
static

Definition at line 2471 of file formatting.c.

2472 {
2473  return from_char_parse_int_len(dest, src, node->key->len, node, have_error);
2474 }

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,
bool have_error 
)
static

Definition at line 2368 of file formatting.c.

2370 {
2371  long result;
2372  char copy[DCH_MAX_ITEM_SIZ + 1];
2373  const char *init = *src;
2374  int used;
2375 
2376  /*
2377  * Skip any whitespace before parsing the integer.
2378  */
2379  *src += strspace_len(*src);
2380 
2382  used = (int) strlcpy(copy, *src, len + 1);
2383 
2384  if (S_FM(node->suffix) || is_next_separator(node))
2385  {
2386  /*
2387  * This node is in Fill Mode, or the next node is known to be a
2388  * non-digit value, so we just slurp as many characters as we can get.
2389  */
2390  char *endptr;
2391 
2392  errno = 0;
2393  result = strtol(init, &endptr, 10);
2394  *src = endptr;
2395  }
2396  else
2397  {
2398  /*
2399  * We need to pull exactly the number of characters given in 'len' out
2400  * of the string, and convert those.
2401  */
2402  char *last;
2403 
2404  if (used < len)
2406  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2407  errmsg("source string too short for \"%s\" "
2408  "formatting field",
2409  node->key->name),
2410  errdetail("Field requires %d characters, "
2411  "but only %d remain.",
2412  len, used),
2413  errhint("If your source string is not fixed-width, "
2414  "try using the \"FM\" modifier."))));
2415 
2416  errno = 0;
2417  result = strtol(copy, &last, 10);
2418  used = last - copy;
2419 
2420  if (used > 0 && used < len)
2422  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2423  errmsg("invalid value \"%s\" for \"%s\"",
2424  copy, node->key->name),
2425  errdetail("Field requires %d characters, "
2426  "but only %d could be parsed.",
2427  len, used),
2428  errhint("If your source string is not fixed-width, "
2429  "try using the \"FM\" modifier."))));
2430 
2431  *src += used;
2432  }
2433 
2434  if (*src == init)
2436  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2437  errmsg("invalid value \"%s\" for \"%s\"",
2438  copy, node->key->name),
2439  errdetail("Value must be an integer."))));
2440 
2441  if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
2443  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2444  errmsg("value for \"%s\" in source string is out of range",
2445  node->key->name),
2446  errdetail("Value must be in the range %d to %d.",
2447  INT_MIN, INT_MAX))));
2448 
2449  if (dest != NULL)
2450  {
2451  from_char_set_int(dest, (int) result, node, have_error);
2452  CHECK_ERROR;
2453  }
2454 
2455  return *src - init;
2456 
2457 on_error:
2458  return -1;
2459 }
int errdetail(const char *fmt,...)
Definition: elog.c:1037
static bool is_next_separator(FormatNode *n)
Definition: formatting.c:2222
static int strspace_len(const char *str)
Definition: formatting.c:2279
int init
Definition: isn.c:75

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

Referenced by DCH_from_char(), and from_char_parse_int().

◆ from_char_seq_search()

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

Definition at line 2629 of file formatting.c.

2632 {
2633  int len;
2634 
2635  if (localized_array == NULL)
2636  *dest = seq_search_ascii(*src, array, &len);
2637  else
2638  *dest = seq_search_localized(*src, localized_array, &len, collid);
2639 
2640  if (len <= 0)
2641  {
2642  /*
2643  * In the error report, truncate the string at the next whitespace (if
2644  * any) to avoid including irrelevant data.
2645  */
2646  char *copy = pstrdup(*src);
2647  char *c;
2648 
2649  for (c = copy; *c; c++)
2650  {
2651  if (scanner_isspace(*c))
2652  {
2653  *c = '\0';
2654  break;
2655  }
2656  }
2657 
2659  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2660  errmsg("invalid value \"%s\" for \"%s\"",
2661  copy, node->key->name),
2662  errdetail("The given value did not match any of "
2663  "the allowed values for this field."))));
2664  }
2665  *src += len;
2666  return len;
2667 
2668 on_error:
2669  return -1;
2670 }
static int seq_search_localized(const char *name, char **array, int *len, Oid collid)
Definition: formatting.c:2545
static int seq_search_ascii(const char *name, const char *const *array, int *len)
Definition: formatting.c:2488
char * pstrdup(const char *in)
Definition: mcxt.c:1305
bool scanner_isspace(char ch)
Definition: scansup.c:117

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

Referenced by DCH_from_char().

◆ from_char_set_int()

static void from_char_set_int ( int *  dest,
const int  value,
const FormatNode node,
bool have_error 
)
static

Definition at line 2327 of file formatting.c.

2329 {
2330  if (*dest != 0 && *dest != value)
2332  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2333  errmsg("conflicting values for \"%s\" field in "
2334  "formatting string",
2335  node->key->name),
2336  errdetail("This value contradicts a previous setting "
2337  "for the same field type."))));
2338  *dest = value;
2339 
2340 on_error:
2341  return;
2342 }

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

Referenced by DCH_from_char(), and from_char_parse_int_len().

◆ from_char_set_mode()

static void from_char_set_mode ( TmFromChar tmfc,
const FromCharDateMode  mode,
bool have_error 
)
static

Definition at line 2300 of file formatting.c.

2301 {
2302  if (mode != FROM_CHAR_DATE_NONE)
2303  {
2304  if (tmfc->mode == FROM_CHAR_DATE_NONE)
2305  tmfc->mode = mode;
2306  else if (tmfc->mode != mode)
2308  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2309  errmsg("invalid combination of date conventions"),
2310  errhint("Do not mix Gregorian and ISO week date "
2311  "conventions in a formatting template."))));
2312  }
2313 
2314 on_error:
2315  return;
2316 }
static PgChecksumMode mode
Definition: pg_checksums.c:65

References ereport, errcode(), errhint(), errmsg(), ERROR, FROM_CHAR_DATE_NONE, TmFromChar::mode, mode, and RETURN_ERROR.

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

static char * get_last_relevant_decnum ( char *  num)
static

Definition at line 5165 of file formatting.c.

5166 {
5167  char *result,
5168  *p = strchr(num, '.');
5169 
5170 #ifdef DEBUG_TO_FROM_CHAR
5171  elog(DEBUG_elog_output, "get_last_relevant_decnum()");
5172 #endif
5173 
5174  if (!p)
5175  return NULL;
5176 
5177  result = p;
5178 
5179  while (*(++p))
5180  {
5181  if (*p != '0')
5182  result = p;
5183  }
5184 
5185  return result;
5186 }

References elog.

Referenced by NUM_processor().

◆ get_th()

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

Definition at line 1542 of file formatting.c.

1543 {
1544  int len = strlen(num),
1545  last;
1546 
1547  last = *(num + (len - 1));
1548  if (!isdigit((unsigned char) last))
1549  ereport(ERROR,
1550  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1551  errmsg("\"%s\" is not a number", num)));
1552 
1553  /*
1554  * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1555  * 'ST/st', 'ND/nd', 'RD/rd', respectively
1556  */
1557  if ((len > 1) && (num[len - 2] == '1'))
1558  last = 0;
1559 
1560  switch (last)
1561  {
1562  case '1':
1563  if (type == TH_UPPER)
1564  return numTH[0];
1565  return numth[0];
1566  case '2':
1567  if (type == TH_UPPER)
1568  return numTH[1];
1569  return numth[1];
1570  case '3':
1571  if (type == TH_UPPER)
1572  return numTH[2];
1573  return numth[2];
1574  default:
1575  if (type == TH_UPPER)
1576  return numTH[3];
1577  return numth[3];
1578  }
1579 }
static const char *const numth[]
Definition: formatting.c:312
static const char *const numTH[]
Definition: formatting.c:311
#define TH_UPPER
Definition: formatting.c:318

References ereport, errcode(), errmsg(), ERROR, len, numTH, numth, TH_UPPER, and generate_unaccent_rules::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 1125 of file formatting.c.

1126 {
1127  int poz;
1128 
1129  if (!KeyWord_INDEX_FILTER(*str))
1130  return NULL;
1131 
1132  if ((poz = *(index + (*str - ' '))) > -1)
1133  {
1134  const KeyWord *k = kw + poz;
1135 
1136  do
1137  {
1138  if (strncmp(str, k->name, k->len) == 0)
1139  return k;
1140  k++;
1141  if (!k->name)
1142  return NULL;
1143  } while (*str == *k->name);
1144  }
1145  return NULL;
1146 }
#define KeyWord_INDEX_FILTER(_c)
Definition: formatting.c:149
Definition: type.h:90

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

Referenced by parse_format().

◆ int4_to_char()

Datum int4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6316 of file formatting.c.

6321 {
6323  text *fmt = PG_GETARG_TEXT_PP(1);
6324  NUMDesc Num;
6325  FormatNode *format;
6326  text *result;
6327  bool shouldFree;
6328  int out_pre_spaces = 0,
6329  sign = 0;
6330  char *numstr,
6331  *orgnum;
6332 
6334 
6335  /*
6336  * On DateType depend part (int32)
6337  */
6338  if (IS_ROMAN(&Num))
6339  numstr = int_to_roman(value);
6340  else if (IS_EEEE(&Num))
6341  {
6342  /* we can do it easily because float8 won't lose any precision */
6343  float8 val = (float8) value;
6344 
6345  orgnum = (char *) psprintf("%+.*e", Num.post, val);
6346 
6347  /*
6348  * Swap a leading positive sign for a space.
6349  */
6350  if (*orgnum == '+')
6351  *orgnum = ' ';
6352 
6353  numstr = orgnum;
6354  }
6355  else
6356  {
6357  int numstr_pre_len;
6358 
6359  if (IS_MULTI(&Num))
6360  {
6362  Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
6363  Num.pre += Num.multi;
6364  }
6365  else
6366  {
6368  Int32GetDatum(value)));
6369  }
6370 
6371  if (*orgnum == '-')
6372  {
6373  sign = '-';
6374  orgnum++;
6375  }
6376  else
6377  sign = '+';
6378 
6379  numstr_pre_len = strlen(orgnum);
6380 
6381  /* post-decimal digits? Pad out with zeros. */
6382  if (Num.post)
6383  {
6384  numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6385  strcpy(numstr, orgnum);
6386  *(numstr + numstr_pre_len) = '.';
6387  memset(numstr + numstr_pre_len + 1, '0', Num.post);
6388  *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6389  }
6390  else
6391  numstr = orgnum;
6392 
6393  /* needs padding? */
6394  if (numstr_pre_len < Num.pre)
6395  out_pre_spaces = Num.pre - numstr_pre_len;
6396  /* overflowed prefix digit format? */
6397  else if (numstr_pre_len > Num.pre)
6398  {
6399  numstr = (char *) palloc(Num.pre + Num.post + 2);
6400  fill_str(numstr, '#', Num.pre + Num.post + 1);
6401  *(numstr + Num.pre) = '.';
6402  }
6403  }
signed int int32
Definition: c.h:429
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:631
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
Datum int4out(PG_FUNCTION_ARGS)
Definition: int.c:301
#define Int32GetDatum(X)
Definition: postgres.h:523
#define DatumGetCString(X)
Definition: postgres.h:610

References DatumGetCString, DirectFunctionCall1, fill_str(), fmt, 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 6410 of file formatting.c.

6415 {
6416  int64 value = PG_GETARG_INT64(0);
6417  text *fmt = PG_GETARG_TEXT_PP(1);
6418  NUMDesc Num;
6419  FormatNode *format;
6420  text *result;
6421  bool shouldFree;
6422  int out_pre_spaces = 0,
6423  sign = 0;
6424  char *numstr,
6425  *orgnum;
6426 
6428 
6429  /*
6430  * On DateType depend part (int32)
6431  */
6432  if (IS_ROMAN(&Num))
6433  {
6434  /* Currently don't support int8 conversion to roman... */
6436  }
6437  else if (IS_EEEE(&Num))
6438  {
6439  /* to avoid loss of precision, must go via numeric not float8 */
6441  Num.post);
6442 
6443  /*
6444  * numeric_out_sci() does not emit a sign for positive numbers. We
6445  * need to add a space in this case so that positive and negative
6446  * numbers are aligned. We don't have to worry about NaN/inf here.
6447  */
6448  if (*orgnum != '-')
6449  {
6450  numstr = (char *) palloc(strlen(orgnum) + 2);
6451  *numstr = ' ';
6452  strcpy(numstr + 1, orgnum);
6453  }
6454  else
6455  {
6456  numstr = orgnum;
6457  }
6458  }
6459  else
6460  {
6461  int numstr_pre_len;
6462 
6463  if (IS_MULTI(&Num))
6464  {
6465  double multi = pow((double) 10, (double) Num.multi);
6466 
6470  Float8GetDatum(multi))));
6471  Num.pre += Num.multi;
6472  }
6473 
6475  Int64GetDatum(value)));
6476 
6477  if (*orgnum == '-')
6478  {
6479  sign = '-';
6480  orgnum++;
6481  }
6482  else
6483  sign = '+';
6484 
6485  numstr_pre_len = strlen(orgnum);
6486 
6487  /* post-decimal digits? Pad out with zeros. */
6488  if (Num.post)
6489  {
6490  numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6491  strcpy(numstr, orgnum);
6492  *(numstr + numstr_pre_len) = '.';
6493  memset(numstr + numstr_pre_len + 1, '0', Num.post);
6494  *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6495  }
6496  else
6497  numstr = orgnum;
6498 
6499  /* needs padding? */
6500  if (numstr_pre_len < Num.pre)
6501  out_pre_spaces = Num.pre - numstr_pre_len;
6502  /* overflowed prefix digit format? */
6503  else if (numstr_pre_len > Num.pre)
6504  {
6505  numstr = (char *) palloc(Num.pre + Num.post + 2);
6506  fill_str(numstr, '#', Num.pre + Num.post + 1);
6507  *(numstr + Num.pre) = '.';
6508  }
6509  }
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4137
char * numeric_out_sci(Numeric num, int scale)
Definition: numeric.c:911
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1683
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1692
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:633
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
Datum int8out(PG_FUNCTION_ARGS)
Definition: int8.c:62
Datum int84(PG_FUNCTION_ARGS)
Definition: int8.c:1250
Datum int8mul(PG_FUNCTION_ARGS)
Definition: int8.c:491
Datum dtoi8(PG_FUNCTION_ARGS)
Definition: int8.c:1298
#define DatumGetInt32(X)
Definition: postgres.h:516
#define DatumGetInt64(X)
Definition: postgres.h:651

References DatumGetCString, DatumGetInt32, DatumGetInt64, DirectFunctionCall1, DirectFunctionCall2, dtoi8(), fill_str(), Float8GetDatum(), fmt, format, int64_to_numeric(), Int64GetDatum(), int84(), 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_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, sign, and value.

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 5034 of file formatting.c.

5035 {
5036  int len,
5037  num;
5038  char *p,
5039  *result,
5040  numstr[12];
5041 
5042  result = (char *) palloc(16);
5043  *result = '\0';
5044 
5045  if (number > 3999 || number < 1)
5046  {
5047  fill_str(result, '#', 15);
5048  return result;
5049  }
5050  len = snprintf(numstr, sizeof(numstr), "%d", number);
5051 
5052  for (p = numstr; *p != '\0'; p++, --len)
5053  {
5054  num = *p - ('0' + 1);
5055  if (num < 0)
5056  continue;
5057 
5058  if (len > 3)
5059  {
5060  while (num-- != -1)
5061  strcat(result, "M");
5062  }
5063  else
5064  {
5065  if (len == 3)
5066  strcat(result, rm100[num]);
5067  else if (len == 2)
5068  strcat(result, rm10[num]);
5069  else if (len == 1)
5070  strcat(result, rm1[num]);
5071  }
5072  }
5073  return result;
5074 }
static const char *const rm100[]
Definition: formatting.c:305
static const char *const rm10[]
Definition: formatting.c:304
static const char *const rm1[]
Definition: formatting.c:303
#define snprintf
Definition: port.h:225

References fill_str(), 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 4193 of file formatting.c.

4194 {
4195  Interval *it = PG_GETARG_INTERVAL_P(0);
4196  text *fmt = PG_GETARG_TEXT_PP(1),
4197  *res;
4198  TmToChar tmtc;
4199  struct fmt_tm *tm;
4200  struct pg_itm tt,
4201  *itm = &tt;
4202 
4203  if (VARSIZE_ANY_EXHDR(fmt) <= 0)
4204  PG_RETURN_NULL();
4205 
4206  ZERO_tmtc(&tmtc);
4207  tm = tmtcTm(&tmtc);
4208 
4209  interval2itm(*it, itm);
4210  tmtc.fsec = itm->tm_usec;
4211  tm->tm_sec = itm->tm_sec;
4212  tm->tm_min = itm->tm_min;
4213  tm->tm_hour = itm->tm_hour;
4214  tm->tm_mday = itm->tm_mday;
4215  tm->tm_mon = itm->tm_mon;
4216  tm->tm_year = itm->tm_year;
4217 
4218  /* wday is meaningless, yday approximates the total span in days */
4220 
4221  if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4222  PG_RETURN_NULL();
4223 
4225 }
void interval2itm(Interval span, struct pg_itm *itm)
Definition: timestamp.c:1962
#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
static text * datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
Definition: formatting.c:4048
#define ZERO_tmtc(_X)
Definitio