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

Go to the source code of this file.

Data Structures

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

Macros

#define DCH_FLAG   0x1 /* DATE-TIME flag */
 
#define NUM_FLAG   0x2 /* NUMBER flag */
 
#define STD_FLAG   0x4 /* STANDARD flag */
 
#define KeyWord_INDEX_SIZE   ('~' - ' ')
 
#define KeyWord_INDEX_FILTER(_c)   ((_c) <= ' ' || (_c) >= '~' ? 0 : 1)
 
#define DCH_MAX_ITEM_SIZ   12 /* max localized day name */
 
#define NUM_MAX_ITEM_SIZ   8 /* roman number (RN has 15 chars) */
 
#define 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 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 195 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 196 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 221 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 222 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 197 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 198 of file formatting.c.

◆ ADJUST_YEAR

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

Definition at line 193 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 223 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 224 of file formatting.c.

◆ AMOUNT_TEST

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

Definition at line 1070 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 200 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 201 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 202 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

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

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 387 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

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

Definition at line 377 of file formatting.c.

◆ DCH_CACHE_SIZE

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

Definition at line 382 of file formatting.c.

◆ DCH_DATED

#define DCH_DATED   0x01

Definition at line 1060 of file formatting.c.

◆ DCH_FLAG

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

Definition at line 98 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

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

Definition at line 111 of file formatting.c.

◆ DCH_SUFFIX_FM

#define DCH_SUFFIX_FM   0x01

Definition at line 558 of file formatting.c.

◆ DCH_SUFFIX_SP

#define DCH_SUFFIX_SP   0x08

Definition at line 561 of file formatting.c.

◆ DCH_SUFFIX_TH

#define DCH_SUFFIX_TH   0x02

Definition at line 559 of file formatting.c.

◆ DCH_SUFFIX_th

#define DCH_SUFFIX_th   0x04

Definition at line 560 of file formatting.c.

◆ DCH_SUFFIX_TM

#define DCH_SUFFIX_TM   0x10

Definition at line 562 of file formatting.c.

◆ DCH_TIMED

#define DCH_TIMED   0x02

Definition at line 1061 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:586
static bool IS_SUFFIX_THth(uint8 _s)
Definition: formatting.c:580
#define sprintf
Definition: port.h:262

◆ DCH_ZONED

#define DCH_ZONED   0x04

Definition at line 1062 of file formatting.c.

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 476 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

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

◆ IS_BLANK

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

Definition at line 350 of file formatting.c.

◆ IS_BRACKET

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

Definition at line 352 of file formatting.c.

◆ IS_DECIMAL

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

Definition at line 347 of file formatting.c.

◆ IS_EEEE

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

Definition at line 358 of file formatting.c.

◆ IS_FILLMODE

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

Definition at line 351 of file formatting.c.

◆ IS_LDECIMAL

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

Definition at line 348 of file formatting.c.

◆ IS_LSIGN

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

Definition at line 354 of file formatting.c.

◆ IS_MINUS

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

Definition at line 353 of file formatting.c.

◆ IS_MULTI

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

Definition at line 357 of file formatting.c.

◆ IS_PLUS

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

Definition at line 355 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:349

Definition at line 5532 of file formatting.c.

◆ IS_ROMAN

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

Definition at line 356 of file formatting.c.

◆ IS_VALID_SUB_COMB

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

Definition at line 266 of file formatting.c.

◆ IS_ZERO

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

Definition at line 349 of file formatting.c.

◆ KeyWord_INDEX_FILTER

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

Definition at line 106 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 105 of file formatting.c.

◆ MAX_ROMAN_LEN

#define MAX_ROMAN_LEN   15

Definition at line 286 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 388 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

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

Definition at line 379 of file formatting.c.

◆ NUM_CACHE_SIZE

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

Definition at line 384 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 332 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 335 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 329 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 342 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 333 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 330 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 334 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 336 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 341 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 339 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 337 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 340 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 338 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 331 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 99 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 112 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:700
#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:5745
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 6224 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:4949
#define NUM_MAX_ITEM_SIZ
Definition: formatting.c:112
void * palloc0(Size size)
Definition: mcxt.c:1395
Definition: c.h:695
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 6212 of file formatting.c.

◆ OVERLOAD_TEST

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

Definition at line 1069 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 226 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 227 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 228 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

Definition at line 229 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 274 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:1024

Definition at line 1998 of file formatting.c.

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 100 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 607 of file formatting.c.

◆ tmtcFsec

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

Definition at line 508 of file formatting.c.

◆ tmtcTm

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

Definition at line 506 of file formatting.c.

◆ tmtcTzn

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

Definition at line 507 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 525 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:506

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

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

◆ FormatNodeType

Enumerator
NODE_TYPE_END 
NODE_TYPE_ACTION 
NODE_TYPE_CHAR 
NODE_TYPE_SEPARATOR 
NODE_TYPE_SPACE 

Definition at line 155 of file formatting.c.

156{
157 NODE_TYPE_END = 1,
159 NODE_TYPE_CHAR = 3,
161 NODE_TYPE_SPACE = 5,
162};
@ NODE_TYPE_CHAR
Definition: formatting.c:159
@ NODE_TYPE_ACTION
Definition: formatting.c:158
@ NODE_TYPE_SEPARATOR
Definition: formatting.c:160
@ NODE_TYPE_END
Definition: formatting.c:157
@ NODE_TYPE_SPACE
Definition: formatting.c:161

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 139 of file formatting.c.

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

