PostgreSQL Source Code git master
formatting.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <unistd.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include "catalog/pg_type.h"
#include "common/int.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 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 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 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 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_SUFFIX_FM   0x01
 
#define DCH_SUFFIX_TH   0x02
 
#define DCH_SUFFIX_th   0x04
 
#define DCH_SUFFIX_SP   0x08
 
#define DCH_SUFFIX_TM   0x10
 
#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 IS_PREDEC_SPACE(_n)
 
#define NUM_TOCHAR_prepare
 
#define NUM_TOCHAR_finish
 

Typedefs

typedef struct TmToChar TmToChar
 
typedef struct NUMProc NUMProc
 

Enumerations

enum  KeySuffixType { SUFFTYPE_PREFIX = 1 , SUFFTYPE_POSTFIX = 2 }
 
enum  FromCharDateMode { FROM_CHAR_DATE_NONE = 0 , FROM_CHAR_DATE_GREGORIAN , FROM_CHAR_DATE_ISOWEEK }
 
enum  FormatNodeType {
  NODE_TYPE_END = 1 , NODE_TYPE_ACTION = 2 , NODE_TYPE_CHAR = 3 , NODE_TYPE_SEPARATOR = 4 ,
  NODE_TYPE_SPACE = 5
}
 
enum  TH_Case { TH_UPPER = 1 , TH_LOWER = 2 }
 
enum  NUMDesc_lsign { NUM_LSIGN_PRE = -1 , NUM_LSIGN_POST = 1 , NUM_LSIGN_NONE = 0 }
 
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 bool IS_SUFFIX_TH (uint8 _s)
 
static bool IS_SUFFIX_th (uint8 _s)
 
static bool IS_SUFFIX_THth (uint8 _s)
 
static enum TH_Case SUFFIX_TH_TYPE (uint8 _s)
 
static bool IS_SUFFIX_FM (uint8 _s)
 
static bool IS_SUFFIX_TM (uint8 _s)
 
static const KeyWordindex_seq_search (const char *str, const KeyWord *kw, const int *index)
 
static const KeySuffixsuff_search (const char *str, const KeySuffix *suf, enum KeySuffixType 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 (const char *num, enum TH_Case type)
 
static char * str_numth (char *dest, const char *num, enum TH_Case type)
 
static int adjust_partial_year_to_2020 (int year)
 
static size_t 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 size_t 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, size_t *len)
 
static int seq_search_localized (const char *name, char **array, size_t *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 (const text *date_txt, const text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext)
 
static void fill_str (char *str, int c, int max)
 
static FormatNodeNUM_cache (int len, NUMDesc *Num, const text *pars_str, bool *shouldFree)
 
static char * int_to_roman (int number)
 
static int roman_to_int (NUMProc *Np, size_t input_len)
 
static void NUM_prepare_locale (NUMProc *Np)
 
static const char * get_last_relevant_decnum (const char *num)
 
static void NUM_numpart_from_char (NUMProc *Np, int id, size_t input_len)
 
static void NUM_numpart_to_char (NUMProc *Np, int id)
 
static char * NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, size_t 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, const 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, size_t 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 187 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 188 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 213 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 214 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 189 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 190 of file formatting.c.

◆ ADJUST_YEAR

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

Definition at line 185 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 215 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 216 of file formatting.c.

◆ AMOUNT_TEST

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

Definition at line 1063 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 192 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 193 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 194 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

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

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 379 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

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

Definition at line 369 of file formatting.c.

◆ DCH_CACHE_SIZE

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

Definition at line 374 of file formatting.c.

◆ DCH_DATED

#define DCH_DATED   0x01

Definition at line 1053 of file formatting.c.

◆ DCH_FLAG

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

Definition at line 90 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

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

Definition at line 103 of file formatting.c.

◆ DCH_SUFFIX_FM

#define DCH_SUFFIX_FM   0x01

Definition at line 550 of file formatting.c.

◆ DCH_SUFFIX_SP

#define DCH_SUFFIX_SP   0x08

Definition at line 553 of file formatting.c.

◆ DCH_SUFFIX_TH

#define DCH_SUFFIX_TH   0x02

Definition at line 551 of file formatting.c.

◆ DCH_SUFFIX_th

#define DCH_SUFFIX_th   0x04

Definition at line 552 of file formatting.c.

◆ DCH_SUFFIX_TM

#define DCH_SUFFIX_TM   0x10

Definition at line 554 of file formatting.c.

◆ DCH_TIMED

#define DCH_TIMED   0x02

Definition at line 1054 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 (IS_SUFFIX_THth(n->suffix)) \
str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); \
s += strlen(s)
static enum TH_Case SUFFIX_TH_TYPE(uint8 _s)
Definition: formatting.c:578
static bool IS_SUFFIX_THth(uint8 _s)
Definition: formatting.c:572
#define sprintf
Definition: port.h:262

◆ DCH_ZONED

#define DCH_ZONED   0x04

Definition at line 1055 of file formatting.c.

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 468 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 467 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:1330
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39

Definition at line 534 of file formatting.c.

◆ IS_BLANK

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

Definition at line 342 of file formatting.c.

◆ IS_BRACKET

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

Definition at line 344 of file formatting.c.

◆ IS_DECIMAL

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

Definition at line 339 of file formatting.c.

◆ IS_EEEE

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

Definition at line 350 of file formatting.c.

◆ IS_FILLMODE

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

Definition at line 343 of file formatting.c.

◆ IS_LDECIMAL

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

Definition at line 340 of file formatting.c.

◆ IS_LSIGN

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

Definition at line 346 of file formatting.c.

◆ IS_MINUS

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

Definition at line 345 of file formatting.c.

◆ IS_MULTI

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

Definition at line 349 of file formatting.c.

◆ IS_PLUS

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

Definition at line 347 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:341

Definition at line 5525 of file formatting.c.

◆ IS_ROMAN

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

Definition at line 348 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:225

Definition at line 258 of file formatting.c.

◆ IS_ZERO

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

Definition at line 341 of file formatting.c.

◆ KeyWord_INDEX_FILTER

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

Definition at line 98 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 97 of file formatting.c.

◆ MAX_ROMAN_LEN

#define MAX_ROMAN_LEN   15

Definition at line 278 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 380 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

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

Definition at line 371 of file formatting.c.

◆ NUM_CACHE_SIZE

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

Definition at line 376 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 324 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 327 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 321 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 334 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 325 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 322 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 326 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 328 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 333 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 331 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 329 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 332 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 330 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 323 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 91 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 104 of file formatting.c.

◆ NUM_TOCHAR_finish

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

Definition at line 6217 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)
static FormatNode * NUM_cache(int len, NUMDesc *Num, const text *pars_str, bool *shouldFree)
Definition: formatting.c:4942
#define NUM_MAX_ITEM_SIZ
Definition: formatting.c:104
void * palloc0(Size size)
Definition: mcxt.c:1417
Definition: c.h:712
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition: varatt.h:472
text * cstring_to_text(const char *s)
Definition: varlena.c:181

Definition at line 6205 of file formatting.c.

◆ OVERLOAD_TEST

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

Definition at line 1062 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 218 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 219 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 220 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

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

◆ SKIP_THth

#define SKIP_THth (   ptr,
  _suf 
)
Value:
do { \
if (IS_SUFFIX_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:1026

Definition at line 1991 of file formatting.c.

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 92 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 599 of file formatting.c.

◆ tmtcFsec

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

Definition at line 500 of file formatting.c.

◆ tmtcTm

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

Definition at line 498 of file formatting.c.

◆ tmtcTzn

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

Definition at line 499 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 517 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:498

Definition at line 523 of file formatting.c.

Typedef Documentation

◆ NUMProc

typedef struct NUMProc NUMProc

◆ TmToChar

typedef struct TmToChar TmToChar

Enumeration Type Documentation

◆ DCH_poz

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

Definition at line 640 of file formatting.c.

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

◆ FormatNodeType

Enumerator
NODE_TYPE_END 
NODE_TYPE_ACTION 
NODE_TYPE_CHAR 
NODE_TYPE_SEPARATOR 
NODE_TYPE_SPACE 

Definition at line 147 of file formatting.c.

148{
149 NODE_TYPE_END = 1,
151 NODE_TYPE_CHAR = 3,
153 NODE_TYPE_SPACE = 5,
154};
@ NODE_TYPE_CHAR
Definition: formatting.c:151
@ NODE_TYPE_ACTION
Definition: formatting.c:150
@ NODE_TYPE_SEPARATOR
Definition: formatting.c:152
@ NODE_TYPE_END
Definition: formatting.c:149
@ NODE_TYPE_SPACE
Definition: formatting.c:153

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 131 of file formatting.c.

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

◆ KeySuffixType

Enumerator
SUFFTYPE_PREFIX 
SUFFTYPE_POSTFIX 

Definition at line 111 of file formatting.c.

112{
113 SUFFTYPE_PREFIX = 1,
115};
@ SUFFTYPE_PREFIX
Definition: formatting.c:113
@ SUFFTYPE_POSTFIX
Definition: formatting.c:114

◆ NUM_poz

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

Definition at line 759 of file formatting.c.

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

◆ NUMDesc_lsign

Enumerator
NUM_LSIGN_PRE 
NUM_LSIGN_POST 
NUM_LSIGN_NONE 

Definition at line 295 of file formatting.c.

296{
297 NUM_LSIGN_PRE = -1,
298 NUM_LSIGN_POST = 1,
299 NUM_LSIGN_NONE = 0,
300};
@ NUM_LSIGN_POST
Definition: formatting.c:298
@ NUM_LSIGN_PRE
Definition: formatting.c:297
@ NUM_LSIGN_NONE
Definition: formatting.c:299

◆ TH_Case

enum TH_Case
Enumerator
TH_UPPER 
TH_LOWER 

Definition at line 289 of file formatting.c.

290{
291 TH_UPPER = 1,
292 TH_LOWER = 2,
293};
@ TH_UPPER
Definition: formatting.c:291
@ TH_LOWER
Definition: formatting.c:292

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2069 of file formatting.c.

2070{
2071 /*
2072 * Adjust all dates toward 2020; this is effectively what happens when we
2073 * assume '70' is 1970 and '69' is 2069.
2074 */
2075 /* Force 0-69 into the 2000's */
2076 if (year < 70)
2077 return year + 2000;
2078 /* Force 70-99 into the 1900's */
2079 else if (year < 100)
2080 return year + 1900;
2081 /* Force 100-519 into the 2000's */
2082 else if (year < 520)
2083 return year + 2000;
2084 /* Force 520-999 into the 1000's */
2085 else if (year < 1000)
2086 return year + 1000;
2087 else
2088 return year;
2089}

Referenced by DCH_from_char().

◆ asc_initcap()

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

Definition at line 1924 of file formatting.c.

1925{
1926 char *result;
1927 int wasalnum = false;
1928
1929 if (!buff)
1930 return NULL;
1931
1932 result = pnstrdup(buff, nbytes);
1933
1934 for (char *p = result; *p; p++)
1935 {
1936 char c;
1937
1938 if (wasalnum)
1939 *p = c = pg_ascii_tolower((unsigned char) *p);
1940 else
1941 *p = c = pg_ascii_toupper((unsigned char) *p);
1942 /* we don't trust isalnum() here */
1943 wasalnum = ((c >= 'A' && c <= 'Z') ||
1944 (c >= 'a' && c <= 'z') ||
1945 (c >= '0' && c <= '9'));
1946 }
1947
1948 return result;
1949}
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1792
static unsigned char pg_ascii_tolower(unsigned char ch)
Definition: port.h:188
static unsigned char pg_ascii_toupper(unsigned char ch)
Definition: port.h:177
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 1880 of file formatting.c.

1881{
1882 char *result;
1883
1884 if (!buff)
1885 return NULL;
1886
1887 result = pnstrdup(buff, nbytes);
1888
1889 for (char *p = result; *p; p++)
1890 *p = pg_ascii_tolower((unsigned char) *p);
1891
1892 return result;
1893}

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

1973{
1974 return asc_tolower(buff, strlen(buff));
1975}
char * asc_tolower(const char *buff, size_t nbytes)
Definition: formatting.c:1880

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

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

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

1979{
1980 return asc_toupper(buff, strlen(buff));
1981}
char * asc_toupper(const char *buff, size_t nbytes)
Definition: formatting.c:1902

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char *  fmt_str)

Definition at line 4317 of file formatting.c.

4318{
4319 bool incache;
4320 size_t fmt_len = strlen(fmt_str);
4321 int result;
4323
4324 if (fmt_len > DCH_CACHE_SIZE)
4325 {
4326 /*
4327 * Allocate new memory if format picture is bigger than static cache
4328 * and do not use cache (call parser always)
4329 */
4330 incache = false;
4331
4332 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4333
4335 DCH_suff, DCH_index, DCH_FLAG, NULL);
4336 }
4337 else
4338 {
4339 /*
4340 * Use cache buffers
4341 */
4342 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4343
4344 incache = true;
4345 format = ent->format;
4346 }
4347
4348 result = DCH_datetime_type(format);
4349
4350 if (!incache)
4351 pfree(format);
4352
4353 return result & DCH_ZONED;
4354}
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:976
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:1370
#define DCH_FLAG
Definition: formatting.c:90
static const KeySuffix DCH_suff[]
Definition: formatting.c:601
#define DCH_CACHE_SIZE
Definition: formatting.c:374
#define DCH_ZONED
Definition: formatting.c:1055
static int DCH_datetime_type(FormatNode *node)
Definition: formatting.c:3684
static const KeyWord DCH_keywords[]
Definition: formatting.c:805
static DCHCacheEntry * DCH_cache_fetch(const char *str, bool std)
Definition: formatting.c:3861
void pfree(void *pointer)
Definition: mcxt.c:1616
void * palloc(Size size)
Definition: mcxt.c:1387
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:384

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,
const text fmt,
bool  is_interval,
Oid  collid 
)
static

Definition at line 3888 of file formatting.c.

3889{
3891 char *fmt_str,
3892 *result;
3893 bool incache;
3894 size_t fmt_len;
3895 text *res;
3896
3897 /*
3898 * Convert fmt to C string
3899 */
3900 fmt_str = text_to_cstring(fmt);
3901 fmt_len = strlen(fmt_str);
3902
3903 /*
3904 * Allocate workspace for result as C string
3905 */
3906 result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
3907 *result = '\0';
3908
3909 if (fmt_len > DCH_CACHE_SIZE)
3910 {
3911 /*
3912 * Allocate new memory if format picture is bigger than static cache
3913 * and do not use cache (call parser always)
3914 */
3915 incache = false;
3916
3917 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3918
3920 DCH_suff, DCH_index, DCH_FLAG, NULL);
3921 }
3922 else
3923 {
3924 /*
3925 * Use cache buffers
3926 */
3927 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
3928
3929 incache = true;
3930 format = ent->format;
3931 }
3932
3933 /* The real work is here */
3934 DCH_to_char(format, is_interval, tmtc, result, collid);
3935
3936 if (!incache)
3937 pfree(format);
3938
3939 pfree(fmt_str);
3940
3941 /* convert C-string result to TEXT format */
3942 res = cstring_to_text(result);
3943
3944 pfree(result);
3945 return res;
3946}
Oid collid
static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
Definition: formatting.c:2468
#define DCH_MAX_ITEM_SIZ
Definition: formatting.c:103
char * text_to_cstring(const text *t)
Definition: varlena.c:214

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

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

◆ DCH_cache_fetch()

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

Definition at line 3861 of file formatting.c.

3862{
3863 DCHCacheEntry *ent;
3864
3865 if ((ent = DCH_cache_search(str, std)) == NULL)
3866 {
3867 /*
3868 * Not in the cache, must run parser and save a new format-picture to
3869 * the cache. Do not mark the cache entry valid until parsing
3870 * succeeds.
3871 */
3872 ent = DCH_cache_getnew(str, std);
3873
3875 DCH_FLAG | (std ? STD_FLAG : 0), NULL);
3876
3877 ent->valid = true;
3878 }
3879 return ent;
3880}
#define STD_FLAG
Definition: formatting.c:92
static DCHCacheEntry * DCH_cache_getnew(const char *str, bool std)
Definition: formatting.c:3780
static DCHCacheEntry * DCH_cache_search(const char *str, bool std)
Definition: formatting.c:3840
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 3780 of file formatting.c.

