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

Go to the source code of this file.

Data Structures

struct  KeySuffix
 
struct  KeyWord
 
struct  FormatNode
 
struct  NUMDesc
 
struct  DCHCacheEntry
 
struct  NUMCacheEntry
 
struct  TmFromChar
 
struct  fmt_tz
 
struct  fmt_tm
 
struct  TmToChar
 
struct  NUMProc
 

Macros

#define DCH_FLAG   0x1 /* DATE-TIME flag */
 
#define NUM_FLAG   0x2 /* NUMBER flag */
 
#define STD_FLAG   0x4 /* STANDARD flag */
 
#define KeyWord_INDEX_SIZE   ('~' - ' ')
 
#define KeyWord_INDEX_FILTER(_c)   ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
 
#define DCH_MAX_ITEM_SIZ   12 /* max localized day name */
 
#define NUM_MAX_ITEM_SIZ   8 /* roman number (RN has 15 chars) */
 
#define NODE_TYPE_END   1
 
#define NODE_TYPE_ACTION   2
 
#define NODE_TYPE_CHAR   3
 
#define NODE_TYPE_SEPARATOR   4
 
#define NODE_TYPE_SPACE   5
 
#define SUFFTYPE_PREFIX   1
 
#define SUFFTYPE_POSTFIX   2
 
#define CLOCK_24_HOUR   0
 
#define CLOCK_12_HOUR   1
 
#define ADJUST_YEAR(year, is_interval)   ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
 
#define A_D_STR   "A.D."
 
#define a_d_STR   "a.d."
 
#define AD_STR   "AD"
 
#define ad_STR   "ad"
 
#define B_C_STR   "B.C."
 
#define b_c_STR   "b.c."
 
#define BC_STR   "BC"
 
#define bc_STR   "bc"
 
#define A_M_STR   "A.M."
 
#define a_m_STR   "a.m."
 
#define AM_STR   "AM"
 
#define am_STR   "am"
 
#define P_M_STR   "P.M."
 
#define p_m_STR   "p.m."
 
#define PM_STR   "PM"
 
#define pm_STR   "pm"
 
#define IS_VALID_SUB_COMB(curr, next)
 
#define ROMAN_VAL(r)
 
#define MAX_ROMAN_LEN   15
 
#define TH_UPPER   1
 
#define TH_LOWER   2
 
#define NUM_F_DECIMAL   (1 << 1)
 
#define NUM_F_LDECIMAL   (1 << 2)
 
#define NUM_F_ZERO   (1 << 3)
 
#define NUM_F_BLANK   (1 << 4)
 
#define NUM_F_FILLMODE   (1 << 5)
 
#define NUM_F_LSIGN   (1 << 6)
 
#define NUM_F_BRACKET   (1 << 7)
 
#define NUM_F_MINUS   (1 << 8)
 
#define NUM_F_PLUS   (1 << 9)
 
#define NUM_F_ROMAN   (1 << 10)
 
#define NUM_F_MULTI   (1 << 11)
 
#define NUM_F_PLUS_POST   (1 << 12)
 
#define NUM_F_MINUS_POST   (1 << 13)
 
#define NUM_F_EEEE   (1 << 14)
 
#define NUM_LSIGN_PRE   (-1)
 
#define NUM_LSIGN_POST   1
 
#define NUM_LSIGN_NONE   0
 
#define IS_DECIMAL(_f)   ((_f)->flag & NUM_F_DECIMAL)
 
#define IS_LDECIMAL(_f)   ((_f)->flag & NUM_F_LDECIMAL)
 
#define IS_ZERO(_f)   ((_f)->flag & NUM_F_ZERO)
 
#define IS_BLANK(_f)   ((_f)->flag & NUM_F_BLANK)
 
#define IS_FILLMODE(_f)   ((_f)->flag & NUM_F_FILLMODE)
 
#define IS_BRACKET(_f)   ((_f)->flag & NUM_F_BRACKET)
 
#define IS_MINUS(_f)   ((_f)->flag & NUM_F_MINUS)
 
#define IS_LSIGN(_f)   ((_f)->flag & NUM_F_LSIGN)
 
#define IS_PLUS(_f)   ((_f)->flag & NUM_F_PLUS)
 
#define IS_ROMAN(_f)   ((_f)->flag & NUM_F_ROMAN)
 
#define IS_MULTI(_f)   ((_f)->flag & NUM_F_MULTI)
 
#define IS_EEEE(_f)   ((_f)->flag & NUM_F_EEEE)
 
#define DCH_CACHE_OVERHEAD    MAXALIGN(sizeof(bool) + sizeof(int))
 
#define NUM_CACHE_OVERHEAD    MAXALIGN(sizeof(bool) + sizeof(int) + sizeof(NUMDesc))
 
#define DCH_CACHE_SIZE    ((2048 - DCH_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
 
#define NUM_CACHE_SIZE    ((1024 - NUM_CACHE_OVERHEAD) / (sizeof(FormatNode) + sizeof(char)) - 1)
 
#define DCH_CACHE_ENTRIES   20
 
#define NUM_CACHE_ENTRIES   20
 
#define ZERO_tmfc(_X)   memset(_X, 0, sizeof(TmFromChar))
 
#define DEBUG_TMFC(_X)
 
#define DEBUG_TM(_X)
 
#define tmtcTm(_X)   (&(_X)->tm)
 
#define tmtcTzn(_X)   ((_X)->tzn)
 
#define tmtcFsec(_X)   ((_X)->fsec)
 
#define COPY_tm(_DST, _SRC)
 
#define ZERO_tm(_X)
 
#define ZERO_tmtc(_X)
 
#define INVALID_FOR_INTERVAL
 
#define DCH_S_FM   0x01
 
#define DCH_S_TH   0x02
 
#define DCH_S_th   0x04
 
#define DCH_S_SP   0x08
 
#define DCH_S_TM   0x10
 
#define S_THth(_s)   ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)
 
#define S_TH(_s)   (((_s) & DCH_S_TH) ? 1 : 0)
 
#define S_th(_s)   (((_s) & DCH_S_th) ? 1 : 0)
 
#define S_TH_TYPE(_s)   (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)
 
#define S_FM(_s)   (((_s) & DCH_S_FM) ? 1 : 0)
 
#define S_SP(_s)   (((_s) & DCH_S_SP) ? 1 : 0)
 
#define S_TM(_s)   (((_s) & DCH_S_TM) ? 1 : 0)
 