◆ KeySuffixType

Enumerator
SUFFTYPE_PREFIX 
SUFFTYPE_POSTFIX 

Definition at line 119 of file formatting.c.

120{
121 SUFFTYPE_PREFIX = 1,
123};
@ SUFFTYPE_PREFIX
Definition: formatting.c:121
@ SUFFTYPE_POSTFIX
Definition: formatting.c:122

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

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

◆ NUMDesc_lsign

Enumerator
NUM_LSIGN_PRE 
NUM_LSIGN_POST 
NUM_LSIGN_NONE 

Definition at line 303 of file formatting.c.

304{
305 NUM_LSIGN_PRE = -1,
306 NUM_LSIGN_POST = 1,
307 NUM_LSIGN_NONE = 0,
308};
@ NUM_LSIGN_POST
Definition: formatting.c:306
@ NUM_LSIGN_PRE
Definition: formatting.c:305
@ NUM_LSIGN_NONE
Definition: formatting.c:307

◆ TH_Case

enum TH_Case
Enumerator
TH_UPPER 
TH_LOWER 

Definition at line 297 of file formatting.c.

298{
299 TH_UPPER = 1,
300 TH_LOWER = 2,
301};
@ TH_UPPER
Definition: formatting.c:299
@ TH_LOWER
Definition: formatting.c:300

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2076 of file formatting.c.

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

Referenced by DCH_from_char().

◆ asc_initcap()

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

Definition at line 1931 of file formatting.c.

1932{
1933 char *result;
1934 int wasalnum = false;
1935
1936 if (!buff)
1937 return NULL;
1938
1939 result = pnstrdup(buff, nbytes);
1940
1941 for (char *p = result; *p; p++)
1942 {
1943 char c;
1944
1945 if (wasalnum)
1946 *p = c = pg_ascii_tolower((unsigned char) *p);
1947 else
1948 *p = c = pg_ascii_toupper((unsigned char) *p);
1949 /* we don't trust isalnum() here */
1950 wasalnum = ((c >= 'A' && c <= 'Z') ||
1951 (c >= 'a' && c <= 'z') ||
1952 (c >= '0' && c <= '9'));
1953 }
1954
1955 return result;
1956}
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1770
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 1887 of file formatting.c.

1888{
1889 char *result;
1890
1891 if (!buff)
1892 return NULL;
1893
1894 result = pnstrdup(buff, nbytes);
1895
1896 for (char *p = result; *p; p++)
1897 *p = pg_ascii_tolower((unsigned char) *p);
1898
1899 return result;
1900}

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

1980{
1981 return asc_tolower(buff, strlen(buff));
1982}
char * asc_tolower(const char *buff, size_t nbytes)
Definition: formatting.c:1887

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

1910{
1911 char *result;
1912
1913 if (!buff)
1914 return NULL;
1915
1916 result = pnstrdup(buff, nbytes);
1917
1918 for (char *p = result; *p; p++)
1919 *p = pg_ascii_toupper((unsigned char) *p);
1920
1921 return result;
1922}

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

1986{
1987 return asc_toupper(buff, strlen(buff));
1988}
char * asc_toupper(const char *buff, size_t nbytes)
Definition: formatting.c:1909

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char *  fmt_str)

Definition at line 4324 of file formatting.c.

4325{
4326 bool incache;
4327 size_t fmt_len = strlen(fmt_str);
4328 int result;
4330
4331 if (fmt_len > DCH_CACHE_SIZE)
4332 {
4333 /*
4334 * Allocate new memory if format picture is bigger than static cache
4335 * and do not use cache (call parser always)
4336 */
4337 incache = false;
4338
4339 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4340
4342 DCH_suff, DCH_index, DCH_FLAG, NULL);
4343 }
4344 else
4345 {
4346 /*
4347 * Use cache buffers
4348 */
4349 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4350
4351 incache = true;
4352 format = ent->format;
4353 }
4354
4355 result = DCH_datetime_type(format);
4356
4357 if (!incache)
4358 pfree(format);
4359
4360 return result & DCH_ZONED;
4361}
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:984
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:1377
#define DCH_FLAG
Definition: formatting.c:98
static const KeySuffix DCH_suff[]
Definition: formatting.c:609
#define DCH_CACHE_SIZE
Definition: formatting.c:382
#define DCH_ZONED
Definition: formatting.c:1062
static int DCH_datetime_type(FormatNode *node)
Definition: formatting.c:3691
static const KeyWord DCH_keywords[]
Definition: formatting.c:813
static DCHCacheEntry * DCH_cache_fetch(const char *str, bool std)
Definition: formatting.c:3868
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:392

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

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

3869{
3870 DCHCacheEntry *ent;
3871
3872 if ((ent = DCH_cache_search(str, std)) == NULL)
3873 {
3874 /*
3875 * Not in the cache, must run parser and save a new format-picture to
3876 * the cache. Do not mark the cache entry valid until parsing
3877 * succeeds.
3878 */
3879 ent = DCH_cache_getnew(str, std);
3880
3882 DCH_FLAG | (std ? STD_FLAG : 0), NULL);
3883
3884 ent->valid = true;
3885 }
3886 return ent;
3887}
#define STD_FLAG
Definition: formatting.c:100
static DCHCacheEntry * DCH_cache_getnew(const char *str, bool std)
Definition: formatting.c:3787
static DCHCacheEntry * DCH_cache_search(const char *str, bool std)
Definition: formatting.c:3847
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 3787 of file formatting.c.

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

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