3781{
3782 DCHCacheEntry *ent;
3783
3784 /* Ensure we can advance DCHCounter below */
3786
3787 /*
3788 * If cache is full, remove oldest entry (or recycle first not-valid one)
3789 */
3791 {
3792 DCHCacheEntry *old = DCHCache[0];
3793
3794#ifdef DEBUG_TO_FROM_CHAR
3795 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3796#endif
3797 if (old->valid)
3798 {
3799 for (int i = 1; i < DCH_CACHE_ENTRIES; i++)
3800 {
3801 ent = DCHCache[i];
3802 if (!ent->valid)
3803 {
3804 old = ent;
3805 break;
3806 }
3807 if (ent->age < old->age)
3808 old = ent;
3809 }
3810 }
3811#ifdef DEBUG_TO_FROM_CHAR
3812 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3813#endif
3814 old->valid = false;
3815 strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
3816 old->age = (++DCHCounter);
3817 /* caller is expected to fill format, then set valid */
3818 return old;
3819 }
3820 else
3821 {
3822#ifdef DEBUG_TO_FROM_CHAR
3823 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3824#endif
3825 Assert(DCHCache[n_DCHCache] == NULL);
3826 DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
3828 ent->valid = false;
3829 strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
3830 ent->std = std;
3831 ent->age = (++DCHCounter);
3832 /* caller is expected to fill format, then set valid */
3833 ++n_DCHCache;
3834 return ent;
3835 }
3836}
#define elog(elevel,...)
Definition: elog.h:226
static void DCH_prevent_counter_overflow(void)
Definition: formatting.c:3670
static int DCHCounter
Definition: formatting.c:403
static int n_DCHCache
Definition: formatting.c:402
static DCHCacheEntry * DCHCache[DCH_CACHE_ENTRIES]
Definition: formatting.c:401
#define DCH_CACHE_ENTRIES
Definition: formatting.c:379
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1266
MemoryContext TopMemoryContext
Definition: mcxt.c:166
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char str[DCH_CACHE_SIZE+1]
Definition: formatting.c:385

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

3841{
3842 /* Ensure we can advance DCHCounter below */
3844
3845 for (int i = 0; i < n_DCHCache; i++)
3846 {
3847 DCHCacheEntry *ent = DCHCache[i];
3848
3849 if (ent->valid && strcmp(ent->str, str) == 0 && ent->std == std)
3850 {
3851 ent->age = (++DCHCounter);
3852 return ent;
3853 }
3854 }
3855
3856 return NULL;
3857}

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

3685{
3686 int flags = 0;
3687
3688 for (FormatNode *n = node; n->type != NODE_TYPE_END; n++)
3689 {
3690 if (n->type != NODE_TYPE_ACTION)
3691 continue;
3692
3693 switch (n->key->id)
3694 {
3695 case DCH_FX:
3696 break;
3697 case DCH_A_M:
3698 case DCH_P_M:
3699 case DCH_a_m:
3700 case DCH_p_m:
3701 case DCH_AM:
3702 case DCH_PM:
3703 case DCH_am:
3704 case DCH_pm:
3705 case DCH_HH:
3706 case DCH_HH12:
3707 case DCH_HH24:
3708 case DCH_MI:
3709 case DCH_SS:
3710 case DCH_MS: /* millisecond */
3711 case DCH_US: /* microsecond */
3712 case DCH_FF1:
3713 case DCH_FF2:
3714 case DCH_FF3:
3715 case DCH_FF4:
3716 case DCH_FF5:
3717 case DCH_FF6:
3718 case DCH_SSSS:
3719 flags |= DCH_TIMED;
3720 break;
3721 case DCH_tz:
3722 case DCH_TZ:
3723 case DCH_OF:
3724 case DCH_TZH:
3725 case DCH_TZM:
3726 flags |= DCH_ZONED;
3727 break;
3728 case DCH_A_D:
3729 case DCH_B_C:
3730 case DCH_a_d:
3731 case DCH_b_c:
3732 case DCH_AD:
3733 case DCH_BC:
3734 case DCH_ad:
3735 case DCH_bc:
3736 case DCH_MONTH:
3737 case DCH_Month:
3738 case DCH_month:
3739 case DCH_MON:
3740 case DCH_Mon:
3741 case DCH_mon:
3742 case DCH_MM:
3743 case DCH_DAY:
3744 case DCH_Day:
3745 case DCH_day:
3746 case DCH_DY:
3747 case DCH_Dy:
3748 case DCH_dy:
3749 case DCH_DDD:
3750 case DCH_IDDD:
3751 case DCH_DD:
3752 case DCH_D:
3753 case DCH_ID:
3754 case DCH_WW:
3755 case DCH_Q:
3756 case DCH_CC:
3757 case DCH_Y_YYY:
3758 case DCH_YYYY:
3759 case DCH_IYYY:
3760 case DCH_YYY:
3761 case DCH_IYY:
3762 case DCH_YY:
3763 case DCH_IY:
3764 case DCH_Y:
3765 case DCH_I:
3766 case DCH_RM:
3767 case DCH_rm:
3768 case DCH_W:
3769 case DCH_J:
3770 flags |= DCH_DATED;
3771 break;
3772 }
3773 }
3774
3775 return flags;
3776}
#define DCH_DATED
Definition: formatting.c:1053
#define DCH_TIMED
Definition: formatting.c:1054
enum FormatNodeType type
Definition: formatting.c:158

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

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

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_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(), IS_SUFFIX_TM(), 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, 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 3670 of file formatting.c.

3671{
3672 if (DCHCounter >= (INT_MAX - 1))
3673 {
3674 for (int i = 0; i < n_DCHCache; i++)
3675 DCHCache[i]->age >>= 1;
3676 DCHCounter >>= 1;
3677 }
3678}

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