#define TM_SUFFIX_LEN   2
 
#define DCH_DATED   0x01
 
#define DCH_TIMED   0x02
 
#define DCH_ZONED   0x04
 
#define OVERLOAD_TEST   (Np->inout_p >= Np->inout + input_len)
 
#define AMOUNT_TEST(s)   (Np->inout_p <= Np->inout + (input_len - (s)))
 
#define SKIP_THth(ptr, _suf)
 
#define DCH_to_char_fsec(frac_fmt, frac_val)
 
#define zeroize_NUM(_n)
 
#define IS_PREDEC_SPACE(_n)
 
#define NUM_TOCHAR_prepare
 
#define NUM_TOCHAR_finish
 

Typedefs

typedef struct TmToChar TmToChar
 
typedef struct NUMProc NUMProc
 

Enumerations

enum  FromCharDateMode { FROM_CHAR_DATE_NONE = 0 , FROM_CHAR_DATE_GREGORIAN , FROM_CHAR_DATE_ISOWEEK }
 
enum  DCH_poz {
  DCH_A_D , DCH_A_M , DCH_AD , DCH_AM ,
  DCH_B_C , DCH_BC , DCH_CC , DCH_DAY ,
  DCH_DDD , DCH_DD , DCH_DY , DCH_Day ,
  DCH_Dy , DCH_D , DCH_FF1 , DCH_FF2 ,
  DCH_FF3 , DCH_FF4 , DCH_FF5 , DCH_FF6 ,
  DCH_FX , DCH_HH24 , DCH_HH12 , DCH_HH ,
  DCH_IDDD , DCH_ID , DCH_IW , DCH_IYYY ,
  DCH_IYY , DCH_IY , DCH_I , DCH_J ,
  DCH_MI , DCH_MM , DCH_MONTH , DCH_MON ,
  DCH_MS , DCH_Month , DCH_Mon , DCH_OF ,
  DCH_P_M , DCH_PM , DCH_Q , DCH_RM ,
  DCH_SSSSS , DCH_SSSS , DCH_SS , DCH_TZH ,
  DCH_TZM , DCH_TZ , DCH_US , DCH_WW ,
  DCH_W , DCH_Y_YYY , DCH_YYYY , DCH_YYY ,
  DCH_YY , DCH_Y , DCH_a_d , DCH_a_m ,
  DCH_ad , DCH_am , DCH_b_c , DCH_bc ,
  DCH_cc , DCH_day , DCH_ddd , DCH_dd ,
  DCH_dy , DCH_d , DCH_ff1 , DCH_ff2 ,
  DCH_ff3 , DCH_ff4 , DCH_ff5 , DCH_ff6 ,
  DCH_fx , DCH_hh24 , DCH_hh12 , DCH_hh ,
  DCH_iddd , DCH_id , DCH_iw , DCH_iyyy ,
  DCH_iyy , DCH_iy , DCH_i , DCH_j ,
  DCH_mi , DCH_mm , DCH_month , DCH_mon ,
  DCH_ms , DCH_of , DCH_p_m , DCH_pm ,
  DCH_q , DCH_rm , DCH_sssss , DCH_ssss ,
  DCH_ss , DCH_tzh , DCH_tzm , DCH_tz ,
  DCH_us , DCH_ww , DCH_w , DCH_y_yyy ,
  DCH_yyyy , DCH_yyy , DCH_yy , DCH_y ,
  _DCH_last_
}
 
enum  NUM_poz {
  NUM_COMMA , NUM_DEC , NUM_0 , NUM_9 ,
  NUM_B , NUM_C , NUM_D , NUM_E ,
  NUM_FM , NUM_G , NUM_L , NUM_MI ,
  NUM_PL , NUM_PR , NUM_RN , NUM_SG ,
  NUM_SP , NUM_S , NUM_TH , NUM_V ,
  NUM_b , NUM_c , NUM_d , NUM_e ,
  NUM_fm , NUM_g , NUM_l , NUM_mi ,
  NUM_pl , NUM_pr , NUM_rn , NUM_sg ,
  NUM_sp , NUM_s , NUM_th , NUM_v ,
  _NUM_last_
}
 

Functions

static const KeyWordindex_seq_search (const char *str, const KeyWord *kw, const int *index)
 
static const KeySuffixsuff_search (const char *str, const KeySuffix *suf, int type)
 
static bool is_separator_char (const char *str)
 
static void NUMDesc_prepare (NUMDesc *num, FormatNode *n)
 
static void parse_format (FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, uint32 flags, NUMDesc *Num)
 