3848{
3849 /* Ensure we can advance DCHCounter below */
3851
3852 for (int i = 0; i < n_DCHCache; i++)
3853 {
3854 DCHCacheEntry *ent = DCHCache[i];
3855
3856 if (ent->valid && strcmp(ent->str, str) == 0 && ent->std == std)
3857 {
3858 ent->age = (++DCHCounter);
3859 return ent;
3860 }
3861 }
3862
3863 return NULL;
3864}

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

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

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

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

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

3678{
3679 if (DCHCounter >= (INT_MAX - 1))
3680 {
3681 for (int i = 0; i < n_DCHCache; i++)
3682 DCHCache[i]->age >>= 1;
3683 DCHCounter >>= 1;
3684 }
3685}

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

2476{
2477 char *s;
2478 struct fmt_tm *tm = &in->tm;
2479 int i;
2480
2481 /* cache localized days and months */
2483
2484 s = out;
2485 for (FormatNode *n = node; n->type != NODE_TYPE_END; n++)
2486 {
2487 if (n->type != NODE_TYPE_ACTION)
2488 {
2489 strcpy(s, n->character);
2490 s += strlen(s);
2491 continue;
2492 }
2493
2494 switch (n->key->id)
2495 {
2496 case DCH_A_M:
2497 case DCH_P_M:
2498 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2499 ? P_M_STR : A_M_STR);
2500 s += strlen(s);
2501 break;
2502 case DCH_AM:
2503 case DCH_PM:
2504 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2505 ? PM_STR : AM_STR);
2506 s += strlen(s);
2507 break;
2508 case DCH_a_m:
2509 case DCH_p_m:
2510 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2511 ? p_m_STR : a_m_STR);
2512 s += strlen(s);
2513 break;
2514 case DCH_am:
2515 case DCH_pm:
2516 strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2517 ? pm_STR : am_STR);
2518 s += strlen(s);
2519 break;
2520 case DCH_HH:
2521 case DCH_HH12:
2522
2523 /*
2524 * display time as shown on a 12-hour clock, even for
2525 * intervals
2526 */
2527 sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2528 tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ?
2529 (long long) (HOURS_PER_DAY / 2) :
2530 (long long) (tm->tm_hour % (HOURS_PER_DAY / 2)));
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_HH24:
2536 sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2537 (long long) tm->tm_hour);
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_MI:
2543 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2544 tm->tm_min);
2545 if (IS_SUFFIX_THth(n->suffix))
2546 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2547 s += strlen(s);
2548 break;
2549 case DCH_SS:
2550 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2551 tm->tm_sec);
2552 if (IS_SUFFIX_THth(n->suffix))
2553 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2554 s += strlen(s);
2555 break;
2556
2557#define DCH_to_char_fsec(frac_fmt, frac_val) \
2558 sprintf(s, frac_fmt, (int) (frac_val)); \
2559 if (IS_SUFFIX_THth(n->suffix)) \
2560 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); \
2561 s += strlen(s)
2562
2563 case DCH_FF1: /* tenth of second */
2564 DCH_to_char_fsec("%01d", in->fsec / 100000);
2565 break;
2566 case DCH_FF2: /* hundredth of second */
2567 DCH_to_char_fsec("%02d", in->fsec / 10000);
2568 break;
2569 case DCH_FF3:
2570 case DCH_MS: /* millisecond */
2571 DCH_to_char_fsec("%03d", in->fsec / 1000);
2572 break;
2573 case DCH_FF4: /* tenth of a millisecond */
2574 DCH_to_char_fsec("%04d", in->fsec / 100);
2575 break;
2576 case DCH_FF5: /* hundredth of a millisecond */
2577 DCH_to_char_fsec("%05d", in->fsec / 10);
2578 break;
2579 case DCH_FF6:
2580 case DCH_US: /* microsecond */
2581 DCH_to_char_fsec("%06d", in->fsec);
2582 break;
2583#undef DCH_to_char_fsec
2584 case DCH_SSSS:
2585 sprintf(s, "%lld",
2586 (long long) (tm->tm_hour * SECS_PER_HOUR +
2588 tm->tm_sec));
2589 if (IS_SUFFIX_THth(n->suffix))
2590 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2591 s += strlen(s);
2592 break;
2593 case DCH_tz:
2595 if (tmtcTzn(in))
2596 {
2597 /* We assume here that timezone names aren't localized */
2598 char *p = asc_tolower_z(tmtcTzn(in));
2599
2600 strcpy(s, p);
2601 pfree(p);
2602 s += strlen(s);
2603 }
2604 break;
2605 case DCH_TZ:
2607 if (tmtcTzn(in))
2608 {
2609 strcpy(s, tmtcTzn(in));
2610 s += strlen(s);
2611 }
2612 break;
2613 case DCH_TZH:
2615 sprintf(s, "%c%02d",
2616 (tm->tm_gmtoff >= 0) ? '+' : '-',
2617 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2618 s += strlen(s);
2619 break;
2620 case DCH_TZM:
2622 sprintf(s, "%02d",
2623 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2624 s += strlen(s);
2625 break;
2626 case DCH_OF:
2628 sprintf(s, "%c%0*d",
2629 (tm->tm_gmtoff >= 0) ? '+' : '-',
2630 IS_SUFFIX_FM(n->suffix) ? 0 : 2,
2631 abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2632 s += strlen(s);
2633 if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2634 {
2635 sprintf(s, ":%02d",
2636 (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2637 s += strlen(s);
2638 }
2639 break;
2640 case DCH_A_D:
2641 case DCH_B_C:
2643 strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2644 s += strlen(s);
2645 break;
2646 case DCH_AD:
2647 case DCH_BC:
2649 strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2650 s += strlen(s);
2651 break;
2652 case DCH_a_d:
2653 case DCH_b_c:
2655 strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2656 s += strlen(s);
2657 break;
2658 case DCH_ad:
2659 case DCH_bc:
2661 strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2662 s += strlen(s);
2663 break;
2664 case DCH_MONTH:
2666 if (!tm->tm_mon)
2667 break;
2668 if (IS_SUFFIX_TM(n->suffix))
2669 {
2671
2672 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2673 strcpy(s, str);
2674 else
2675 ereport(ERROR,
2676 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2677 errmsg("localized string format value too long")));
2678 }
2679 else
2680 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2682 s += strlen(s);
2683 break;
2684 case DCH_Month:
2686 if (!tm->tm_mon)
2687 break;
2688 if (IS_SUFFIX_TM(n->suffix))
2689 {
2691
2692 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2693 strcpy(s, str);
2694 else
2695 ereport(ERROR,
2696 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2697 errmsg("localized string format value too long")));
2698 }
2699 else
2700 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2701 months_full[tm->tm_mon - 1]);
2702 s += strlen(s);
2703 break;
2704 case DCH_month:
2706 if (!tm->tm_mon)
2707 break;
2708 if (IS_SUFFIX_TM(n->suffix))
2709 {
2711
2712 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2713 strcpy(s, str);
2714 else
2715 ereport(ERROR,
2716 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2717 errmsg("localized string format value too long")));
2718 }
2719 else
2720 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2722 s += strlen(s);
2723 break;
2724 case DCH_MON:
2726 if (!tm->tm_mon)
2727 break;
2728 if (IS_SUFFIX_TM(n->suffix))
2729 {
2731
2732 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2733 strcpy(s, str);
2734 else
2735 ereport(ERROR,
2736 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2737 errmsg("localized string format value too long")));
2738 }
2739 else
2740 strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2741 s += strlen(s);
2742 break;
2743 case DCH_Mon:
2745 if (!tm->tm_mon)
2746 break;
2747 if (IS_SUFFIX_TM(n->suffix))
2748 {
2750
2751 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2752 strcpy(s, str);
2753 else
2754 ereport(ERROR,
2755 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2756 errmsg("localized string format value too long")));
2757 }
2758 else
2759 strcpy(s, months[tm->tm_mon - 1]);
2760 s += strlen(s);
2761 break;
2762 case DCH_mon:
2764 if (!tm->tm_mon)
2765 break;
2766 if (IS_SUFFIX_TM(n->suffix))
2767 {
2769
2770 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2771 strcpy(s, str);
2772 else
2773 ereport(ERROR,
2774 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2775 errmsg("localized string format value too long")));
2776 }
2777 else
2778 strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
2779 s += strlen(s);
2780 break;
2781 case DCH_MM:
2782 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
2783 tm->tm_mon);
2784 if (IS_SUFFIX_THth(n->suffix))
2785 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2786 s += strlen(s);
2787 break;
2788 case DCH_DAY:
2790 if (IS_SUFFIX_TM(n->suffix))
2791 {
2793
2794 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2795 strcpy(s, str);
2796 else
2797 ereport(ERROR,
2798 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2799 errmsg("localized string format value too long")));
2800 }
2801 else
2802 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2804 s += strlen(s);
2805 break;
2806 case DCH_Day:
2808 if (IS_SUFFIX_TM(n->suffix))
2809 {
2811
2812 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2813 strcpy(s, str);
2814 else
2815 ereport(ERROR,
2816 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2817 errmsg("localized string format value too long")));
2818 }
2819 else
2820 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2821 days[tm->tm_wday]);
2822 s += strlen(s);
2823 break;
2824 case DCH_day:
2826 if (IS_SUFFIX_TM(n->suffix))
2827 {
2829
2830 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2831 strcpy(s, str);
2832 else
2833 ereport(ERROR,
2834 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2835 errmsg("localized string format value too long")));
2836 }
2837 else
2838 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9,
2840 s += strlen(s);
2841 break;
2842 case DCH_DY:
2844 if (IS_SUFFIX_TM(n->suffix))
2845 {
2847
2848 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2849 strcpy(s, str);
2850 else
2851 ereport(ERROR,
2852 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2853 errmsg("localized string format value too long")));
2854 }
2855 else
2856 strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
2857 s += strlen(s);
2858 break;
2859 case DCH_Dy:
2861 if (IS_SUFFIX_TM(n->suffix))
2862 {
2864
2865 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2866 strcpy(s, str);
2867 else
2868 ereport(ERROR,
2869 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2870 errmsg("localized string format value too long")));
2871 }
2872 else
2873 strcpy(s, days_short[tm->tm_wday]);
2874 s += strlen(s);
2875 break;
2876 case DCH_dy:
2878 if (IS_SUFFIX_TM(n->suffix))
2879 {
2881
2882 if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2883 strcpy(s, str);
2884 else
2885 ereport(ERROR,
2886 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2887 errmsg("localized string format value too long")));
2888 }
2889 else
2890 strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
2891 s += strlen(s);
2892 break;
2893 case DCH_DDD:
2894 case DCH_IDDD:
2895 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 3,
2896 (n->key->id == DCH_DDD) ?
2897 tm->tm_yday :
2899 if (IS_SUFFIX_THth(n->suffix))
2900 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2901 s += strlen(s);
2902 break;
2903 case DCH_DD:
2904 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2, tm->tm_mday);
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_D:
2911 sprintf(s, "%d", tm->tm_wday + 1);
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_ID:
2918 sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
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_WW:
2924 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2,
2925 (tm->tm_yday - 1) / 7 + 1);
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_IW:
2931 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2,
2933 if (IS_SUFFIX_THth(n->suffix))
2934 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2935 s += strlen(s);
2936 break;
2937 case DCH_Q:
2938 if (!tm->tm_mon)
2939 break;
2940 sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
2941 if (IS_SUFFIX_THth(n->suffix))
2942 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2943 s += strlen(s);
2944 break;
2945 case DCH_CC:
2946 if (is_interval) /* straight calculation */
2947 i = tm->tm_year / 100;
2948 else
2949 {
2950 if (tm->tm_year > 0)
2951 /* Century 20 == 1901 - 2000 */
2952 i = (tm->tm_year - 1) / 100 + 1;
2953 else
2954 /* Century 6BC == 600BC - 501BC */
2955 i = tm->tm_year / 100 - 1;
2956 }
2957 if (i <= 99 && i >= -99)
2958 sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
2959 else
2960 sprintf(s, "%d", i);
2961 if (IS_SUFFIX_THth(n->suffix))
2962 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2963 s += strlen(s);
2964 break;
2965 case DCH_Y_YYY:
2966 i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
2967 sprintf(s, "%d,%03d", i,
2968 ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
2969 if (IS_SUFFIX_THth(n->suffix))
2970 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2971 s += strlen(s);
2972 break;
2973 case DCH_YYYY:
2974 case DCH_IYYY:
2975 sprintf(s, "%0*d",
2976 IS_SUFFIX_FM(n->suffix) ? 0 :
2977 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
2978 (n->key->id == DCH_YYYY ?
2979 ADJUST_YEAR(tm->tm_year, is_interval) :
2981 tm->tm_mon,
2982 tm->tm_mday),
2983 is_interval)));
2984 if (IS_SUFFIX_THth(n->suffix))
2985 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
2986 s += strlen(s);
2987 break;
2988 case DCH_YYY:
2989 case DCH_IYY:
2990 sprintf(s, "%0*d",
2991 IS_SUFFIX_FM(n->suffix) ? 0 :
2992 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
2993 (n->key->id == DCH_YYY ?
2994 ADJUST_YEAR(tm->tm_year, is_interval) :
2996 tm->tm_mon,
2997 tm->tm_mday),
2998 is_interval)) % 1000);
2999 if (IS_SUFFIX_THth(n->suffix))
3000 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3001 s += strlen(s);
3002 break;
3003 case DCH_YY:
3004 case DCH_IY:
3005 sprintf(s, "%0*d",
3006 IS_SUFFIX_FM(n->suffix) ? 0 :
3007 (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
3008 (n->key->id == DCH_YY ?
3009 ADJUST_YEAR(tm->tm_year, is_interval) :
3011 tm->tm_mon,
3012 tm->tm_mday),
3013 is_interval)) % 100);
3014 if (IS_SUFFIX_THth(n->suffix))
3015 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3016 s += strlen(s);
3017 break;
3018 case DCH_Y:
3019 case DCH_I:
3020 sprintf(s, "%1d",
3021 (n->key->id == DCH_Y ?
3022 ADJUST_YEAR(tm->tm_year, is_interval) :
3024 tm->tm_mon,
3025 tm->tm_mday),
3026 is_interval)) % 10);
3027 if (IS_SUFFIX_THth(n->suffix))
3028 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3029 s += strlen(s);
3030 break;
3031 case DCH_RM:
3032 /* FALLTHROUGH */
3033 case DCH_rm:
3034
3035 /*
3036 * For intervals, values like '12 month' will be reduced to 0
3037 * month and some years. These should be processed.
3038 */
3039 if (!tm->tm_mon && !tm->tm_year)
3040 break;
3041 else
3042 {
3043 int mon = 0;
3044 const char *const *months;
3045
3046 if (n->key->id == DCH_RM)
3048 else
3050
3051 /*
3052 * Compute the position in the roman-numeral array. Note
3053 * that the contents of the array are reversed, December
3054 * being first and January last.
3055 */
3056 if (tm->tm_mon == 0)
3057 {
3058 /*
3059 * This case is special, and tracks the case of full
3060 * interval years.
3061 */
3062 mon = tm->tm_year >= 0 ? 0 : MONTHS_PER_YEAR - 1;
3063 }
3064 else if (tm->tm_mon < 0)
3065 {
3066 /*
3067 * Negative case. In this case, the calculation is
3068 * reversed, where -1 means December, -2 November,
3069 * etc.
3070 */
3071 mon = -1 * (tm->tm_mon + 1);
3072 }
3073 else
3074 {
3075 /*
3076 * Common case, with a strictly positive value. The
3077 * position in the array matches with the value of
3078 * tm_mon.
3079 */
3080 mon = MONTHS_PER_YEAR - tm->tm_mon;
3081 }
3082
3083 sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -4,
3084 months[mon]);
3085 s += strlen(s);
3086 }
3087 break;
3088 case DCH_W:
3089 sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
3090 if (IS_SUFFIX_THth(n->suffix))
3091 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3092 s += strlen(s);
3093 break;
3094 case DCH_J:
3095 sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
3096 if (IS_SUFFIX_THth(n->suffix))
3097 str_numth(s, s, SUFFIX_TH_TYPE(n->suffix));
3098 s += strlen(s);
3099 break;
3100 }
3101 }
3102
3103 *s = '\0';
3104}
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:198
#define bc_STR
Definition: formatting.c:203
#define AD_STR
Definition: formatting.c:197
#define a_d_STR
Definition: formatting.c:196
#define DCH_to_char_fsec(frac_fmt, frac_val)
#define PM_STR
Definition: formatting.c:228
#define BC_STR
Definition: formatting.c:202
#define a_m_STR
Definition: formatting.c:222
#define A_D_STR
Definition: formatting.c:195
#define pm_STR
Definition: formatting.c:229
#define B_C_STR
Definition: formatting.c:200
static bool IS_SUFFIX_FM(uint8 _s)
Definition: formatting.c:593
#define ADJUST_YEAR(year, is_interval)
Definition: formatting.c:193
static char * str_tolower_z(const char *buff, Oid collid)
Definition: formatting.c:1961
static char * asc_toupper_z(const char *buff)
Definition: formatting.c:1985
#define TM_SUFFIX_LEN
Definition: formatting.c:607
static char * str_toupper_z(const char *buff, Oid collid)
Definition: formatting.c:1967
#define b_c_STR
Definition: formatting.c:201
#define INVALID_FOR_INTERVAL
Definition: formatting.c:542
static char * str_initcap_z(const char *buff, Oid collid)
Definition: formatting.c:1973
#define tmtcTzn(_X)
Definition: formatting.c:507
#define P_M_STR
Definition: formatting.c:226
#define p_m_STR
Definition: formatting.c:227
#define A_M_STR
Definition: formatting.c:221
#define am_STR
Definition: formatting.c:224
static char * asc_tolower_z(const char *buff)
Definition: formatting.c:1979
#define AM_STR
Definition: formatting.c:223
static const char *const rm_months_upper[]
Definition: formatting.c:249
static char * str_numth(char *dest, const char *num, enum TH_Case type)
Definition: formatting.c:1607
static struct pg_tm tm
Definition: localtime.c:104
struct fmt_tm tm
Definition: formatting.c:501
fsec_t fsec
Definition: formatting.c:502
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 4387 of file formatting.c.

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

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