2469{
2470 char *s;
2471 struct fmt_tm *tm = &in->tm;
2472 int i;
2473
2474 /* cache localized days and months */
2476
2477 s = out;
2478 for (FormatNode *n = node; n->type != NODE_TYPE_END; n++)
2479 {
2480 if (n->type != NODE_TYPE_ACTION)
2481 {
2482 strcpy(s, n->character);
2483 s += strlen(s);
2484 continue;
2485 }
2486
2487 switch (n->key->id)
2488 {
2489 case DCH_A_M:
2490 case DCH_P_M:
2491 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2492 ? P_M_STR : A_M_STR);
2493 s += strlen(s);
2494 break;
2495 case DCH_AM:
2496 case DCH_PM:
2497 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2498 ? PM_STR : AM_STR);
2499 s += strlen(s);
2500 break;
2501 case DCH_a_m:
2502 case DCH_p_m:
2503 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2504 ? p_m_STR : a_m_STR);
2505 s += strlen(s);
2506 break;
2507 case DCH_am:
2508 case DCH_pm:
2509 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2510 ? pm_STR : am_STR);
2511 s += strlen(s);
2512 break;
2513 case DCH_HH:
2514 case DCH_HH12:
2515
2516 /*
2517 * display time as shown on a 12-hour clock, even for
2518 * intervals
2519 */
2520 sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2521 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ?
2522 (long long) (HOURS_PER_DAY / 2) :
2523 (long long) (tm->tm_hour % (HOURS_PER_DAY / 2)));
2524 if (IS_SUFFIX_THth(n->suffix))
2525 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2526 s += strlen(s);
2527 break;
2528 case DCH_HH24:
2529 sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2530 (long long) tm->tm_hour);
2531 if (IS_SUFFIX_THth(n->suffix))
2532 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2533 s += strlen(s);
2534 break;
2535 case DCH_MI:
2536 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2537 tm->tm_min);
2538 if (IS_SUFFIX_THth(n->suffix))
2539 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2540 s += strlen(s);
2541 break;
2542 case DCH_SS:
2543 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2544 tm->tm_sec);
2545 if (IS_SUFFIX_THth(n->suffix))
2546 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2547 s += strlen(s);
2548 break;
2549
2550#define DCH_to_char_fsec(frac_fmt, frac_val) \
2551 sprintf(s, frac_fmt, (int) (frac_val)); \
2552 if (IS_SUFFIX_THth(n->suffix)) \
2553 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); \
2554 s += strlen(s)
2555
2556 case DCH_FF1: /* tenth of second */
2557 DCH_to_char_fsec("%01d", in->fsec / 100000);
2558 break;
2559 case DCH_FF2: /* hundredth of second */
2560 DCH_to_char_fsec("%02d", in->fsec / 10000);
2561 break;
2562 case DCH_FF3:
2563 case DCH_MS: /* millisecond */
2564 DCH_to_char_fsec("%03d", in->fsec / 1000);
2565 break;
2566 case DCH_FF4: /* tenth of a millisecond */
2567 DCH_to_char_fsec("%04d", in->fsec / 100);
2568 break;
2569 case DCH_FF5: /* hundredth of a millisecond */
2570 DCH_to_char_fsec("%05d", in->fsec / 10);
2571 break;
2572 case DCH_FF6:
2573 case DCH_US: /* microsecond */
2574 DCH_to_char_fsec("%06d", in->fsec);
2575 break;
2576#undef DCH_to_char_fsec
2577 case DCH_SSSS:
2578 sprintf(s, "%lld",
2579 (long long) (tm->tm_hour * SECS_PER_HOUR +
2581 tm->tm_sec));
2582 if (IS_SUFFIX_THth(n->suffix))
2583 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2584 s += strlen(s);
2585 break;
2586 case DCH_tz:
2588 if (tmtcTzn(in))
2589 {
2590 /* We assume here that timezone names aren't localized */
2591 char *p = asc_tolower_z(tmtcTzn(in));
2592
2593 strcpy(s, p);
2594 pfree(p);
2595 s += strlen(s);
2596 }
2597 break;
2598 case DCH_TZ:
2600 if (tmtcTzn(in))
2601 {
2602 strcpy(s, tmtcTzn(in));
2603 s += strlen(s);
2604 }
2605 break;
2606 case DCH_TZH:
2608 sprintf(s, "%c%02d",
2609 (tm->tm_gmtoff >= 0) ? '+' : '-',
2610 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2611 s += strlen(s);
2612 break;
2613 case DCH_TZM:
2615 sprintf(s, "%02d",
2616 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2617 s += strlen(s);
2618 break;
2619 case DCH_OF:
2621 sprintf(s, "%c%0*d",
2622 (tm->tm_gmtoff >= 0) ? '+' : '-',
2623 IS_SUFFIX_FM(n->suffix) ? 0 : 2,
2624 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2625 s += strlen(s);
2626 if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2627 {
2628 sprintf(s, ":%02d",
2629 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2630 s += strlen(s);
2631 }
2632 break;
2633 case DCH_A_D:
2634 case DCH_B_C:
2636 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2637 s += strlen(s);
2638 break;
2639 case DCH_AD:
2640 case DCH_BC:
2642 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2643 s += strlen(s);
2644 break;
2645 case DCH_a_d:
2646 case DCH_b_c:
2648 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2649 s += strlen(s);
2650 break;
2651 case DCH_ad:
2652 case DCH_bc:
2654 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2655 s += strlen(s);
2656 break;
2657 case DCH_MONTH:
2659 if (!tm->tm_mon)
2660 break;
2661 if (IS_SUFFIX_TM(n->suffix))
2662 {
2664
2665 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2666 strcpy(s, str);
2667 else
2668 ereport(ERROR,
2669 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2670 errmsg("localized string format value too long")));
2671 }
2672 else
2673 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2675 s += strlen(s);
2676 break;
2677 case DCH_Month:
2679 if (!tm->tm_mon)
2680 break;
2681 if (IS_SUFFIX_TM(n->suffix))
2682 {
2684
2685 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2686 strcpy(s, str);
2687 else
2688 ereport(ERROR,
2689 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2690 errmsg("localized string format value too long")));
2691 }
2692 else
2693 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2694 months_full[tm->tm_mon - 1]);
2695 s += strlen(s);
2696 break;
2697 case DCH_month:
2699 if (!tm->tm_mon)
2700 break;
2701 if (IS_SUFFIX_TM(n->suffix))
2702 {
2704
2705 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2706 strcpy(s, str);
2707 else
2708 ereport(ERROR,
2709 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2710 errmsg("localized string format value too long")));
2711 }
2712 else
2713 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2715 s += strlen(s);
2716 break;
2717 case DCH_MON:
2719 if (!tm->tm_mon)
2720 break;
2721 if (IS_SUFFIX_TM(n->suffix))
2722 {
2724
2725 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2726 strcpy(s, str);
2727 else
2728 ereport(ERROR,
2729 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2730 errmsg("localized string format value too long")));
2731 }
2732 else
2733 strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2734 s += strlen(s);
2735 break;
2736 case DCH_Mon:
2738 if (!tm->tm_mon)
2739 break;
2740 if (IS_SUFFIX_TM(n->suffix))
2741 {
2743
2744 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2745 strcpy(s, str);
2746 else
2747 ereport(ERROR,
2748 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2749 errmsg("localized string format value too long")));
2750 }
2751 else
2752 strcpy(s, months[tm->tm_mon - 1]);
2753 s += strlen(s);
2754 break;
2755 case DCH_mon:
2757 if (!tm->tm_mon)
2758 break;
2759 if (IS_SUFFIX_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_tolower_z(months[tm->tm_mon - 1]));
2772 s += strlen(s);
2773 break;
2774 case DCH_MM:
2775 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
2776 tm->tm_mon);
2777 if (IS_SUFFIX_THth(n->suffix))
2778 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2779 s += strlen(s);
2780 break;
2781 case DCH_DAY:
2783 if (IS_SUFFIX_TM(n->suffix))
2784 {
2786
2787 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2788 strcpy(s, str);
2789 else
2790 ereport(ERROR,
2791 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2792 errmsg("localized string format value too long")));
2793 }
2794 else
2795 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2797 s += strlen(s);
2798 break;
2799 case DCH_Day:
2801 if (IS_SUFFIX_TM(n->suffix))
2802 {
2804
2805 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2806 strcpy(s, str);
2807 else
2808 ereport(ERROR,
2809 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2810 errmsg("localized string format value too long")));
2811 }
2812 else
2813 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2814 days[tm->tm_wday]);
2815 s += strlen(s);
2816 break;
2817 case DCH_day:
2819 if (IS_SUFFIX_TM(n->suffix))
2820 {
2822
2823 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2824 strcpy(s, str);
2825 else
2826 ereport(ERROR,
2827 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2828 errmsg("localized string format value too long")));
2829 }
2830 else
2831 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2833 s += strlen(s);
2834 break;
2835 case DCH_DY:
2837 if (IS_SUFFIX_TM(n->suffix))
2838 {
2840
2841 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2842 strcpy(s, str);
2843 else
2844 ereport(ERROR,
2845 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2846 errmsg("localized string format value too long")));
2847 }
2848 else
2849 strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
2850 s += strlen(s);
2851 break;
2852 case DCH_Dy:
2854 if (IS_SUFFIX_TM(n->suffix))
2855 {
2857
2858 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2859 strcpy(s, str);
2860 else
2861 ereport(ERROR,
2862 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2863 errmsg("localized string format value too long")));
2864 }
2865 else
2866 strcpy(s, days_short[tm->tm_wday]);
2867 s += strlen(s);
2868 break;
2869 case DCH_dy:
2871 if (IS_SUFFIX_TM(n->suffix))
2872 {
2874
2875 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2876 strcpy(s, str);
2877 else
2878 ereport(ERROR,
2879 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2880 errmsg("localized string format value too long")));
2881 }
2882 else
2883 strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
2884 s += strlen(s);
2885 break;
2886 case DCH_DDD:
2887 case DCH_IDDD:
2888 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 3,
2889 (n->key->id == DCH_DDD) ?
2890 tm->tm_yday :
2892 if (IS_SUFFIX_THth(n->suffix))
2893 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2894 s += strlen(s);
2895 break;
2896 case DCH_DD:
2897 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2, tm->tm_mday);
2898 if (IS_SUFFIX_THth(n->suffix))
2899 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2900 s += strlen(s);
2901 break;
2902 case DCH_D:
2904 sprintf(s, "%d", tm->tm_wday + 1);
2905 if (IS_SUFFIX_THth(n->suffix))
2906 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2907 s += strlen(s);
2908 break;
2909 case DCH_ID:
2911 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
2912 if (IS_SUFFIX_THth(n->suffix))
2913 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2914 s += strlen(s);
2915 break;
2916 case DCH_WW:
2917 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2,
2918 (tm->tm_yday - 1) / 7 + 1);
2919 if (IS_SUFFIX_THth(n->suffix))
2920 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2921 s += strlen(s);
2922 break;
2923 case DCH_IW:
2924 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2,
2926 if (IS_SUFFIX_THth(n->suffix))
2927 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2928 s += strlen(s);
2929 break;
2930 case DCH_Q:
2931 if (!tm->tm_mon)
2932 break;
2933 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
2934 if (IS_SUFFIX_THth(n->suffix))
2935 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2936 s += strlen(s);
2937 break;
2938 case DCH_CC:
2939 if (is_interval) /* straight calculation */
2940 i = tm->tm_year / 100;
2941 else
2942 {
2943 if (tm->tm_year > 0)
2944 /* Century 20 == 1901 - 2000 */
2945 i = (tm->tm_year - 1) / 100 + 1;
2946 else
2947 /* Century 6BC == 600BC - 501BC */
2948 i = tm->tm_year / 100 - 1;
2949 }
2950 if (i <= 99 && i >= -99)
2951 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
2952 else
2953 sprintf(s, "%d", i);
2954 if (IS_SUFFIX_THth(n->suffix))
2955 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2956 s += strlen(s);
2957 break;
2958 case DCH_Y_YYY:
2959 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
2960 sprintf(s, "%d,%03d", i,
2961 ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
2962 if (IS_SUFFIX_THth(n->suffix))
2963 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2964 s += strlen(s);
2965 break;
2966 case DCH_YYYY:
2967 case DCH_IYYY:
2968 sprintf(s, "%0*d",
2969 IS_SUFFIX_FM(n->suffix) ? 0 :
2970 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
2971 (n->key->id == DCH_YYYY ?
2972 ADJUST_YEAR(tm->tm_year, is_interval) :
2974 tm->tm_mon,
2975 tm->tm_mday),
2976 is_interval)));
2977 if (IS_SUFFIX_THth(n->suffix))
2978 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2979 s += strlen(s);
2980 break;
2981 case DCH_YYY:
2982 case DCH_IYY:
2983 sprintf(s, "%0*d",
2984 IS_SUFFIX_FM(n->suffix) ? 0 :
2985 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
2986 (n->key->id == DCH_YYY ?
2987 ADJUST_YEAR(tm->tm_year, is_interval) :
2989 tm->tm_mon,
2990 tm->tm_mday),
2991 is_interval)) % 1000);
2992 if (IS_SUFFIX_THth(n->suffix))
2993 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2994 s += strlen(s);
2995 break;
2996 case DCH_YY:
2997 case DCH_IY:
2998 sprintf(s, "%0*d",
2999 IS_SUFFIX_FM(n->suffix) ? 0 :
3000 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
3001 (n->key->id == DCH_YY ?
3002 ADJUST_YEAR(tm->tm_year, is_interval) :
3004 tm->tm_mon,
3005 tm->tm_mday),
3006 is_interval)) % 100);
3007 if (IS_SUFFIX_THth(n->suffix))
3008 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3009 s += strlen(s);
3010 break;
3011 case DCH_Y:
3012 case DCH_I:
3013 sprintf(s, "%1d",
3014 (n->key->id == DCH_Y ?
3015 ADJUST_YEAR(tm->tm_year, is_interval) :
3017 tm->tm_mon,
3018 tm->tm_mday),
3019 is_interval)) % 10);
3020 if (IS_SUFFIX_THth(n->suffix))
3021 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3022 s += strlen(s);
3023 break;
3024 case DCH_RM:
3025 /* FALLTHROUGH */
3026 case DCH_rm:
3027
3028 /*
3029 * For intervals, values like '12 month' will be reduced to 0
3030 * month and some years. These should be processed.
3031 */
3032 if (!tm->tm_mon && !tm->tm_year)
3033 break;
3034 else
3035 {
3036 int mon = 0;
3037 const char *const *months;
3038
3039 if (n->key->id == DCH_RM)
3041 else
3043
3044 /*
3045 * Compute the position in the roman-numeral array. Note
3046 * that the contents of the array are reversed, December
3047 * being first and January last.
3048 */
3049 if (tm->tm_mon == 0)
3050 {
3051 /*
3052 * This case is special, and tracks the case of full
3053 * interval years.
3054 */
3055 mon = tm->tm_year >= 0 ? 0 : MONTHS_PER_YEAR - 1;
3056 }
3057 else if (tm->tm_mon < 0)
3058 {
3059 /*
3060 * Negative case. In this case, the calculation is
3061 * reversed, where -1 means December, -2 November,
3062 * etc.
3063 */
3064 mon = -1 * (tm->tm_mon + 1);
3065 }
3066 else
3067 {
3068 /*
3069 * Common case, with a strictly positive value. The
3070 * position in the array matches with the value of
3071 * tm_mon.
3072 */
3073 mon = MONTHS_PER_YEAR - tm->tm_mon;
3074 }
3075
3076 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -4,
3077 months[mon]);
3078 s += strlen(s);
3079 }
3080 break;
3081 case DCH_W:
3082 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
3083 if (IS_SUFFIX_THth(n->suffix))
3084 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3085 s += strlen(s);
3086 break;
3087 case DCH_J:
3088 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
3089 if (IS_SUFFIX_THth(n->suffix))
3090 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3091 s += strlen(s);
3092 break;
3093 }
3094 }
3095
3096 *s = '\0';
3097}
int date2j(int year, int month, int day)
Definition: datetime.c:296
int date2isoweek(int year, int mon, int mday)
Definition: timestamp.c:5295
int date2isoyearday(int year, int mon, int mday)
Definition: timestamp.c:5407
int date2isoyear(int year, int mon, int mday)
Definition: timestamp.c:5350
#define SECS_PER_HOUR
Definition: timestamp.h:127
#define SECS_PER_MINUTE
Definition: timestamp.h:128
#define HOURS_PER_DAY
Definition: timestamp.h:118
#define ereport(elevel,...)
Definition: elog.h:150
#define ad_STR
Definition: formatting.c:190
#define bc_STR
Definition: formatting.c:195
#define AD_STR
Definition: formatting.c:189
#define a_d_STR
Definition: formatting.c:188
#define DCH_to_char_fsec(frac_fmt, frac_val)
#define PM_STR
Definition: formatting.c:220
#define BC_STR
Definition: formatting.c:194
#define a_m_STR
Definition: formatting.c:214
#define A_D_STR
Definition: formatting.c:187
#define pm_STR
Definition: formatting.c:221
#define B_C_STR
Definition: formatting.c:192
static bool IS_SUFFIX_FM(uint8 _s)
Definition: formatting.c:585
#define ADJUST_YEAR(year, is_interval)
Definition: formatting.c:185
static char * str_tolower_z(const char *buff, Oid collid)
Definition: formatting.c:1954
static char * asc_toupper_z(const char *buff)
Definition: formatting.c:1978
#define TM_SUFFIX_LEN
Definition: formatting.c:599
static char * str_toupper_z(const char *buff, Oid collid)
Definition: formatting.c:1960
#define b_c_STR
Definition: formatting.c:193
#define INVALID_FOR_INTERVAL
Definition: formatting.c:534
static char * str_initcap_z(const char *buff, Oid collid)
Definition: formatting.c:1966
#define tmtcTzn(_X)
Definition: formatting.c:499
#define P_M_STR
Definition: formatting.c:218
#define p_m_STR
Definition: formatting.c:219
#define A_M_STR
Definition: formatting.c:213
#define am_STR
Definition: formatting.c:216
static char * asc_tolower_z(const char *buff)
Definition: formatting.c:1972
#define AM_STR
Definition: formatting.c:215
static const char *const rm_months_upper[]
Definition: formatting.c:241
static char * str_numth(char *dest, const char *num, enum TH_Case type)
Definition: formatting.c:1600
static struct pg_tm tm
Definition: localtime.c:104
struct fmt_tm tm
Definition: formatting.c:493
fsec_t fsec
Definition: formatting.c:494
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, IS_SUFFIX_FM(), IS_SUFFIX_THth(), IS_SUFFIX_TM(), 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, SECS_PER_HOUR, SECS_PER_MINUTE, sprintf, str, str_initcap_z(), str_numth(), str_tolower_z(), str_toupper_z(), FormatNode::suffix, SUFFIX_TH_TYPE(), 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 ( const text date_txt,
const 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 4380 of file formatting.c.

4383{
4384 FormatNode *format = NULL;
4385 TmFromChar tmfc = {0};
4386 int fmt_len;
4387 char *date_str;
4388 int fmask;
4389 bool incache = false;
4390
4391 Assert(tm != NULL);
4392 Assert(fsec != NULL);
4393
4394 date_str = text_to_cstring(date_txt);
4395
4396 ZERO_tm(tm);
4397 *fsec = 0;
4398 tz->has_tz = false;
4399 if (fprec)
4400 *fprec = 0;
4401 if (flags)
4402 *flags = 0;
4403 fmask = 0; /* bit mask for ValidateDate() */
4404
4405 fmt_len = VARSIZE_ANY_EXHDR(fmt);
4406
4407 if (fmt_len)
4408 {
4409 char *fmt_str;
4410
4411 fmt_str = text_to_cstring(fmt);
4412
4413 if (fmt_len > DCH_CACHE_SIZE)
4414 {
4415 /*
4416 * Allocate new memory if format picture is bigger than static
4417 * cache and do not use cache (call parser always)
4418 */
4419 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4420
4422 DCH_FLAG | (std ? STD_FLAG : 0), NULL);
4423 }
4424 else
4425 {
4426 /*
4427 * Use cache buffers
4428 */
4429 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, std);
4430
4431 incache = true;
4432 format = ent->format;
4433 }
4434
4435#ifdef DEBUG_TO_FROM_CHAR
4436 /* dump_node(format, fmt_len); */
4437 /* dump_index(DCH_keywords, DCH_index); */
4438#endif
4439
4440 DCH_from_char(format, date_str, &tmfc, collid, std, escontext);
4441 pfree(fmt_str);
4442 if (SOFT_ERROR_OCCURRED(escontext))
4443 goto fail;
4444
4445 if (flags)
4446 *flags = DCH_datetime_type(format);
4447
4448 if (!incache)
4449 {
4450 pfree(format);
4451 format = NULL;
4452 }
4453 }
4454
4455 DEBUG_TMFC(&tmfc);
4456
4457 /*
4458 * Convert to_date/to_timestamp input fields to standard 'tm'
4459 */
4460 if (tmfc.ssss)
4461 {
4462 int x = tmfc.ssss;
4463
4465 x %= SECS_PER_HOUR;
4467 x %= SECS_PER_MINUTE;
4468 tm->tm_sec = x;
4469 }
4470
4471 if (tmfc.ss)
4472 tm->tm_sec = tmfc.ss;
4473 if (tmfc.mi)
4474 tm->tm_min = tmfc.mi;
4475 if (tmfc.hh)
4476 tm->tm_hour = tmfc.hh;
4477
4478 if (tmfc.clock_12_hour)
4479 {
4480 if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
4481 {
4482 errsave(escontext,
4483 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4484 errmsg("hour \"%d\" is invalid for the 12-hour clock", tm->tm_hour),
4485 errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
4486 goto fail;
4487 }
4488
4489 if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
4490 tm->tm_hour += HOURS_PER_DAY / 2;
4491 else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
4492 tm->tm_hour = 0;
4493 }
4494
4495 if (tmfc.year)
4496 {
4497 /*
4498 * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
4499 * the year in the given century. Keep in mind that the 21st century
4500 * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
4501 * 600BC to 501BC.
4502 */
4503 if (tmfc.cc && tmfc.yysz <= 2)
4504 {
4505 if (tmfc.bc)
4506 tmfc.cc = -tmfc.cc;
4507 tm->tm_year = tmfc.year % 100;
4508 if (tm->tm_year)
4509 {
4510 int tmp;
4511
4512 if (tmfc.cc >= 0)
4513 {
4514 /* tm->tm_year += (tmfc.cc - 1) * 100; */
4515 tmp = tmfc.cc - 1;
4516 if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
4518 {
4520 text_to_cstring(date_txt), "timestamp",
4521 escontext);
4522 goto fail;
4523 }
4524 }
4525 else
4526 {
4527 /* tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1; */
4528 tmp = tmfc.cc + 1;
4529 if (pg_mul_s32_overflow(tmp, 100, &tmp) ||
4530 pg_sub_s32_overflow(tmp, tm->tm_year, &tmp) ||
4531 pg_add_s32_overflow(tmp, 1, &tm->tm_year))
4532 {
4534 text_to_cstring(date_txt), "timestamp",
4535 escontext);
4536 goto fail;
4537 }
4538 }
4539 }
4540 else
4541 {
4542 /* find century year for dates ending in "00" */
4543 tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
4544 }
4545 }
4546 else
4547 {
4548 /* If a 4-digit year is provided, we use that and ignore CC. */
4549 tm->tm_year = tmfc.year;
4550 if (tmfc.bc)
4551 tm->tm_year = -tm->tm_year;
4552 /* correct for our representation of BC years */
4553 if (tm->tm_year < 0)
4554 tm->tm_year++;
4555 }
4556 fmask |= DTK_M(YEAR);
4557 }
4558 else if (tmfc.cc)
4559 {
4560 /* use first year of century */
4561 if (tmfc.bc)
4562 tmfc.cc = -tmfc.cc;
4563 if (tmfc.cc >= 0)
4564 {
4565 /* +1 because 21st century started in 2001 */
4566 /* tm->tm_year = (tmfc.cc - 1) * 100 + 1; */
4567 if (pg_mul_s32_overflow(tmfc.cc - 1, 100, &tm->tm_year) ||
4569 {
4571 text_to_cstring(date_txt), "timestamp",
4572 escontext);
4573 goto fail;
4574 }
4575 }
4576 else
4577 {
4578 /* +1 because year == 599 is 600 BC */
4579 /* tm->tm_year = tmfc.cc * 100 + 1; */
4580 if (pg_mul_s32_overflow(tmfc.cc, 100, &tm->tm_year) ||
4582 {
4584 text_to_cstring(date_txt), "timestamp",
4585 escontext);
4586 goto fail;
4587 }
4588 }
4589 fmask |= DTK_M(YEAR);
4590 }
4591
4592 if (tmfc.j)
4593 {
4594 j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4595 fmask |= DTK_DATE_M;
4596 }
4597
4598 if (tmfc.ww)
4599 {
4600 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4601 {
4602 /*
4603 * If tmfc.d is not set, then the date is left at the beginning of
4604 * the ISO week (Monday).
4605 */
4606 if (tmfc.d)
4607 isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4608 else
4609 isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4610 fmask |= DTK_DATE_M;
4611 }
4612 else
4613 {
4614 /* tmfc.ddd = (tmfc.ww - 1) * 7 + 1; */
4615 if (pg_sub_s32_overflow(tmfc.ww, 1, &tmfc.ddd) ||
4616 pg_mul_s32_overflow(tmfc.ddd, 7, &tmfc.ddd) ||
4617 pg_add_s32_overflow(tmfc.ddd, 1, &tmfc.ddd))
4618 {
4620 date_str, "timestamp", escontext);
4621 goto fail;
4622 }
4623 }
4624 }
4625
4626 if (tmfc.w)
4627 {
4628 /* tmfc.dd = (tmfc.w - 1) * 7 + 1; */
4629 if (pg_sub_s32_overflow(tmfc.w, 1, &tmfc.dd) ||
4630 pg_mul_s32_overflow(tmfc.dd, 7, &tmfc.dd) ||
4631 pg_add_s32_overflow(tmfc.dd, 1, &tmfc.dd))
4632 {
4634 date_str, "timestamp", escontext);
4635 goto fail;
4636 }
4637 }
4638 if (tmfc.dd)
4639 {
4640 tm->tm_mday = tmfc.dd;
4641 fmask |= DTK_M(DAY);
4642 }
4643 if (tmfc.mm)
4644 {
4645 tm->tm_mon = tmfc.mm;
4646 fmask |= DTK_M(MONTH);
4647 }
4648
4649 if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
4650 {
4651 /*
4652 * The month and day field have not been set, so we use the
4653 * day-of-year field to populate them. Depending on the date mode,
4654 * this field may be interpreted as a Gregorian day-of-year, or an ISO
4655 * week date day-of-year.
4656 */
4657
4658 if (!tm->tm_year && !tmfc.bc)
4659 {
4660 errsave(escontext,
4661 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4662 errmsg("cannot calculate day of year without year information")));
4663 goto fail;
4664 }
4665
4666 if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4667 {
4668 int j0; /* zeroth day of the ISO year, in Julian */
4669
4670 j0 = isoweek2j(tm->tm_year, 1) - 1;
4671
4672 j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4673 fmask |= DTK_DATE_M;
4674 }
4675 else
4676 {
4677 const int *y;
4678 int i;
4679
4680 static const int ysum[2][13] = {
4681 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
4682 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
4683
4684 y = ysum[isleap(tm->tm_year)];
4685
4686 for (i = 1; i <= MONTHS_PER_YEAR; i++)
4687 {
4688 if (tmfc.ddd <= y[i])
4689 break;
4690 }
4691 if (tm->tm_mon <= 1)
4692 tm->tm_mon = i;
4693
4694 if (tm->tm_mday <= 1)
4695 tm->tm_mday = tmfc.ddd - y[i - 1];
4696
4697 fmask |= DTK_M(MONTH) | DTK_M(DAY);
4698 }
4699 }
4700
4701 if (tmfc.ms)
4702 {
4703 int tmp = 0;
4704
4705 /* *fsec += tmfc.ms * 1000; */
4706 if (pg_mul_s32_overflow(tmfc.ms, 1000, &tmp) ||
4707 pg_add_s32_overflow(*fsec, tmp, fsec))
4708 {
4710 date_str, "timestamp", escontext);
4711 goto fail;
4712 }
4713 }
4714 if (tmfc.us)
4715 *fsec += tmfc.us;
4716 if (fprec)
4717 *fprec = tmfc.ff; /* fractional precision, if specified */
4718
4719 /* Range-check date fields according to bit mask computed above */
4720 if (fmask != 0)
4721 {
4722 /* We already dealt with AD/BC, so pass isjulian = true */
4723 int dterr = ValidateDate(fmask, true, false, false, tm);
4724
4725 if (dterr != 0)
4726 {
4727 /*
4728 * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
4729 * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
4730 * irrelevant hint about datestyle.
4731 */
4733 date_str, "timestamp", escontext);
4734 goto fail;
4735 }
4736 }
4737
4738 /* Range-check time fields too */
4739 if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY ||
4740 tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR ||
4741 tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
4742 *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
4743 {
4745 date_str, "timestamp", escontext);
4746 goto fail;
4747 }
4748
4749 /*
4750 * If timezone info was present, reduce it to a GMT offset. (We cannot do
4751 * this until we've filled all of the tm struct, since the zone's offset
4752 * might be time-varying.)
4753 */
4754 if (tmfc.tzsign)
4755 {
4756 /* TZH and/or TZM fields */
4757 if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
4758 tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
4759 {
4761 date_str, "timestamp", escontext);
4762 goto fail;
4763 }
4764
4765 tz->has_tz = true;
4766 tz->gmtoffset = (tmfc.tzh * MINS_PER_HOUR + tmfc.tzm) * SECS_PER_MINUTE;
4767 /* note we are flipping the sign convention here */
4768 if (tmfc.tzsign > 0)
4769 tz->gmtoffset = -tz->gmtoffset;
4770 }
4771 else if (tmfc.has_tz)
4772 {
4773 /* TZ field */
4774 tz->has_tz = true;
4775 if (tmfc.tzp == NULL)
4776 {
4777 /* fixed-offset abbreviation; flip the sign convention */
4778 tz->gmtoffset = -tmfc.gmtoffset;
4779 }
4780 else
4781 {
4782 /* dynamic-offset abbreviation, resolve using specified time */
4784 tmfc.tzp);
4785 }
4786 }
4787
4788 DEBUG_TM(tm);
4789
4790 if (format && !incache)
4791 pfree(format);
4792 pfree(date_str);
4793
4794 return true;
4795
4796fail:
4797 if (format && !incache)
4798 pfree(format);
4799 pfree(date_str);
4800
4801 return false;
4802}
void DateTimeParseError(int dterr, DateTimeErrorExtra *extra, const char *str, const char *datatype, Node *escontext)
Definition: datetime.c:4214
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2561
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:321
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1765
void isoweek2date(int woy, int *year, int *mon, int *mday)
Definition: timestamp.c:5264
int isoweek2j(int year, int week)
Definition: timestamp.c:5244
void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
Definition: timestamp.c:5277
#define INT64CONST(x)
Definition: c.h:566
#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:3114
#define DEBUG_TM(_X)
Definition: formatting.c:468
#define DEBUG_TMFC(_X)
Definition: formatting.c:467
#define ZERO_tm(_X)
Definition: formatting.c:517
#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:415
bool has_tz
Definition: formatting.c:447
int gmtoffset
Definition: formatting.c:448

