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 const char * get_last_relevant_decnum (const char *num)
 
static void NUM_numpart_from_char (NUMProc *Np, int id, size_t input_len)
 
static void NUM_numpart_to_char (NUMProc *Np, int id)
 
static char * NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, size_t input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
 
static DCHCacheEntryDCH_cache_getnew (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_search (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_fetch (const char *str, bool std)
 
static NUMCacheEntryNUM_cache_getnew (const char *str)
 
static NUMCacheEntryNUM_cache_search (const char *str)
 
static NUMCacheEntryNUM_cache_fetch (const char *str)
 
char * str_tolower (const char *buff, size_t nbytes, Oid collid)
 
char * str_toupper (const char *buff, size_t nbytes, Oid collid)
 
char * str_initcap (const char *buff, size_t nbytes, Oid collid)
 
char * str_casefold (const char *buff, size_t nbytes, Oid collid)
 
char * asc_tolower (const char *buff, size_t nbytes)
 
char * asc_toupper (const char *buff, size_t nbytes)
 
char * asc_initcap (const char *buff, size_t nbytes)
 
static char * str_tolower_z (const char *buff, Oid collid)
 
static char * str_toupper_z (const char *buff, Oid collid)
 
static char * str_initcap_z (const char *buff, Oid collid)
 
static char * asc_tolower_z (const char *buff)
 
static char * asc_toupper_z (const char *buff)
 
static bool is_next_separator (FormatNode *n)
 
static void DCH_prevent_counter_overflow (void)
 
static int DCH_datetime_type (FormatNode *node)
 
static textdatetime_to_char_body (TmToChar *tmtc, const text *fmt, bool is_interval, Oid collid)
 
Datum timestamp_to_char (PG_FUNCTION_ARGS)
 
Datum timestamptz_to_char (PG_FUNCTION_ARGS)
 
Datum interval_to_char (PG_FUNCTION_ARGS)
 
Datum to_timestamp (PG_FUNCTION_ARGS)
 
Datum to_date (PG_FUNCTION_ARGS)
 
Datum parse_datetime (text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, Node *escontext)
 
bool datetime_format_has_tz (const char *fmt_str)
 
static void NUM_prevent_counter_overflow (void)
 
static void NUM_eat_non_data_chars (NUMProc *Np, int n, size_t input_len)
 
Datum numeric_to_number (PG_FUNCTION_ARGS)
 
Datum numeric_to_char (PG_FUNCTION_ARGS)
 
Datum int4_to_char (PG_FUNCTION_ARGS)
 
Datum int8_to_char (PG_FUNCTION_ARGS)
 
Datum float4_to_char (PG_FUNCTION_ARGS)
 
Datum float8_to_char (PG_FUNCTION_ARGS)
 

Variables

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

Macro Definition Documentation

◆ A_D_STR

#define A_D_STR   "A.D."

Definition at line 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 1071 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 1061 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 1062 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 1063 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 5533 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:711
#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:5746
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 6225 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:4950
#define NUM_MAX_ITEM_SIZ
Definition: formatting.c:112
void * palloc0(Size size)
Definition: mcxt.c:1395
Definition: c.h:706
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 6213 of file formatting.c.

◆ OVERLOAD_TEST

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

Definition at line 1070 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:1026

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

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

Referenced by DCH_from_char().

◆ asc_initcap()

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

Definition at line 1932 of file formatting.c.

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

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

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

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

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

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

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

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

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char *  fmt_str)

Definition at line 4325 of file formatting.c.

4326{
4327 bool incache;
4328 size_t fmt_len = strlen(fmt_str);
4329 int result;
4331
4332 if (fmt_len > DCH_CACHE_SIZE)
4333 {
4334 /*
4335 * Allocate new memory if format picture is bigger than static cache
4336 * and do not use cache (call parser always)
4337 */
4338 incache = false;
4339
4340 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4341
4343 DCH_suff, DCH_index, DCH_FLAG, NULL);
4344 }
4345 else
4346 {
4347 /*
4348 * Use cache buffers
4349 */
4350 DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4351
4352 incache = true;
4353 format = ent->format;
4354 }
4355
4356 result = DCH_datetime_type(format);
4357
4358 if (!incache)
4359 pfree(format);
4360
4361 return result & DCH_ZONED;
4362}
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:1378
#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:1063
static int DCH_datetime_type(FormatNode *node)
Definition: formatting.c:3692
static const KeyWord DCH_keywords[]
Definition: formatting.c:813
static DCHCacheEntry * DCH_cache_fetch(const char *str, bool std)
Definition: formatting.c:3869
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 3896 of file formatting.c.

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

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