4823{
4824 memset(str, c, max);
4825 str[max] = '\0';
4826}

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

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

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

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

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

◆ from_char_parse_int()

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

Definition at line 2278 of file formatting.c.

2280{
2281 return from_char_parse_int_len(dest, src, node->key->len, node, escontext);
2282}
size_t len
Definition: formatting.c:149

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

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

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

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

Referenced by DCH_from_char().

◆ from_char_set_int()

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

Definition at line 2148 of file formatting.c.

2150{
2151 if (*dest != 0 && *dest != value)
2152 ereturn(escontext, false,
2153 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2154 errmsg("conflicting values for \"%s\" field in formatting string",
2155 node->key->name),
2156 errdetail("This value contradicts a previous setting for the same field type.")));
2157 *dest = value;
2158 return true;
2159}

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

2124{
2126 {
2127 if (tmfc->mode == FROM_CHAR_DATE_NONE)
2128 tmfc->mode = mode;
2129 else if (tmfc->mode != mode)
2130 ereturn(escontext, false,
2131 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2132 errmsg("invalid combination of date conventions"),
2133 errhint("Do not mix Gregorian and ISO week date conventions in a formatting template.")));
2134 }
2135 return true;
2136}
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 char * get_last_relevant_decnum ( const char *  num)
static