References TmFromChar::abbrev, Assert(), TmFromChar::bc, TmFromChar::cc, TmFromChar::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, and ZERO_tm.

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

◆ fill_str()

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

Definition at line 4815 of file formatting.c.

4816{
4817 memset(str, c, max);
4818 str[max] = '\0';
4819}

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

6629{
6631 text *fmt = PG_GETARG_TEXT_PP(1);
6632 NUMDesc Num;
6634 text *result;
6635 bool shouldFree;
6636 int out_pre_spaces = 0,
6637 sign = 0;
6638 char *numstr,
6639 *p;
6640
6642
6643 if (IS_ROMAN(&Num))
6644 {
6645 int32 intvalue;
6646
6647 /* See notes in ftoi4() */
6648 value = rint(value);
6649 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6650 if (!isnan(value) && FLOAT4_FITS_IN_INT32(value))
6651 intvalue = (int32) value;
6652 else
6653 intvalue = PG_INT32_MAX;
6654 numstr = int_to_roman(intvalue);
6655 }
6656 else if (IS_EEEE(&Num))
6657 {
6658 if (isnan(value) || isinf(value))
6659 {
6660 /*
6661 * Allow 6 characters for the leading sign, the decimal point,
6662 * "e", the exponent's sign and two exponent digits.
6663 */
6664 numstr = (char *) palloc(Num.pre + Num.post + 7);
6665 fill_str(numstr, '#', Num.pre + Num.post + 6);
6666 *numstr = ' ';
6667 *(numstr + Num.pre + 1) = '.';
6668 }
6669 else
6670 {
6671 numstr = psprintf("%+.*e", Num.post, value);
6672
6673 /*
6674 * Swap a leading positive sign for a space.
6675 */
6676 if (*numstr == '+')
6677 *numstr = ' ';
6678 }
6679 }
6680 else
6681 {
6682 float4 val = value;
6683 char *orgnum;
6684 size_t numstr_pre_len;
6685
6686 if (IS_MULTI(&Num))
6687 {
6688 float multi = pow((double) 10, (double) Num.multi);
6689
6690 val = value * multi;
6691 Num.pre += Num.multi;
6692 }
6693
6694 orgnum = psprintf("%.0f", fabs(val));
6695 numstr_pre_len = strlen(orgnum);
6696
6697 /* adjust post digits to fit max float digits */
6698 if (numstr_pre_len >= FLT_DIG)
6699 Num.post = 0;
6700 else if (numstr_pre_len + Num.post > FLT_DIG)
6701 Num.post = FLT_DIG - numstr_pre_len;
6702 orgnum = psprintf("%.*f", Num.post, val);
6703
6704 if (*orgnum == '-')
6705 { /* < 0 */
6706 sign = '-';
6707 numstr = orgnum + 1;
6708 }
6709 else
6710 {
6711 sign = '+';
6712 numstr = orgnum;
6713 }
6714
6715 if ((p = strchr(numstr, '.')))
6716 numstr_pre_len = p - numstr;
6717 else
6718 numstr_pre_len = strlen(numstr);
6719
6720 /* needs padding? */
6721 if (numstr_pre_len < Num.pre)
6722 out_pre_spaces = Num.pre - numstr_pre_len;
6723 /* overflowed prefix digit format? */
6724 else if (numstr_pre_len > Num.pre)
6725 {
6726 numstr = (char *) palloc(Num.pre + Num.post + 2);
6727 fill_str(numstr, '#', Num.pre + Num.post + 1);
6728 *(numstr + Num.pre) = '.';
6729 }
6730 }
#define FLOAT4_FITS_IN_INT32(num)
Definition: c.h:1083
#define PG_INT32_MAX
Definition: c.h:609
int32_t int32
Definition: c.h:548
float float4
Definition: c.h:649
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:310
#define PG_GETARG_FLOAT4(n)
Definition: fmgr.h:282
static void fill_str(char *str, int c, int max)
Definition: formatting.c:4815
#define NUM_TOCHAR_prepare
Definition: formatting.c:6205
#define IS_MULTI(_f)
Definition: formatting.c:349
#define IS_ROMAN(_f)
Definition: formatting.c:348
#define IS_EEEE(_f)
Definition: formatting.c:350
static char * int_to_roman(int number)
Definition: formatting.c:5005
long val
Definition: informix.c:689
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
int pre
Definition: formatting.c:307
int multi
Definition: formatting.c:312
int post
Definition: formatting.c:308

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

6741{
6743 text *fmt = PG_GETARG_TEXT_PP(1);
6744 NUMDesc Num;
6746 text *result;
6747 bool shouldFree;
6748 int out_pre_spaces = 0,
6749 sign = 0;
6750 char *numstr,
6751 *p;
6752
6754
6755 if (IS_ROMAN(&Num))
6756 {
6757 int32 intvalue;
6758
6759 /* See notes in dtoi4() */
6760 value = rint(value);
6761 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6762 if (!isnan(value) && FLOAT8_FITS_IN_INT32(value))
6763 intvalue = (int32) value;
6764 else
6765 intvalue = PG_INT32_MAX;
6766 numstr = int_to_roman(intvalue);
6767 }
6768 else if (IS_EEEE(&Num))
6769 {
6770 if (isnan(value) || isinf(value))
6771 {
6772 /*
6773 * Allow 6 characters for the leading sign, the decimal point,
6774 * "e", the exponent's sign and two exponent digits.
6775 */
6776 numstr = (char *) palloc(Num.pre + Num.post + 7);
6777 fill_str(numstr, '#', Num.pre + Num.post + 6);
6778 *numstr = ' ';
6779 *(numstr + Num.pre + 1) = '.';
6780 }
6781 else
6782 {
6783 numstr = psprintf("%+.*e", Num.post, value);
6784
6785 /*
6786 * Swap a leading positive sign for a space.
6787 */
6788 if (*numstr == '+')
6789 *numstr = ' ';
6790 }
6791 }
6792 else
6793 {
6794 float8 val = value;
6795 char *orgnum;
6796 size_t numstr_pre_len;
6797
6798 if (IS_MULTI(&Num))
6799 {
6800 double multi = pow((double) 10, (double) Num.multi);
6801
6802 val = value * multi;
6803 Num.pre += Num.multi;
6804 }
6805
6806 orgnum = psprintf("%.0f", fabs(val));
6807 numstr_pre_len = strlen(orgnum);
6808
6809 /* adjust post digits to fit max double digits */
6810 if (numstr_pre_len >= DBL_DIG)
6811 Num.post = 0;
6812 else if (numstr_pre_len + Num.post > DBL_DIG)
6813 Num.post = DBL_DIG - numstr_pre_len;
6814 orgnum = psprintf("%.*f", Num.post, val);
6815
6816 if (*orgnum == '-')
6817 { /* < 0 */
6818 sign = '-';
6819 numstr = orgnum + 1;
6820 }
6821 else
6822 {
6823 sign = '+';
6824 numstr = orgnum;
6825 }
6826
6827 if ((p = strchr(numstr, '.')))
6828 numstr_pre_len = p - numstr;
6829 else
6830 numstr_pre_len = strlen(numstr);
6831
6832 /* needs padding? */
6833 if (numstr_pre_len < Num.pre)
6834 out_pre_spaces = Num.pre - numstr_pre_len;
6835 /* overflowed prefix digit format? */
6836 else if (numstr_pre_len > Num.pre)
6837 {
6838 numstr = (char *) palloc(Num.pre + Num.post + 2);
6839 fill_str(numstr, '#', Num.pre + Num.post + 1);
6840 *(numstr + Num.pre) = '.';
6841 }
6842 }
#define FLOAT8_FITS_IN_INT32(num)
Definition: c.h:1089
double float8
Definition: c.h:650
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:283

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

2273{
2274 return from_char_parse_int_len(dest, src, node->key->len, node, escontext);
2275}
size_t len
Definition: formatting.c:141

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 size_t  len,
FormatNode node,
Node escontext 
)
static

Definition at line 2176 of file formatting.c.

2178{
2179 long result;
2180 char copy[DCH_MAX_ITEM_SIZ + 1];
2181 const char *init = *src;
2182 size_t used;
2183
2184 /*
2185 * Skip any whitespace before parsing the integer.
2186 */
2187 *src += strspace_len(*src);
2188
2190 used = strlcpy(copy, *src, len + 1);
2191
2192 if (IS_SUFFIX_FM(node->suffix) || is_next_separator(node))
2193 {
2194 /*
2195 * This node is in Fill Mode, or the next node is known to be a
2196 * non-digit value, so we just slurp as many characters as we can get.
2197 */
2198 char *endptr;
2199
2200 errno = 0;
2201 result = strtol(init, &endptr, 10);
2202 *src = endptr;
2203 }
2204 else
2205 {
2206 /*
2207 * We need to pull exactly the number of characters given in 'len' out
2208 * of the string, and convert those.
2209 */
2210 char *last;
2211
2212 if (used < len)
2213 ereturn(escontext, -1,
2214 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2215 errmsg("source string too short for \"%s\" formatting field",
2216 node->key->name),
2217 errdetail("Field requires %zu characters, but only %zu remain.",
2218 len, used),
2219 errhint("If your source string is not fixed-width, try using the \"FM\" modifier.")));
2220
2221 errno = 0;
2222 result = strtol(copy, &last, 10);
2223 used = last - copy;
2224
2225 if (used > 0 && used < len)
2226 ereturn(escontext, -1,
2227 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2228 errmsg("invalid value \"%s\" for \"%s\"",
2229 copy, node->key->name),
2230 errdetail("Field requires %zu characters, but only %zu could be parsed.",
2231 len, used),
2232 errhint("If your source string is not fixed-width, try using the \"FM\" modifier.")));
2233
2234 *src += used;
2235 }
2236
2237 if (*src == init)
2238 ereturn(escontext, -1,
2239 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2240 errmsg("invalid value \"%s\" for \"%s\"",
2241 copy, node->key->name),
2242 errdetail("Value must be an integer.")));
2243
2244 if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
2245 ereturn(escontext, -1,
2246 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2247 errmsg("value for \"%s\" in source string is out of range",
2248 node->key->name),
2249 errdetail("Value must be in the range %d to %d.",
2250 INT_MIN, INT_MAX)));
2251
2252 if (dest != NULL)
2253 {
2254 if (!from_char_set_int(dest, (int) result, node, escontext))
2255 return -1;
2256 }
2257
2258 return *src - init;
2259}
static bool is_next_separator(FormatNode *n)
Definition: formatting.c:2036
static size_t strspace_len(const char *str)
Definition: formatting.c:2093
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(), IS_SUFFIX_FM(), FormatNode::key, len, KeyWord::name, 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 2425 of file formatting.c.

2428{
2429 size_t len;
2430
2431 if (localized_array == NULL)
2432 *dest = seq_search_ascii(*src, array, &len);
2433 else
2434 *dest = seq_search_localized(*src, localized_array, &len, collid);
2435
2436 if (len <= 0)
2437 {
2438 /*
2439 * In the error report, truncate the string at the next whitespace (if
2440 * any) to avoid including irrelevant data.
2441 */
2442 char *copy = pstrdup(*src);
2443
2444 for (char *c = copy; *c; c++)
2445 {
2446 if (scanner_isspace(*c))
2447 {
2448 *c = '\0';
2449 break;
2450 }
2451 }
2452
2453 ereturn(escontext, false,
2454 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2455 errmsg("invalid value \"%s\" for \"%s\"",
2456 copy, node->key->name),
2457 errdetail("The given value did not match any of the allowed values for this field.")));
2458 }
2459 *src += len;
2460 return true;
2461}
static int seq_search_ascii(const char *name, const char *const *array, size_t *len)
Definition: formatting.c:2289
static int seq_search_localized(const char *name, char **array, size_t *len, Oid collid)
Definition: formatting.c:2342
char * pstrdup(const char *in)
Definition: mcxt.c:1781
bool scanner_isspace(char ch)
Definition: scansup.c:105

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

2143{
2144 if (*dest != 0 && *dest != value)
2145 ereturn(escontext, false,
2146 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2147 errmsg("conflicting values for \"%s\" field in formatting string",
2148 node->key->name),
2149 errdetail("This value contradicts a previous setting for the same field type.")));
2150 *dest = value;
2151 return true;
2152}

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

2117{
2119 {
2120 if (tmfc->mode == FROM_CHAR_DATE_NONE)
2121 tmfc->mode = mode;
2122 else if (tmfc->mode != mode)
2123 ereturn(escontext, false,
2124 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2125 errmsg("invalid combination of date conventions"),
2126 errhint("Do not mix Gregorian and ISO week date conventions in a formatting template.")));
2127 }
2128 return true;
2129}
static PgChecksumMode mode
Definition: pg_checksums.c:56

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

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

static const char * get_last_relevant_decnum ( const char *  num)
static

Definition at line 5294 of file formatting.c.

5295{
5296 const char *result,
5297 *p = strchr(num, '.');
5298
5299#ifdef DEBUG_TO_FROM_CHAR
5300 elog(DEBUG_elog_output, "get_last_relevant_decnum()");
5301#endif
5302
5303 if (!p)
5304 return NULL;
5305
5306 result = p;
5307
5308 while (*(++p))
5309 {
5310 if (*p != '0')
5311 result = p;
5312 }
5313
5314 return result;
5315}

References elog.

Referenced by NUM_processor().

◆ get_th()

static const char * get_th ( const char *  num,
enum TH_Case  type 
)
static

Definition at line 1555 of file formatting.c.

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

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

Referenced by NUM_processor(), and str_numth().

◆ index_seq_search()

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