3789{
3790 DCHCacheEntry *ent;
3791
3792 /* Ensure we can advance DCHCounter below */
3794
3795 /*
3796 * If cache is full, remove oldest entry (or recycle first not-valid one)
3797 */
3799 {
3800 DCHCacheEntry *old = DCHCache[0];
3801
3802#ifdef DEBUG_TO_FROM_CHAR
3803 elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3804#endif
3805 if (old->valid)
3806 {
3807 for (int i = 1; i < DCH_CACHE_ENTRIES; i++)
3808 {
3809 ent = DCHCache[i];
3810 if (!ent->valid)
3811 {
3812 old = ent;
3813 break;
3814 }
3815 if (ent->age < old->age)
3816 old = ent;
3817 }
3818 }
3819#ifdef DEBUG_TO_FROM_CHAR
3820 elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3821#endif
3822 old->valid = false;
3823 strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
3824 old->age = (++DCHCounter);
3825 /* caller is expected to fill format, then set valid */
3826 return old;
3827 }
3828 else
3829 {
3830#ifdef DEBUG_TO_FROM_CHAR
3831 elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3832#endif
3833 Assert(DCHCache[n_DCHCache] == NULL);
3834 DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
3836 ent->valid = false;
3837 strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
3838 ent->std = std;
3839 ent->age = (++DCHCounter);
3840 /* caller is expected to fill format, then set valid */
3841 ++n_DCHCache;
3842 return ent;
3843 }
3844}
#define elog(elevel,...)
Definition: elog.h:226
static void DCH_prevent_counter_overflow(void)
Definition: formatting.c:3678
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 3848 of file formatting.c.

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

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

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

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

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

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

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

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

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

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

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

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

2281{
2282 return from_char_parse_int_len(dest, src, node->key->len, node, escontext);
2283}
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 2184 of file formatting.c.

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

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

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

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

2125{
2127 {
2128 if (tmfc->mode == FROM_CHAR_DATE_NONE)
2129 tmfc->mode = mode;
2130 else if (tmfc->mode != mode)
2131 ereturn(escontext, false,
2132 (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2133 errmsg("invalid combination of date conventions"),
2134 errhint("Do not mix Gregorian and ISO week date conventions in a formatting template.")));
2135 }
2136 return true;
2137}
static PgChecksumMode mode
Definition: pg_checksums.c:56

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

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

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

Definition at line 5302 of file formatting.c.

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

References elog.

Referenced by NUM_processor().

◆ get_th()

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

Definition at line 1563 of file formatting.c.

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

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

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

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

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

4040{
4042 text *fmt = PG_GETARG_TEXT_PP(1),
4043 *res;
4044 TmToChar tmtc;
4045 struct fmt_tm *tm;
4046 struct pg_itm tt,
4047 *itm = &tt;
4048
4049 if (VARSIZE_ANY_EXHDR(fmt) <= 0 || INTERVAL_NOT_FINITE(it))
4051
4052 ZERO_tmtc(&tmtc);
4053 tm = tmtcTm(&tmtc);
4054
4055 interval2itm(*it, itm);
4056 tmtc.fsec = itm->tm_usec;
4057 tm->tm_sec = itm->tm_sec;
4058 tm->tm_min = itm->tm_min;
4059 tm->tm_hour = itm->tm_hour;
4060 tm->tm_mday = itm->tm_mday;
4061 tm->tm_mon = itm->tm_mon;
4062 tm->tm_year = itm->tm_year;
4063
4064 /* wday is meaningless, yday approximates the total span in days */
4066
4067 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4069
4070 PG_RETURN_TEXT_P(res);
4071}
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:3896
#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 2044 of file formatting.c.

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

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

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