Definition at line 5301 of file formatting.c.

5302{
5303 char *result,
5304 *p = strchr(num, '.');
5305
5306#ifdef DEBUG_TO_FROM_CHAR
5307 elog(DEBUG_elog_output, "get_last_relevant_decnum()");
5308#endif
5309
5310 if (!p)
5311 return NULL;
5312
5313 result = p;
5314
5315 while (*(++p))
5316 {
5317 if (*p != '0')
5318 result = p;
5319 }
5320
5321 return result;
5322}

References elog.

Referenced by NUM_processor().

◆ get_th()

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

Definition at line 1562 of file formatting.c.

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

1142{
1143 int poz;
1144
1146 return NULL;
1147
1148 if ((poz = index[*str - ' ']) > -1)
1149 {
1150 const KeyWord *k = kw + poz;
1151
1152 do
1153 {
1154 if (strncmp(str, k->name, k->len) == 0)
1155 return k;
1156 k++;
1157 if (!k->name)
1158 return NULL;
1159 } while (*str == *k->name);
1160 }
1161 return NULL;
1162}
#define KeyWord_INDEX_FILTER(_c)
Definition: formatting.c:106
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 6427 of file formatting.c.

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

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

◆ int8_to_char()

Datum int8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6520 of file formatting.c.

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

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

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 5012 of file formatting.c.

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