static void DCH_to_char (FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
 
static void DCH_from_char (FormatNode *node, const char *in, TmFromChar *out, Oid collid, bool std, Node *escontext)
 
static const char * get_th (char *num, int type)
 
static char * str_numth (char *dest, char *num, int type)
 
static int adjust_partial_year_to_2020 (int year)
 
static int strspace_len (const char *str)
 
static bool from_char_set_mode (TmFromChar *tmfc, const FromCharDateMode mode, Node *escontext)
 
static bool from_char_set_int (int *dest, const int value, const FormatNode *node, Node *escontext)
 
static int from_char_parse_int_len (int *dest, const char **src, const int len, FormatNode *node, Node *escontext)
 
static int from_char_parse_int (int *dest, const char **src, FormatNode *node, Node *escontext)
 
static int seq_search_ascii (const char *name, const char *const *array, int *len)
 
static int seq_search_localized (const char *name, char **array, int *len, Oid collid)
 
static bool from_char_seq_search (int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, Node *escontext)
 
static bool do_to_timestamp (text *date_txt, text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext)
 
static char * fill_str (char *str, int c, int max)
 
static FormatNodeNUM_cache (int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
 
static char * int_to_roman (int number)
 
static int roman_to_int (NUMProc *Np, int input_len)
 
static void NUM_prepare_locale (NUMProc *Np)
 
static char * get_last_relevant_decnum (char *num)
 
static void NUM_numpart_from_char (NUMProc *Np, int id, int input_len)
 
static void NUM_numpart_to_char (NUMProc *Np, int id)
 
static char * NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
 
static DCHCacheEntryDCH_cache_getnew (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_search (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_fetch (const char *str, bool std)
 
static NUMCacheEntryNUM_cache_getnew (const char *str)
 
static NUMCacheEntryNUM_cache_search (const char *str)
 
static NUMCacheEntryNUM_cache_fetch (const char *str)
 
char * str_tolower (const char *buff, size_t nbytes, Oid collid)
 
char * str_toupper (const char *buff, size_t nbytes, Oid collid)
 
char * str_initcap (const char *buff, size_t nbytes, Oid collid)
 
char * str_casefold (const char *buff, size_t nbytes, Oid collid)
 
char * asc_tolower (const char *buff, size_t nbytes)
 
char * asc_toupper (const char *buff, size_t nbytes)
 
char * asc_initcap (const char *buff, size_t nbytes)
 
static char * str_tolower_z (const char *buff, Oid collid)
 
static char * str_toupper_z (const char *buff, Oid collid)
 
static char * str_initcap_z (const char *buff, Oid collid)
 
static char * asc_tolower_z (const char *buff)
 
static char * asc_toupper_z (const char *buff)
 
static bool is_next_separator (FormatNode *n)
 
static void DCH_prevent_counter_overflow (void)
 
static int DCH_datetime_type (FormatNode *node)
 
static textdatetime_to_char_body (TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
 
Datum timestamp_to_char (PG_FUNCTION_ARGS)
 
Datum timestamptz_to_char (PG_FUNCTION_ARGS)
 
Datum interval_to_char (PG_FUNCTION_ARGS)
 
Datum to_timestamp (PG_FUNCTION_ARGS)
 
Datum to_date (PG_FUNCTION_ARGS)
 
Datum parse_datetime (text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, Node *escontext)
 
bool datetime_format_has_tz (const char *fmt_str)
 
static void NUM_prevent_counter_overflow (void)
 
static void NUM_eat_non_data_chars (NUMProc *Np, int n, int input_len)
 
Datum numeric_to_number (PG_FUNCTION_ARGS)
 
Datum numeric_to_char (PG_FUNCTION_ARGS)
 
Datum int4_to_char (PG_FUNCTION_ARGS)
 
Datum int8_to_char (PG_FUNCTION_ARGS)
 
Datum float4_to_char (PG_FUNCTION_ARGS)
 
Datum float8_to_char (PG_FUNCTION_ARGS)
 

Variables

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

Macro Definition Documentation

◆ A_D_STR

#define A_D_STR   "A.D."

Definition at line 196 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 197 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 223 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 224 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 198 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 199 of file formatting.c.

◆ ADJUST_YEAR

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

Definition at line 194 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 225 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 226 of file formatting.c.

◆ AMOUNT_TEST

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

Definition at line 1062 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 201 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 202 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 203 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

Definition at line 204 of file formatting.c.

◆ CLOCK_12_HOUR

#define CLOCK_12_HOUR   1

Definition at line 171 of file formatting.c.

◆ CLOCK_24_HOUR

#define CLOCK_24_HOUR   0

Definition at line 170 of file formatting.c.

◆ COPY_tm

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

Definition at line 520 of file formatting.c.

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 391 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

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

Definition at line 381 of file formatting.c.

◆ DCH_CACHE_SIZE

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

Definition at line 386 of file formatting.c.

◆ DCH_DATED

#define DCH_DATED   0x01

Definition at line 1052 of file formatting.c.

◆ DCH_FLAG

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

Definition at line 99 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

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

Definition at line 114 of file formatting.c.

◆ DCH_S_FM

#define DCH_S_FM   0x01

Definition at line 568 of file formatting.c.

◆ DCH_S_SP

#define DCH_S_SP   0x08

Definition at line 571 of file formatting.c.

◆ DCH_S_TH

#define DCH_S_TH   0x02

Definition at line 569 of file formatting.c.

◆ DCH_S_th

#define DCH_S_th   0x04

Definition at line 570 of file formatting.c.

◆ DCH_S_TM

#define DCH_S_TM   0x10

Definition at line 572 of file formatting.c.

◆ DCH_TIMED

#define DCH_TIMED   0x02

Definition at line 1053 of file formatting.c.

◆ DCH_to_char_fsec

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

◆ DCH_ZONED

#define DCH_ZONED   0x04

Definition at line 1054 of file formatting.c.

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 484 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 483 of file formatting.c.

◆ INVALID_FOR_INTERVAL

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

Definition at line 551 of file formatting.c.

◆ IS_BLANK

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

Definition at line 353 of file formatting.c.

◆ IS_BRACKET

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

Definition at line 355 of file formatting.c.

◆ IS_DECIMAL

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

Definition at line 350 of file formatting.c.

◆ IS_EEEE

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

Definition at line 361 of file formatting.c.

◆ IS_FILLMODE

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

Definition at line 354 of file formatting.c.

◆ IS_LDECIMAL

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

Definition at line 351 of file formatting.c.

◆ IS_LSIGN

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

Definition at line 357 of file formatting.c.

◆ IS_MINUS

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

Definition at line 356 of file formatting.c.

◆ IS_MULTI

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

Definition at line 360 of file formatting.c.

◆ IS_PLUS

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

Definition at line 358 of file formatting.c.

◆ IS_PREDEC_SPACE

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

Definition at line 5590 of file formatting.c.

◆ IS_ROMAN

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

Definition at line 359 of file formatting.c.

◆ IS_VALID_SUB_COMB

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

Definition at line 270 of file formatting.c.

◆ IS_ZERO

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

Definition at line 352 of file formatting.c.

◆ KeyWord_INDEX_FILTER

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

Definition at line 108 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 107 of file formatting.c.

◆ MAX_ROMAN_LEN

#define MAX_ROMAN_LEN   15

Definition at line 290 of file formatting.c.

◆ NODE_TYPE_ACTION

#define NODE_TYPE_ACTION   2

Definition at line 162 of file formatting.c.

◆ NODE_TYPE_CHAR

#define NODE_TYPE_CHAR   3

Definition at line 163 of file formatting.c.

◆ NODE_TYPE_END

#define NODE_TYPE_END   1

Definition at line 161 of file formatting.c.

◆ NODE_TYPE_SEPARATOR

#define NODE_TYPE_SEPARATOR   4

Definition at line 164 of file formatting.c.

◆ NODE_TYPE_SPACE

#define NODE_TYPE_SPACE   5

Definition at line 165 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 392 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

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

Definition at line 383 of file formatting.c.

◆ NUM_CACHE_SIZE

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

Definition at line 388 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 330 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 333 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 327 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 340 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 331 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 328 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 332 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 334 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 339 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 337 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 335 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 338 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 336 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 329 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 100 of file formatting.c.

◆ NUM_LSIGN_NONE

#define NUM_LSIGN_NONE   0

Definition at line 344 of file formatting.c.

◆ NUM_LSIGN_POST

#define NUM_LSIGN_POST   1

Definition at line 343 of file formatting.c.

◆ NUM_LSIGN_PRE

#define NUM_LSIGN_PRE   (-1)

Definition at line 342 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 115 of file formatting.c.

◆ NUM_TOCHAR_finish

#define NUM_TOCHAR_finish
Value:
do { \
int len; \
NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \
if (shouldFree) \
pfree(format); \
\
/* \
* Convert null-terminated representation of result to standard text. \
* The result is usually much bigger than it needs to be, but there \
* seems little point in realloc'ing it smaller. \
*/ \
len = strlen(VARDATA(result)); \
SET_VARSIZE(result, len + VARHDRSZ); \
} while (0)
#define VARHDRSZ
Definition: c.h:663
#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:5804
char sign
Definition: informix.c:693
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
static char format
const void size_t len
#define VARDATA(PTR)
Definition: varatt.h:278

Definition at line 6285 of file formatting.c.

◆ NUM_TOCHAR_prepare

#define NUM_TOCHAR_prepare
Value:
do { \
int len = VARSIZE_ANY_EXHDR(fmt); \
if (len <= 0 || len >= (INT_MAX-VARHDRSZ)/NUM_MAX_ITEM_SIZ) \
PG_RETURN_TEXT_P(cstring_to_text("")); \
result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
format = NUM_cache(len, &Num, fmt, &shouldFree); \
} while (0)
#define NUM_MAX_ITEM_SIZ
Definition: formatting.c:115
static FormatNode * NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
Definition: formatting.c:5003
void * palloc0(Size size)
Definition: mcxt.c:1969
Definition: c.h:658
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
text * cstring_to_text(const char *s)
Definition: varlena.c:192

Definition at line 6272 of file formatting.c.

◆ OVERLOAD_TEST

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

Definition at line 1061 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 228 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 229 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 230 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

Definition at line 231 of file formatting.c.

◆ ROMAN_VAL

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

Definition at line 278 of file formatting.c.

◆ S_FM

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

Definition at line 584 of file formatting.c.

◆ S_SP

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

Definition at line 585 of file formatting.c.

◆ S_TH

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

Definition at line 579 of file formatting.c.

◆ S_th

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

Definition at line 580 of file formatting.c.

◆ S_TH_TYPE

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

Definition at line 581 of file formatting.c.

◆ S_THth

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

Definition at line 578 of file formatting.c.

◆ S_TM

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

Definition at line 586 of file formatting.c.

◆ SKIP_THth

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

Definition at line 2013 of file formatting.c.

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 101 of file formatting.c.

◆ SUFFTYPE_POSTFIX

#define SUFFTYPE_POSTFIX   2

Definition at line 168 of file formatting.c.

◆ SUFFTYPE_PREFIX

#define SUFFTYPE_PREFIX   1

Definition at line 167 of file formatting.c.

◆ TH_LOWER

#define TH_LOWER   2

Definition at line 304 of file formatting.c.

◆ TH_UPPER

#define TH_UPPER   1

Definition at line 303 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 592 of file formatting.c.

◆ tmtcFsec

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

Definition at line 517 of file formatting.c.

◆ tmtcTm

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

Definition at line 515 of file formatting.c.

◆ tmtcTzn

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

Definition at line 516 of file formatting.c.

◆ ZERO_tm

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

Definition at line 534 of file formatting.c.

◆ ZERO_tmfc

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

Definition at line 458 of file formatting.c.

◆ ZERO_tmtc

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

Definition at line 540 of file formatting.c.

◆ zeroize_NUM

#define zeroize_NUM (   _n)
Value:
do { \
(_n)->flag = 0; \
(_n)->lsign = 0; \
(_n)->pre = 0; \
(_n)->post = 0; \
(_n)->pre_lsign_num = 0; \
(_n)->need_locale = 0; \
(_n)->multi = 0; \
(_n)->zero_start = 0; \
(_n)->zero_end = 0; \
} while(0)
char * flag(int b)
Definition: test-ctype.c:33

Definition at line 4868 of file formatting.c.

Typedef Documentation

◆ NUMProc

typedef struct NUMProc NUMProc

◆ TmToChar

typedef struct TmToChar TmToChar

Enumeration Type Documentation

◆ DCH_poz

enum DCH_poz
Enumerator
DCH_A_D 
DCH_A_M 
DCH_AD 
DCH_AM 
DCH_B_C 
DCH_BC 
DCH_CC 
DCH_DAY 
DCH_DDD 
DCH_DD 
DCH_DY 
DCH_Day 
DCH_Dy 
DCH_D 
DCH_FF1 
DCH_FF2 
DCH_FF3 
DCH_FF4 
DCH_FF5 
DCH_FF6 
DCH_FX 
DCH_HH24 
DCH_HH12 
DCH_HH 
DCH_IDDD 
DCH_ID 
DCH_IW 
DCH_IYYY 
DCH_IYY 
DCH_IY 
DCH_I 
DCH_J 
DCH_MI 
DCH_MM 
DCH_MONTH 
DCH_MON 
DCH_MS 
DCH_Month 
DCH_Mon 
DCH_OF 
DCH_P_M 
DCH_PM 
DCH_Q 
DCH_RM 
DCH_SSSSS 
DCH_SSSS 
DCH_SS 
DCH_TZH 
DCH_TZM 
DCH_TZ 
DCH_US 
DCH_WW 
DCH_W 
DCH_Y_YYY 
DCH_YYYY 
DCH_YYY 
DCH_YY 
DCH_Y 
DCH_a_d 
DCH_a_m 
DCH_ad 
DCH_am 
DCH_b_c 
DCH_bc 
DCH_cc 
DCH_day 
DCH_ddd 
DCH_dd 
DCH_dy 
DCH_d 
DCH_ff1 
DCH_ff2 
DCH_ff3 
DCH_ff4 
DCH_ff5 
DCH_ff6 
DCH_fx 
DCH_hh24 
DCH_hh12 
DCH_hh 
DCH_iddd 
DCH_id 
DCH_iw 
DCH_iyyy 
DCH_iyy 
DCH_iy 
DCH_i 
DCH_j 
DCH_mi 
DCH_mm 
DCH_month 
DCH_mon 
DCH_ms 
DCH_of 
DCH_p_m 
DCH_pm 
DCH_q 
DCH_rm 
DCH_sssss 
DCH_ssss 
DCH_ss 
DCH_tzh 
DCH_tzm 
DCH_tz 
DCH_us 
DCH_ww 
DCH_w 
DCH_y_yyy 
DCH_yyyy 
DCH_yyy 
DCH_yy 
DCH_y 
_DCH_last_ 

Definition at line 635 of file formatting.c.

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

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 137 of file formatting.c.

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

◆ NUM_poz

enum NUM_poz
Enumerator
NUM_COMMA 
NUM_DEC 
NUM_0 
NUM_9 
NUM_B 
NUM_C 
NUM_D 
NUM_E 
NUM_FM 
NUM_G 
NUM_L 
NUM_MI 
NUM_PL 
NUM_PR 
NUM_RN 
NUM_SG 
NUM_SP 
NUM_S 
NUM_TH 
NUM_V 
NUM_b 
NUM_c 
NUM_d 
NUM_e 
NUM_fm 
NUM_g 
NUM_l 
NUM_mi 
NUM_pl 
NUM_pr 
NUM_rn 
NUM_sg 
NUM_sp 
NUM_s 
NUM_th 
NUM_v 
_NUM_last_ 

Definition at line 754 of file formatting.c.

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

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2094 of file formatting.c.

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

Referenced by DCH_from_char().

◆ asc_initcap()

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

Definition at line 1944 of file formatting.c.

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

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

References pg_ascii_tolower(), and pnstrdup().

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

◆ asc_tolower_z()

static char * asc_tolower_z ( const char *  buff)
static

Definition at line 1993 of file formatting.c.

1994{
1995 return asc_tolower(buff, strlen(buff));
1996}
char * asc_tolower(const char *buff, size_t nbytes)
Definition: formatting.c:1898

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

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

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

2000{
2001 return asc_toupper(buff, strlen(buff));
2002}
char * asc_toupper(const char *buff, size_t nbytes)
Definition: formatting.c:1921

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char *  fmt_str)

Definition at line 4365 of file formatting.c.

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

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

Referenced by jspIsMutableWalker().

◆ datetime_to_char_body()

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

Definition at line 3928 of file formatting.c.

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

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

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

◆ DCH_cache_fetch()

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

Definition at line 3901 of file formatting.c.

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

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

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

◆ DCH_cache_getnew()

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

Definition at line 3820 of file formatting.c.

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

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

Referenced by DCH_cache_fetch().

◆ DCH_cache_search()

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

Definition at line 3880 of file formatting.c.

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

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

Referenced by DCH_cache_fetch().

◆ DCH_datetime_type()

static int DCH_datetime_type ( FormatNode node)
static

Definition at line 3723 of file formatting.c.

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

References DCH_A_D, DCH_a_d, DCH_A_M, DCH_a_m, DCH_AD, DCH_ad, DCH_AM, DCH_am, DCH_B_C, DCH_b_c, DCH_BC, DCH_bc, DCH_CC, DCH_D, DCH_DATED, DCH_DAY, DCH_Day, DCH_day, DCH_DD, DCH_DDD, DCH_DY, DCH_Dy, DCH_dy, DCH_FF1, DCH_FF2, DCH_FF3, DCH_FF4, DCH_FF5, DCH_FF6, DCH_FX, DCH_HH, DCH_HH12, DCH_HH24, DCH_I, DCH_ID, DCH_IDDD, DCH_IY, DCH_IYY, DCH_IYYY, DCH_J, DCH_MI, DCH_MM, DCH_MON, DCH_Mon, DCH_mon, DCH_MONTH, DCH_Month, DCH_month, DCH_MS, DCH_OF, DCH_P_M, DCH_p_m, DCH_PM, DCH_pm, DCH_Q, DCH_RM, DCH_rm, DCH_SS, DCH_SSSS, DCH_TIMED, DCH_TZ, DCH_tz, DCH_TZH, DCH_TZM, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, DCH_ZONED, KeyWord::id, FormatNode::key, NODE_TYPE_ACTION, NODE_TYPE_END, and FormatNode::type.

Referenced by datetime_format_has_tz(), and do_to_timestamp().

◆ DCH_from_char()

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

Definition at line 3152 of file formatting.c.

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

References TmFromChar::abbrev, adbc_strings, adbc_strings_long, adjust_partial_year_to_2020(), ampm_strings, ampm_strings_long, Assert(), TmFromChar::bc, cache_locale_time(), TmFromChar::cc, FormatNode::character, TmFromChar::clock, CLOCK_12_HOUR, collid, TmFromChar::d, KeyWord::date_mode, days, days_short, DCH_A_D, DCH_a_d, DCH_A_M, DCH_a_m, DCH_AD, DCH_ad, DCH_AM, DCH_am, DCH_B_C, DCH_b_c, DCH_BC, DCH_bc, DCH_CC, DCH_D, DCH_DAY, DCH_Day, DCH_day, DCH_DD, DCH_DDD, DCH_DY, DCH_Dy, DCH_dy, DCH_FF1, DCH_FF2, DCH_FF3, DCH_FF4, DCH_FF5, DCH_FF6, DCH_FX, DCH_HH, DCH_HH12, DCH_HH24, DCH_I, DCH_ID, DCH_IDDD, DCH_IW, DCH_IY, DCH_IYY, DCH_IYYY, DCH_J, DCH_MI, DCH_MM, DCH_MON, DCH_Mon, DCH_mon, DCH_MONTH, DCH_Month, DCH_month, DCH_MS, DCH_OF, DCH_P_M, DCH_p_m, DCH_PM, DCH_pm, DCH_Q, DCH_RM, DCH_rm, DCH_SS, DCH_SSSS, DCH_TZ, DCH_tz, DCH_TZH, DCH_TZM, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, TmFromChar::dd, TmFromChar::ddd, DecodeTimezoneAbbrevPrefix(), ereturn, errcode(), errdetail(), errmsg(), TmFromChar::ff, from_char_parse_int(), from_char_parse_int_len(), from_char_seq_search(), from_char_set_int(), from_char_set_mode(), TmFromChar::gmtoffset, TmFromChar::has_tz, TmFromChar::hh, KeyWord::id, InvalidOid, is_separator_char(), TmFromChar::j, FormatNode::key, len, localized_abbrev_days, localized_abbrev_months, localized_full_days, localized_full_months, TmFromChar::mi, TmFromChar::mm, months, months_full, MONTHS_PER_YEAR, TmFromChar::ms, KeyWord::name, NODE_TYPE_ACTION, NODE_TYPE_CHAR, NODE_TYPE_END, NODE_TYPE_SEPARATOR, NODE_TYPE_SPACE, pg_add_s32_overflow(), pg_mblen(), pg_mul_s32_overflow(), TmFromChar::pm, pnstrdup(), rm_months_lower, S_TM, SKIP_THth, TmFromChar::ss, TmFromChar::ssss, FormatNode::suffix, FormatNode::type, TmFromChar::tzh, TmFromChar::tzm, TmFromChar::tzp, TmFromChar::tzsign, TmFromChar::us, value, TmFromChar::w, TmFromChar::ww, TmFromChar::year, and TmFromChar::yysz.

Referenced by do_to_timestamp().

◆ DCH_prevent_counter_overflow()

static void DCH_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 3709 of file formatting.c.

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

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

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

References A_D_STR, a_d_STR, A_M_STR, a_m_STR, AD_STR, ad_STR, ADJUST_YEAR, AM_STR, am_STR, asc_tolower_z(), asc_toupper_z(), B_C_STR, b_c_STR, BC_STR, bc_STR, cache_locale_time(), FormatNode::character, collid, date2isoweek(), date2isoyear(), date2isoyearday(), date2j(), days, days_short, DCH_A_D, DCH_a_d, DCH_A_M, DCH_a_m, DCH_AD, DCH_ad, DCH_AM, DCH_am, DCH_B_C, DCH_b_c, DCH_BC, DCH_bc, DCH_CC, DCH_D, DCH_DAY, DCH_Day, DCH_day, DCH_DD, DCH_DDD, DCH_DY, DCH_Dy, DCH_dy, DCH_FF1, DCH_FF2, DCH_FF3, DCH_FF4, DCH_FF5, DCH_FF6, DCH_HH, DCH_HH12, DCH_HH24, DCH_I, DCH_ID, DCH_IDDD, DCH_IW, DCH_IY, DCH_IYY, DCH_IYYY, DCH_J, DCH_MAX_ITEM_SIZ, DCH_MI, DCH_MM, DCH_MON, DCH_Mon, DCH_mon, DCH_MONTH, DCH_Month, DCH_month, DCH_MS, DCH_OF, DCH_P_M, DCH_p_m, DCH_PM, DCH_pm, DCH_Q, DCH_RM, DCH_rm, DCH_SS, DCH_SSSS, DCH_to_char_fsec, DCH_TZ, DCH_tz, DCH_TZH, DCH_TZM, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, ereport, errcode(), errmsg(), ERROR, TmToChar::fsec, HOURS_PER_DAY, i, KeyWord::id, INVALID_FOR_INTERVAL, FormatNode::key, KeyWord::len, localized_abbrev_days, localized_abbrev_months, localized_full_days, localized_full_months, months, months_full, MONTHS_PER_YEAR, NODE_TYPE_ACTION, NODE_TYPE_END, P_M_STR, p_m_STR, pfree(), PM_STR, pm_STR, rm_months_lower, rm_months_upper, S_FM, S_TH_TYPE, S_THth, S_TM, SECS_PER_HOUR, SECS_PER_MINUTE, sprintf, str, str_initcap_z(), str_numth(), str_tolower_z(), str_toupper_z(), FormatNode::suffix, TmToChar::tm, tm, pg_tm::tm_gmtoff, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, TM_SUFFIX_LEN, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcTzn, and FormatNode::type.

Referenced by datetime_to_char_body().

◆ do_to_timestamp()

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

Definition at line 4428 of file formatting.c.

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

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

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

◆ fill_str()

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

Definition at line 4861 of file formatting.c.

4862{
4863 memset(str, c, max);
4864 *(str + max) = '\0';
4865 return str;
4866}

References str.

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

◆ float4_to_char()

Datum float4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6697 of file formatting.c.

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

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

◆ float8_to_char()

Datum float8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6810 of file formatting.c.

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

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

◆ from_char_parse_int()

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

Definition at line 2300 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ from_char_parse_int_len()

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

Definition at line 2203 of file formatting.c.

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

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

Referenced by DCH_from_char(), and from_char_parse_int().

◆ from_char_seq_search()

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

Definition at line 2459 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ from_char_set_int()

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

Definition at line 2167 of file formatting.c.

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

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

Referenced by DCH_from_char(), and from_char_parse_int_len().

◆ from_char_set_mode()

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

Definition at line 2140 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

static char * get_last_relevant_decnum ( char *  num)
static

Definition at line 5358 of file formatting.c.

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

References elog.

Referenced by NUM_processor().

◆ get_th()

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

Definition at line 1563 of file formatting.c.

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

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

Referenced by NUM_processor(), and str_numth().

◆ index_seq_search()

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

Definition at line 1135 of file formatting.c.

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

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

Referenced by parse_format().

◆ int4_to_char()

Datum int4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6491 of file formatting.c.

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

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

◆ int8_to_char()

Datum int8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6585 of file formatting.c.

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

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

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 5066 of file formatting.c.

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

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

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

◆ interval_to_char()

Datum interval_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4073 of file formatting.c.

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

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

◆ is_next_separator()

static bool is_next_separator ( FormatNode n)
static

Definition at line 2061 of file formatting.c.

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

References FormatNode::character, KeyWord::is_digit, FormatNode::key, NODE_TYPE_ACTION, NODE_TYPE_END, S_THth, FormatNode::suffix, and FormatNode::type.

Referenced by from_char_parse_int_len().

◆ is_separator_char()

static bool is_separator_char ( const char *  str)
static

Definition at line 1175 of file formatting.c.

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

References str.

Referenced by DCH_from_char(), and parse_format().

◆ NUM_cache()

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

Definition at line 5003 of file formatting.c.

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

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

Referenced by numeric_to_number().

◆ NUM_cache_fetch()

static NUMCacheEntry * NUM_cache_fetch ( const char *  str)
static

Definition at line 4975 of file formatting.c.

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

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

Referenced by NUM_cache().

◆ NUM_cache_getnew()

static NUMCacheEntry * NUM_cache_getnew ( const char *  str)
static

Definition at line 4895 of file formatting.c.

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

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

Referenced by NUM_cache_fetch().

◆ NUM_cache_search()

static NUMCacheEntry * NUM_cache_search ( const char *  str)
static

Definition at line 4954 of file formatting.c.

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

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

Referenced by NUM_cache_fetch().

◆ NUM_eat_non_data_chars()

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

Definition at line 5791 of file formatting.c.

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

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

Referenced by NUM_processor().

◆ NUM_numpart_from_char()

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

Definition at line 5386 of file formatting.c.

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

References AMOUNT_TEST, NUMProc::decimal, elog, NUMProc::inout, NUMProc::inout_p, IS_BRACKET, IS_DECIMAL, IS_LSIGN, IS_MINUS, IS_PLUS, NUMProc::L_negative_sign, NUMProc::L_positive_sign, NUMDesc::lsign, NUMProc::Num, NUM_0, NUM_9, NUM_DEC, NUM_LSIGN_PRE, NUMProc::number, NUMProc::number_p, OVERLOAD_TEST, NUMDesc::post, NUMProc::read_dec, NUMProc::read_post, NUMProc::read_pre, and x.

Referenced by NUM_processor().

◆ NUM_numpart_to_char()

static void NUM_numpart_to_char ( NUMProc Np,
int  id 
)
static

Definition at line 5601 of file formatting.c.

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

References NUMProc::decimal, elog, NUMProc::inout, NUMProc::inout_p, IS_BRACKET, IS_DECIMAL, IS_FILLMODE, IS_LSIGN, IS_PREDEC_SPACE, IS_ROMAN, IS_ZERO, NUMProc::L_negative_sign, NUMProc::L_positive_sign, NUMProc::last_relevant, NUMDesc::lsign, NUMProc::Num, NUM_0, NUM_9, NUMProc::num_count, NUMProc::num_curr, NUM_D, NUM_DEC, NUMProc::num_in, NUM_LSIGN_POST, NUM_LSIGN_PRE, NUMProc::number_p, NUMProc::out_pre_spaces, NUMProc::sign, NUMProc::sign_wrote, and NUMDesc::zero_start.

Referenced by NUM_processor().

◆ NUM_prepare_locale()

static void NUM_prepare_locale ( NUMProc Np)
static

Definition at line 5276 of file formatting.c.

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

References NUMProc::decimal, IS_LDECIMAL, NUMProc::L_currency_symbol, NUMProc::L_negative_sign, NUMProc::L_positive_sign, NUMProc::L_thousands_sep, NUMDesc::need_locale, NUMProc::Num, and PGLC_localeconv().

Referenced by NUM_processor().

◆ NUM_prevent_counter_overflow()

static void NUM_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 4883 of file formatting.c.

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

References i, n_NUMCache, NUMCache, and NUMCounter.

Referenced by NUM_cache_getnew(), and NUM_cache_search().

◆ NUM_processor()

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

Definition at line 5804 of file formatting.c.

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

References AMOUNT_TEST, asc_tolower_z(), FormatNode::character, elog, ereport, errcode(), errmsg(), ERROR, NUMDesc::flag, get_last_relevant_decnum(), get_th(), KeyWord::id, NUMProc::inout, NUMProc::inout_p, IS_BRACKET, IS_DECIMAL, IS_EEEE, IS_FILLMODE, IS_LSIGN, IS_MINUS, IS_PLUS, IS_ROMAN, NUMProc::is_to_char, IS_ZERO, FormatNode::key, NUMProc::L_currency_symbol, NUMProc::L_thousands_sep, NUMProc::last_relevant, NUMDesc::lsign, MemSet, Min, NODE_TYPE_ACTION, NODE_TYPE_END, NUMProc::Num, NUM_0, NUM_9, NUM_COMMA, NUMProc::num_count, NUMProc::num_curr, NUM_D, NUM_DEC, NUM_eat_non_data_chars(), NUM_G, NUMProc::num_in, NUM_L, NUM_LSIGN_POST, NUM_LSIGN_PRE, NUM_MI, NUM_numpart_from_char(), NUM_numpart_to_char(), NUM_PL, NUM_prepare_locale(), NUM_RN, NUM_rn, NUM_SG, NUM_TH, NUM_th, NUMProc::number, NUMProc::number_p, NUMProc::out_pre_spaces, OVERLOAD_TEST, pg_mblen(), pg_mbstrlen(), NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, NUMProc::read_dec, NUMProc::read_post, NUMProc::read_pre, roman_to_int(), NUMProc::sign, sign, NUMProc::sign_wrote, sprintf, TH_LOWER, TH_UPPER, FormatNode::type, NUMDesc::zero_end, and NUMDesc::zero_start.

Referenced by numeric_to_number().

◆ NUMDesc_prepare()

static void NUMDesc_prepare ( NUMDesc num,
FormatNode n 
)
static

Definition at line 1189 of file formatting.c.

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

References ereport, errcode(), errdetail(), errmsg(), ERROR, NUMDesc::flag, KeyWord::id, IS_BLANK, IS_BRACKET, IS_DECIMAL, IS_EEEE, IS_FILLMODE, IS_LSIGN, IS_MINUS, IS_MULTI, IS_PLUS, IS_ROMAN, IS_ZERO, FormatNode::key, NUMDesc::lsign, NUMDesc::multi, NUMDesc::need_locale, NODE_TYPE_ACTION, NUM_0, NUM_9, NUM_B, NUM_D, NUM_DEC, NUM_E, NUM_F_BLANK, NUM_F_BRACKET, NUM_F_DECIMAL, NUM_F_EEEE, NUM_F_FILLMODE, NUM_F_LDECIMAL, NUM_F_LSIGN, NUM_F_MINUS, NUM_F_MINUS_POST, NUM_F_MULTI, NUM_F_PLUS, NUM_F_PLUS_POST, NUM_F_ROMAN, NUM_F_ZERO, NUM_FM, NUM_G, NUM_L, NUM_LSIGN_NONE, NUM_LSIGN_POST, NUM_LSIGN_PRE, NUM_MI, NUM_PL, NUM_PR, NUM_RN, NUM_rn, NUM_S, NUM_SG, NUM_V, NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, FormatNode::type, NUMDesc::zero_end, and NUMDesc::zero_start.

Referenced by parse_format().

◆ numeric_to_char()

Datum numeric_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6363 of file formatting.c.

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

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

◆ numeric_to_number()

Datum numeric_to_number ( PG_FUNCTION_ARGS  )

Definition at line 6304 of file formatting.c.

6309{
6311 text *fmt = PG_GETARG_TEXT_PP(1);
6312 NUMDesc Num;
6313 Datum result;
6315 char *numstr;
6316 bool shouldFree;
6317 int len = 0;
6318 int scale,
6319 precision;
6320
6321 len = VARSIZE_ANY_EXHDR(fmt);
6322
6323 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
6325
6326 format = NUM_cache(len, &Num, fmt, &shouldFree);
6327
6328 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
6329
6330 NUM_processor(format, &Num, VARDATA_ANY(value), numstr,
6331 VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
6332
6333 scale = Num.post;
6334 precision = Num.pre + Num.multi + scale;
6335
6336 if (shouldFree)
6337 pfree(format);
6338
6340 CStringGetDatum(numstr),
6342 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
6343
6344 if (IS_MULTI(&Num))
6345 {
6346 Numeric x;
6349
6352 NumericGetDatum(b)));
6354 result,
6356 }
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:637
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:686
static int scale
Definition: pgbench.c:182
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
#define VARDATA_ANY(PTR)
Definition: varatt.h:324

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

◆ parse_datetime()

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

Definition at line 4202 of file formatting.c.

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

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

Referenced by executeDateTimeMethod().

◆ parse_format()

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

Definition at line 1375 of file formatting.c.

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

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

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

◆ roman_to_int()

static int roman_to_int ( NUMProc Np,
int  input_len 
)
static

Definition at line 5126 of file formatting.c.

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

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

Referenced by NUM_processor().

◆ seq_search_ascii()

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

Definition at line 2318 of file formatting.c.

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

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

Referenced by from_char_seq_search().

◆ seq_search_localized()

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

Definition at line 2375 of file formatting.c.

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

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

Referenced by from_char_seq_search().

◆ str_casefold()

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

Definition at line 1829 of file formatting.c.

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

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

Referenced by casefold().

◆ str_initcap()

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

Definition at line 1765 of file formatting.c.

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

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

Referenced by initcap(), and str_initcap_z().

◆ str_initcap_z()

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

Definition at line 1987 of file formatting.c.

1988{
1989 return str_initcap(buff, strlen(buff), collid);
1990}
char * str_initcap(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1765

References collid, and str_initcap().

Referenced by DCH_to_char().

◆ str_numth()

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

Definition at line 1608 of file formatting.c.

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

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

Referenced by DCH_to_char().

◆ str_tolower()

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

Definition at line 1637 of file formatting.c.

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

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

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

◆ str_tolower_z()

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

Definition at line 1975 of file formatting.c.

1976{
1977 return str_tolower(buff, strlen(buff), collid);
1978}

References collid, and str_tolower().

Referenced by DCH_to_char().

◆ str_toupper()

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

Definition at line 1701 of file formatting.c.

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

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

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

◆ str_toupper_z()

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

Definition at line 1981 of file formatting.c.

1982{
1983 return str_toupper(buff, strlen(buff), collid);
1984}

References collid, and str_toupper().

Referenced by DCH_to_char().

◆ strspace_len()

static int strspace_len ( const char *  str)
static

Definition at line 2118 of file formatting.c.

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

References len, and str.

Referenced by from_char_parse_int_len().

◆ suff_search()

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

Definition at line 1159 of file formatting.c.

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

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

Referenced by parse_format().

◆ timestamp_to_char()

Datum timestamp_to_char ( PG_FUNCTION_ARGS  )

Definition at line 3997 of file formatting.c.

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

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, VARSIZE_ANY_EXHDR, and ZERO_tmtc.

◆ timestamptz_to_char()

Datum timestamptz_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4032 of file formatting.c.

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

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_wday, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, tmtcTzn, VARSIZE_ANY_EXHDR, and ZERO_tmtc.

◆ to_date()

Datum to_date ( PG_FUNCTION_ARGS  )

Definition at line 4154 of file formatting.c.

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

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

◆ to_timestamp()

Datum to_timestamp ( PG_FUNCTION_ARGS  )

Definition at line 4115 of file formatting.c.

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

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

Variable Documentation

◆ adbc_strings

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

Definition at line 216 of file formatting.c.

Referenced by DCH_from_char().

◆ adbc_strings_long

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

Definition at line 217 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings

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

Definition at line 243 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings_long

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

Definition at line 244 of file formatting.c.

Referenced by DCH_from_char().

◆ days_short

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

Definition at line 183 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ DCH_index

const int DCH_index[KeyWord_INDEX_SIZE]
static
Initial value:
= {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
DCH_FF1, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, DCH_OF,
-1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
DCH_day, -1, DCH_ff1, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
-1, DCH_y_yyy, -1, -1, -1, -1
}

Definition at line 974 of file formatting.c.

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

◆ DCH_keywords

const KeyWord DCH_keywords[]
static

◆ DCH_suff

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

Definition at line 594 of file formatting.c.

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

◆ DCHCache

DCHCacheEntry* DCHCache[DCH_CACHE_ENTRIES]
static

Definition at line 413 of file formatting.c.

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

◆ DCHCounter

int DCHCounter = 0
static

Definition at line 415 of file formatting.c.

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

◆ months_full

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

Definition at line 178 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ n_DCHCache

int n_DCHCache = 0
static

Definition at line 414 of file formatting.c.

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

◆ n_NUMCache

int n_NUMCache = 0
static

Definition at line 419 of file formatting.c.

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

◆ NUM_index

const int NUM_index[KeyWord_INDEX_SIZE]
static
Initial value:
= {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
-1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
-1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
-1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
-1, -1, -1, -1, -1, -1
}

Definition at line 998 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUM_keywords

const KeyWord NUM_keywords[]
static

Definition at line 926 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUMCache

NUMCacheEntry* NUMCache[NUM_CACHE_ENTRIES]
static

Definition at line 418 of file formatting.c.

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

◆ NUMCounter

int NUMCounter = 0
static

Definition at line 420 of file formatting.c.

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

◆ numTH

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

Definition at line 296 of file formatting.c.

Referenced by get_th().

◆ numth

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

Definition at line 297 of file formatting.c.

Referenced by get_th().

◆ rm1

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

Definition at line 262 of file formatting.c.

Referenced by int_to_roman().

◆ rm10

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

Definition at line 263 of file formatting.c.

Referenced by int_to_roman().

◆ rm100

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

Definition at line 264 of file formatting.c.

Referenced by int_to_roman().

◆ rm_months_lower

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

Definition at line 255 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ rm_months_upper

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

Definition at line 252 of file formatting.c.

Referenced by DCH_to_char().