Definition at line 1134 of file formatting.c.

1135{
1136 int poz;
1137
1139 return NULL;
1140
1141 if ((poz = index[*str - ' ']) > -1)
1142 {
1143 const KeyWord *k = kw + poz;
1144
1145 do
1146 {
1147 if (strncmp(str, k->name, k->len) == 0)
1148 return k;
1149 k++;
1150 if (!k->name)
1151 return NULL;
1152 } while (*str == *k->name);
1153 }
1154 return NULL;
1155}
#define KeyWord_INDEX_FILTER(_c)
Definition: formatting.c:98
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 6420 of file formatting.c.

6425{
6427 text *fmt = PG_GETARG_TEXT_PP(1);
6428 NUMDesc Num;
6430 text *result;
6431 bool shouldFree;
6432 int out_pre_spaces = 0,
6433 sign = 0;
6434 char *numstr,
6435 *orgnum;
6436
6438
6439 /*
6440 * On DateType depend part (int32)
6441 */
6442 if (IS_ROMAN(&Num))
6443 numstr = int_to_roman(value);
6444 else if (IS_EEEE(&Num))
6445 {
6446 /* we can do it easily because float8 won't lose any precision */
6447 float8 val = (float8) value;
6448
6449 orgnum = (char *) psprintf("%+.*e", Num.post, val);
6450
6451 /*
6452 * Swap a leading positive sign for a space.
6453 */
6454 if (*orgnum == '+')
6455 *orgnum = ' ';
6456
6457 numstr = orgnum;
6458 }
6459 else
6460 {
6461 size_t numstr_pre_len;
6462
6463 if (IS_MULTI(&Num))
6464 {
6466 Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
6467 Num.pre += Num.multi;
6468 }
6469 else
6470 {
6473 }
6474
6475 if (*orgnum == '-')
6476 {
6477 sign = '-';
6478 orgnum++;
6479 }
6480 else
6481 sign = '+';
6482
6483 numstr_pre_len = strlen(orgnum);
6484
6485 /* post-decimal digits? Pad out with zeros. */
6486 if (Num.post)
6487 {
6488 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6489 strcpy(numstr, orgnum);
6490 *(numstr + numstr_pre_len) = '.';
6491 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6492 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6493 }
6494 else
6495 numstr = orgnum;
6496
6497 /* needs padding? */
6498 if (numstr_pre_len < Num.pre)
6499 out_pre_spaces = Num.pre - numstr_pre_len;
6500 /* overflowed prefix digit format? */
6501 else if (numstr_pre_len > Num.pre)
6502 {
6503 numstr = (char *) palloc(Num.pre + Num.post + 2);
6504 fill_str(numstr, '#', Num.pre + Num.post + 1);
6505 *(numstr + Num.pre) = '.';
6506 }
6507 }
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:684
#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:365
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:222

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

◆ int8_to_char()

Datum int8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6513 of file formatting.c.

6518{
6520 text *fmt = PG_GETARG_TEXT_PP(1);
6521 NUMDesc Num;
6523 text *result;
6524 bool shouldFree;
6525 int out_pre_spaces = 0,
6526 sign = 0;
6527 char *numstr,
6528 *orgnum;
6529
6531
6532 /*
6533 * On DateType depend part (int64)
6534 */
6535 if (IS_ROMAN(&Num))
6536 {
6537 int32 intvalue;
6538
6539 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6540 if (value <= PG_INT32_MAX && value >= PG_INT32_MIN)
6541 intvalue = (int32) value;
6542 else
6543 intvalue = PG_INT32_MAX;
6544 numstr = int_to_roman(intvalue);
6545 }
6546 else if (IS_EEEE(&Num))
6547 {
6548 /* to avoid loss of precision, must go via numeric not float8 */
6550 Num.post);
6551
6552 /*
6553 * numeric_out_sci() does not emit a sign for positive numbers. We
6554 * need to add a space in this case so that positive and negative
6555 * numbers are aligned. We don't have to worry about NaN/inf here.
6556 */
6557 if (*orgnum != '-')
6558 {
6559 numstr = (char *) palloc(strlen(orgnum) + 2);
6560 *numstr = ' ';
6561 strcpy(numstr + 1, orgnum);
6562 }
6563 else
6564 {
6565 numstr = orgnum;
6566 }
6567 }
6568 else
6569 {
6570 size_t numstr_pre_len;
6571
6572 if (IS_MULTI(&Num))
6573 {
6574 double multi = pow((double) 10, (double) Num.multi);
6575
6579 Float8GetDatum(multi))));
6580 Num.pre += Num.multi;
6581 }
6582
6585
6586 if (*orgnum == '-')
6587 {
6588 sign = '-';
6589 orgnum++;
6590 }
6591 else
6592 sign = '+';
6593
6594 numstr_pre_len = strlen(orgnum);
6595
6596 /* post-decimal digits? Pad out with zeros. */
6597 if (Num.post)
6598 {
6599 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6600 strcpy(numstr, orgnum);
6601 *(numstr + numstr_pre_len) = '.';
6602 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6603 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6604 }
6605 else
6606 numstr = orgnum;
6607
6608 /* needs padding? */
6609 if (numstr_pre_len < Num.pre)
6610 out_pre_spaces = Num.pre - numstr_pre_len;
6611 /* overflowed prefix digit format? */
6612 else if (numstr_pre_len > Num.pre)
6613 {
6614 numstr = (char *) palloc(Num.pre + Num.post + 2);
6615 fill_str(numstr, '#', Num.pre + Num.post + 1);
6616 *(numstr + Num.pre) = '.';
6617 }
6618 }
char * numeric_out_sci(Numeric num, int scale)
Definition: numeric.c:975
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4259
int64_t int64
Definition: c.h:549
#define PG_INT32_MIN
Definition: c.h:608
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:686
#define PG_GETARG_INT64(n)
Definition: fmgr.h:284
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 Datum Int64GetDatum(int64 X)
Definition: postgres.h:423
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:413
static Datum Float8GetDatum(float8 X)
Definition: postgres.h:512

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

5006{
5007 int len,
5008 num;
5009 char *result,
5010 numstr[12];
5011
5012 result = (char *) palloc(MAX_ROMAN_LEN + 1);
5013 *result = '\0';
5014
5015 /*
5016 * This range limit is the same as in Oracle(TM). The difficulty with
5017 * handling 4000 or more is that we'd need to use more than 3 "M"'s, and
5018 * more than 3 of the same digit isn't considered a valid Roman string.
5019 */
5020 if (number > 3999 || number < 1)
5021 {
5022 fill_str(result, '#', MAX_ROMAN_LEN);
5023 return result;
5024 }
5025
5026 /* Convert to decimal, then examine each digit */
5027 len = snprintf(numstr, sizeof(numstr), "%d", number);
5028 Assert(len > 0 && len <= 4);
5029
5030 for (char *p = numstr; *p != '\0'; p++, --len)
5031 {
5032 num = *p - ('0' + 1);
5033 if (num < 0)
5034 continue; /* ignore zeroes */
5035 /* switch on current column position */
5036 switch (len)
5037 {
5038 case 4:
5039 while (num-- >= 0)
5040 strcat(result, "M");
5041 break;
5042 case 3:
5043 strcat(result, rm100[num]);
5044 break;
5045 case 2:
5046 strcat(result, rm10[num]);
5047 break;
5048 case 1:
5049 strcat(result, rm1[num]);
5050 break;
5051 }
5052 }
5053 return result;
5054}
#define MAX_ROMAN_LEN
Definition: formatting.c:278
static const char *const rm100[]
Definition: formatting.c:252
static const char *const rm10[]
Definition: formatting.c:251
static const char *const rm1[]
Definition: formatting.c:250
#define snprintf
Definition: port.h:260

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

4032{
4034 text *fmt = PG_GETARG_TEXT_PP(1),
4035 *res;
4036 TmToChar tmtc;
4037 struct fmt_tm *tm;
4038 struct pg_itm tt,
4039 *itm = &tt;
4040
4041 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || INTERVAL_NOT_FINITE(it))
4043
4044 ZERO_tmtc(&tmtc);
4045 tm = tmtcTm(&tmtc);
4046
4047 interval2itm(*it, itm);
4048 tmtc.fsec = itm->tm_usec;
4049 tm->tm_sec = itm->tm_sec;
4050 tm->tm_min = itm->tm_min;
4051 tm->tm_hour = itm->tm_hour;
4052 tm->tm_mday = itm->tm_mday;
4053 tm->tm_mon = itm->tm_mon;
4054 tm->tm_year = itm->tm_year;
4055
4056 /* wday is meaningless, yday approximates the total span in days */
4058
4059 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4061
4062 PG_RETURN_TEXT_P(res);
4063}
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:346
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:374
static text * datetime_to_char_body(TmToChar *tmtc, const text *fmt, bool is_interval, Oid collid)
Definition: formatting.c:3888
#define ZERO_tmtc(_X)
Definition: formatting.c:523
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 2036 of file formatting.c.

2037{
2038 if (n->type == NODE_TYPE_END)
2039 return false;
2040
2041 if (n->type == NODE_TYPE_ACTION && IS_SUFFIX_THth(n->suffix))
2042 return true;
2043
2044 /*
2045 * Next node
2046 */
2047 n++;
2048
2049 /* end of format string is treated like a non-digit separator */
2050 if (n->type == NODE_TYPE_END)
2051 return true;
2052
2053 if (n->type == NODE_TYPE_ACTION)
2054 {
2055 if (n->key->is_digit)
2056 return false;
2057
2058 return true;
2059 }
2060 else if (n->character[1] == '\0' &&
2061 isdigit((unsigned char) n->character[0]))
2062 return false;
2063
2064 return true; /* some non-digit input (separator) */
2065}
bool is_digit
Definition: formatting.c:143

References FormatNode::character, KeyWord::is_digit, IS_SUFFIX_THth(), FormatNode::key, NODE_TYPE_ACTION, NODE_TYPE_END, 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 1172 of file formatting.c.

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

References str.

Referenced by DCH_from_char(), and parse_format().

◆ IS_SUFFIX_FM()

static bool IS_SUFFIX_FM ( uint8  _s)
inlinestatic

Definition at line 585 of file formatting.c.

586{
587 return (_s & DCH_SUFFIX_FM);
588}
#define DCH_SUFFIX_FM
Definition: formatting.c:550

References DCH_SUFFIX_FM.

Referenced by DCH_to_char(), and from_char_parse_int_len().

◆ IS_SUFFIX_TH()

static bool IS_SUFFIX_TH ( uint8  _s)
inlinestatic

Definition at line 560 of file formatting.c.

561{
562 return (_s & DCH_SUFFIX_TH);
563}
#define DCH_SUFFIX_TH
Definition: formatting.c:551

References DCH_SUFFIX_TH.

Referenced by IS_SUFFIX_THth().

◆ IS_SUFFIX_th()

static bool IS_SUFFIX_th ( uint8  _s)
inlinestatic

Definition at line 566 of file formatting.c.

567{
568 return (_s & DCH_SUFFIX_th);
569}
#define DCH_SUFFIX_th
Definition: formatting.c:552

References DCH_SUFFIX_th.

Referenced by IS_SUFFIX_THth().

◆ IS_SUFFIX_THth()

static bool IS_SUFFIX_THth ( uint8  _s)
inlinestatic

Definition at line 572 of file formatting.c.

573{
574 return IS_SUFFIX_TH(_s) || IS_SUFFIX_th(_s);
575}
static bool IS_SUFFIX_TH(uint8 _s)
Definition: formatting.c:560
static bool IS_SUFFIX_th(uint8 _s)
Definition: formatting.c:566

References IS_SUFFIX_TH(), and IS_SUFFIX_th().

Referenced by DCH_to_char(), and is_next_separator().

◆ IS_SUFFIX_TM()

static bool IS_SUFFIX_TM ( uint8  _s)
inlinestatic

Definition at line 591 of file formatting.c.

592{
593 return (_s & DCH_SUFFIX_TM);
594}
#define DCH_SUFFIX_TM
Definition: formatting.c:554

References DCH_SUFFIX_TM.

Referenced by DCH_from_char(), and DCH_to_char().

◆ NUM_cache()

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

Definition at line 4942 of file formatting.c.

4943{
4944 FormatNode *format = NULL;
4945 char *str;
4946
4947 str = text_to_cstring(pars_str);
4948
4949 if (len > NUM_CACHE_SIZE)
4950 {
4951 /*
4952 * Allocate new memory if format picture is bigger than static cache
4953 * and do not use cache (call parser always)
4954 */
4955 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
4956
4957 *shouldFree = true;
4958
4959 memset(Num, 0, sizeof *Num);
4960
4962 NULL, NUM_index, NUM_FLAG, Num);
4963 }
4964 else
4965 {
4966 /*
4967 * Use cache buffers
4968 */
4970
4971 *shouldFree = false;
4972
4973 format = ent->format;
4974
4975 /*
4976 * Copy cache to used struct
4977 */
4978 Num->flag = ent->Num.flag;
4979 Num->lsign = ent->Num.lsign;
4980 Num->pre = ent->Num.pre;
4981 Num->post = ent->Num.post;
4982 Num->pre_lsign_num = ent->Num.pre_lsign_num;
4983 Num->need_locale = ent->Num.need_locale;
4984 Num->multi = ent->Num.multi;
4985 Num->zero_start = ent->Num.zero_start;
4986 Num->zero_end = ent->Num.zero_end;
4987 }
4988
4989#ifdef DEBUG_TO_FROM_CHAR
4990 /* dump_node(format, len); */
4991 dump_index(NUM_keywords, NUM_index);
4992#endif
4993
4994 pfree(str);
4995 return format;
4996}
static const KeyWord NUM_keywords[]
Definition: formatting.c:929
#define NUM_CACHE_SIZE
Definition: formatting.c:376
static NUMCacheEntry * NUM_cache_fetch(const char *str)
Definition: formatting.c:4915
#define NUM_FLAG
Definition: formatting.c:91
static const int NUM_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:999
NUMDesc Num
Definition: formatting.c:397
FormatNode format[NUM_CACHE_SIZE+1]
Definition: formatting.c:393
int pre_lsign_num
Definition: formatting.c:311
enum NUMDesc_lsign lsign
Definition: formatting.c:309
int zero_end
Definition: formatting.c:314
int flag
Definition: formatting.c:310
bool need_locale
Definition: formatting.c:315
int zero_start
Definition: formatting.c:313

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, and NUMDesc::zero_start.

Referenced by numeric_to_number().

◆ NUM_cache_fetch()

static NUMCacheEntry * NUM_cache_fetch ( const char *  str)
static

Definition at line 4915 of file formatting.c.

4916{
4917 NUMCacheEntry *ent;
4918
4919 if ((ent = NUM_cache_search(str)) == NULL)
4920 {
4921 /*
4922 * Not in the cache, must run parser and save a new format-picture to
4923 * the cache. Do not mark the cache entry valid until parsing
4924 * succeeds.
4925 */
4926 ent = NUM_cache_getnew(str);
4927
4928 memset(&ent->Num, 0, sizeof ent->Num);
4929
4931 NULL, NUM_index, NUM_FLAG, &ent->Num);
4932
4933 ent->valid = true;
4934 }
4935 return ent;
4936}
static NUMCacheEntry * NUM_cache_getnew(const char *str)
Definition: formatting.c:4835
static NUMCacheEntry * NUM_cache_search(const char *str)
Definition: formatting.c:4894

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

Referenced by NUM_cache().

◆ NUM_cache_getnew()

static NUMCacheEntry * NUM_cache_getnew ( const char *  str)
static

Definition at line 4835 of file formatting.c.

4836{
4837 NUMCacheEntry *ent;
4838
4839 /* Ensure we can advance NUMCounter below */
4841
4842 /*
4843 * If cache is full, remove oldest entry (or recycle first not-valid one)
4844 */
4846 {
4847 NUMCacheEntry *old = NUMCache[0];
4848
4849#ifdef DEBUG_TO_FROM_CHAR
4850 elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
4851#endif
4852 if (old->valid)
4853 {
4854 for (int i = 1; i < NUM_CACHE_ENTRIES; i++)
4855 {
4856 ent = NUMCache[i];
4857 if (!ent->valid)
4858 {
4859 old = ent;
4860 break;
4861 }
4862 if (ent->age < old->age)
4863 old = ent;
4864 }
4865 }
4866#ifdef DEBUG_TO_FROM_CHAR
4867 elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
4868#endif
4869 old->valid = false;
4870 strlcpy(old->str, str, NUM_CACHE_SIZE + 1);
4871 old->age = (++NUMCounter);
4872 /* caller is expected to fill format and Num, then set valid */
4873 return old;
4874 }
4875 else
4876 {
4877#ifdef DEBUG_TO_FROM_CHAR
4878 elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
4879#endif
4880 Assert(NUMCache[n_NUMCache] == NULL);
4881 NUMCache[n_NUMCache] = ent = (NUMCacheEntry *)
4883 ent->valid = false;
4884 strlcpy(ent->str, str, NUM_CACHE_SIZE + 1);
4885 ent->age = (++NUMCounter);
4886 /* caller is expected to fill format and Num, then set valid */
4887 ++n_NUMCache;
4888 return ent;
4889 }
4890}
static NUMCacheEntry * NUMCache[NUM_CACHE_ENTRIES]
Definition: formatting.c:406
#define NUM_CACHE_ENTRIES
Definition: formatting.c:380
static void NUM_prevent_counter_overflow(void)
Definition: formatting.c:4823
static int NUMCounter
Definition: formatting.c:408
static int n_NUMCache
Definition: formatting.c:407
char str[NUM_CACHE_SIZE+1]
Definition: formatting.c:394

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