4039{
4041 text *fmt = PG_GETARG_TEXT_PP(1),
4042 *res;
4043 TmToChar tmtc;
4044 struct fmt_tm *tm;
4045 struct pg_itm tt,
4046 *itm = &tt;
4047
4048 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || INTERVAL_NOT_FINITE(it))
4050
4051 ZERO_tmtc(&tmtc);
4052 tm = tmtcTm(&tmtc);
4053
4054 interval2itm(*it, itm);
4055 tmtc.fsec = itm->tm_usec;
4056 tm->tm_sec = itm->tm_sec;
4057 tm->tm_min = itm->tm_min;
4058 tm->tm_hour = itm->tm_hour;
4059 tm->tm_mday = itm->tm_mday;
4060 tm->tm_mon = itm->tm_mon;
4061 tm->tm_year = itm->tm_year;
4062
4063 /* wday is meaningless, yday approximates the total span in days */
4065
4066 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4068
4069 PG_RETURN_TEXT_P(res);
4070}
void interval2itm(Interval span, struct pg_itm *itm)
Definition: timestamp.c:2047
#define INTERVAL_NOT_FINITE(i)
Definition: timestamp.h:195
#define DAYS_PER_MONTH
Definition: timestamp.h:116
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
static text * datetime_to_char_body(TmToChar *tmtc, const text *fmt, bool is_interval, Oid collid)
Definition: formatting.c:3895
#define ZERO_tmtc(_X)
Definition: formatting.c:531
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 2043 of file formatting.c.

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

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

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