4951{
4952 FormatNode *format = NULL;
4953 char *str;
4954
4955 str = text_to_cstring(pars_str);
4956
4957 if (len > NUM_CACHE_SIZE)
4958 {
4959 /*
4960 * Allocate new memory if format picture is bigger than static cache
4961 * and do not use cache (call parser always)
4962 */
4963 format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
4964
4965 *shouldFree = true;
4966
4967 memset(Num, 0, sizeof *Num);
4968
4970 NULL, NUM_index, NUM_FLAG, Num);
4971 }
4972 else
4973 {
4974 /*
4975 * Use cache buffers
4976 */
4978
4979 *shouldFree = false;
4980
4981 format = ent->format;
4982
4983 /*
4984 * Copy cache to used struct
4985 */
4986 Num->flag = ent->Num.flag;
4987 Num->lsign = ent->Num.lsign;
4988 Num->pre = ent->Num.pre;
4989 Num->post = ent->Num.post;
4990 Num->pre_lsign_num = ent->Num.pre_lsign_num;
4991 Num->need_locale = ent->Num.need_locale;
4992 Num->multi = ent->Num.multi;
4993 Num->zero_start = ent->Num.zero_start;
4994 Num->zero_end = ent->Num.zero_end;
4995 }
4996
4997#ifdef DEBUG_TO_FROM_CHAR
4998 /* dump_node(format, len); */
4999 dump_index(NUM_keywords, NUM_index);
5000#endif
5001
5002 pfree(str);
5003 return format;
5004}
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:4923
#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 4923 of file formatting.c.

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

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

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

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

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

5734{
5735 while (n-- > 0)
5736 {
5737 if (OVERLOAD_TEST)
5738 break; /* end of input */
5739 if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
5740 break; /* it's a data character */
5741 Np->inout_p += pg_mblen(Np->inout_p);
5742 }
5743}
#define OVERLOAD_TEST
Definition: formatting.c:1070
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 5329 of file formatting.c.

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

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

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

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

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

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

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

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

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

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

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

◆ numeric_to_number()

Datum numeric_to_number ( PG_FUNCTION_ARGS  )

Definition at line 6243 of file formatting.c.

6248{
6250 text *fmt = PG_GETARG_TEXT_PP(1);
6251 NUMDesc Num;
6252 Datum result;
6254 char *numstr;
6255 bool shouldFree;
6256 int len = 0;
6257 int scale,
6258 precision;
6259
6260 len = VARSIZE_ANY_EXHDR(fmt);
6261
6262 if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
6264
6265 format = NUM_cache(len, &Num, fmt, &shouldFree);
6266
6267 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
6268
6269 NUM_processor(format, &Num, VARDATA_ANY(value), numstr,
6270 VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
6271
6272 scale = Num.post;
6273 precision = Num.pre + Num.multi + scale;
6274
6275 if (shouldFree)
6276 pfree(format);
6277
6279 CStringGetDatum(numstr),
6281 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
6282
6283 if (IS_MULTI(&Num))
6284 {
6285 Numeric x;
6288
6291 NumericGetDatum(b)));
6293 result,
6295 }
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 4164 of file formatting.c.

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

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

Referenced by executeDateTimeMethod().

◆ parse_format()

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

Definition at line 1378 of file formatting.c.

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

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

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

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

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

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

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

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

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

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

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

Referenced by DCH_to_char().

◆ str_tolower()

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

Definition at line 1627 of file formatting.c.

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

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

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

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

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

References collid, and str_toupper().

Referenced by DCH_to_char().

◆ strspace_len()

static size_t strspace_len ( const char *  str)
static

Definition at line 2101 of file formatting.c.

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

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

1167{
1168 for (const KeySuffix *s = suf; s->name != NULL; s++)
1169 {
1170 if (s->type != type)
1171 continue;
1172
1173 if (strncmp(str, s->name, s->len) == 0)
1174 return s;
1175 }
1176 return NULL;
1177}
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 3964 of file formatting.c.

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

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

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

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

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

◆ to_timestamp()

Datum to_timestamp ( PG_FUNCTION_ARGS  )

Definition at line 4080 of file formatting.c.

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