4895{
4896 /* Ensure we can advance NUMCounter below */
4898
4899 for (int i = 0; i < n_NUMCache; i++)
4900 {
4901 NUMCacheEntry *ent = NUMCache[i];
4902
4903 if (ent->valid && strcmp(ent->str, str) == 0)
4904 {
4905 ent->age = (++NUMCounter);
4906 return ent;
4907 }
4908 }
4909
4910 return NULL;
4911}

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,
size_t  input_len 
)
static

Definition at line 5725 of file formatting.c.

5726{
5727 while (n-- > 0)
5728 {
5729 if (OVERLOAD_TEST)
5730 break; /* end of input */
5731 if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
5732 break; /* it's a data character */
5733 Np->inout_p += pg_mblen(Np->inout_p);
5734 }
5735}
#define OVERLOAD_TEST
Definition: formatting.c:1062
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,
size_t  input_len 
)
static

Definition at line 5321 of file formatting.c.

5322{
5323 bool isread = false;
5324
5325#ifdef DEBUG_TO_FROM_CHAR
5326 elog(DEBUG_elog_output, " --- scan start --- id=%s",
5327 (id == NUM_0 || id == NUM_9) ? "NUM_0/9" : id == NUM_DEC ? "NUM_DEC" : "???");
5328#endif
5329
5330 if (OVERLOAD_TEST)
5331 return;
5332
5333 if (*Np->inout_p == ' ')
5334 Np->inout_p++;
5335
5336 if (OVERLOAD_TEST)
5337 return;
5338
5339 /*
5340 * read sign before number
5341 */
5342 if (*Np->number == ' ' && (id == NUM_0 || id == NUM_9) &&
5343 (Np->read_pre + Np->read_post) == 0)
5344 {
5345#ifdef DEBUG_TO_FROM_CHAR
5346 elog(DEBUG_elog_output, "Try read sign (%c), locale positive: %s, negative: %s",
5347 *Np->inout_p, Np->L_positive_sign, Np->L_negative_sign);
5348#endif
5349
5350 /*
5351 * locale sign
5352 */
5353 if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE)
5354 {
5355 size_t x = 0;
5356
5357#ifdef DEBUG_TO_FROM_CHAR
5358 elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p);
5359#endif
5360 if ((x = strlen(Np->L_negative_sign)) &&
5361 AMOUNT_TEST(x) &&
5362 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
5363 {
5364 Np->inout_p += x;
5365 *Np->number = '-';
5366 }
5367 else if ((x = strlen(Np->L_positive_sign)) &&
5368 AMOUNT_TEST(x) &&
5369 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
5370 {
5371 Np->inout_p += x;
5372 *Np->number = '+';
5373 }
5374 }
5375 else
5376 {
5377#ifdef DEBUG_TO_FROM_CHAR
5378 elog(DEBUG_elog_output, "Try read simple sign (%c)", *Np->inout_p);
5379#endif
5380
5381 /*
5382 * simple + - < >
5383 */
5384 if (*Np->inout_p == '-' || (IS_BRACKET(Np->Num) &&
5385 *Np->inout_p == '<'))
5386 {
5387 *Np->number = '-'; /* set - */
5388 Np->inout_p++;
5389 }
5390 else if (*Np->inout_p == '+')
5391 {
5392 *Np->number = '+'; /* set + */
5393 Np->inout_p++;
5394 }
5395 }
5396 }
5397
5398 if (OVERLOAD_TEST)
5399 return;
5400
5401#ifdef DEBUG_TO_FROM_CHAR
5402 elog(DEBUG_elog_output, "Scan for numbers (%c), current number: '%s'", *Np->inout_p, Np->number);
5403#endif
5404
5405 /*
5406 * read digit or decimal point
5407 */
5408 if (isdigit((unsigned char) *Np->inout_p))
5409 {
5410 if (Np->read_dec && Np->read_post == Np->Num->post)
5411 return;
5412
5413 *Np->number_p = *Np->inout_p;
5414 Np->number_p++;
5415
5416 if (Np->read_dec)
5417 Np->read_post++;
5418 else
5419 Np->read_pre++;
5420
5421 isread = true;
5422
5423#ifdef DEBUG_TO_FROM_CHAR
5424 elog(DEBUG_elog_output, "Read digit (%c)", *Np->inout_p);
5425#endif
5426 }
5427 else if (IS_DECIMAL(Np->Num) && Np->read_dec == false)
5428 {
5429 /*
5430 * We need not test IS_LDECIMAL(Np->Num) explicitly here, because
5431 * Np->decimal is always just "." if we don't have a D format token.
5432 * So we just unconditionally match to Np->decimal.
5433 */
5434 size_t x = strlen(Np->decimal);
5435
5436#ifdef DEBUG_TO_FROM_CHAR
5437 elog(DEBUG_elog_output, "Try read decimal point (%c)",
5438 *Np->inout_p);
5439#endif
5440 if (x && AMOUNT_TEST(x) && strncmp(Np->inout_p, Np->decimal, x) == 0)
5441 {
5442 Np->inout_p += x - 1;
5443 *Np->number_p = '.';
5444 Np->number_p++;
5445 Np->read_dec = true;
5446 isread = true;
5447 }
5448 }
5449
5450 if (OVERLOAD_TEST)
5451 return;
5452
5453 /*
5454 * Read sign behind "last" number
5455 *
5456 * We need sign detection because determine exact position of post-sign is
5457 * difficult:
5458 *
5459 * FM9999.9999999S -> 123.001- 9.9S -> .5- FM9.999999MI ->
5460 * 5.01-
5461 */
5462 if (*Np->number == ' ' && Np->read_pre + Np->read_post > 0)
5463 {
5464 /*
5465 * locale sign (NUM_S) is always anchored behind a last number, if: -
5466 * locale sign expected - last read char was NUM_0/9 or NUM_DEC - and
5467 * next char is not digit
5468 */
5469 if (IS_LSIGN(Np->Num) && isread &&
5470 (Np->inout_p + 1) < Np->inout + input_len &&
5471 !isdigit((unsigned char) *(Np->inout_p + 1)))
5472 {
5473 size_t x;
5474 char *tmp = Np->inout_p++;
5475
5476#ifdef DEBUG_TO_FROM_CHAR
5477 elog(DEBUG_elog_output, "Try read locale post-sign (%c)", *Np->inout_p);
5478#endif
5479 if ((x = strlen(Np->L_negative_sign)) &&
5480 AMOUNT_TEST(x) &&
5481 strncmp(Np->inout_p, Np->L_negative_sign, x) == 0)
5482 {
5483 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
5484 *Np->number = '-';
5485 }
5486 else if ((x = strlen(Np->L_positive_sign)) &&
5487 AMOUNT_TEST(x) &&
5488 strncmp(Np->inout_p, Np->L_positive_sign, x) == 0)
5489 {
5490 Np->inout_p += x - 1; /* -1 .. NUM_processor() do inout_p++ */
5491 *Np->number = '+';
5492 }
5493 if (*Np->number == ' ')
5494 /* no sign read */
5495 Np->inout_p = tmp;
5496 }
5497
5498 /*
5499 * try read non-locale sign, which happens only if format is not exact
5500 * and we cannot determine sign position of MI/PL/SG, an example:
5501 *
5502 * FM9.999999MI -> 5.01-
5503 *
5504 * if (.... && IS_LSIGN(Np->Num)==false) prevents read wrong formats
5505 * like to_number('1 -', '9S') where sign is not anchored to last
5506 * number.
5507 */
5508 else if (isread == false && IS_LSIGN(Np->Num) == false &&
5509 (IS_PLUS(Np->Num) || IS_MINUS(Np->Num)))
5510 {
5511#ifdef DEBUG_TO_FROM_CHAR
5512 elog(DEBUG_elog_output, "Try read simple post-sign (%c)", *Np->inout_p);
5513#endif
5514
5515 /*
5516 * simple + -
5517 */
5518 if (*Np->inout_p == '-' || *Np->inout_p == '+')
5519 /* NUM_processor() do inout_p++ */
5520 *Np->number = *Np->inout_p;
5521 }
5522 }
5523}
#define IS_LSIGN(_f)
Definition: formatting.c:346
#define IS_BRACKET(_f)
Definition: formatting.c:344
#define AMOUNT_TEST(s)
Definition: formatting.c:1063
#define IS_MINUS(_f)
Definition: formatting.c:345
#define IS_DECIMAL(_f)
Definition: formatting.c:339
#define IS_PLUS(_f)
Definition: formatting.c:347
const char * L_negative_sign
Definition: formatting.c:1045
int read_post
Definition: formatting.c:1035
char * number_p
Definition: formatting.c:1039
NUMDesc * Num
Definition: formatting.c:1025
char * number
Definition: formatting.c:1038
const char * L_positive_sign
Definition: formatting.c:1046
int read_pre
Definition: formatting.c:1036
int read_dec
Definition: formatting.c:1034
char * inout
Definition: formatting.c:1040
const char * decimal
Definition: formatting.c:1047

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

5536{
5537 int end;
5538
5539 if (IS_ROMAN(Np->Num))
5540 return;
5541
5542 /* Note: in this elog() output not set '\0' in 'inout' */
5543
5544#ifdef DEBUG_TO_FROM_CHAR
5545
5546 /*
5547 * Np->num_curr is number of current item in format-picture, it is not
5548 * current position in inout!
5549 */
5550 elog(DEBUG_elog_output,
5551 "SIGN_WROTE: %d, CURRENT: %d, NUMBER_P: \"%s\", INOUT: \"%s\"",
5552 Np->sign_wrote,
5553 Np->num_curr,
5554 Np->number_p,
5555 Np->inout);
5556#endif
5557 Np->num_in = false;
5558
5559 /*
5560 * Write sign if real number will write to output Note: IS_PREDEC_SPACE()
5561 * handle "9.9" --> " .1"
5562 */
5563 if (Np->sign_wrote == false &&
5564 (Np->num_curr >= Np->out_pre_spaces || (IS_ZERO(Np->Num) && Np->Num->zero_start == Np->num_curr)) &&
5565 (IS_PREDEC_SPACE(Np) == false || (Np->last_relevant && *Np->last_relevant == '.')))
5566 {
5567 if (IS_LSIGN(Np->Num))
5568 {
5569 if (Np->Num->lsign == NUM_LSIGN_PRE)
5570 {
5571 if (Np->sign == '-')
5572 strcpy(Np->inout_p, Np->L_negative_sign);
5573 else
5574 strcpy(Np->inout_p, Np->L_positive_sign);
5575 Np->inout_p += strlen(Np->inout_p);
5576 Np->sign_wrote = true;
5577 }
5578 }
5579 else if (IS_BRACKET(Np->Num))
5580 {
5581 *Np->inout_p = Np->sign == '+' ? ' ' : '<';
5582 ++Np->inout_p;
5583 Np->sign_wrote = true;
5584 }
5585 else if (Np->sign == '+')
5586 {
5587 if (!IS_FILLMODE(Np->Num))
5588 {
5589 *Np->inout_p = ' '; /* Write + */
5590 ++Np->inout_p;
5591 }
5592 Np->sign_wrote = true;
5593 }
5594 else if (Np->sign == '-')
5595 { /* Write - */
5596 *Np->inout_p = '-';
5597 ++Np->inout_p;
5598 Np->sign_wrote = true;
5599 }
5600 }
5601
5602
5603 /*
5604 * digits / FM / Zero / Dec. point
5605 */
5606 if (id == NUM_9 || id == NUM_0 || id == NUM_D || id == NUM_DEC)
5607 {
5608 if (Np->num_curr < Np->out_pre_spaces &&
5609 (Np->Num->zero_start > Np->num_curr || !IS_ZERO(Np->Num)))
5610 {
5611 /*
5612 * Write blank space
5613 */
5614 if (!IS_FILLMODE(Np->Num))
5615 {
5616 *Np->inout_p = ' '; /* Write ' ' */
5617 ++Np->inout_p;
5618 }
5619 }
5620 else if (IS_ZERO(Np->Num) &&
5621 Np->num_curr < Np->out_pre_spaces &&
5622 Np->Num->zero_start <= Np->num_curr)
5623 {
5624 /*
5625 * Write ZERO
5626 */
5627 *Np->inout_p = '0'; /* Write '0' */
5628 ++Np->inout_p;
5629 Np->num_in = true;
5630 }
5631 else
5632 {
5633 /*
5634 * Write Decimal point
5635 */
5636 if (*Np->number_p == '.')
5637 {
5638 if (!Np->last_relevant || *Np->last_relevant != '.')
5639 {
5640 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
5641 Np->inout_p += strlen(Np->inout_p);
5642 }
5643
5644 /*
5645 * Ora 'n' -- FM9.9 --> 'n.'
5646 */
5647 else if (IS_FILLMODE(Np->Num) &&
5648 Np->last_relevant && *Np->last_relevant == '.')
5649 {
5650 strcpy(Np->inout_p, Np->decimal); /* Write DEC/D */
5651 Np->inout_p += strlen(Np->inout_p);
5652 }
5653 }
5654 else
5655 {
5656 /*
5657 * Write Digits
5658 */
5659 if (Np->last_relevant && Np->number_p > Np->last_relevant &&
5660 id != NUM_0)
5661 ;
5662
5663 /*
5664 * '0.1' -- 9.9 --> ' .1'
5665 */
5666 else if (IS_PREDEC_SPACE(Np))
5667 {
5668 if (!IS_FILLMODE(Np->Num))
5669 {
5670 *Np->inout_p = ' ';
5671 ++Np->inout_p;
5672 }
5673
5674 /*
5675 * '0' -- FM9.9 --> '0.'
5676 */
5677 else if (Np->last_relevant && *Np->last_relevant == '.')
5678 {
5679 *Np->inout_p = '0';
5680 ++Np->inout_p;
5681 }
5682 }
5683 else
5684 {
5685 *Np->inout_p = *Np->number_p; /* Write DIGIT */
5686 ++Np->inout_p;
5687 Np->num_in = true;
5688 }
5689 }
5690 /* do no exceed string length */
5691 if (*Np->number_p)
5692 ++Np->number_p;
5693 }
5694
5695 end = Np->num_count + (Np->out_pre_spaces ? 1 : 0) + (IS_DECIMAL(Np->Num) ? 1 : 0);
5696
5697 if (Np->last_relevant && Np->last_relevant == Np->number_p)
5698 end = Np->num_curr;
5699
5700 if (Np->num_curr + 1 == end)
5701 {
5702 if (Np->sign_wrote == true && IS_BRACKET(Np->Num))
5703 {
5704 *Np->inout_p = Np->sign == '+' ? ' ' : '>';
5705 ++Np->inout_p;
5706 }
5707 else if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_POST)
5708 {
5709 if (Np->sign == '-')
5710 strcpy(Np->inout_p, Np->L_negative_sign);
5711 else
5712 strcpy(Np->inout_p, Np->L_positive_sign);
5713 Np->inout_p += strlen(Np->inout_p);
5714 }
5715 }
5716 }
5717
5718 ++Np->num_curr;
5719}
#define IS_FILLMODE(_f)
Definition: formatting.c:343
#define IS_PREDEC_SPACE(_n)
Definition: formatting.c:5525
int num_curr
Definition: formatting.c:1031
int num_in
Definition: formatting.c:1030
const char * last_relevant
Definition: formatting.c:1043
int out_pre_spaces
Definition: formatting.c:1032
int sign
Definition: formatting.c:1027
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 5213 of file formatting.c.