References str.

Referenced by DCH_from_char(), and parse_format().

◆ IS_SUFFIX_FM()

static bool IS_SUFFIX_FM ( uint8  _s)
inlinestatic

Definition at line 593 of file formatting.c.

594{
595 return (_s & DCH_SUFFIX_FM);
596}
#define DCH_SUFFIX_FM
Definition: formatting.c:558

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

569{
570 return (_s & DCH_SUFFIX_TH);
571}
#define DCH_SUFFIX_TH
Definition: formatting.c:559

References DCH_SUFFIX_TH.

Referenced by IS_SUFFIX_THth().

◆ IS_SUFFIX_th()

static bool IS_SUFFIX_th ( uint8  _s)
inlinestatic

Definition at line 574 of file formatting.c.

575{
576 return (_s & DCH_SUFFIX_th);
577}
#define DCH_SUFFIX_th
Definition: formatting.c:560

References DCH_SUFFIX_th.

Referenced by IS_SUFFIX_THth().

◆ IS_SUFFIX_THth()

static bool IS_SUFFIX_THth ( uint8  _s)
inlinestatic

Definition at line 580 of file formatting.c.

581{
582 return IS_SUFFIX_TH(_s) || IS_SUFFIX_th(_s);
583}
static bool IS_SUFFIX_TH(uint8 _s)
Definition: formatting.c:568
static bool IS_SUFFIX_th(uint8 _s)
Definition: formatting.c:574

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

600{
601 return (_s & DCH_SUFFIX_TM);
602}
#define DCH_SUFFIX_TM
Definition: formatting.c:562

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

4950{
4951 FormatNode *format = NULL;
4952 char *str;
4953
4954 str = text_to_cstring(pars_str);
4955
4956 if (len > NUM_CACHE_SIZE)
4957 {
4958 /*
4959 * Allocate new memory if format picture is bigger than static cache
4960 * and do not use cache (call parser always)
4961 */
4962 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
4963
4964 *shouldFree = true;
4965
4966 memset(Num, 0, sizeof *Num);
4967
4969 NULL, NUM_index, NUM_FLAG, Num);
4970 }
4971 else
4972 {
4973 /*
4974 * Use cache buffers
4975 */
4977
4978 *shouldFree = false;
4979
4980 format = ent->format;
4981
4982 /*
4983 * Copy cache to used struct
4984 */
4985 Num->flag = ent->Num.flag;
4986 Num->lsign = ent->Num.lsign;
4987 Num->pre = ent->Num.pre;
4988 Num->post = ent->Num.post;
4989 Num->pre_lsign_num = ent->Num.pre_lsign_num;
4990 Num->need_locale = ent->Num.need_locale;
4991 Num->multi = ent->Num.multi;
4992 Num->zero_start = ent->Num.zero_start;
4993 Num->zero_end = ent->Num.zero_end;
4994 }
4995
4996#ifdef DEBUG_TO_FROM_CHAR
4997 /* dump_node(format, len); */
4998 dump_index(NUM_keywords, NUM_index);
4999#endif
5000
5001 pfree(str);
5002 return format;
5003}
static const KeyWord NUM_keywords[]
Definition: formatting.c:937
#define NUM_CACHE_SIZE
Definition: formatting.c:384
static NUMCacheEntry * NUM_cache_fetch(const char *str)
Definition: formatting.c:4922
#define NUM_FLAG
Definition: formatting.c:99
static const int NUM_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:1007
NUMDesc Num
Definition: formatting.c:405
FormatNode format[NUM_CACHE_SIZE+1]
Definition: formatting.c:401
int pre_lsign_num
Definition: formatting.c:319
enum NUMDesc_lsign lsign
Definition: formatting.c:317
int zero_end
Definition: formatting.c:322
int flag
Definition: formatting.c:318
bool need_locale
Definition: formatting.c:323
int zero_start
Definition: formatting.c:321

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