5214{
5215 if (Np->Num->need_locale)
5216 {
5217 struct lconv *lconv;
5218
5219 /*
5220 * Get locales
5221 */
5222 lconv = PGLC_localeconv();
5223
5224 /*
5225 * Positive / Negative number sign
5226 */
5227 if (lconv->negative_sign && *lconv->negative_sign)
5228 Np->L_negative_sign = lconv->negative_sign;
5229 else
5230 Np->L_negative_sign = "-";
5231
5232 if (lconv->positive_sign && *lconv->positive_sign)
5233 Np->L_positive_sign = lconv->positive_sign;
5234 else
5235 Np->L_positive_sign = "+";
5236
5237 /*
5238 * Number decimal point
5239 */
5240 if (lconv->decimal_point && *lconv->decimal_point)
5241 Np->decimal = lconv->decimal_point;
5242
5243 else
5244 Np->decimal = ".";
5245
5246 if (!IS_LDECIMAL(Np->Num))
5247 Np->decimal = ".";
5248
5249 /*
5250 * Number thousands separator
5251 *
5252 * Some locales (e.g. broken glibc pt_BR), have a comma for decimal,
5253 * but "" for thousands_sep, so we set the thousands_sep too.
5254 * http://archives.postgresql.org/pgsql-hackers/2007-11/msg00772.php
5255 */
5256 if (lconv->thousands_sep && *lconv->thousands_sep)
5257 Np->L_thousands_sep = lconv->thousands_sep;
5258 /* Make sure thousands separator doesn't match decimal point symbol. */
5259 else if (strcmp(Np->decimal, ",") != 0)
5260 Np->L_thousands_sep = ",";
5261 else
5262 Np->L_thousands_sep = ".";
5263
5264 /*
5265 * Currency symbol
5266 */
5267 if (lconv->currency_symbol && *lconv->currency_symbol)
5268 Np->L_currency_symbol = lconv->currency_symbol;
5269 else
5270 Np->L_currency_symbol = " ";
5271 }
5272 else
5273 {
5274 /*
5275 * Default values
5276 */
5277 Np->L_negative_sign = "-";
5278 Np->L_positive_sign = "+";
5279 Np->decimal = ".";
5280
5281 Np->L_thousands_sep = ",";
5282 Np->L_currency_symbol = " ";
5283 }
5284}
#define IS_LDECIMAL(_f)
Definition: formatting.c:340
struct lconv * PGLC_localeconv(void)
Definition: pg_locale.c:506
const char * L_thousands_sep
Definition: formatting.c:1048
const char * L_currency_symbol
Definition: formatting.c:1049

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

4824{
4825 if (NUMCounter >= (INT_MAX - 1))
4826 {
4827 for (int i = 0; i < n_NUMCache; i++)
4828 NUMCache[i]->age >>= 1;
4829 NUMCounter >>= 1;
4830 }
4831}

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,
size_t  input_len,
int  to_char_out_pre_spaces,
int  sign,
bool  is_to_char,
Oid  collid 
)
static

Definition at line 5738 of file formatting.c.

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

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

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

6298{
6300 text *fmt = PG_GETARG_TEXT_PP(1);
6301 NUMDesc Num;
6303 text *result;
6304 bool shouldFree;
6305 int out_pre_spaces = 0,
6306 sign = 0;
6307 char *numstr,
6308 *orgnum,
6309 *p;
6310
6312
6313 /*
6314 * On DateType depend part (numeric)
6315 */
6316 if (IS_ROMAN(&Num))
6317 {
6318 int32 intvalue;
6319 ErrorSaveContext escontext = {T_ErrorSaveContext};
6320
6321 /* Round and convert to int */
6322 intvalue = numeric_int4_safe(value, (Node *) &escontext);
6323 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6324 if (escontext.error_occurred)
6325 intvalue = PG_INT32_MAX;
6326 numstr = int_to_roman(intvalue);
6327 }
6328 else if (IS_EEEE(&Num))
6329 {
6330 orgnum = numeric_out_sci(value, Num.post);
6331
6332 /*
6333 * numeric_out_sci() does not emit a sign for positive numbers. We
6334 * need to add a space in this case so that positive and negative
6335 * numbers are aligned. Also must check for NaN/infinity cases, which
6336 * we handle the same way as in float8_to_char.
6337 */
6338 if (strcmp(orgnum, "NaN") == 0 ||
6339 strcmp(orgnum, "Infinity") == 0 ||
6340 strcmp(orgnum, "-Infinity") == 0)
6341 {
6342 /*
6343 * Allow 6 characters for the leading sign, the decimal point,
6344 * "e", the exponent's sign and two exponent digits.
6345 */
6346 numstr = (char *) palloc(Num.pre + Num.post + 7);
6347 fill_str(numstr, '#', Num.pre + Num.post + 6);
6348 *numstr = ' ';
6349 *(numstr + Num.pre + 1) = '.';
6350 }
6351 else if (*orgnum != '-')
6352 {
6353 numstr = (char *) palloc(strlen(orgnum) + 2);
6354 *numstr = ' ';
6355 strcpy(numstr + 1, orgnum);
6356 }
6357 else
6358 {
6359 numstr = orgnum;
6360 }
6361 }
6362 else
6363 {
6364 size_t numstr_pre_len;
6365 Numeric val = value;
6366 Numeric x;
6367
6368 if (IS_MULTI(&Num))
6369 {
6372
6375 NumericGetDatum(b)));
6378 NumericGetDatum(x)));
6379 Num.pre += Num.multi;
6380 }
6381
6384 Int32GetDatum(Num.post)));
6386 NumericGetDatum(x)));
6387
6388 if (*orgnum == '-')
6389 {
6390 sign = '-';
6391 numstr = orgnum + 1;
6392 }
6393 else
6394 {
6395 sign = '+';
6396 numstr = orgnum;
6397 }
6398
6399 if ((p = strchr(numstr, '.')))
6400 numstr_pre_len = p - numstr;
6401 else
6402 numstr_pre_len = strlen(numstr);
6403
6404 /* needs padding? */
6405 if (numstr_pre_len < Num.pre)
6406 out_pre_spaces = Num.pre - numstr_pre_len;
6407 /* overflowed prefix digit format? */
6408 else if (numstr_pre_len > Num.pre)
6409 {
6410 numstr = (char *) palloc(Num.pre + Num.post + 2);
6411 fill_str(numstr, '#', Num.pre + Num.post + 1);
6412 *(numstr + Num.pre) = '.';
6413 }
6414 }
Datum numeric_round(PG_FUNCTION_ARGS)
Definition: numeric.c:1526
int32 numeric_int4_safe(Numeric num, Node *escontext)
Definition: numeric.c:4364
Datum numeric_power(PG_FUNCTION_ARGS)
Definition: numeric.c:3911
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:799
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3015
int b
Definition: isn.c:74
int a
Definition: isn.c:73
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:64
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:81
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:76
bool error_occurred
Definition: miscnodes.h:47
Definition: nodes.h:135

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

◆ numeric_to_number()

Datum numeric_to_number ( PG_FUNCTION_ARGS  )

Definition at line 6235 of file formatting.c.

6240{
6242 text *fmt = PG_GETARG_TEXT_PP(1);
6243 NUMDesc Num;
6244 Datum result;
6246 char *numstr;
6247 bool shouldFree;
6248 int len = 0;
6249 int scale,
6250 precision;
6251
6252 len = VARSIZE_ANY_EXHDR(fmt);
6253
6254 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
6256
6257 format = NUM_cache(len, &Num, fmt, &shouldFree);
6258
6259 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
6260
6261 NUM_processor(format, &Num, VARDATA_ANY(value), numstr,
6262 VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
6263
6264 scale = Num.post;
6265 precision = Num.pre + Num.multi + scale;
6266
6267 if (shouldFree)
6268 pfree(format);
6269
6271 CStringGetDatum(numstr),
6273 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
6274
6275 if (IS_MULTI(&Num))
6276 {
6277 Numeric x;
6280
6283 NumericGetDatum(b)));
6285 result,
6287 }
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:626
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:688
static int scale
Definition: pgbench.c:182
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:380
static char * VARDATA_ANY(const void *PTR)
Definition: varatt.h:486

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

◆ parse_datetime()

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

Definition at line 4156 of file formatting.c.

4159{
4160 struct pg_tm tm;
4161 struct fmt_tz ftz;
4162 fsec_t fsec;
4163 int fprec;
4164 uint32 flags;
4165
4166 if (!do_to_timestamp(date_txt, fmt, collid, strict,
4167 &tm, &fsec, &ftz, &fprec, &flags, escontext))
4168 return (Datum) 0;
4169
4170 *typmod = fprec ? fprec : -1; /* fractional part precision */
4171
4172 if (flags & DCH_DATED)
4173 {
4174 if (flags & DCH_TIMED)
4175 {
4176 if (flags & DCH_ZONED)
4177 {
4178 TimestampTz result;
4179
4180 if (ftz.has_tz)
4181 {
4182 *tz = ftz.gmtoffset;
4183 }
4184 else
4185 {
4186 /*
4187 * Time zone is present in format string, but not in input
4188 * string. Assuming do_to_timestamp() triggers no error
4189 * this should be possible only in non-strict case.
4190 */
4191 Assert(!strict);
4192
4193 ereturn(escontext, (Datum) 0,
4194 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4195 errmsg("missing time zone in input string for type timestamptz")));
4196 }
4197
4198 if (tm2timestamp(&tm, fsec, tz, &result) != 0)
4199 ereturn(escontext, (Datum) 0,
4200 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4201 errmsg("timestamptz out of range")));
4202
4203 AdjustTimestampForTypmod(&result, *typmod, escontext);
4204
4205 *typid = TIMESTAMPTZOID;
4206 return TimestampTzGetDatum(result);
4207 }
4208 else
4209 {
4210 Timestamp result;
4211
4212 if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
4213 ereturn(escontext, (Datum) 0,
4214 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4215 errmsg("timestamp out of range")));
4216
4217 AdjustTimestampForTypmod(&result, *typmod, escontext);
4218
4219 *typid = TIMESTAMPOID;
4220 return TimestampGetDatum(result);
4221 }
4222 }
4223 else
4224 {
4225 if (flags & DCH_ZONED)
4226 {
4227 ereturn(escontext, (Datum) 0,
4228 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4229 errmsg("datetime format is zoned but not timed")));
4230 }
4231 else
4232 {
4233 DateADT result;
4234
4235 /* Prevent overflow in Julian-day routines */
4237 ereturn(escontext, (Datum) 0,
4238 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4239 errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
4240
4241 result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) -
4243
4244 /* Now check for just-out-of-range dates */
4245 if (!IS_VALID_DATE(result))
4246 ereturn(escontext, (Datum) 0,
4247 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4248 errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
4249
4250 *typid = DATEOID;
4251 return DateADTGetDatum(result);
4252 }
4253 }
4254 }
4255 else if (flags & DCH_TIMED)
4256 {
4257 if (flags & DCH_ZONED)
4258 {
4260
4261 if (ftz.has_tz)
4262 {
4263 *tz = ftz.gmtoffset;
4264 }
4265 else
4266 {
4267 /*
4268 * Time zone is present in format string, but not in input
4269 * string. Assuming do_to_timestamp() triggers no error this
4270 * should be possible only in non-strict case.
4271 */
4272 Assert(!strict);
4273
4274 ereturn(escontext, (Datum) 0,
4275 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4276 errmsg("missing time zone in input string for type timetz")));
4277 }
4278
4279 if (tm2timetz(&tm, fsec, *tz, result) != 0)
4280 ereturn(escontext, (Datum) 0,
4281 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4282 errmsg("timetz out of range")));
4283
4284 AdjustTimeForTypmod(&result->time, *typmod);
4285
4286 *typid = TIMETZOID;
4287 return TimeTzADTPGetDatum(result);
4288 }
4289 else
4290 {
4291 TimeADT result;
4292
4293 if (tm2time(&tm, fsec, &result) != 0)
4294 ereturn(escontext, (Datum) 0,
4295 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4296 errmsg("time out of range")));
4297
4298 AdjustTimeForTypmod(&result, *typmod);
4299
4300 *typid = TIMEOID;
4301 return TimeADTGetDatum(result);
4302 }
4303 }
4304 else
4305 {
4306 ereturn(escontext, (Datum) 0,
4307 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4308 errmsg("datetime format is not dated and not timed")));
4309 }
4310}
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:552
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:1512
int tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
Definition: date.c:2359
void AdjustTimeForTypmod(TimeADT *time, int32 typmod)
Definition: date.c:1741
static Datum DateADTGetDatum(DateADT X)
Definition: date.h:80
int32 DateADT
Definition: date.h:23
static Datum TimeTzADTPGetDatum(const TimeTzADT *X)
Definition: date.h:92
int64 TimeADT
Definition: date.h:25
static Datum TimeADTGetDatum(TimeADT X)
Definition: date.h:86
#define palloc_object(type)
Definition: fe_memutils.h:74
static bool do_to_timestamp(const text *date_txt, const 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:4380
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_object, 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 1370 of file formatting.c.

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

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,
size_t  input_len 
)
static

Definition at line 5064 of file formatting.c.

5065{
5066 int result = 0;
5067 size_t len;
5068 char romanChars[MAX_ROMAN_LEN];
5069 int romanValues[MAX_ROMAN_LEN];
5070 int repeatCount = 1;
5071 int vCount = 0,
5072 lCount = 0,
5073 dCount = 0;
5074 bool subtractionEncountered = false;
5075 int lastSubtractedValue = 0;
5076
5077 /*
5078 * Skip any leading whitespace. Perhaps we should limit the amount of
5079 * space skipped to MAX_ROMAN_LEN, but that seems unnecessarily picky.
5080 */
5081 while (!OVERLOAD_TEST && isspace((unsigned char) *Np->inout_p))
5082 Np->inout_p++;
5083
5084 /*
5085 * Collect and decode valid roman numerals, consuming at most
5086 * MAX_ROMAN_LEN characters. We do this in a separate loop to avoid
5087 * repeated decoding and because the main loop needs to know when it's at
5088 * the last numeral.
5089 */
5090 for (len = 0; len < MAX_ROMAN_LEN && !OVERLOAD_TEST; len++)
5091 {
5092 char currChar = pg_ascii_toupper(*Np->inout_p);
5093 int currValue = ROMAN_VAL(currChar);
5094
5095 if (currValue == 0)
5096 break; /* Not a valid roman numeral. */
5097 romanChars[len] = currChar;
5098 romanValues[len] = currValue;
5099 Np->inout_p++;
5100 }
5101
5102 if (len == 0)
5103 return -1; /* No valid roman numerals. */
5104
5105 /* Check for valid combinations and compute the represented value. */
5106 for (size_t i = 0; i < len; i++)
5107 {
5108 char currChar = romanChars[i];
5109 int currValue = romanValues[i];
5110
5111 /*
5112 * Ensure no numeral greater than or equal to the subtracted numeral
5113 * appears after a subtraction.
5114 */
5115 if (subtractionEncountered && currValue >= lastSubtractedValue)
5116 return -1;
5117
5118 /*
5119 * V, L, and D should not appear before a larger numeral, nor should
5120 * they be repeated.
5121 */
5122 if ((vCount && currValue >= ROMAN_VAL('V')) ||
5123 (lCount && currValue >= ROMAN_VAL('L')) ||
5124 (dCount && currValue >= ROMAN_VAL('D')))
5125 return -1;
5126 if (currChar == 'V')
5127 vCount++;
5128 else if (currChar == 'L')
5129 lCount++;
5130 else if (currChar == 'D')
5131 dCount++;
5132
5133 if (i < len - 1)
5134 {
5135 /* Compare current numeral to next numeral. */
5136 char nextChar = romanChars[i + 1];
5137 int nextValue = romanValues[i + 1];
5138
5139 /*
5140 * If the current value is less than the next value, handle
5141 * subtraction. Verify valid subtractive combinations and update
5142 * the result accordingly.
5143 */
5144 if (currValue < nextValue)
5145 {
5146 if (!IS_VALID_SUB_COMB(currChar, nextChar))
5147 return -1;
5148
5149 /*
5150 * Reject cases where same numeral is repeated with
5151 * subtraction (e.g. 'MCCM' or 'DCCCD').
5152 */
5153 if (repeatCount > 1)
5154 return -1;
5155
5156 /*
5157 * We are going to skip nextChar, so first make checks needed
5158 * for V, L, and D. These are the same as we'd have applied
5159 * if we reached nextChar without a subtraction.
5160 */
5161 if ((vCount && nextValue >= ROMAN_VAL('V')) ||
5162 (lCount && nextValue >= ROMAN_VAL('L')) ||
5163 (dCount && nextValue >= ROMAN_VAL('D')))
5164 return -1;
5165 if (nextChar == 'V')
5166 vCount++;
5167 else if (nextChar == 'L')
5168 lCount++;
5169 else if (nextChar == 'D')
5170 dCount++;
5171
5172 /*
5173 * Skip the next numeral as it is part of the subtractive
5174 * combination.
5175 */
5176 i++;
5177
5178 /* Update state. */
5179 repeatCount = 1;
5180 subtractionEncountered = true;
5181 lastSubtractedValue = currValue;
5182 result += (nextValue - currValue);
5183 }
5184 else
5185 {
5186 /* For same numerals, check for repetition. */
5187 if (currChar == nextChar)
5188 {
5189 repeatCount++;
5190 if (repeatCount > 3)
5191 return -1;
5192 }
5193 else
5194 repeatCount = 1;
5195 result += currValue;
5196 }
5197 }
5198 else
5199 {
5200 /* This is the last numeral; just add it to the result. */
5201 result += currValue;
5202 }
5203 }
5204
5205 return result;
5206}
#define IS_VALID_SUB_COMB(curr, next)
Definition: formatting.c:258
#define ROMAN_VAL(r)
Definition: formatting.c:266

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,
size_t *  len 
)
static

Definition at line 2289 of file formatting.c.

2290{
2291 unsigned char firstc;
2292
2293 *len = 0;
2294
2295 /* empty string can't match anything */
2296 if (!*name)
2297 return -1;
2298
2299 /* we handle first char specially to gain some speed */
2300 firstc = pg_ascii_tolower((unsigned char) *name);
2301
2302 for (const char *const *a = array; *a != NULL; a++)
2303 {
2304 /* compare first chars */
2305 if (pg_ascii_tolower((unsigned char) **a) != firstc)
2306 continue;
2307
2308 /* compare rest of string */
2309 for (const char *p = *a + 1, *n = name + 1;; p++, n++)
2310 {
2311 /* return success if we matched whole array entry */
2312 if (*p == '\0')
2313 {
2314 *len = n - name;
2315 return a - array;
2316 }
2317 /* else, must have another character in "name" ... */
2318 if (*n == '\0')
2319 break;
2320 /* ... and it must match */
2321 if (pg_ascii_tolower((unsigned char) *p) !=
2322 pg_ascii_tolower((unsigned char) *n))
2323 break;
2324 }
2325 }
2326
2327 return -1;
2328}
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,
size_t *  len,
Oid  collid 
)
static

Definition at line 2342 of file formatting.c.

2343{
2344 char *upper_name;
2345 char *lower_name;
2346
2347 *len = 0;
2348
2349 /* empty string can't match anything */
2350 if (!*name)
2351 return -1;
2352
2353 /*
2354 * The case-folding processing done below is fairly expensive, so before
2355 * doing that, make a quick pass to see if there is an exact match.
2356 */
2357 for (char **a = array; *a != NULL; a++)
2358 {
2359 size_t element_len = strlen(*a);
2360
2361 if (strncmp(name, *a, element_len) == 0)
2362 {
2363 *len = element_len;
2364 return a - array;
2365 }
2366 }
2367
2368 /*
2369 * Fold to upper case, then to lower case, so that we can match reliably
2370 * even in languages in which case conversions are not injective.
2371 */
2372 upper_name = str_toupper(name, strlen(name), collid);
2373 lower_name = str_tolower(upper_name, strlen(upper_name), collid);
2374 pfree(upper_name);
2375
2376 for (char **a = array; *a != NULL; a++)
2377 {
2378 char *upper_element;
2379 char *lower_element;
2380 size_t element_len;
2381
2382 /* Likewise upper/lower-case array element */
2383 upper_element = str_toupper(*a, strlen(*a), collid);
2384 lower_element = str_tolower(upper_element, strlen(upper_element),
2385 collid);
2386 pfree(upper_element);
2387 element_len = strlen(lower_element);
2388
2389 /* Match? */
2390 if (strncmp(lower_name, lower_element, element_len) == 0)
2391 {
2392 *len = element_len;
2393 pfree(lower_element);
2394 pfree(lower_name);
2395 return a - array;
2396 }
2397 pfree(lower_element);
2398 }
2399
2400 pfree(lower_name);
2401 return -1;
2402}
char * str_toupper(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1683
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1619

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

1812{
1813 char *result;
1814 pg_locale_t mylocale;
1815
1816 if (!buff)
1817 return NULL;
1818
1819 if (!OidIsValid(collid))
1820 {
1821 /*
1822 * This typically means that the parser could not resolve a conflict
1823 * of implicit collations, so report it that way.
1824 */
1825 ereport(ERROR,
1826 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1827 errmsg("could not determine which collation to use for %s function",
1828 "lower()"),
1829 errhint("Use the COLLATE clause to set the collation explicitly.")));
1830 }
1831
1833 ereport(ERROR,
1834 (errcode(ERRCODE_SYNTAX_ERROR),
1835 errmsg("Unicode case folding can only be performed if server encoding is UTF8")));
1836
1838
1839 /* C/POSIX collations use this path regardless of database encoding */
1840 if (mylocale->ctype_is_c)
1841 {
1842 result = asc_tolower(buff, nbytes);
1843 }
1844 else
1845 {
1846 const char *src = buff;
1847 size_t srclen = nbytes;
1848 size_t dstsize;
1849 char *dst;
1850 size_t needed;
1851
1852 /* first try buffer of equal size plus terminating NUL */
1853 dstsize = srclen + 1;
1854 dst = palloc(dstsize);
1855
1856 needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
1857 if (needed + 1 > dstsize)
1858 {
1859 /* grow buffer if needed and retry */
1860 dstsize = needed + 1;
1861 dst = repalloc(dst, dstsize);
1862 needed = pg_strfold(dst, dstsize, src, srclen, mylocale);
1863 Assert(needed + 1 <= dstsize);
1864 }
1865
1866 Assert(dst[needed] == '\0');
1867 result = dst;
1868 }
1869
1870 return result;
1871}
#define OidIsValid(objectId)
Definition: c.h:794
int GetDatabaseEncoding(void)
Definition: mbutils.c:1264
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1632
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1189
size_t pg_strfold(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1348
@ 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 1747 of file formatting.c.

1748{
1749 char *result;
1750 pg_locale_t mylocale;
1751
1752 if (!buff)
1753 return NULL;
1754
1755 if (!OidIsValid(collid))
1756 {
1757 /*
1758 * This typically means that the parser could not resolve a conflict
1759 * of implicit collations, so report it that way.
1760 */
1761 ereport(ERROR,
1762 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1763 errmsg("could not determine which collation to use for %s function",
1764 "initcap()"),
1765 errhint("Use the COLLATE clause to set the collation explicitly.")));
1766 }
1767
1769
1770 /* C/POSIX collations use this path regardless of database encoding */
1771 if (mylocale->ctype_is_c)
1772 {
1773 result = asc_initcap(buff, nbytes);
1774 }
1775 else
1776 {
1777 const char *src = buff;
1778 size_t srclen = nbytes;
1779 size_t dstsize;
1780 char *dst;
1781 size_t needed;
1782
1783 /* first try buffer of equal size plus terminating NUL */
1784 dstsize = srclen + 1;
1785 dst = palloc(dstsize);
1786
1787 needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
1788 if (needed + 1 > dstsize)
1789 {
1790 /* grow buffer if needed and retry */
1791 dstsize = needed + 1;
1792 dst = repalloc(dst, dstsize);
1793 needed = pg_strtitle(dst, dstsize, src, srclen, mylocale);
1794 Assert(needed + 1 <= dstsize);
1795 }
1796
1797 Assert(dst[needed] == '\0');
1798 result = dst;
1799 }
1800
1801 return result;
1802}
char * asc_initcap(const char *buff, size_t nbytes)
Definition: formatting.c:1924
size_t pg_strtitle(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1328

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

1967{
1968 return str_initcap(buff, strlen(buff), collid);
1969}
char * str_initcap(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1747

References collid, and str_initcap().

Referenced by DCH_to_char().

◆ str_numth()

static char * str_numth ( char *  dest,
const char *  num,
enum TH_Case  type 
)
static

Definition at line 1600 of file formatting.c.

1601{
1602 if (dest != num)
1603 strcpy(dest, num);
1604 strcat(dest, get_th(num, type));
1605 return dest;
1606}

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

1620{
1621 char *result;
1622 pg_locale_t mylocale;
1623
1624 if (!buff)
1625 return NULL;
1626
1627 if (!OidIsValid(collid))
1628 {
1629 /*
1630 * This typically means that the parser could not resolve a conflict
1631 * of implicit collations, so report it that way.
1632 */
1633 ereport(ERROR,
1634 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1635 errmsg("could not determine which collation to use for %s function",
1636 "lower()"),
1637 errhint("Use the COLLATE clause to set the collation explicitly.")));
1638 }
1639
1641
1642 /* C/POSIX collations use this path regardless of database encoding */
1643 if (mylocale->ctype_is_c)
1644 {
1645 result = asc_tolower(buff, nbytes);
1646 }
1647 else
1648 {
1649 const char *src = buff;
1650 size_t srclen = nbytes;
1651 size_t dstsize;
1652 char *dst;
1653 size_t needed;
1654
1655 /* first try buffer of equal size plus terminating NUL */
1656 dstsize = srclen + 1;
1657 dst = palloc(dstsize);
1658
1659 needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
1660 if (needed + 1 > dstsize)
1661 {
1662 /* grow buffer if needed and retry */
1663 dstsize = needed + 1;
1664 dst = repalloc(dst, dstsize);
1665 needed = pg_strlower(dst, dstsize, src, srclen, mylocale);
1666 Assert(needed + 1 <= dstsize);
1667 }
1668
1669 Assert(dst[needed] == '\0');
1670 result = dst;
1671 }
1672
1673 return result;
1674}
size_t pg_strlower(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1318

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

1955{
1956 return str_tolower(buff, strlen(buff), collid);
1957}

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

1684{
1685 char *result;
1686 pg_locale_t mylocale;
1687
1688 if (!buff)
1689 return NULL;
1690
1691 if (!OidIsValid(collid))
1692 {
1693 /*
1694 * This typically means that the parser could not resolve a conflict
1695 * of implicit collations, so report it that way.
1696 */
1697 ereport(ERROR,
1698 (errcode(ERRCODE_INDETERMINATE_COLLATION),
1699 errmsg("could not determine which collation to use for %s function",
1700 "upper()"),
1701 errhint("Use the COLLATE clause to set the collation explicitly.")));
1702 }
1703
1705
1706 /* C/POSIX collations use this path regardless of database encoding */
1707 if (mylocale->ctype_is_c)
1708 {
1709 result = asc_toupper(buff, nbytes);
1710 }
1711 else
1712 {
1713 const char *src = buff;
1714 size_t srclen = nbytes;
1715 size_t dstsize;
1716 char *dst;
1717 size_t needed;
1718
1719 /* first try buffer of equal size plus terminating NUL */
1720 dstsize = srclen + 1;
1721 dst = palloc(dstsize);
1722
1723 needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
1724 if (needed + 1 > dstsize)
1725 {
1726 /* grow buffer if needed and retry */
1727 dstsize = needed + 1;
1728 dst = repalloc(dst, dstsize);
1729 needed = pg_strupper(dst, dstsize, src, srclen, mylocale);
1730 Assert(needed + 1 <= dstsize);
1731 }
1732
1733 Assert(dst[needed] == '\0');
1734 result = dst;
1735 }
1736
1737 return result;
1738}
size_t pg_strupper(char *dst, size_t dstsize, const char *src, ssize_t srclen, pg_locale_t locale)
Definition: pg_locale.c:1338

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

1961{
1962 return str_toupper(buff, strlen(buff), collid);
1963}

References collid, and str_toupper().

Referenced by DCH_to_char().

◆ strspace_len()

static size_t strspace_len ( const char *  str)
static

Definition at line 2093 of file formatting.c.

2094{
2095 size_t len = 0;
2096
2097 while (*str && isspace((unsigned char) *str))
2098 {
2099 str++;
2100 len++;
2101 }
2102 return len;
2103}

References len, and str.

Referenced by from_char_parse_int_len().

◆ suff_search()

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

Definition at line 1158 of file formatting.c.

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

References KeySuffix::name, str, and type.

Referenced by parse_format().

◆ SUFFIX_TH_TYPE()

static enum TH_Case SUFFIX_TH_TYPE ( uint8  _s)
inlinestatic

Definition at line 578 of file formatting.c.

579{
580 return _s & DCH_SUFFIX_TH ? TH_UPPER : TH_LOWER;
581}

References DCH_SUFFIX_TH, TH_LOWER, and TH_UPPER.

Referenced by DCH_to_char().

◆ timestamp_to_char()

Datum timestamp_to_char ( PG_FUNCTION_ARGS  )

Definition at line 3956 of file formatting.c.

3957{
3959 text *fmt = PG_GETARG_TEXT_PP(1),
3960 *res;
3961 TmToChar tmtc;
3962 struct pg_tm tt;
3963 struct fmt_tm *tm;
3964 int thisdate;
3965
3966 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
3968
3969 ZERO_tmtc(&tmtc);
3970 tm = tmtcTm(&tmtc);
3971
3972 if (timestamp2tm(dt, NULL, &tt, &tmtcFsec(&tmtc), NULL, NULL) != 0)
3973 ereport(ERROR,
3974 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3975 errmsg("timestamp out of range")));
3976
3977 /* calculate wday and yday, because timestamp2tm doesn't */
3978 thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
3979 tt.tm_wday = (thisdate + 1) % 7;
3980 tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
3981
3982 COPY_tm(tm, &tt);
3983
3984 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
3986
3987 PG_RETURN_TEXT_P(res);
3988}
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:500
#define COPY_tm(_DST, _SRC)
Definition: formatting.c:503
#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 3991 of file formatting.c.

3992{
3994 text *fmt = PG_GETARG_TEXT_PP(1),
3995 *res;
3996 TmToChar tmtc;
3997 int tz;
3998 struct pg_tm tt;
3999 struct fmt_tm *tm;
4000 int thisdate;
4001
4002 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
4004
4005 ZERO_tmtc(&tmtc);
4006 tm = tmtcTm(&tmtc);
4007
4008 if (timestamp2tm(dt, &tz, &tt, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
4009 ereport(ERROR,
4010 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4011 errmsg("timestamp out of range")));
4012
4013 /* calculate wday and yday, because timestamp2tm doesn't */
4014 thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
4015 tt.tm_wday = (thisdate + 1) % 7;
4016 tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
4017
4018 COPY_tm(tm, &tt);
4019
4020 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
4022
4023 PG_RETURN_TEXT_P(res);
4024}

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

4111{
4112 text *date_txt = PG_GETARG_TEXT_PP(0);
4113 text *fmt = PG_GETARG_TEXT_PP(1);
4115 DateADT result;
4116 struct pg_tm tm;
4117 struct fmt_tz ftz;
4118 fsec_t fsec;
4119
4120 do_to_timestamp(date_txt, fmt, collid, false,
4121 &tm, &fsec, &ftz, NULL, NULL, NULL);
4122
4123 /* Prevent overflow in Julian-day routines */
4125 ereport(ERROR,
4126 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4127 errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
4128
4130
4131 /* Now check for just-out-of-range dates */
4132 if (!IS_VALID_DATE(result))
4133 ereport(ERROR,
4134 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4135 errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
4136
4137 PG_RETURN_DATEADT(result);
4138}
#define PG_RETURN_DATEADT(x)
Definition: date.h:101
unsigned int Oid
Definition: postgres_ext.h:32

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

◆ to_timestamp()

Datum to_timestamp ( PG_FUNCTION_ARGS  )

Definition at line 4072 of file formatting.c.

4073{
4074 text *date_txt = PG_GETARG_TEXT_PP(0);
4075 text *fmt = PG_GETARG_TEXT_PP(1);
4077 Timestamp result;
4078 int tz;
4079 struct pg_tm tm;
4080 struct fmt_tz ftz;
4081 fsec_t fsec;
4082 int fprec;
4083
4084 do_to_timestamp(date_txt, fmt, collid, false,
4085 &tm, &fsec, &ftz, &fprec, NULL, NULL);
4086
4087 /* Use the specified time zone, if any. */
4088 if (ftz.has_tz)
4089 tz = ftz.gmtoffset;
4090 else
4092
4093 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
4094 ereport(ERROR,
4095 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4096 errmsg("timestamp out of range")));
4097
4098 /* Use the specified fractional precision, if any. */
4099 if (fprec)
4100 AdjustTimestampForTypmod(&result, fprec, NULL);
4101
4102 PG_RETURN_TIMESTAMP(result);
4103}
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1604
PGDLLIMPORT pg_tz * session_timezone
Definition: pgtz.c:28
#define PG_RETURN_TIMESTAMP(x)
Definition: timestamp.h:67

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

Variable Documentation

◆ adbc_strings

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

Definition at line 207 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 208 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 233 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 234 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 174 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 976 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:

Definition at line 601 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 401 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 403 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 169 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ n_DCHCache

int n_DCHCache = 0
static

Definition at line 402 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 407 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 999 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUM_keywords

const KeyWord NUM_keywords[]
static

Definition at line 929 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUMCache

NUMCacheEntry* NUMCache[NUM_CACHE_ENTRIES]
static

Definition at line 406 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 408 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 283 of file formatting.c.

Referenced by get_th().

◆ numth

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

Definition at line 284 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 250 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 251 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 252 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 244 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 241 of file formatting.c.

Referenced by DCH_to_char().