4923{
4924 NUMCacheEntry *ent;
4925
4926 if ((ent = NUM_cache_search(str)) == NULL)
4927 {
4928 /*
4929 * Not in the cache, must run parser and save a new format-picture to
4930 * the cache. Do not mark the cache entry valid until parsing
4931 * succeeds.
4932 */
4933 ent = NUM_cache_getnew(str);
4934
4935 memset(&ent->Num, 0, sizeof ent->Num);
4936
4938 NULL, NUM_index, NUM_FLAG, &ent->Num);
4939
4940 ent->valid = true;
4941 }
4942 return ent;
4943}
static NUMCacheEntry * NUM_cache_getnew(const char *str)
Definition: formatting.c:4842
static NUMCacheEntry * NUM_cache_search(const char *str)
Definition: formatting.c:4901

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

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

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

4902{
4903 /* Ensure we can advance NUMCounter below */
4905
4906 for (int i = 0; i < n_NUMCache; i++)
4907 {
4908 NUMCacheEntry *ent = NUMCache[i];
4909
4910 if (ent->valid && strcmp(ent->str, str) == 0)
4911 {
4912 ent->age = (++NUMCounter);
4913 return ent;
4914 }
4915 }
4916
4917 return NULL;
4918}

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

5733{
5734 while (n-- > 0)
5735 {
5736 if (OVERLOAD_TEST)
5737 break; /* end of input */
5738 if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
5739 break; /* it's a data character */
5740 Np->inout_p += pg_mblen(Np->inout_p);
5741 }
5742}
#define OVERLOAD_TEST
Definition: formatting.c:1069
char * inout_p
Definition: formatting.c:1049

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

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

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

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

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

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

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

4831{
4832 if (NUMCounter >= (INT_MAX - 1))
4833 {
4834 for (int i = 0; i < n_NUMCache; i++)
4835 NUMCache[i]->age >>= 1;
4836 NUMCounter >>= 1;
4837 }
4838}

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

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

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

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

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

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

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

◆ numeric_to_number()

Datum numeric_to_number ( PG_FUNCTION_ARGS  )

Definition at line 6242 of file formatting.c.

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

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

◆ parse_datetime()

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

Definition at line 4163 of file formatting.c.

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

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

Referenced by executeDateTimeMethod().

◆ parse_format()

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

Definition at line 1377 of file formatting.c.

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

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

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

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

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

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

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

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

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

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

1974{
1975 return str_initcap(buff, strlen(buff), collid);
1976}
char * str_initcap(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1754

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

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

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

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

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

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

◆ str_tolower_z()

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

Definition at line 1961 of file formatting.c.

1962{
1963 return str_tolower(buff, strlen(buff), collid);
1964}

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

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

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

1968{
1969 return str_toupper(buff, strlen(buff), collid);
1970}

References collid, and str_toupper().

Referenced by DCH_to_char().

◆ strspace_len()

static size_t strspace_len ( const char *  str)
static

Definition at line 2100 of file formatting.c.

2101{
2102 size_t len = 0;
2103
2104 while (*str && isspace((unsigned char) *str))
2105 {
2106 str++;
2107 len++;
2108 }
2109 return len;
2110}

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

1166{
1167 for (const KeySuffix *s = suf; s->name != NULL; s++)
1168 {
1169 if (s->type != type)
1170 continue;
1171
1172 if (strncmp(str, s->name, s->len) == 0)
1173 return s;
1174 }
1175 return NULL;
1176}
const char * name
Definition: formatting.c:127

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

587{
588 return _s & DCH_SUFFIX_TH ? TH_UPPER : TH_LOWER;
589}

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

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

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

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

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

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

◆ to_timestamp()

Datum to_timestamp ( PG_FUNCTION_ARGS  )

Definition at line 4079 of file formatting.c.

4080{
4081 text *date_txt = PG_GETARG_TEXT_PP(0);
4082 text *fmt = PG_GETARG_TEXT_PP(1);
4084 Timestamp result;
4085 int tz;
4086 struct pg_tm tm;
4087 struct fmt_tz ftz;
4088 fsec_t fsec;
4089 int fprec;
4090
4091 do_to_timestamp(date_txt, fmt, collid, false,
4092 &tm, &fsec, &ftz, &fprec, NULL, NULL);
4093
4094 /* Use the specified time zone, if any. */
4095 if (ftz.has_tz)
4096 tz = ftz.gmtoffset;
4097 else
4099
4100 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
4101 ereport(ERROR,
4102 (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4103 errmsg("timestamp out of range")));
4104
4105 /* Use the specified fractional precision, if any. */
4106 if (fprec)
4107 AdjustTimestampForTypmod(&result, fprec, NULL);
4108
4109 PG_RETURN_TIMESTAMP(result);
4110}
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 215 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 216 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 241 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 242 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 182 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 984 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 609 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 409 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 411 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 177 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ n_DCHCache

int n_DCHCache = 0
static

Definition at line 410 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 415 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 1007 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUM_keywords

const KeyWord NUM_keywords[]
static

Definition at line 937 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUMCache

NUMCacheEntry* NUMCache[NUM_CACHE_ENTRIES]
static

Definition at line 414 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 416 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 291 of file formatting.c.

Referenced by get_th().

◆ numth

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

Definition at line 292 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 258 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 259 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 260 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 252 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 249 of file formatting.c.

Referenced by DCH_to_char().