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/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
 
struct  WordBoundaryState
 

Macros

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

Typedefs

typedef struct TmToChar TmToChar
 
typedef struct NUMProc NUMProc
 

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ A_D_STR

#define A_D_STR   "A.D."

Definition at line 196 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 197 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 223 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 224 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 198 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 199 of file formatting.c.

◆ ADJUST_YEAR

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

Definition at line 194 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 225 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 226 of file formatting.c.

◆ AMOUNT_TEST

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

Definition at line 5398 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 201 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 202 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 203 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

Definition at line 204 of file formatting.c.

◆ CLOCK_12_HOUR

#define CLOCK_12_HOUR   1

Definition at line 171 of file formatting.c.

◆ CLOCK_24_HOUR

#define CLOCK_24_HOUR   0

Definition at line 170 of file formatting.c.

◆ COPY_tm

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

Definition at line 494 of file formatting.c.

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 365 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

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

Definition at line 355 of file formatting.c.

◆ DCH_CACHE_SIZE

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

Definition at line 360 of file formatting.c.

◆ DCH_DATED

#define DCH_DATED   0x01

Definition at line 1026 of file formatting.c.

◆ DCH_FLAG

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

Definition at line 99 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

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

Definition at line 114 of file formatting.c.

◆ DCH_S_FM

#define DCH_S_FM   0x01

Definition at line 542 of file formatting.c.

◆ DCH_S_SP

#define DCH_S_SP   0x08

Definition at line 545 of file formatting.c.

◆ DCH_S_TH

#define DCH_S_TH   0x02

Definition at line 543 of file formatting.c.

◆ DCH_S_th

#define DCH_S_th   0x04

Definition at line 544 of file formatting.c.

◆ DCH_S_TM

#define DCH_S_TM   0x10

Definition at line 546 of file formatting.c.

◆ DCH_TIMED

#define DCH_TIMED   0x02

Definition at line 1027 of file formatting.c.

◆ DCH_to_char_fsec

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

◆ DCH_ZONED

#define DCH_ZONED   0x04

Definition at line 1028 of file formatting.c.

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 458 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 457 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:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39

Definition at line 525 of file formatting.c.

◆ IS_BLANK

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

Definition at line 327 of file formatting.c.

◆ IS_BRACKET

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

Definition at line 329 of file formatting.c.

◆ IS_DECIMAL

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

Definition at line 324 of file formatting.c.

◆ IS_EEEE

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

Definition at line 335 of file formatting.c.

◆ IS_FILLMODE

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

Definition at line 328 of file formatting.c.

◆ IS_LDECIMAL

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

Definition at line 325 of file formatting.c.

◆ IS_LSIGN

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

Definition at line 331 of file formatting.c.

◆ IS_MINUS

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

Definition at line 330 of file formatting.c.

◆ IS_MULTI

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

Definition at line 334 of file formatting.c.

◆ IS_PLUS

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

Definition at line 332 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:326

Definition at line 5609 of file formatting.c.

◆ IS_ROMAN

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

Definition at line 333 of file formatting.c.

◆ IS_ZERO

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

Definition at line 326 of file formatting.c.

◆ KeyWord_INDEX_FILTER

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

Definition at line 108 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 107 of file formatting.c.

◆ NODE_TYPE_ACTION

#define NODE_TYPE_ACTION   2

Definition at line 162 of file formatting.c.

◆ NODE_TYPE_CHAR

#define NODE_TYPE_CHAR   3

Definition at line 163 of file formatting.c.

◆ NODE_TYPE_END

#define NODE_TYPE_END   1

Definition at line 161 of file formatting.c.

◆ NODE_TYPE_SEPARATOR

#define NODE_TYPE_SEPARATOR   4

Definition at line 164 of file formatting.c.

◆ NODE_TYPE_SPACE

#define NODE_TYPE_SPACE   5

Definition at line 165 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 366 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

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

Definition at line 357 of file formatting.c.

◆ NUM_CACHE_SIZE

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

Definition at line 362 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 304 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 307 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 301 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 314 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 305 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 302 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 306 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 308 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 313 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 311 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 309 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 312 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 310 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 303 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 100 of file formatting.c.

◆ NUM_LSIGN_NONE

#define NUM_LSIGN_NONE   0

Definition at line 318 of file formatting.c.

◆ NUM_LSIGN_POST

#define NUM_LSIGN_POST   1

Definition at line 317 of file formatting.c.

◆ NUM_LSIGN_PRE

#define NUM_LSIGN_PRE   (-1)

Definition at line 316 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 115 of file formatting.c.

◆ NUM_TOCHAR_finish

#define NUM_TOCHAR_finish
Value:
do { \
int len; \
NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \
if (shouldFree) \
pfree(format); \
\
/* \
* Convert null-terminated representation of result to standard text. \
* The result is usually much bigger than it needs to be, but there \
* seems little point in realloc'ing it smaller. \
*/ \
len = strlen(VARDATA(result)); \
SET_VARSIZE(result, len + VARHDRSZ); \
} while (0)
#define VARHDRSZ
Definition: c.h:692
#define PG_GET_COLLATION()
Definition: fmgr.h:198
static char * NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
Definition: formatting.c:5823
char sign
Definition: informix.c:674
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static char format
const void size_t len
#define VARDATA(PTR)
Definition: varatt.h:278

Definition at line 6320 of file formatting.c.

◆ NUM_TOCHAR_prepare

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

Definition at line 6307 of file formatting.c.

◆ OVERLOAD_TEST

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

Definition at line 5397 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 228 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 229 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 230 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

Definition at line 231 of file formatting.c.

◆ S_FM

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

Definition at line 558 of file formatting.c.

◆ S_SP

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

Definition at line 559 of file formatting.c.

◆ S_TH

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

Definition at line 553 of file formatting.c.

◆ S_th

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

Definition at line 554 of file formatting.c.

◆ S_TH_TYPE

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

Definition at line 555 of file formatting.c.

◆ S_THth

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

Definition at line 552 of file formatting.c.

◆ S_TM

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

Definition at line 560 of file formatting.c.

◆ SKIP_THth

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

Definition at line 2273 of file formatting.c.

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 101 of file formatting.c.

◆ SUFFTYPE_POSTFIX

#define SUFFTYPE_POSTFIX   2

Definition at line 168 of file formatting.c.

◆ SUFFTYPE_PREFIX

#define SUFFTYPE_PREFIX   1

Definition at line 167 of file formatting.c.

◆ TH_LOWER

#define TH_LOWER   2

Definition at line 278 of file formatting.c.

◆ TH_UPPER

#define TH_UPPER   1

Definition at line 277 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 566 of file formatting.c.

◆ tmtcFsec

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

Definition at line 491 of file formatting.c.

◆ tmtcTm

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

Definition at line 489 of file formatting.c.

◆ tmtcTzn

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

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

◆ ZERO_tmfc

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

Definition at line 432 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:489

Definition at line 514 of file formatting.c.

◆ zeroize_NUM

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

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

610 {
611  DCH_A_D,
612  DCH_A_M,
613  DCH_AD,
614  DCH_AM,
615  DCH_B_C,
616  DCH_BC,
617  DCH_CC,
618  DCH_DAY,
619  DCH_DDD,
620  DCH_DD,
621  DCH_DY,
622  DCH_Day,
623  DCH_Dy,
624  DCH_D,
625  DCH_FF1,
626  DCH_FF2,
627  DCH_FF3,
628  DCH_FF4,
629  DCH_FF5,
630  DCH_FF6,
631  DCH_FX, /* global suffix */
632  DCH_HH24,
633  DCH_HH12,
634  DCH_HH,
635  DCH_IDDD,
636  DCH_ID,
637  DCH_IW,
638  DCH_IYYY,
639  DCH_IYY,
640  DCH_IY,
641  DCH_I,
642  DCH_J,
643  DCH_MI,
644  DCH_MM,
645  DCH_MONTH,
646  DCH_MON,
647  DCH_MS,
648  DCH_Month,
649  DCH_Mon,
650  DCH_OF,
651  DCH_P_M,
652  DCH_PM,
653  DCH_Q,
654  DCH_RM,
655  DCH_SSSSS,
656  DCH_SSSS,
657  DCH_SS,
658  DCH_TZH,
659  DCH_TZM,
660  DCH_TZ,
661  DCH_US,
662  DCH_WW,
663  DCH_W,
664  DCH_Y_YYY,
665  DCH_YYYY,
666  DCH_YYY,
667  DCH_YY,
668  DCH_Y,
669  DCH_a_d,
670  DCH_a_m,
671  DCH_ad,
672  DCH_am,
673  DCH_b_c,
674  DCH_bc,
675  DCH_cc,
676  DCH_day,
677  DCH_ddd,
678  DCH_dd,
679  DCH_dy,
680  DCH_d,
681  DCH_ff1,
682  DCH_ff2,
683  DCH_ff3,
684  DCH_ff4,
685  DCH_ff5,
686  DCH_ff6,
687  DCH_fx,
688  DCH_hh24,
689  DCH_hh12,
690  DCH_hh,
691  DCH_iddd,
692  DCH_id,
693  DCH_iw,
694  DCH_iyyy,
695  DCH_iyy,
696  DCH_iy,
697  DCH_i,
698  DCH_j,
699  DCH_mi,
700  DCH_mm,
701  DCH_month,
702  DCH_mon,
703  DCH_ms,
704  DCH_of,
705  DCH_p_m,
706  DCH_pm,
707  DCH_q,
708  DCH_rm,
709  DCH_sssss,
710  DCH_ssss,
711  DCH_ss,
712  DCH_tzh,
713  DCH_tzm,
714  DCH_tz,
715  DCH_us,
716  DCH_ww,
717  DCH_w,
718  DCH_y_yyy,
719  DCH_yyyy,
720  DCH_yyy,
721  DCH_yy,
722  DCH_y,
723 
724  /* last */
725  _DCH_last_
726 } DCH_poz;
DCH_poz
Definition: formatting.c:610
@ DCH_rm
Definition: formatting.c:708
@ DCH_FF1
Definition: formatting.c:625
@ DCH_p_m
Definition: formatting.c:705
@ DCH_BC
Definition: formatting.c:616
@ DCH_ww
Definition: formatting.c:716
@ DCH_mm
Definition: formatting.c:700
@ DCH_id
Definition: formatting.c:692
@ DCH_WW
Definition: formatting.c:662
@ DCH_y
Definition: formatting.c:722
@ DCH_a_m
Definition: formatting.c:670
@ DCH_bc
Definition: formatting.c:674
@ DCH_ff1
Definition: formatting.c:681
@ DCH_YYYY
Definition: formatting.c:665
@ DCH_i
Definition: formatting.c:697
@ DCH_TZH
Definition: formatting.c:658
@ DCH_P_M
Definition: formatting.c:651
@ DCH_iy
Definition: formatting.c:696
@ DCH_A_D
Definition: formatting.c:611
@ DCH_OF
Definition: formatting.c:650
@ DCH_SS
Definition: formatting.c:657
@ DCH_day
Definition: formatting.c:676
@ DCH_tzm
Definition: formatting.c:713
@ DCH_tz
Definition: formatting.c:714
@ DCH_y_yyy
Definition: formatting.c:718
@ DCH_ff4
Definition: formatting.c:684
@ DCH_b_c
Definition: formatting.c:673
@ DCH_month
Definition: formatting.c:701
@ DCH_HH12
Definition: formatting.c:633
@ DCH_mon
Definition: formatting.c:702
@ DCH_iddd
Definition: formatting.c:691
@ DCH_AM
Definition: formatting.c:614
@ DCH_SSSSS
Definition: formatting.c:655
@ DCH_pm
Definition: formatting.c:706
@ DCH_RM
Definition: formatting.c:654
@ DCH_dd
Definition: formatting.c:678
@ DCH_DY
Definition: formatting.c:621
@ DCH_hh24
Definition: formatting.c:688
@ DCH_HH24
Definition: formatting.c:632
@ DCH_ms
Definition: formatting.c:703
@ DCH_IYY
Definition: formatting.c:639
@ DCH_CC
Definition: formatting.c:617
@ DCH_US
Definition: formatting.c:661
@ DCH_J
Definition: formatting.c:642
@ DCH_FF4
Definition: formatting.c:628
@ DCH_ff2
Definition: formatting.c:682
@ DCH_Month
Definition: formatting.c:648
@ DCH_DDD
Definition: formatting.c:619
@ DCH_fx
Definition: formatting.c:687
@ DCH_DD
Definition: formatting.c:620
@ DCH_Dy
Definition: formatting.c:623
@ DCH_MM
Definition: formatting.c:644
@ DCH_am
Definition: formatting.c:672
@ DCH_FF5
Definition: formatting.c:629
@ DCH_Y_YYY
Definition: formatting.c:664
@ DCH_W
Definition: formatting.c:663
@ DCH_MON
Definition: formatting.c:646
@ DCH_IW
Definition: formatting.c:637
@ DCH_ad
Definition: formatting.c:671
@ DCH_PM
Definition: formatting.c:652
@ DCH_HH
Definition: formatting.c:634
@ DCH_a_d
Definition: formatting.c:669
@ DCH_IY
Definition: formatting.c:640
@ DCH_iw
Definition: formatting.c:693
@ DCH_IDDD
Definition: formatting.c:635
@ DCH_FF2
Definition: formatting.c:626
@ DCH_hh
Definition: formatting.c:690
@ DCH_TZM
Definition: formatting.c:659
@ DCH_FF6
Definition: formatting.c:630
@ DCH_of
Definition: formatting.c:704
@ DCH_YYY
Definition: formatting.c:666
@ DCH_YY
Definition: formatting.c:667
@ DCH_j
Definition: formatting.c:698
@ DCH_MS
Definition: formatting.c:647
@ DCH_TZ
Definition: formatting.c:660
@ DCH_ff6
Definition: formatting.c:686
@ DCH_AD
Definition: formatting.c:613
@ DCH_ddd
Definition: formatting.c:677
@ DCH_FX
Definition: formatting.c:631
@ DCH_IYYY
Definition: formatting.c:638
@ DCH_yyyy
Definition: formatting.c:719
@ DCH_ff3
Definition: formatting.c:683
@ DCH_I
Definition: formatting.c:641
@ _DCH_last_
Definition: formatting.c:725
@ DCH_w
Definition: formatting.c:717
@ DCH_dy
Definition: formatting.c:679
@ DCH_iyy
Definition: formatting.c:695
@ DCH_A_M
Definition: formatting.c:612
@ DCH_Y
Definition: formatting.c:668
@ DCH_iyyy
Definition: formatting.c:694
@ DCH_ff5
Definition: formatting.c:685
@ DCH_Day
Definition: formatting.c:622
@ DCH_tzh
Definition: formatting.c:712
@ DCH_B_C
Definition: formatting.c:615
@ DCH_mi
Definition: formatting.c:699
@ DCH_Mon
Definition: formatting.c:649
@ DCH_FF3
Definition: formatting.c:627
@ DCH_Q
Definition: formatting.c:653
@ DCH_d
Definition: formatting.c:680
@ DCH_ssss
Definition: formatting.c:710
@ DCH_SSSS
Definition: formatting.c:656
@ DCH_ss
Definition: formatting.c:711
@ DCH_us
Definition: formatting.c:715
@ DCH_ID
Definition: formatting.c:636
@ DCH_sssss
Definition: formatting.c:709
@ DCH_yy
Definition: formatting.c:721
@ DCH_q
Definition: formatting.c:707
@ DCH_DAY
Definition: formatting.c:618
@ DCH_MONTH
Definition: formatting.c:645
@ DCH_MI
Definition: formatting.c:643
@ DCH_yyy
Definition: formatting.c:720
@ DCH_D
Definition: formatting.c:624
@ DCH_cc
Definition: formatting.c:675
@ DCH_hh12
Definition: formatting.c:689

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 137 of file formatting.c.

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

◆ NUM_poz

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

Definition at line 728 of file formatting.c.

729 {
730  NUM_COMMA,
731  NUM_DEC,
732  NUM_0,
733  NUM_9,
734  NUM_B,
735  NUM_C,
736  NUM_D,
737  NUM_E,
738  NUM_FM,
739  NUM_G,
740  NUM_L,
741  NUM_MI,
742  NUM_PL,
743  NUM_PR,
744  NUM_RN,
745  NUM_SG,
746  NUM_SP,
747  NUM_S,
748  NUM_TH,
749  NUM_V,
750  NUM_b,
751  NUM_c,
752  NUM_d,
753  NUM_e,
754  NUM_fm,
755  NUM_g,
756  NUM_l,
757  NUM_mi,
758  NUM_pl,
759  NUM_pr,
760  NUM_rn,
761  NUM_sg,
762  NUM_sp,
763  NUM_s,
764  NUM_th,
765  NUM_v,
766 
767  /* last */
768  _NUM_last_
769 } NUM_poz;
NUM_poz
Definition: formatting.c:729
@ NUM_COMMA
Definition: formatting.c:730
@ NUM_rn
Definition: formatting.c:760
@ NUM_0
Definition: formatting.c:732
@ NUM_g
Definition: formatting.c:755
@ _NUM_last_
Definition: formatting.c:768
@ NUM_pl
Definition: formatting.c:758
@ NUM_sg
Definition: formatting.c:761
@ NUM_D
Definition: formatting.c:736
@ NUM_PL
Definition: formatting.c:742
@ NUM_c
Definition: formatting.c:751
@ NUM_e
Definition: formatting.c:753
@ NUM_S
Definition: formatting.c:747
@ NUM_PR
Definition: formatting.c:743
@ NUM_SP
Definition: formatting.c:746
@ NUM_TH
Definition: formatting.c:748
@ NUM_SG
Definition: formatting.c:745
@ NUM_l
Definition: formatting.c:756
@ NUM_FM
Definition: formatting.c:738
@ NUM_RN
Definition: formatting.c:744
@ NUM_L
Definition: formatting.c:740
@ NUM_th
Definition: formatting.c:764
@ NUM_V
Definition: formatting.c:749
@ NUM_fm
Definition: formatting.c:754
@ NUM_DEC
Definition: formatting.c:731
@ NUM_C
Definition: formatting.c:735
@ NUM_9
Definition: formatting.c:733
@ NUM_mi
Definition: formatting.c:757
@ NUM_b
Definition: formatting.c:750
@ NUM_s
Definition: formatting.c:763
@ NUM_v
Definition: formatting.c:765
@ NUM_MI
Definition: formatting.c:741
@ NUM_G
Definition: formatting.c:739
@ NUM_E
Definition: formatting.c:737
@ NUM_d
Definition: formatting.c:752
@ NUM_sp
Definition: formatting.c:762
@ NUM_pr
Definition: formatting.c:759
@ NUM_B
Definition: formatting.c:734

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2354 of file formatting.c.

2355 {
2356  /*
2357  * Adjust all dates toward 2020; this is effectively what happens when we
2358  * assume '70' is 1970 and '69' is 2069.
2359  */
2360  /* Force 0-69 into the 2000's */
2361  if (year < 70)
2362  return year + 2000;
2363  /* Force 70-99 into the 1900's */
2364  else if (year < 100)
2365  return year + 1900;
2366  /* Force 100-519 into the 2000's */
2367  else if (year < 520)
2368  return year + 2000;
2369  /* Force 520-999 into the 1000's */
2370  else if (year < 1000)
2371  return year + 1000;
2372  else
2373  return year;
2374 }

Referenced by DCH_from_char().

◆ asc_initcap()

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

Definition at line 2204 of file formatting.c.

2205 {
2206  char *result;
2207  char *p;
2208  int wasalnum = false;
2209 
2210  if (!buff)
2211  return NULL;
2212 
2213  result = pnstrdup(buff, nbytes);
2214 
2215  for (p = result; *p; p++)
2216  {
2217  char c;
2218 
2219  if (wasalnum)
2220  *p = c = pg_ascii_tolower((unsigned char) *p);
2221  else
2222  *p = c = pg_ascii_toupper((unsigned char) *p);
2223  /* we don't trust isalnum() here */
2224  wasalnum = ((c >= 'A' && c <= 'Z') ||
2225  (c >= 'a' && c <= 'z') ||
2226  (c >= '0' && c <= '9'));
2227  }
2228 
2229  return result;
2230 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1706
unsigned char pg_ascii_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:146
unsigned char pg_ascii_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:135
char * c

References pg_ascii_tolower(), pg_ascii_toupper(), and pnstrdup().

Referenced by str_initcap().

◆ asc_tolower()

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

Definition at line 2158 of file formatting.c.

2159 {
2160  char *result;
2161  char *p;
2162 
2163  if (!buff)
2164  return NULL;
2165 
2166  result = pnstrdup(buff, nbytes);
2167 
2168  for (p = result; *p; p++)
2169  *p = pg_ascii_tolower((unsigned char) *p);
2170 
2171  return result;
2172 }

References pg_ascii_tolower(), and pnstrdup().

Referenced by asc_tolower_z(), and str_tolower().

◆ asc_tolower_z()

static char* asc_tolower_z ( const char *  buff)
static

Definition at line 2253 of file formatting.c.

2254 {
2255  return asc_tolower(buff, strlen(buff));
2256 }
char * asc_tolower(const char *buff, size_t nbytes)
Definition: formatting.c:2158

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

2182 {
2183  char *result;
2184  char *p;
2185 
2186  if (!buff)
2187  return NULL;
2188 
2189  result = pnstrdup(buff, nbytes);
2190 
2191  for (p = result; *p; p++)
2192  *p = pg_ascii_toupper((unsigned char) *p);
2193 
2194  return result;
2195 }

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

2260 {
2261  return asc_toupper(buff, strlen(buff));
2262 }
char * asc_toupper(const char *buff, size_t nbytes)
Definition: formatting.c:2181

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char *  fmt_str)

Definition at line 4618 of file formatting.c.

4619 {
4620  bool incache;
4621  int fmt_len = strlen(fmt_str);
4622  int result;
4623  FormatNode *format;
4624 
4625  if (fmt_len > DCH_CACHE_SIZE)
4626  {
4627  /*
4628  * Allocate new memory if format picture is bigger than static cache
4629  * and do not use cache (call parser always)
4630  */
4631  incache = false;
4632 
4633  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4634 
4635  parse_format(format, fmt_str, DCH_keywords,
4636  DCH_suff, DCH_index, DCH_FLAG, NULL);
4637  }
4638  else
4639  {
4640  /*
4641  * Use cache buffers
4642  */
4643  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4644 
4645  incache = true;
4646  format = ent->format;
4647  }
4648 
4649  result = DCH_datetime_type(format);
4650 
4651  if (!incache)
4652  pfree(format);
4653 
4654  return result & DCH_ZONED;
4655 }
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:948
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:1328
#define DCH_FLAG
Definition: formatting.c:99
static const KeySuffix DCH_suff[]
Definition: formatting.c:568
#define DCH_CACHE_SIZE
Definition: formatting.c:360
#define DCH_ZONED
Definition: formatting.c:1028
static int DCH_datetime_type(FormatNode *node)
Definition: formatting.c:3976
static const KeyWord DCH_keywords[]
Definition: formatting.c:775
static DCHCacheEntry * DCH_cache_fetch(const char *str, bool std)
Definition: formatting.c:4154
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:370

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().

◆ datetime_to_char_body()

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

Definition at line 4181 of file formatting.c.

4182 {
4183  FormatNode *format;
4184  char *fmt_str,
4185  *result;
4186  bool incache;
4187  int fmt_len;
4188  text *res;
4189 
4190  /*
4191  * Convert fmt to C string
4192  */
4193  fmt_str = text_to_cstring(fmt);
4194  fmt_len = strlen(fmt_str);
4195 
4196  /*
4197  * Allocate workspace for result as C string
4198  */
4199  result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
4200  *result = '\0';
4201 
4202  if (fmt_len > DCH_CACHE_SIZE)
4203  {
4204  /*
4205  * Allocate new memory if format picture is bigger than static cache
4206  * and do not use cache (call parser always)
4207  */
4208  incache = false;
4209 
4210  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4211 
4212  parse_format(format, fmt_str, DCH_keywords,
4213  DCH_suff, DCH_index, DCH_FLAG, NULL);
4214  }
4215  else
4216  {
4217  /*
4218  * Use cache buffers
4219  */
4220  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
4221 
4222  incache = true;
4223  format = ent->format;
4224  }
4225 
4226  /* The real work is here */
4227  DCH_to_char(format, is_interval, tmtc, result, collid);
4228 
4229  if (!incache)
4230  pfree(format);
4231 
4232  pfree(fmt_str);
4233 
4234  /* convert C-string result to TEXT format */
4235  res = cstring_to_text(result);
4236 
4237  pfree(result);
4238  return res;
4239 }
Oid collid
static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
Definition: formatting.c:2765
#define DCH_MAX_ITEM_SIZ
Definition: formatting.c:114
char * text_to_cstring(const text *t)
Definition: varlena.c:217

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(), fmt, DCHCacheEntry::format, format, palloc(), parse_format(), pfree(), res, and text_to_cstring().

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

◆ DCH_cache_fetch()

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

Definition at line 4154 of file formatting.c.

4155 {
4156  DCHCacheEntry *ent;
4157 
4158  if ((ent = DCH_cache_search(str, std)) == NULL)
4159  {
4160  /*
4161  * Not in the cache, must run parser and save a new format-picture to
4162  * the cache. Do not mark the cache entry valid until parsing
4163  * succeeds.
4164  */
4165  ent = DCH_cache_getnew(str, std);
4166 
4168  DCH_FLAG | (std ? STD_FLAG : 0), NULL);
4169 
4170  ent->valid = true;
4171  }
4172  return ent;
4173 }
#define STD_FLAG
Definition: formatting.c:101
static DCHCacheEntry * DCH_cache_getnew(const char *str, bool std)
Definition: formatting.c:4073
static DCHCacheEntry * DCH_cache_search(const char *str, bool std)
Definition: formatting.c:4133
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 4073 of file formatting.c.

4074 {
4075  DCHCacheEntry *ent;
4076 
4077  /* Ensure we can advance DCHCounter below */
4079 
4080  /*
4081  * If cache is full, remove oldest entry (or recycle first not-valid one)
4082  */
4084  {
4085  DCHCacheEntry *old = DCHCache[0];
4086 
4087 #ifdef DEBUG_TO_FROM_CHAR
4088  elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
4089 #endif
4090  if (old->valid)
4091  {
4092  for (int i = 1; i < DCH_CACHE_ENTRIES; i++)
4093  {
4094  ent = DCHCache[i];
4095  if (!ent->valid)
4096  {
4097  old = ent;
4098  break;
4099  }
4100  if (ent->age < old->age)
4101  old = ent;
4102  }
4103  }
4104 #ifdef DEBUG_TO_FROM_CHAR
4105  elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
4106 #endif
4107  old->valid = false;
4108  strlcpy(old->str, str, DCH_CACHE_SIZE + 1);
4109  old->age = (++DCHCounter);
4110  /* caller is expected to fill format, then set valid */
4111  return old;
4112  }
4113  else
4114  {
4115 #ifdef DEBUG_TO_FROM_CHAR
4116  elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
4117 #endif
4118  Assert(DCHCache[n_DCHCache] == NULL);
4119  DCHCache[n_DCHCache] = ent = (DCHCacheEntry *)
4121  ent->valid = false;
4122  strlcpy(ent->str, str, DCH_CACHE_SIZE + 1);
4123  ent->std = std;
4124  ent->age = (++DCHCounter);
4125  /* caller is expected to fill format, then set valid */
4126  ++n_DCHCache;
4127  return ent;
4128  }
4129 }
#define Assert(condition)
Definition: c.h:858
#define elog(elevel,...)
Definition: elog.h:224
static void DCH_prevent_counter_overflow(void)
Definition: formatting.c:3962
static int DCHCounter
Definition: formatting.c:389
static int n_DCHCache
Definition: formatting.c:388
static DCHCacheEntry * DCHCache[DCH_CACHE_ENTRIES]
Definition: formatting.c:387
#define DCH_CACHE_ENTRIES
Definition: formatting.c:365
int i
Definition: isn.c:73
MemoryContext TopMemoryContext
Definition: mcxt.c:149
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1214
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char str[DCH_CACHE_SIZE+1]
Definition: formatting.c:371

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

4134 {
4135  /* Ensure we can advance DCHCounter below */
4137 
4138  for (int i = 0; i < n_DCHCache; i++)
4139  {
4140  DCHCacheEntry *ent = DCHCache[i];
4141 
4142  if (ent->valid && strcmp(ent->str, str) == 0 && ent->std == std)
4143  {
4144  ent->age = (++DCHCounter);
4145  return ent;
4146  }
4147  }
4148 
4149  return NULL;
4150 }

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

3977 {
3978  FormatNode *n;
3979  int flags = 0;
3980 
3981  for (n = node; n->type != NODE_TYPE_END; n++)
3982  {
3983  if (n->type != NODE_TYPE_ACTION)
3984  continue;
3985 
3986  switch (n->key->id)
3987  {
3988  case DCH_FX:
3989  break;
3990  case DCH_A_M:
3991  case DCH_P_M:
3992  case DCH_a_m:
3993  case DCH_p_m:
3994  case DCH_AM:
3995  case DCH_PM:
3996  case DCH_am:
3997  case DCH_pm:
3998  case DCH_HH:
3999  case DCH_HH12:
4000  case DCH_HH24:
4001  case DCH_MI:
4002  case DCH_SS:
4003  case DCH_MS: /* millisecond */
4004  case DCH_US: /* microsecond */
4005  case DCH_FF1:
4006  case DCH_FF2:
4007  case DCH_FF3:
4008  case DCH_FF4:
4009  case DCH_FF5:
4010  case DCH_FF6:
4011  case DCH_SSSS:
4012  flags |= DCH_TIMED;
4013  break;
4014  case DCH_tz:
4015  case DCH_TZ:
4016  case DCH_OF:
4017  case DCH_TZH:
4018  case DCH_TZM:
4019  flags |= DCH_ZONED;
4020  break;
4021  case DCH_A_D:
4022  case DCH_B_C:
4023  case DCH_a_d:
4024  case DCH_b_c:
4025  case DCH_AD:
4026  case DCH_BC:
4027  case DCH_ad:
4028  case DCH_bc:
4029  case DCH_MONTH:
4030  case DCH_Month:
4031  case DCH_month:
4032  case DCH_MON:
4033  case DCH_Mon:
4034  case DCH_mon:
4035  case DCH_MM:
4036  case DCH_DAY:
4037  case DCH_Day:
4038  case DCH_day:
4039  case DCH_DY:
4040  case DCH_Dy:
4041  case DCH_dy:
4042  case DCH_DDD:
4043  case DCH_IDDD:
4044  case DCH_DD:
4045  case DCH_D:
4046  case DCH_ID:
4047  case DCH_WW:
4048  case DCH_Q:
4049  case DCH_CC:
4050  case DCH_Y_YYY:
4051  case DCH_YYYY:
4052  case DCH_IYYY:
4053  case DCH_YYY:
4054  case DCH_IYY:
4055  case DCH_YY:
4056  case DCH_IY:
4057  case DCH_Y:
4058  case DCH_I:
4059  case DCH_RM:
4060  case DCH_rm:
4061  case DCH_W:
4062  case DCH_J:
4063  flags |= DCH_DATED;
4064  break;
4065  }
4066  }
4067 
4068  return flags;
4069 }
#define DCH_DATED
Definition: formatting.c:1026
#define DCH_TIMED
Definition: formatting.c:1027
#define NODE_TYPE_ACTION
Definition: formatting.c:162
#define NODE_TYPE_END
Definition: formatting.c:161
const KeyWord * key
Definition: formatting.c:158
uint8 type
Definition: formatting.c:155
int id
Definition: formatting.c:148

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

Referenced by datetime_format_has_tz(), and do_to_timestamp().

◆ DCH_from_char()

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

Definition at line 3412 of file formatting.c.

3414 {
3415  FormatNode *n;
3416  const char *s;
3417  int len,
3418  value;
3419  bool fx_mode = std;
3420 
3421  /* number of extra skipped characters (more than given in format string) */
3422  int extra_skip = 0;
3423 
3424  /* cache localized days and months */
3426 
3427  for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
3428  {
3429  /*
3430  * Ignore spaces at the beginning of the string and before fields when
3431  * not in FX (fixed width) mode.
3432  */
3433  if (!fx_mode && (n->type != NODE_TYPE_ACTION || n->key->id != DCH_FX) &&
3434  (n->type == NODE_TYPE_ACTION || n == node))
3435  {
3436  while (*s != '\0' && isspace((unsigned char) *s))
3437  {
3438  s++;
3439  extra_skip++;
3440  }
3441  }
3442 
3443  if (n->type == NODE_TYPE_SPACE || n->type == NODE_TYPE_SEPARATOR)
3444  {
3445  if (std)
3446  {
3447  /*
3448  * Standard mode requires strict matching between format
3449  * string separators/spaces and input string.
3450  */
3451  Assert(n->character[0] && !n->character[1]);
3452 
3453  if (*s == n->character[0])
3454  s++;
3455  else
3456  ereturn(escontext,,
3457  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3458  errmsg("unmatched format separator \"%c\"",
3459  n->character[0])));
3460  }
3461  else if (!fx_mode)
3462  {
3463  /*
3464  * In non FX (fixed format) mode one format string space or
3465  * separator match to one space or separator in input string.
3466  * Or match nothing if there is no space or separator in the
3467  * current position of input string.
3468  */
3469  extra_skip--;
3470  if (isspace((unsigned char) *s) || is_separator_char(s))
3471  {
3472  s++;
3473  extra_skip++;
3474  }
3475  }
3476  else
3477  {
3478  /*
3479  * In FX mode, on format string space or separator we consume
3480  * exactly one character from input string. Notice we don't
3481  * insist that the consumed character match the format's
3482  * character.
3483  */
3484  s += pg_mblen(s);
3485  }
3486  continue;
3487  }
3488  else if (n->type != NODE_TYPE_ACTION)
3489  {
3490  /*
3491  * Text character, so consume one character from input string.
3492  * Notice we don't insist that the consumed character match the
3493  * format's character.
3494  */
3495  if (!fx_mode)
3496  {
3497  /*
3498  * In non FX mode we might have skipped some extra characters
3499  * (more than specified in format string) before. In this
3500  * case we don't skip input string character, because it might
3501  * be part of field.
3502  */
3503  if (extra_skip > 0)
3504  extra_skip--;
3505  else
3506  s += pg_mblen(s);
3507  }
3508  else
3509  {
3510  int chlen = pg_mblen(s);
3511 
3512  /*
3513  * Standard mode requires strict match of format characters.
3514  */
3515  if (std && n->type == NODE_TYPE_CHAR &&
3516  strncmp(s, n->character, chlen) != 0)
3517  ereturn(escontext,,
3518  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3519  errmsg("unmatched format character \"%s\"",
3520  n->character)));
3521 
3522  s += chlen;
3523  }
3524  continue;
3525  }
3526 
3527  if (!from_char_set_mode(out, n->key->date_mode, escontext))
3528  return;
3529 
3530  switch (n->key->id)
3531  {
3532  case DCH_FX:
3533  fx_mode = true;
3534  break;
3535  case DCH_A_M:
3536  case DCH_P_M:
3537  case DCH_a_m:
3538  case DCH_p_m:
3540  NULL, InvalidOid,
3541  n, escontext))
3542  return;
3543  if (!from_char_set_int(&out->pm, value % 2, n, escontext))
3544  return;
3545  out->clock = CLOCK_12_HOUR;
3546  break;
3547  case DCH_AM:
3548  case DCH_PM:
3549  case DCH_am:
3550  case DCH_pm:
3552  NULL, InvalidOid,
3553  n, escontext))
3554  return;
3555  if (!from_char_set_int(&out->pm, value % 2, n, escontext))
3556  return;
3557  out->clock = CLOCK_12_HOUR;
3558  break;
3559  case DCH_HH:
3560  case DCH_HH12:
3561  if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
3562  return;
3563  out->clock = CLOCK_12_HOUR;
3564  SKIP_THth(s, n->suffix);
3565  break;
3566  case DCH_HH24:
3567  if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0)
3568  return;
3569  SKIP_THth(s, n->suffix);
3570  break;
3571  case DCH_MI:
3572  if (from_char_parse_int(&out->mi, &s, n, escontext) < 0)
3573  return;
3574  SKIP_THth(s, n->suffix);
3575  break;
3576  case DCH_SS:
3577  if (from_char_parse_int(&out->ss, &s, n, escontext) < 0)
3578  return;
3579  SKIP_THth(s, n->suffix);
3580  break;
3581  case DCH_MS: /* millisecond */
3582  len = from_char_parse_int_len(&out->ms, &s, 3, n, escontext);
3583  if (len < 0)
3584  return;
3585 
3586  /*
3587  * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
3588  */
3589  out->ms *= len == 1 ? 100 :
3590  len == 2 ? 10 : 1;
3591 
3592  SKIP_THth(s, n->suffix);
3593  break;
3594  case DCH_FF1:
3595  case DCH_FF2:
3596  case DCH_FF3:
3597  case DCH_FF4:
3598  case DCH_FF5:
3599  case DCH_FF6:
3600  out->ff = n->key->id - DCH_FF1 + 1;
3601  /* FALLTHROUGH */
3602  case DCH_US: /* microsecond */
3603  len = from_char_parse_int_len(&out->us, &s,
3604  n->key->id == DCH_US ? 6 :
3605  out->ff, n, escontext);
3606  if (len < 0)
3607  return;
3608 
3609  out->us *= len == 1 ? 100000 :
3610  len == 2 ? 10000 :
3611  len == 3 ? 1000 :
3612  len == 4 ? 100 :
3613  len == 5 ? 10 : 1;
3614 
3615  SKIP_THth(s, n->suffix);
3616  break;
3617  case DCH_SSSS:
3618  if (from_char_parse_int(&out->ssss, &s, n, escontext) < 0)
3619  return;
3620  SKIP_THth(s, n->suffix);
3621  break;
3622  case DCH_tz:
3623  case DCH_TZ:
3624  {
3625  int tzlen;
3626 
3627  tzlen = DecodeTimezoneAbbrevPrefix(s,
3628  &out->gmtoffset,
3629  &out->tzp);
3630  if (tzlen > 0)
3631  {
3632  out->has_tz = true;
3633  /* we only need the zone abbrev for DYNTZ case */
3634  if (out->tzp)
3635  out->abbrev = pnstrdup(s, tzlen);
3636  out->tzsign = 0; /* drop any earlier TZH/TZM info */
3637  s += tzlen;
3638  break;
3639  }
3640  else if (isalpha((unsigned char) *s))
3641  {
3642  /*
3643  * It doesn't match any abbreviation, but it starts
3644  * with a letter. OF format certainly won't succeed;
3645  * assume it's a misspelled abbreviation and complain
3646  * accordingly.
3647  */
3648  ereturn(escontext,,
3649  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3650  errmsg("invalid value \"%s\" for \"%s\"",
3651  s, n->key->name),
3652  errdetail("Time zone abbreviation is not recognized.")));
3653  }
3654  /* otherwise parse it like OF */
3655  }
3656  /* FALLTHROUGH */
3657  case DCH_OF:
3658  /* OF is equivalent to TZH or TZH:TZM */
3659  /* see TZH comments below */
3660  if (*s == '+' || *s == '-' || *s == ' ')
3661  {
3662  out->tzsign = *s == '-' ? -1 : +1;
3663  s++;
3664  }
3665  else
3666  {
3667  if (extra_skip > 0 && *(s - 1) == '-')
3668  out->tzsign = -1;
3669  else
3670  out->tzsign = +1;
3671  }
3672  if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
3673  return;
3674  if (*s == ':')
3675  {
3676  s++;
3677  if (from_char_parse_int_len(&out->tzm, &s, 2, n,
3678  escontext) < 0)
3679  return;
3680  }
3681  break;
3682  case DCH_TZH:
3683 
3684  /*
3685  * Value of TZH might be negative. And the issue is that we
3686  * might swallow minus sign as the separator. So, if we have
3687  * skipped more characters than specified in the format
3688  * string, then we consider prepending last skipped minus to
3689  * TZH.
3690  */
3691  if (*s == '+' || *s == '-' || *s == ' ')
3692  {
3693  out->tzsign = *s == '-' ? -1 : +1;
3694  s++;
3695  }
3696  else
3697  {
3698  if (extra_skip > 0 && *(s - 1) == '-')
3699  out->tzsign = -1;
3700  else
3701  out->tzsign = +1;
3702  }
3703 
3704  if (from_char_parse_int_len(&out->tzh, &s, 2, n, escontext) < 0)
3705  return;
3706  break;
3707  case DCH_TZM:
3708  /* assign positive timezone sign if TZH was not seen before */
3709  if (!out->tzsign)
3710  out->tzsign = +1;
3711  if (from_char_parse_int_len(&out->tzm, &s, 2, n, escontext) < 0)
3712  return;
3713  break;
3714  case DCH_A_D:
3715  case DCH_B_C:
3716  case DCH_a_d:
3717  case DCH_b_c:
3719  NULL, InvalidOid,
3720  n, escontext))
3721  return;
3722  if (!from_char_set_int(&out->bc, value % 2, n, escontext))
3723  return;
3724  break;
3725  case DCH_AD:
3726  case DCH_BC:
3727  case DCH_ad:
3728  case DCH_bc:
3730  NULL, InvalidOid,
3731  n, escontext))
3732  return;
3733  if (!from_char_set_int(&out->bc, value % 2, n, escontext))
3734  return;
3735  break;
3736  case DCH_MONTH:
3737  case DCH_Month:
3738  case DCH_month:
3740  S_TM(n->suffix) ? localized_full_months : NULL,
3741  collid,
3742  n, escontext))
3743  return;
3744  if (!from_char_set_int(&out->mm, value + 1, n, escontext))
3745  return;
3746  break;
3747  case DCH_MON:
3748  case DCH_Mon:
3749  case DCH_mon:
3750  if (!from_char_seq_search(&value, &s, months,
3751  S_TM(n->suffix) ? localized_abbrev_months : NULL,
3752  collid,
3753  n, escontext))
3754  return;
3755  if (!from_char_set_int(&out->mm, value + 1, n, escontext))
3756  return;
3757  break;
3758  case DCH_MM:
3759  if (from_char_parse_int(&out->mm, &s, n, escontext) < 0)
3760  return;
3761  SKIP_THth(s, n->suffix);
3762  break;
3763  case DCH_DAY:
3764  case DCH_Day:
3765  case DCH_day:
3766  if (!from_char_seq_search(&value, &s, days,
3767  S_TM(n->suffix) ? localized_full_days : NULL,
3768  collid,
3769  n, escontext))
3770  return;
3771  if (!from_char_set_int(&out->d, value, n, escontext))
3772  return;
3773  out->d++;
3774  break;
3775  case DCH_DY:
3776  case DCH_Dy:
3777  case DCH_dy:
3779  S_TM(n->suffix) ? localized_abbrev_days : NULL,
3780  collid,
3781  n, escontext))
3782  return;
3783  if (!from_char_set_int(&out->d, value, n, escontext))
3784  return;
3785  out->d++;
3786  break;
3787  case DCH_DDD:
3788  if (from_char_parse_int(&out->ddd, &s, n, escontext) < 0)
3789  return;
3790  SKIP_THth(s, n->suffix);
3791  break;
3792  case DCH_IDDD:
3793  if (from_char_parse_int_len(&out->ddd, &s, 3, n, escontext) < 0)
3794  return;
3795  SKIP_THth(s, n->suffix);
3796  break;
3797  case DCH_DD:
3798  if (from_char_parse_int(&out->dd, &s, n, escontext) < 0)
3799  return;
3800  SKIP_THth(s, n->suffix);
3801  break;
3802  case DCH_D:
3803  if (from_char_parse_int(&out->d, &s, n, escontext) < 0)
3804  return;
3805  SKIP_THth(s, n->suffix);
3806  break;
3807  case DCH_ID:
3808  if (from_char_parse_int_len(&out->d, &s, 1, n, escontext) < 0)
3809  return;
3810  /* Shift numbering to match Gregorian where Sunday = 1 */
3811  if (++out->d > 7)
3812  out->d = 1;
3813  SKIP_THth(s, n->suffix);
3814  break;
3815  case DCH_WW:
3816  case DCH_IW:
3817  if (from_char_parse_int(&out->ww, &s, n, escontext) < 0)
3818  return;
3819  SKIP_THth(s, n->suffix);
3820  break;
3821  case DCH_Q:
3822 
3823  /*
3824  * We ignore 'Q' when converting to date because it is unclear
3825  * which date in the quarter to use, and some people specify
3826  * both quarter and month, so if it was honored it might
3827  * conflict with the supplied month. That is also why we don't
3828  * throw an error.
3829  *
3830  * We still parse the source string for an integer, but it
3831  * isn't stored anywhere in 'out'.
3832  */
3833  if (from_char_parse_int((int *) NULL, &s, n, escontext) < 0)
3834  return;
3835  SKIP_THth(s, n->suffix);
3836  break;
3837  case DCH_CC:
3838  if (from_char_parse_int(&out->cc, &s, n, escontext) < 0)
3839  return;
3840  SKIP_THth(s, n->suffix);
3841  break;
3842  case DCH_Y_YYY:
3843  {
3844  int matched,
3845  years,
3846  millennia,
3847  nch;
3848 
3849  matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch);
3850  if (matched < 2)
3851  ereturn(escontext,,
3852  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3853  errmsg("invalid input string for \"Y,YYY\"")));
3854  years += (millennia * 1000);
3855  if (!from_char_set_int(&out->year, years, n, escontext))
3856  return;
3857  out->yysz = 4;
3858  s += nch;
3859  SKIP_THth(s, n->suffix);
3860  }
3861  break;
3862  case DCH_YYYY:
3863  case DCH_IYYY:
3864  if (from_char_parse_int(&out->year, &s, n, escontext) < 0)
3865  return;
3866  out->yysz = 4;
3867  SKIP_THth(s, n->suffix);
3868  break;
3869  case DCH_YYY:
3870  case DCH_IYY:
3871  len = from_char_parse_int(&out->year, &s, n, escontext);
3872  if (len < 0)
3873  return;
3874  if (len < 4)
3875  out->year = adjust_partial_year_to_2020(out->year);
3876  out->yysz = 3;
3877  SKIP_THth(s, n->suffix);
3878  break;
3879  case DCH_YY:
3880  case DCH_IY:
3881  len = from_char_parse_int(&out->year, &s, n, escontext);
3882  if (len < 0)
3883  return;
3884  if (len < 4)
3885  out->year = adjust_partial_year_to_2020(out->year);
3886  out->yysz = 2;
3887  SKIP_THth(s, n->suffix);
3888  break;
3889  case DCH_Y:
3890  case DCH_I:
3891  len = from_char_parse_int(&out->year, &s, n, escontext);
3892  if (len < 0)
3893  return;
3894  if (len < 4)
3895  out->year = adjust_partial_year_to_2020(out->year);
3896  out->yysz = 1;
3897  SKIP_THth(s, n->suffix);
3898  break;
3899  case DCH_RM:
3900  case DCH_rm:
3902  NULL, InvalidOid,
3903  n, escontext))
3904  return;
3905  if (!from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n,
3906  escontext))
3907  return;
3908  break;
3909  case DCH_W:
3910  if (from_char_parse_int(&out->w, &s, n, escontext) < 0)
3911  return;
3912  SKIP_THth(s, n->suffix);
3913  break;
3914  case DCH_J:
3915  if (from_char_parse_int(&out->j, &s, n, escontext) < 0)
3916  return;
3917  SKIP_THth(s, n->suffix);
3918  break;
3919  }
3920 
3921  /* Ignore all spaces after fields */
3922  if (!fx_mode)
3923  {
3924  extra_skip = 0;
3925  while (*s != '\0' && isspace((unsigned char) *s))
3926  {
3927  s++;
3928  extra_skip++;
3929  }
3930  }
3931  }
3932 
3933  /*
3934  * Standard parsing mode doesn't allow unmatched format patterns or
3935  * trailing characters in the input string.
3936  */
3937  if (std)
3938  {
3939  if (n->type != NODE_TYPE_END)
3940  ereturn(escontext,,
3941  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3942  errmsg("input string is too short for datetime format")));
3943 
3944  while (*s != '\0' && isspace((unsigned char) *s))
3945  s++;
3946 
3947  if (*s != '\0')
3948  ereturn(escontext,,
3949  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3950  errmsg("trailing characters remain in input string after datetime format")));
3951  }
3952 }
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:3262
#define MONTHS_PER_YEAR
Definition: timestamp.h:108
int errdetail(const char *fmt,...)
Definition: elog.c:1205
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
#define CLOCK_12_HOUR
Definition: formatting.c:171
#define SKIP_THth(ptr, _suf)
Definition: formatting.c:2273
static bool from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode, Node *escontext)
Definition: formatting.c:2400
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:2719
#define S_TM(_s)
Definition: formatting.c:560
#define NODE_TYPE_SPACE
Definition: formatting.c:165
static int from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode *node, Node *escontext)
Definition: formatting.c:2463
static int adjust_partial_year_to_2020(int year)
Definition: formatting.c:2354
static const char *const months_full[]
Definition: formatting.c:178
#define NODE_TYPE_SEPARATOR
Definition: formatting.c:164
static const char *const adbc_strings_long[]
Definition: formatting.c:217
static const char *const days_short[]
Definition: formatting.c:183
static const char *const ampm_strings[]
Definition: formatting.c:243
static bool from_char_set_int(int *dest, const int value, const FormatNode *node, Node *escontext)
Definition: formatting.c:2427
#define NODE_TYPE_CHAR
Definition: formatting.c:163
static const char *const rm_months_lower[]
Definition: formatting.c:255
static const char *const adbc_strings[]
Definition: formatting.c:216
static int from_char_parse_int(int *dest, const char **src, FormatNode *node, Node *escontext)
Definition: formatting.c:2560
static const char *const ampm_strings_long[]
Definition: formatting.c:244
static bool is_separator_char(const char *str)
Definition: formatting.c:1139
static struct @155 value
void cache_locale_time(void)
Definition: pg_locale.c:806
char * localized_full_months[12+1]
Definition: pg_locale.c:114
char * localized_abbrev_months[12+1]
Definition: pg_locale.c:113
char * localized_full_days[7+1]
Definition: pg_locale.c:112
char * localized_abbrev_days[7+1]
Definition: pg_locale.c:111
#define InvalidOid
Definition: postgres_ext.h:36
uint8 suffix
Definition: formatting.c:157
char character[MAX_MULTIBYTE_CHAR_LEN+1]
Definition: formatting.c:156
FromCharDateMode date_mode
Definition: formatting.c:150
const char * name
Definition: formatting.c:146
int gmtoffset
Definition: formatting.c:427
pg_tz * tzp
Definition: formatting.c:428
bool has_tz
Definition: formatting.c:426
char * abbrev
Definition: formatting.c:429

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

Referenced by do_to_timestamp().

◆ DCH_prevent_counter_overflow()

static void DCH_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 3962 of file formatting.c.

3963 {
3964  if (DCHCounter >= (INT_MAX - 1))
3965  {
3966  for (int i = 0; i < n_DCHCache; i++)
3967  DCHCache[i]->age >>= 1;
3968  DCHCounter >>= 1;
3969  }
3970 }

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

2766 {
2767  FormatNode *n;
2768  char *s;
2769  struct fmt_tm *tm = &in->tm;
2770  int i;
2771 
2772  /* cache localized days and months */
2774 
2775  s = out;
2776  for (n = node; n->type != NODE_TYPE_END; n++)
2777  {
2778  if (n->type != NODE_TYPE_ACTION)
2779  {
2780  strcpy(s, n->character);
2781  s += strlen(s);
2782  continue;
2783  }
2784 
2785  switch (n->key->id)
2786  {
2787  case DCH_A_M:
2788  case DCH_P_M:
2789  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2790  ? P_M_STR : A_M_STR);
2791  s += strlen(s);
2792  break;
2793  case DCH_AM:
2794  case DCH_PM:
2795  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2796  ? PM_STR : AM_STR);
2797  s += strlen(s);
2798  break;
2799  case DCH_a_m:
2800  case DCH_p_m:
2801  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2802  ? p_m_STR : a_m_STR);
2803  s += strlen(s);
2804  break;
2805  case DCH_am:
2806  case DCH_pm:
2807  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2808  ? pm_STR : am_STR);
2809  s += strlen(s);
2810  break;
2811  case DCH_HH:
2812  case DCH_HH12:
2813 
2814  /*
2815  * display time as shown on a 12-hour clock, even for
2816  * intervals
2817  */
2818  sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2819  tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ?
2820  (long long) (HOURS_PER_DAY / 2) :
2821  (long long) (tm->tm_hour % (HOURS_PER_DAY / 2)));
2822  if (S_THth(n->suffix))
2823  str_numth(s, s, S_TH_TYPE(n->suffix));
2824  s += strlen(s);
2825  break;
2826  case DCH_HH24:
2827  sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2828  (long long) tm->tm_hour);
2829  if (S_THth(n->suffix))
2830  str_numth(s, s, S_TH_TYPE(n->suffix));
2831  s += strlen(s);
2832  break;
2833  case DCH_MI:
2834  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2835  tm->tm_min);
2836  if (S_THth(n->suffix))
2837  str_numth(s, s, S_TH_TYPE(n->suffix));
2838  s += strlen(s);
2839  break;
2840  case DCH_SS:
2841  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2842  tm->tm_sec);
2843  if (S_THth(n->suffix))
2844  str_numth(s, s, S_TH_TYPE(n->suffix));
2845  s += strlen(s);
2846  break;
2847 
2848 #define DCH_to_char_fsec(frac_fmt, frac_val) \
2849  sprintf(s, frac_fmt, (int) (frac_val)); \
2850  if (S_THth(n->suffix)) \
2851  str_numth(s, s, S_TH_TYPE(n->suffix)); \
2852  s += strlen(s)
2853 
2854  case DCH_FF1: /* tenth of second */
2855  DCH_to_char_fsec("%01d", in->fsec / 100000);
2856  break;
2857  case DCH_FF2: /* hundredth of second */
2858  DCH_to_char_fsec("%02d", in->fsec / 10000);
2859  break;
2860  case DCH_FF3:
2861  case DCH_MS: /* millisecond */
2862  DCH_to_char_fsec("%03d", in->fsec / 1000);
2863  break;
2864  case DCH_FF4: /* tenth of a millisecond */
2865  DCH_to_char_fsec("%04d", in->fsec / 100);
2866  break;
2867  case DCH_FF5: /* hundredth of a millisecond */
2868  DCH_to_char_fsec("%05d", in->fsec / 10);
2869  break;
2870  case DCH_FF6:
2871  case DCH_US: /* microsecond */
2872  DCH_to_char_fsec("%06d", in->fsec);
2873  break;
2874 #undef DCH_to_char_fsec
2875  case DCH_SSSS:
2876  sprintf(s, "%lld",
2877  (long long) (tm->tm_hour * SECS_PER_HOUR +
2879  tm->tm_sec));
2880  if (S_THth(n->suffix))
2881  str_numth(s, s, S_TH_TYPE(n->suffix));
2882  s += strlen(s);
2883  break;
2884  case DCH_tz:
2886  if (tmtcTzn(in))
2887  {
2888  /* We assume here that timezone names aren't localized */
2889  char *p = asc_tolower_z(tmtcTzn(in));
2890 
2891  strcpy(s, p);
2892  pfree(p);
2893  s += strlen(s);
2894  }
2895  break;
2896  case DCH_TZ:
2898  if (tmtcTzn(in))
2899  {
2900  strcpy(s, tmtcTzn(in));
2901  s += strlen(s);
2902  }
2903  break;
2904  case DCH_TZH:
2906  sprintf(s, "%c%02d",
2907  (tm->tm_gmtoff >= 0) ? '+' : '-',
2908  abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2909  s += strlen(s);
2910  break;
2911  case DCH_TZM:
2913  sprintf(s, "%02d",
2914  (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2915  s += strlen(s);
2916  break;
2917  case DCH_OF:
2919  sprintf(s, "%c%0*d",
2920  (tm->tm_gmtoff >= 0) ? '+' : '-',
2921  S_FM(n->suffix) ? 0 : 2,
2922  abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2923  s += strlen(s);
2924  if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2925  {
2926  sprintf(s, ":%02d",
2927  (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2928  s += strlen(s);
2929  }
2930  break;
2931  case DCH_A_D:
2932  case DCH_B_C:
2934  strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2935  s += strlen(s);
2936  break;
2937  case DCH_AD:
2938  case DCH_BC:
2940  strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2941  s += strlen(s);
2942  break;
2943  case DCH_a_d:
2944  case DCH_b_c:
2946  strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2947  s += strlen(s);
2948  break;
2949  case DCH_ad:
2950  case DCH_bc:
2952  strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2953  s += strlen(s);
2954  break;
2955  case DCH_MONTH:
2957  if (!tm->tm_mon)
2958  break;
2959  if (S_TM(n->suffix))
2960  {
2962 
2963  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2964  strcpy(s, str);
2965  else
2966  ereport(ERROR,
2967  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2968  errmsg("localized string format value too long")));
2969  }
2970  else
2971  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2973  s += strlen(s);
2974  break;
2975  case DCH_Month:
2977  if (!tm->tm_mon)
2978  break;
2979  if (S_TM(n->suffix))
2980  {
2982 
2983  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2984  strcpy(s, str);
2985  else
2986  ereport(ERROR,
2987  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2988  errmsg("localized string format value too long")));
2989  }
2990  else
2991  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2992  months_full[tm->tm_mon - 1]);
2993  s += strlen(s);
2994  break;
2995  case DCH_month:
2997  if (!tm->tm_mon)
2998  break;
2999  if (S_TM(n->suffix))
3000  {
3002 
3003  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3004  strcpy(s, str);
3005  else
3006  ereport(ERROR,
3007  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3008  errmsg("localized string format value too long")));
3009  }
3010  else
3011  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
3013  s += strlen(s);
3014  break;
3015  case DCH_MON:
3017  if (!tm->tm_mon)
3018  break;
3019  if (S_TM(n->suffix))
3020  {
3022 
3023  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3024  strcpy(s, str);
3025  else
3026  ereport(ERROR,
3027  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3028  errmsg("localized string format value too long")));
3029  }
3030  else
3031  strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
3032  s += strlen(s);
3033  break;
3034  case DCH_Mon:
3036  if (!tm->tm_mon)
3037  break;
3038  if (S_TM(n->suffix))
3039  {
3041 
3042  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3043  strcpy(s, str);
3044  else
3045  ereport(ERROR,
3046  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3047  errmsg("localized string format value too long")));
3048  }
3049  else
3050  strcpy(s, months[tm->tm_mon - 1]);
3051  s += strlen(s);
3052  break;
3053  case DCH_mon:
3055  if (!tm->tm_mon)
3056  break;
3057  if (S_TM(n->suffix))
3058  {
3060 
3061  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3062  strcpy(s, str);
3063  else
3064  ereport(ERROR,
3065  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3066  errmsg("localized string format value too long")));
3067  }
3068  else
3069  strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
3070  s += strlen(s);
3071  break;
3072  case DCH_MM:
3073  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
3074  tm->tm_mon);
3075  if (S_THth(n->suffix))
3076  str_numth(s, s, S_TH_TYPE(n->suffix));
3077  s += strlen(s);
3078  break;
3079  case DCH_DAY:
3081  if (S_TM(n->suffix))
3082  {
3084 
3085  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3086  strcpy(s, str);
3087  else
3088  ereport(ERROR,
3089  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3090  errmsg("localized string format value too long")));
3091  }
3092  else
3093  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
3095  s += strlen(s);
3096  break;
3097  case DCH_Day:
3099  if (S_TM(n->suffix))
3100  {
3102 
3103  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3104  strcpy(s, str);
3105  else
3106  ereport(ERROR,
3107  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3108  errmsg("localized string format value too long")));
3109  }
3110  else
3111  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
3112  days[tm->tm_wday]);
3113  s += strlen(s);
3114  break;
3115  case DCH_day:
3117  if (S_TM(n->suffix))
3118  {
3120 
3121  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3122  strcpy(s, str);
3123  else
3124  ereport(ERROR,
3125  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3126  errmsg("localized string format value too long")));
3127  }
3128  else
3129  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
3131  s += strlen(s);
3132  break;
3133  case DCH_DY:
3135  if (S_TM(n->suffix))
3136  {
3138 
3139  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3140  strcpy(s, str);
3141  else
3142  ereport(ERROR,
3143  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3144  errmsg("localized string format value too long")));
3145  }
3146  else
3147  strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
3148  s += strlen(s);
3149  break;
3150  case DCH_Dy:
3152  if (S_TM(n->suffix))
3153  {
3155 
3156  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3157  strcpy(s, str);
3158  else
3159  ereport(ERROR,
3160  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3161  errmsg("localized string format value too long")));
3162  }
3163  else
3164  strcpy(s, days_short[tm->tm_wday]);
3165  s += strlen(s);
3166  break;
3167  case DCH_dy:
3169  if (S_TM(n->suffix))
3170  {
3172 
3173  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
3174  strcpy(s, str);
3175  else
3176  ereport(ERROR,
3177  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
3178  errmsg("localized string format value too long")));
3179  }
3180  else
3181  strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
3182  s += strlen(s);
3183  break;
3184  case DCH_DDD:
3185  case DCH_IDDD:
3186  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
3187  (n->key->id == DCH_DDD) ?
3188  tm->tm_yday :
3190  if (S_THth(n->suffix))
3191  str_numth(s, s, S_TH_TYPE(n->suffix));
3192  s += strlen(s);
3193  break;
3194  case DCH_DD:
3195  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
3196  if (S_THth(n->suffix))
3197  str_numth(s, s, S_TH_TYPE(n->suffix));
3198  s += strlen(s);
3199  break;
3200  case DCH_D:
3202  sprintf(s, "%d", tm->tm_wday + 1);
3203  if (S_THth(n->suffix))
3204  str_numth(s, s, S_TH_TYPE(n->suffix));
3205  s += strlen(s);
3206  break;
3207  case DCH_ID:
3209  sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
3210  if (S_THth(n->suffix))
3211  str_numth(s, s, S_TH_TYPE(n->suffix));
3212  s += strlen(s);
3213  break;
3214  case DCH_WW:
3215  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
3216  (tm->tm_yday - 1) / 7 + 1);
3217  if (S_THth(n->suffix))
3218  str_numth(s, s, S_TH_TYPE(n->suffix));
3219  s += strlen(s);
3220  break;
3221  case DCH_IW:
3222  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
3224  if (S_THth(n->suffix))
3225  str_numth(s, s, S_TH_TYPE(n->suffix));
3226  s += strlen(s);
3227  break;
3228  case DCH_Q:
3229  if (!tm->tm_mon)
3230  break;
3231  sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
3232  if (S_THth(n->suffix))
3233  str_numth(s, s, S_TH_TYPE(n->suffix));
3234  s += strlen(s);
3235  break;
3236  case DCH_CC:
3237  if (is_interval) /* straight calculation */
3238  i = tm->tm_year / 100;
3239  else
3240  {
3241  if (tm->tm_year > 0)
3242  /* Century 20 == 1901 - 2000 */
3243  i = (tm->tm_year - 1) / 100 + 1;
3244  else
3245  /* Century 6BC == 600BC - 501BC */
3246  i = tm->tm_year / 100 - 1;
3247  }
3248  if (i <= 99 && i >= -99)
3249  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
3250  else
3251  sprintf(s, "%d", i);
3252  if (S_THth(n->suffix))
3253  str_numth(s, s, S_TH_TYPE(n->suffix));
3254  s += strlen(s);
3255  break;
3256  case DCH_Y_YYY:
3257  i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
3258  sprintf(s, "%d,%03d", i,
3259  ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
3260  if (S_THth(n->suffix))
3261  str_numth(s, s, S_TH_TYPE(n->suffix));
3262  s += strlen(s);
3263  break;
3264  case DCH_YYYY:
3265  case DCH_IYYY:
3266  sprintf(s, "%0*d",
3267  S_FM(n->suffix) ? 0 :
3268  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
3269  (n->key->id == DCH_YYYY ?
3270  ADJUST_YEAR(tm->tm_year, is_interval) :
3272  tm->tm_mon,
3273  tm->tm_mday),
3274  is_interval)));
3275  if (S_THth(n->suffix))
3276  str_numth(s, s, S_TH_TYPE(n->suffix));
3277  s += strlen(s);
3278  break;
3279  case DCH_YYY:
3280  case DCH_IYY:
3281  sprintf(s, "%0*d",
3282  S_FM(n->suffix) ? 0 :
3283  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
3284  (n->key->id == DCH_YYY ?
3285  ADJUST_YEAR(tm->tm_year, is_interval) :
3287  tm->tm_mon,
3288  tm->tm_mday),
3289  is_interval)) % 1000);
3290  if (S_THth(n->suffix))
3291  str_numth(s, s, S_TH_TYPE(n->suffix));
3292  s += strlen(s);
3293  break;
3294  case DCH_YY:
3295  case DCH_IY:
3296  sprintf(s, "%0*d",
3297  S_FM(n->suffix) ? 0 :
3298  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
3299  (n->key->id == DCH_YY ?
3300  ADJUST_YEAR(tm->tm_year, is_interval) :
3302  tm->tm_mon,
3303  tm->tm_mday),
3304  is_interval)) % 100);
3305  if (S_THth(n->suffix))
3306  str_numth(s, s, S_TH_TYPE(n->suffix));
3307  s += strlen(s);
3308  break;
3309  case DCH_Y:
3310  case DCH_I:
3311  sprintf(s, "%1d",
3312  (n->key->id == DCH_Y ?
3313  ADJUST_YEAR(tm->tm_year, is_interval) :
3315  tm->tm_mon,
3316  tm->tm_mday),
3317  is_interval)) % 10);
3318  if (S_THth(n->suffix))
3319  str_numth(s, s, S_TH_TYPE(n->suffix));
3320  s += strlen(s);
3321  break;
3322  case DCH_RM:
3323  /* FALLTHROUGH */
3324  case DCH_rm:
3325 
3326  /*
3327  * For intervals, values like '12 month' will be reduced to 0
3328  * month and some years. These should be processed.
3329  */
3330  if (!tm->tm_mon && !tm->tm_year)
3331  break;
3332  else
3333  {
3334  int mon = 0;
3335  const char *const *months;
3336 
3337  if (n->key->id == DCH_RM)
3339  else
3341 
3342  /*
3343  * Compute the position in the roman-numeral array. Note
3344  * that the contents of the array are reversed, December
3345  * being first and January last.
3346  */
3347  if (tm->tm_mon == 0)
3348  {
3349  /*
3350  * This case is special, and tracks the case of full
3351  * interval years.
3352  */
3353  mon = tm->tm_year >= 0 ? 0 : MONTHS_PER_YEAR - 1;
3354  }
3355  else if (tm->tm_mon < 0)
3356  {
3357  /*
3358  * Negative case. In this case, the calculation is
3359  * reversed, where -1 means December, -2 November,
3360  * etc.
3361  */
3362  mon = -1 * (tm->tm_mon + 1);
3363  }
3364  else
3365  {
3366  /*
3367  * Common case, with a strictly positive value. The
3368  * position in the array matches with the value of
3369  * tm_mon.
3370  */
3371  mon = MONTHS_PER_YEAR - tm->tm_mon;
3372  }
3373 
3374  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
3375  months[mon]);
3376  s += strlen(s);
3377  }
3378  break;
3379  case DCH_W:
3380  sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
3381  if (S_THth(n->suffix))
3382  str_numth(s, s, S_TH_TYPE(n->suffix));
3383  s += strlen(s);
3384  break;
3385  case DCH_J:
3386  sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
3387  if (S_THth(n->suffix))
3388  str_numth(s, s, S_TH_TYPE(n->suffix));
3389  s += strlen(s);
3390  break;
3391  }
3392  }
3393 
3394  *s = '\0';
3395 }
int date2j(int year, int month, int day)
Definition: datetime.c:286
int date2isoweek(int year, int mon, int mday)
Definition: timestamp.c:5155
int date2isoyearday(int year, int mon, int mday)
Definition: timestamp.c:5267
int date2isoyear(int year, int mon, int mday)
Definition: timestamp.c:5210
#define SECS_PER_HOUR
Definition: timestamp.h:127
#define SECS_PER_MINUTE
Definition: timestamp.h:128
#define HOURS_PER_DAY
Definition: timestamp.h:118
#define ereport(elevel,...)
Definition: elog.h:149
#define ad_STR
Definition: formatting.c:199
#define bc_STR
Definition: formatting.c:204
#define AD_STR
Definition: formatting.c:198
static char * asc_tolower_z(const char *buff)
Definition: formatting.c:2253
static char * str_numth(char *dest, char *num, int type)
Definition: formatting.c:1561
#define a_d_STR
Definition: formatting.c:197
#define DCH_to_char_fsec(frac_fmt, frac_val)
#define PM_STR
Definition: formatting.c:230
#define BC_STR
Definition: formatting.c:203
#define a_m_STR
Definition: formatting.c:224
#define A_D_STR
Definition: formatting.c:196
static char * str_initcap_z(const char *buff, Oid collid)
Definition: formatting.c:2247
#define pm_STR
Definition: formatting.c:231
static char * str_tolower_z(const char *buff, Oid collid)
Definition: formatting.c:2235
#define B_C_STR
Definition: formatting.c:201
#define ADJUST_YEAR(year, is_interval)
Definition: formatting.c:194
static char * str_toupper_z(const char *buff, Oid collid)
Definition: formatting.c:2241
#define TM_SUFFIX_LEN
Definition: formatting.c:566
#define b_c_STR
Definition: formatting.c:202
#define INVALID_FOR_INTERVAL
Definition: formatting.c:525
#define S_FM(_s)
Definition: formatting.c:558
#define tmtcTzn(_X)
Definition: formatting.c:490
static char * asc_toupper_z(const char *buff)
Definition: formatting.c:2259
#define P_M_STR
Definition: formatting.c:228
#define p_m_STR
Definition: formatting.c:229
#define A_M_STR
Definition: formatting.c:223
#define am_STR
Definition: formatting.c:226
#define AM_STR
Definition: formatting.c:225
static const char *const rm_months_upper[]
Definition: formatting.c:252
static struct pg_tm tm
Definition: localtime.c:104
int len
Definition: formatting.c:147
struct fmt_tm tm
Definition: formatting.c:484
fsec_t fsec
Definition: formatting.c:485
int tm_hour
Definition: pgtime.h:38
int tm_mday
Definition: pgtime.h:39
int tm_mon
Definition: pgtime.h:40
int tm_min
Definition: pgtime.h:37
int tm_yday
Definition: pgtime.h:43
int tm_wday
Definition: pgtime.h:42
int tm_sec
Definition: pgtime.h:36
long int tm_gmtoff
Definition: pgtime.h:45
int tm_year
Definition: pgtime.h:41

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

Referenced by datetime_to_char_body().

◆ do_to_timestamp()

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

Definition at line 4681 of file formatting.c.

4684 {
4685  FormatNode *format = NULL;
4686  TmFromChar tmfc;
4687  int fmt_len;
4688  char *date_str;
4689  int fmask;
4690  bool incache = false;
4691 
4692  Assert(tm != NULL);
4693  Assert(fsec != NULL);
4694 
4695  date_str = text_to_cstring(date_txt);
4696 
4697  ZERO_tmfc(&tmfc);
4698  ZERO_tm(tm);
4699  *fsec = 0;
4700  tz->has_tz = false;
4701  if (fprec)
4702  *fprec = 0;
4703  if (flags)
4704  *flags = 0;
4705  fmask = 0; /* bit mask for ValidateDate() */
4706 
4707  fmt_len = VARSIZE_ANY_EXHDR(fmt);
4708 
4709  if (fmt_len)
4710  {
4711  char *fmt_str;
4712 
4713  fmt_str = text_to_cstring(fmt);
4714 
4715  if (fmt_len > DCH_CACHE_SIZE)
4716  {
4717  /*
4718  * Allocate new memory if format picture is bigger than static
4719  * cache and do not use cache (call parser always)
4720  */
4721  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
4722 
4724  DCH_FLAG | (std ? STD_FLAG : 0), NULL);
4725  }
4726  else
4727  {
4728  /*
4729  * Use cache buffers
4730  */
4731  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, std);
4732 
4733  incache = true;
4734  format = ent->format;
4735  }
4736 
4737 #ifdef DEBUG_TO_FROM_CHAR
4738  /* dump_node(format, fmt_len); */
4739  /* dump_index(DCH_keywords, DCH_index); */
4740 #endif
4741 
4742  DCH_from_char(format, date_str, &tmfc, collid, std, escontext);
4743  pfree(fmt_str);
4744  if (SOFT_ERROR_OCCURRED(escontext))
4745  goto fail;
4746 
4747  if (flags)
4748  *flags = DCH_datetime_type(format);
4749 
4750  if (!incache)
4751  {
4752  pfree(format);
4753  format = NULL;
4754  }
4755  }
4756 
4757  DEBUG_TMFC(&tmfc);
4758 
4759  /*
4760  * Convert to_date/to_timestamp input fields to standard 'tm'
4761  */
4762  if (tmfc.ssss)
4763  {
4764  int x = tmfc.ssss;
4765 
4766  tm->tm_hour = x / SECS_PER_HOUR;
4767  x %= SECS_PER_HOUR;
4768  tm->tm_min = x / SECS_PER_MINUTE;
4769  x %= SECS_PER_MINUTE;
4770  tm->tm_sec = x;
4771  }
4772 
4773  if (tmfc.ss)
4774  tm->tm_sec = tmfc.ss;
4775  if (tmfc.mi)
4776  tm->tm_min = tmfc.mi;
4777  if (tmfc.hh)
4778  tm->tm_hour = tmfc.hh;
4779 
4780  if (tmfc.clock == CLOCK_12_HOUR)
4781  {
4782  if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
4783  {
4784  errsave(escontext,
4785  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4786  errmsg("hour \"%d\" is invalid for the 12-hour clock",
4787  tm->tm_hour),
4788  errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
4789  goto fail;
4790  }
4791 
4792  if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
4793  tm->tm_hour += HOURS_PER_DAY / 2;
4794  else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
4795  tm->tm_hour = 0;
4796  }
4797 
4798  if (tmfc.year)
4799  {
4800  /*
4801  * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
4802  * the year in the given century. Keep in mind that the 21st century
4803  * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
4804  * 600BC to 501BC.
4805  */
4806  if (tmfc.cc && tmfc.yysz <= 2)
4807  {
4808  if (tmfc.bc)
4809  tmfc.cc = -tmfc.cc;
4810  tm->tm_year = tmfc.year % 100;
4811  if (tm->tm_year)
4812  {
4813  if (tmfc.cc >= 0)
4814  tm->tm_year += (tmfc.cc - 1) * 100;
4815  else
4816  tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1;
4817  }
4818  else
4819  {
4820  /* find century year for dates ending in "00" */
4821  tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
4822  }
4823  }
4824  else
4825  {
4826  /* If a 4-digit year is provided, we use that and ignore CC. */
4827  tm->tm_year = tmfc.year;
4828  if (tmfc.bc)
4829  tm->tm_year = -tm->tm_year;
4830  /* correct for our representation of BC years */
4831  if (tm->tm_year < 0)
4832  tm->tm_year++;
4833  }
4834  fmask |= DTK_M(YEAR);
4835  }
4836  else if (tmfc.cc)
4837  {
4838  /* use first year of century */
4839  if (tmfc.bc)
4840  tmfc.cc = -tmfc.cc;
4841  if (tmfc.cc >= 0)
4842  /* +1 because 21st century started in 2001 */
4843  tm->tm_year = (tmfc.cc - 1) * 100 + 1;
4844  else
4845  /* +1 because year == 599 is 600 BC */
4846  tm->tm_year = tmfc.cc * 100 + 1;
4847  fmask |= DTK_M(YEAR);
4848  }
4849 
4850  if (tmfc.j)
4851  {
4852  j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4853  fmask |= DTK_DATE_M;
4854  }
4855 
4856  if (tmfc.ww)
4857  {
4858  if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4859  {
4860  /*
4861  * If tmfc.d is not set, then the date is left at the beginning of
4862  * the ISO week (Monday).
4863  */
4864  if (tmfc.d)
4865  isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4866  else
4867  isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4868  fmask |= DTK_DATE_M;
4869  }
4870  else
4871  tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
4872  }
4873 
4874  if (tmfc.w)
4875  tmfc.dd = (tmfc.w - 1) * 7 + 1;
4876  if (tmfc.dd)
4877  {
4878  tm->tm_mday = tmfc.dd;
4879  fmask |= DTK_M(DAY);
4880  }
4881  if (tmfc.mm)
4882  {
4883  tm->tm_mon = tmfc.mm;
4884  fmask |= DTK_M(MONTH);
4885  }
4886 
4887  if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
4888  {
4889  /*
4890  * The month and day field have not been set, so we use the
4891  * day-of-year field to populate them. Depending on the date mode,
4892  * this field may be interpreted as a Gregorian day-of-year, or an ISO
4893  * week date day-of-year.
4894  */
4895 
4896  if (!tm->tm_year && !tmfc.bc)
4897  {
4898  errsave(escontext,
4899  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4900  errmsg("cannot calculate day of year without year information")));
4901  goto fail;
4902  }
4903 
4904  if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
4905  {
4906  int j0; /* zeroth day of the ISO year, in Julian */
4907 
4908  j0 = isoweek2j(tm->tm_year, 1) - 1;
4909 
4910  j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
4911  fmask |= DTK_DATE_M;
4912  }
4913  else
4914  {
4915  const int *y;
4916  int i;
4917 
4918  static const int ysum[2][13] = {
4919  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
4920  {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
4921 
4922  y = ysum[isleap(tm->tm_year)];
4923 
4924  for (i = 1; i <= MONTHS_PER_YEAR; i++)
4925  {
4926  if (tmfc.ddd <= y[i])
4927  break;
4928  }
4929  if (tm->tm_mon <= 1)
4930  tm->tm_mon = i;
4931 
4932  if (tm->tm_mday <= 1)
4933  tm->tm_mday = tmfc.ddd - y[i - 1];
4934 
4935  fmask |= DTK_M(MONTH) | DTK_M(DAY);
4936  }
4937  }
4938 
4939  if (tmfc.ms)
4940  *fsec += tmfc.ms * 1000;
4941  if (tmfc.us)
4942  *fsec += tmfc.us;
4943  if (fprec)
4944  *fprec = tmfc.ff; /* fractional precision, if specified */
4945 
4946  /* Range-check date fields according to bit mask computed above */
4947  if (fmask != 0)
4948  {
4949  /* We already dealt with AD/BC, so pass isjulian = true */
4950  int dterr = ValidateDate(fmask, true, false, false, tm);
4951 
4952  if (dterr != 0)
4953  {
4954  /*
4955  * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
4956  * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
4957  * irrelevant hint about datestyle.
4958  */
4960  date_str, "timestamp", escontext);
4961  goto fail;
4962  }
4963  }
4964 
4965  /* Range-check time fields too */
4966  if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY ||
4967  tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR ||
4968  tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
4969  *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
4970  {
4972  date_str, "timestamp", escontext);
4973  goto fail;
4974  }
4975 
4976  /*
4977  * If timezone info was present, reduce it to a GMT offset. (We cannot do
4978  * this until we've filled all of the tm struct, since the zone's offset
4979  * might be time-varying.)
4980  */
4981  if (tmfc.tzsign)
4982  {
4983  /* TZH and/or TZM fields */
4984  if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
4985  tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
4986  {
4988  date_str, "timestamp", escontext);
4989  goto fail;
4990  }
4991 
4992  tz->has_tz = true;
4993  tz->gmtoffset = (tmfc.tzh * MINS_PER_HOUR + tmfc.tzm) * SECS_PER_MINUTE;
4994  /* note we are flipping the sign convention here */
4995  if (tmfc.tzsign > 0)
4996  tz->gmtoffset = -tz->gmtoffset;
4997  }
4998  else if (tmfc.has_tz)
4999  {
5000  /* TZ field */
5001  tz->has_tz = true;
5002  if (tmfc.tzp == NULL)
5003  {
5004  /* fixed-offset abbreviation; flip the sign convention */
5005  tz->gmtoffset = -tmfc.gmtoffset;
5006  }
5007  else
5008  {
5009  /* dynamic-offset abbreviation, resolve using specified time */
5011  tmfc.tzp);
5012  }
5013  }
5014 
5015  DEBUG_TM(tm);
5016 
5017  if (format && !incache)
5018  pfree(format);
5019  pfree(date_str);
5020 
5021  return true;
5022 
5023 fail:
5024  if (format && !incache)
5025  pfree(format);
5026  pfree(date_str);
5027 
5028  return false;
5029 }
void DateTimeParseError(int dterr, DateTimeErrorExtra *extra, const char *str, const char *datatype, Node *escontext)
Definition: datetime.c:4081
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2497
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:311
int DetermineTimeZoneAbbrevOffset(struct pg_tm *tm, const char *abbr, pg_tz *tzp)
Definition: datetime.c:1746
void isoweek2date(int woy, int *year, int *mon, int *mday)
Definition: timestamp.c:5124
int isoweek2j(int year, int week)
Definition: timestamp.c:5104
void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
Definition: timestamp.c:5137
#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:260
static void DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, Oid collid, bool std, Node *escontext)
Definition: formatting.c:3412
#define DEBUG_TM(_X)
Definition: formatting.c:458
#define ZERO_tmfc(_X)
Definition: formatting.c:432
#define DEBUG_TMFC(_X)
Definition: formatting.c:457
#define ZERO_tm(_X)
Definition: formatting.c:508
#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
int y
Definition: isn.c:72
int x
Definition: isn.c:71
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:52
FromCharDateMode mode
Definition: formatting.c:402
bool has_tz
Definition: formatting.c:436
int gmtoffset
Definition: formatting.c:437

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

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

◆ fill_str()

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

Definition at line 5038 of file formatting.c.

5039 {
5040  memset(str, c, max);
5041  *(str + max) = '\0';
5042  return str;
5043 }

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

6728 {
6730  text *fmt = PG_GETARG_TEXT_PP(1);
6731  NUMDesc Num;
6732  FormatNode *format;
6733  text *result;
6734  bool shouldFree;
6735  int out_pre_spaces = 0,
6736  sign = 0;
6737  char *numstr,
6738  *p;
6739 
6741 
6742  if (IS_ROMAN(&Num))
6743  numstr = int_to_roman((int) rint(value));
6744  else if (IS_EEEE(&Num))
6745  {
6746  if (isnan(value) || isinf(value))
6747  {
6748  /*
6749  * Allow 6 characters for the leading sign, the decimal point,
6750  * "e", the exponent's sign and two exponent digits.
6751  */
6752  numstr = (char *) palloc(Num.pre + Num.post + 7);
6753  fill_str(numstr, '#', Num.pre + Num.post + 6);
6754  *numstr = ' ';
6755  *(numstr + Num.pre + 1) = '.';
6756  }
6757  else
6758  {
6759  numstr = psprintf("%+.*e", Num.post, value);
6760 
6761  /*
6762  * Swap a leading positive sign for a space.
6763  */
6764  if (*numstr == '+')
6765  *numstr = ' ';
6766  }
6767  }
6768  else
6769  {
6770  float4 val = value;
6771  char *orgnum;
6772  int numstr_pre_len;
6773 
6774  if (IS_MULTI(&Num))
6775  {
6776  float multi = pow((double) 10, (double) Num.multi);
6777 
6778  val = value * multi;
6779  Num.pre += Num.multi;
6780  }
6781 
6782  orgnum = psprintf("%.0f", fabs(val));
6783  numstr_pre_len = strlen(orgnum);
6784 
6785  /* adjust post digits to fit max float digits */
6786  if (numstr_pre_len >= FLT_DIG)
6787  Num.post = 0;
6788  else if (numstr_pre_len + Num.post > FLT_DIG)
6789  Num.post = FLT_DIG - numstr_pre_len;
6790  orgnum = psprintf("%.*f", Num.post, val);
6791 
6792  if (*orgnum == '-')
6793  { /* < 0 */
6794  sign = '-';
6795  numstr = orgnum + 1;
6796  }
6797  else
6798  {
6799  sign = '+';
6800  numstr = orgnum;
6801  }
6802 
6803  if ((p = strchr(numstr, '.')))
6804  numstr_pre_len = p - numstr;
6805  else
6806  numstr_pre_len = strlen(numstr);
6807 
6808  /* needs padding? */
6809  if (numstr_pre_len < Num.pre)
6810  out_pre_spaces = Num.pre - numstr_pre_len;
6811  /* overflowed prefix digit format? */
6812  else if (numstr_pre_len > Num.pre)
6813  {
6814  numstr = (char *) palloc(Num.pre + Num.post + 2);
6815  fill_str(numstr, '#', Num.pre + Num.post + 1);
6816  *(numstr + Num.pre) = '.';
6817  }
6818  }
float float4
Definition: c.h:629
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GETARG_FLOAT4(n)
Definition: fmgr.h:281
#define NUM_TOCHAR_prepare
Definition: formatting.c:6307
#define IS_MULTI(_f)
Definition: formatting.c:334
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:5038
#define IS_ROMAN(_f)
Definition: formatting.c:333
#define IS_EEEE(_f)
Definition: formatting.c:335
static char * int_to_roman(int number)
Definition: formatting.c:5238
long val
Definition: informix.c:670
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
int pre
Definition: formatting.c:286
int multi
Definition: formatting.c:291
int post
Definition: formatting.c:287

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

◆ float8_to_char()

Datum float8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6825 of file formatting.c.

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

References fill_str(), fmt, format, int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, palloc(), PG_GETARG_FLOAT8, PG_GETARG_TEXT_PP, 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 2560 of file formatting.c.

2562 {
2563  return from_char_parse_int_len(dest, src, node->key->len, node, escontext);
2564 }

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

Referenced by DCH_from_char().

◆ from_char_parse_int_len()

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

Definition at line 2463 of file formatting.c.

2465 {
2466  long result;
2467  char copy[DCH_MAX_ITEM_SIZ + 1];
2468  const char *init = *src;
2469  int used;
2470 
2471  /*
2472  * Skip any whitespace before parsing the integer.
2473  */
2474  *src += strspace_len(*src);
2475 
2477  used = (int) strlcpy(copy, *src, len + 1);
2478 
2479  if (S_FM(node->suffix) || is_next_separator(node))
2480  {
2481  /*
2482  * This node is in Fill Mode, or the next node is known to be a
2483  * non-digit value, so we just slurp as many characters as we can get.
2484  */
2485  char *endptr;
2486 
2487  errno = 0;
2488  result = strtol(init, &endptr, 10);
2489  *src = endptr;
2490  }
2491  else
2492  {
2493  /*
2494  * We need to pull exactly the number of characters given in 'len' out
2495  * of the string, and convert those.
2496  */
2497  char *last;
2498 
2499  if (used < len)
2500  ereturn(escontext, -1,
2501  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2502  errmsg("source string too short for \"%s\" formatting field",
2503  node->key->name),
2504  errdetail("Field requires %d characters, but only %d remain.",
2505  len, used),
2506  errhint("If your source string is not fixed-width, "
2507  "try using the \"FM\" modifier.")));
2508 
2509  errno = 0;
2510  result = strtol(copy, &last, 10);
2511  used = last - copy;
2512 
2513  if (used > 0 && used < len)
2514  ereturn(escontext, -1,
2515  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2516  errmsg("invalid value \"%s\" for \"%s\"",
2517  copy, node->key->name),
2518  errdetail("Field requires %d characters, but only %d could be parsed.",
2519  len, used),
2520  errhint("If your source string is not fixed-width, "
2521  "try using the \"FM\" modifier.")));
2522 
2523  *src += used;
2524  }
2525 
2526  if (*src == init)
2527  ereturn(escontext, -1,
2528  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2529  errmsg("invalid value \"%s\" for \"%s\"",
2530  copy, node->key->name),
2531  errdetail("Value must be an integer.")));
2532 
2533  if (errno == ERANGE || result < INT_MIN || result > INT_MAX)
2534  ereturn(escontext, -1,
2535  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2536  errmsg("value for \"%s\" in source string is out of range",
2537  node->key->name),
2538  errdetail("Value must be in the range %d to %d.",
2539  INT_MIN, INT_MAX)));
2540 
2541  if (dest != NULL)
2542  {
2543  if (!from_char_set_int(dest, (int) result, node, escontext))
2544  return -1;
2545  }
2546 
2547  return *src - init;
2548 }
static bool is_next_separator(FormatNode *n)
Definition: formatting.c:2321
static int strspace_len(const char *str)
Definition: formatting.c:2378
int init
Definition: isn.c:75

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

Referenced by DCH_from_char(), and from_char_parse_int().

◆ from_char_seq_search()

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

Definition at line 2719 of file formatting.c.

2722 {
2723  int len;
2724 
2725  if (localized_array == NULL)
2726  *dest = seq_search_ascii(*src, array, &len);
2727  else
2728  *dest = seq_search_localized(*src, localized_array, &len, collid);
2729 
2730  if (len <= 0)
2731  {
2732  /*
2733  * In the error report, truncate the string at the next whitespace (if
2734  * any) to avoid including irrelevant data.
2735  */
2736  char *copy = pstrdup(*src);
2737  char *c;
2738 
2739  for (c = copy; *c; c++)
2740  {
2741  if (scanner_isspace(*c))
2742  {
2743  *c = '\0';
2744  break;
2745  }
2746  }
2747 
2748  ereturn(escontext, false,
2749  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2750  errmsg("invalid value \"%s\" for \"%s\"",
2751  copy, node->key->name),
2752  errdetail("The given value did not match any of "
2753  "the allowed values for this field.")));
2754  }
2755  *src += len;
2756  return true;
2757 }
static int seq_search_localized(const char *name, char **array, int *len, Oid collid)
Definition: formatting.c:2635
static int seq_search_ascii(const char *name, const char *const *array, int *len)
Definition: formatting.c:2578
char * pstrdup(const char *in)
Definition: mcxt.c:1695
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 2427 of file formatting.c.

2429 {
2430  if (*dest != 0 && *dest != value)
2431  ereturn(escontext, false,
2432  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2433  errmsg("conflicting values for \"%s\" field in formatting string",
2434  node->key->name),
2435  errdetail("This value contradicts a previous setting "
2436  "for the same field type.")));
2437  *dest = value;
2438  return true;
2439 }

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

2402 {
2403  if (mode != FROM_CHAR_DATE_NONE)
2404  {
2405  if (tmfc->mode == FROM_CHAR_DATE_NONE)
2406  tmfc->mode = mode;
2407  else if (tmfc->mode != mode)
2408  ereturn(escontext, false,
2409  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2410  errmsg("invalid combination of date conventions"),
2411  errhint("Do not mix Gregorian and ISO week date "
2412  "conventions in a formatting template.")));
2413  }
2414  return true;
2415 }
static PgChecksumMode mode
Definition: pg_checksums.c:56

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

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

static char * get_last_relevant_decnum ( char *  num)
static

Definition at line 5369 of file formatting.c.

5370 {
5371  char *result,
5372  *p = strchr(num, '.');
5373 
5374 #ifdef DEBUG_TO_FROM_CHAR
5375  elog(DEBUG_elog_output, "get_last_relevant_decnum()");
5376 #endif
5377 
5378  if (!p)
5379  return NULL;
5380 
5381  result = p;
5382 
5383  while (*(++p))
5384  {
5385  if (*p != '0')
5386  result = p;
5387  }
5388 
5389  return result;
5390 }

References elog.

Referenced by NUM_processor().

◆ get_th()

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

Definition at line 1516 of file formatting.c.

1517 {
1518  int len = strlen(num),
1519  last;
1520 
1521  last = *(num + (len - 1));
1522  if (!isdigit((unsigned char) last))
1523  ereport(ERROR,
1524  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1525  errmsg("\"%s\" is not a number", num)));
1526 
1527  /*
1528  * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1529  * 'ST/st', 'ND/nd', 'RD/rd', respectively
1530  */
1531  if ((len > 1) && (num[len - 2] == '1'))
1532  last = 0;
1533 
1534  switch (last)
1535  {
1536  case '1':
1537  if (type == TH_UPPER)
1538  return numTH[0];
1539  return numth[0];
1540  case '2':
1541  if (type == TH_UPPER)
1542  return numTH[1];
1543  return numth[1];
1544  case '3':
1545  if (type == TH_UPPER)
1546  return numTH[2];
1547  return numth[2];
1548  default:
1549  if (type == TH_UPPER)
1550  return numTH[3];
1551  return numth[3];
1552  }
1553 }
static const char *const numth[]
Definition: formatting.c:271
static const char *const numTH[]
Definition: formatting.c:270
#define TH_UPPER
Definition: formatting.c:277
const char * type

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

Referenced by NUM_processor(), and str_numth().

◆ index_seq_search()

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

Definition at line 1099 of file formatting.c.

1100 {
1101  int poz;
1102 
1103  if (!KeyWord_INDEX_FILTER(*str))
1104  return NULL;
1105 
1106  if ((poz = *(index + (*str - ' '))) > -1)
1107  {
1108  const KeyWord *k = kw + poz;
1109 
1110  do
1111  {
1112  if (strncmp(str, k->name, k->len) == 0)
1113  return k;
1114  k++;
1115  if (!k->name)
1116  return NULL;
1117  } while (*str == *k->name);
1118  }
1119  return NULL;
1120 }
#define KeyWord_INDEX_FILTER(_c)
Definition: formatting.c:108
Definition: type.h:95

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

Referenced by parse_format().

◆ initcap_wbnext()

static size_t initcap_wbnext ( void *  state)
static

Definition at line 1939 of file formatting.c.

1940 {
1941  struct WordBoundaryState *wbstate = (struct WordBoundaryState *) state;
1942 
1943  while (wbstate->offset < wbstate->len &&
1944  wbstate->str[wbstate->offset] != '\0')
1945  {
1946  pg_wchar u = utf8_to_unicode((unsigned char *) wbstate->str +
1947  wbstate->offset);
1948  bool curr_alnum = pg_u_isalnum(u, true);
1949 
1950  if (!wbstate->init || curr_alnum != wbstate->prev_alnum)
1951  {
1952  size_t prev_offset = wbstate->offset;
1953 
1954  wbstate->init = true;
1955  wbstate->offset += unicode_utf8len(u);
1956  wbstate->prev_alnum = curr_alnum;
1957  return prev_offset;
1958  }
1959 
1960  wbstate->offset += unicode_utf8len(u);
1961  }
1962 
1963  return wbstate->len;
1964 }
static pg_wchar utf8_to_unicode(const unsigned char *c)
Definition: mbprint.c:53
unsigned int pg_wchar
Definition: mbprint.c:31
static int unicode_utf8len(pg_wchar c)
Definition: pg_wchar.h:607
const char * str
Definition: formatting.c:1927
Definition: regguts.h:323
bool pg_u_isalnum(pg_wchar code, bool posix)

References WordBoundaryState::init, WordBoundaryState::len, WordBoundaryState::offset, pg_u_isalnum(), WordBoundaryState::prev_alnum, WordBoundaryState::str, unicode_utf8len(), and utf8_to_unicode().

Referenced by str_initcap().

◆ int4_to_char()

Datum int4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6523 of file formatting.c.

6528 {
6530  text *fmt = PG_GETARG_TEXT_PP(1);
6531  NUMDesc Num;
6532  FormatNode *format;
6533  text *result;
6534  bool shouldFree;
6535  int out_pre_spaces = 0,
6536  sign = 0;
6537  char *numstr,
6538  *orgnum;
6539 
6541 
6542  /*
6543  * On DateType depend part (int32)
6544  */
6545  if (IS_ROMAN(&Num))
6546  numstr = int_to_roman(value);
6547  else if (IS_EEEE(&Num))
6548  {
6549  /* we can do it easily because float8 won't lose any precision */
6550  float8 val = (float8) value;
6551 
6552  orgnum = (char *) psprintf("%+.*e", Num.post, val);
6553 
6554  /*
6555  * Swap a leading positive sign for a space.
6556  */
6557  if (*orgnum == '+')
6558  *orgnum = ' ';
6559 
6560  numstr = orgnum;
6561  }
6562  else
6563  {
6564  int numstr_pre_len;
6565 
6566  if (IS_MULTI(&Num))
6567  {
6569  Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
6570  Num.pre += Num.multi;
6571  }
6572  else
6573  {
6575  Int32GetDatum(value)));
6576  }
6577 
6578  if (*orgnum == '-')
6579  {
6580  sign = '-';
6581  orgnum++;
6582  }
6583  else
6584  sign = '+';
6585 
6586  numstr_pre_len = strlen(orgnum);
6587 
6588  /* post-decimal digits? Pad out with zeros. */
6589  if (Num.post)
6590  {
6591  numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6592  strcpy(numstr, orgnum);
6593  *(numstr + numstr_pre_len) = '.';
6594  memset(numstr + numstr_pre_len + 1, '0', Num.post);
6595  *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6596  }
6597  else
6598  numstr = orgnum;
6599 
6600  /* needs padding? */
6601  if (numstr_pre_len < Num.pre)
6602  out_pre_spaces = Num.pre - numstr_pre_len;
6603  /* overflowed prefix digit format? */
6604  else if (numstr_pre_len > Num.pre)
6605  {
6606  numstr = (char *) palloc(Num.pre + Num.post + 2);
6607  fill_str(numstr, '#', Num.pre + Num.post + 1);
6608  *(numstr + Num.pre) = '.';
6609  }
6610  }
signed int int32
Definition: c.h:494
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#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:335
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212

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

◆ int8_to_char()

Datum int8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6617 of file formatting.c.

6622 {
6623  int64 value = PG_GETARG_INT64(0);
6624  text *fmt = PG_GETARG_TEXT_PP(1);
6625  NUMDesc Num;
6626  FormatNode *format;
6627  text *result;
6628  bool shouldFree;
6629  int out_pre_spaces = 0,
6630  sign = 0;
6631  char *numstr,
6632  *orgnum;
6633 
6635 
6636  /*
6637  * On DateType depend part (int32)
6638  */
6639  if (IS_ROMAN(&Num))
6640  {
6641  /* Currently don't support int8 conversion to roman... */
6643  }
6644  else if (IS_EEEE(&Num))
6645  {
6646  /* to avoid loss of precision, must go via numeric not float8 */
6648  Num.post);
6649 
6650  /*
6651  * numeric_out_sci() does not emit a sign for positive numbers. We
6652  * need to add a space in this case so that positive and negative
6653  * numbers are aligned. We don't have to worry about NaN/inf here.
6654  */
6655  if (*orgnum != '-')
6656  {
6657  numstr = (char *) palloc(strlen(orgnum) + 2);
6658  *numstr = ' ';
6659  strcpy(numstr + 1, orgnum);
6660  }
6661  else
6662  {
6663  numstr = orgnum;
6664  }
6665  }
6666  else
6667  {
6668  int numstr_pre_len;
6669 
6670  if (IS_MULTI(&Num))
6671  {
6672  double multi = pow((double) 10, (double) Num.multi);
6673 
6677  Float8GetDatum(multi))));
6678  Num.pre += Num.multi;
6679  }
6680 
6682  Int64GetDatum(value)));
6683 
6684  if (*orgnum == '-')
6685  {
6686  sign = '-';
6687  orgnum++;
6688  }
6689  else
6690  sign = '+';
6691 
6692  numstr_pre_len = strlen(orgnum);
6693 
6694  /* post-decimal digits? Pad out with zeros. */
6695  if (Num.post)
6696  {
6697  numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6698  strcpy(numstr, orgnum);
6699  *(numstr + numstr_pre_len) = '.';
6700  memset(numstr + numstr_pre_len + 1, '0', Num.post);
6701  *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6702  }
6703  else
6704  numstr = orgnum;
6705 
6706  /* needs padding? */
6707  if (numstr_pre_len < Num.pre)
6708  out_pre_spaces = Num.pre - numstr_pre_len;
6709  /* overflowed prefix digit format? */
6710  else if (numstr_pre_len > Num.pre)
6711  {
6712  numstr = (char *) palloc(Num.pre + Num.post + 2);
6713  fill_str(numstr, '#', Num.pre + Num.post + 1);
6714  *(numstr + Num.pre) = '.';
6715  }
6716  }
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4283
char * numeric_out_sci(Numeric num, int scale)
Definition: numeric.c:983
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1816
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
Datum int8out(PG_FUNCTION_ARGS)
Definition: int8.c:61
Datum int84(PG_FUNCTION_ARGS)
Definition: int8.c:1249
Datum int8mul(PG_FUNCTION_ARGS)
Definition: int8.c:490
Datum dtoi8(PG_FUNCTION_ARGS)
Definition: int8.c:1297
static int64 DatumGetInt64(Datum X)
Definition: postgres.h:385
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202

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

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 5238 of file formatting.c.

5239 {
5240  int len,
5241  num;
5242  char *p,
5243  *result,
5244  numstr[12];
5245 
5246  result = (char *) palloc(16);
5247  *result = '\0';
5248 
5249  if (number > 3999 || number < 1)
5250  {
5251  fill_str(result, '#', 15);
5252  return result;
5253  }
5254  len = snprintf(numstr, sizeof(numstr), "%d", number);
5255 
5256  for (p = numstr; *p != '\0'; p++, --len)
5257  {
5258  num = *p - ('0' + 1);
5259  if (num < 0)
5260  continue;
5261 
5262  if (len > 3)
5263  {
5264  while (num-- != -1)
5265  strcat(result, "M");
5266  }
5267  else
5268  {
5269  if (len == 3)
5270  strcat(result, rm100[num]);
5271  else if (len == 2)
5272  strcat(result, rm10[num]);
5273  else if (len == 1)
5274  strcat(result, rm1[num]);
5275  }
5276  }
5277  return result;
5278 }
static const char *const rm100[]
Definition: formatting.c:264
static const char *const rm10[]
Definition: formatting.c:263
static const char *const rm1[]
Definition: formatting.c:262
#define snprintf
Definition: port.h:238

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

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

◆ interval_to_char()

Datum interval_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4326 of file formatting.c.

4327 {
4328  Interval *it = PG_GETARG_INTERVAL_P(0);
4329  text *fmt = PG_GETARG_TEXT_PP(1),
4330  *res;
4331  TmToChar tmtc;
4332  struct fmt_tm *tm;
4333  struct pg_itm tt,
4334  *itm = &tt;
4335 
4336  if (VARSIZE_ANY_EXHDR(fmt) <= 0 || INTERVAL_NOT_FINITE(it))
4337  PG_RETURN_NULL();
4338 
4339  ZERO_tmtc(&tmtc);
4340  tm = tmtcTm(&tmtc);
4341 
4342  interval2itm(*it, itm);
4343  tmtc.fsec = itm->tm_usec;
4344  tm->tm_sec = itm->tm_sec;
4345  tm->tm_min = itm->tm_min;
4346  tm->tm_hour = itm->tm_hour;
4347  tm->tm_mday = itm->tm_mday;
4348  tm->tm_mon = itm->tm_mon;
4349  tm->tm_year = itm->tm_year;
4350 
4351  /* wday is meaningless, yday approximates the total span in days */
4353 
4354  if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4355  PG_RETURN_NULL();
4356 
4358 }
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, text *fmt, bool is_interval, Oid collid)
Definition: formatting.c:4181
#define ZERO_tmtc(_X)
Definition: formatting.c:514
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, fmt, 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, res, 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 2321 of file formatting.c.

2322 {
2323  if (n->type == NODE_TYPE_END)
2324  return false;
2325 
2326  if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
2327  return true;
2328 
2329  /*
2330  * Next node
2331  */
2332  n++;
2333 
2334  /* end of format string is treated like a non-digit separator */
2335  if (n->type == NODE_TYPE_END)
2336  return true;
2337 
2338  if (n->type == NODE_TYPE_ACTION)
2339  {
2340  if (n->key->is_digit)
2341  return false;
2342 
2343  return true;
2344  }
2345  else if (n->character[1] == '\0' &&
2346  isdigit((unsigned char) n->character[0]))
2347  return false;
2348 
2349  return true; /* some non-digit input (separator) */
2350 }
bool is_digit
Definition: formatting.c:149

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

Referenced by from_char_parse_int_len().

◆ is_separator_char()

static bool is_separator_char ( const char *  str)
static

Definition at line 1139 of file formatting.c.

1140 {
1141  /* ASCII printable character, but not letter or digit */
1142  return (*str > 0x20 && *str < 0x7F &&
1143  !(*str >= 'A' && *str <= 'Z') &&
1144  !(*str >= 'a' && *str <= 'z') &&
1145  !(*str >= '0' && *str <= '9'));
1146 }

References str.

Referenced by DCH_from_char(), and parse_format().

◆ NUM_cache()

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

Definition at line 5180 of file formatting.c.

5181 {
5182  FormatNode *format = NULL;
5183  char *str;
5184 
5185  str = text_to_cstring(pars_str);
5186 
5187  if (len > NUM_CACHE_SIZE)
5188  {
5189  /*
5190  * Allocate new memory if format picture is bigger than static cache
5191  * and do not use cache (call parser always)
5192  */
5193  format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
5194 
5195  *shouldFree = true;
5196 
5197  zeroize_NUM(Num);
5198 
5200  NULL, NUM_index, NUM_FLAG, Num);
5201  }
5202  else
5203  {
5204  /*
5205  * Use cache buffers
5206  */
5208 
5209  *shouldFree = false;
5210 
5211  format = ent->format;
5212 
5213  /*
5214  * Copy cache to used struct
5215  */
5216  Num->flag = ent->Num.flag;
5217  Num->lsign = ent->Num.lsign;
5218  Num->pre = ent->Num.pre;
5219  Num->post = ent->Num.post;
5220  Num->pre_lsign_num = ent->Num.pre_lsign_num;
5221  Num->need_locale = ent->Num.need_locale;
5222  Num->multi = ent->Num.multi;
5223  Num->zero_start = ent->Num.zero_start;
5224  Num->zero_end = ent->Num.zero_end;
5225  }
5226 
5227 #ifdef DEBUG_TO_FROM_CHAR
5228  /* dump_node(format, len); */
5229  dump_index(NUM_keywords, NUM_index);
5230 #endif
5231 
5232  pfree(str);
5233  return format;
5234 }
static const KeyWord NUM_keywords[]
Definition: formatting.c:900
#define NUM_CACHE_SIZE
Definition: formatting.c:362
static NUMCacheEntry * NUM_cache_fetch(const char *str)
Definition: formatting.c:5152
#define NUM_FLAG
Definition: formatting.c:100
#define zeroize_NUM(_n)
Definition: formatting.c:5045
static const int NUM_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:972
NUMDesc Num
Definition: formatting.c:383
FormatNode format[NUM_CACHE_SIZE+1]
Definition: formatting.c:379
int pre_lsign_num
Definition: formatting.c:290
int need_locale
Definition: formatting.c:294
int zero_end
Definition: formatting.c:293
int flag
Definition: formatting.c:289
int lsign
Definition: formatting.c:288
int zero_start
Definition: formatting.c:292

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

Referenced by numeric_to_number().

◆ NUM_cache_fetch()

static NUMCacheEntry * NUM_cache_fetch ( const char *  str)
static

Definition at line 5152 of file formatting.c.

5153 {
5154  NUMCacheEntry *ent;
5155 
5156  if ((ent = NUM_cache_search(str)) == NULL)
5157  {
5158  /*
5159  * Not in the cache, must run parser and save a new format-picture to
5160  * the cache. Do not mark the cache entry valid until parsing
5161  * succeeds.
5162  */
5163  ent = NUM_cache_getnew(str);
5164 
5165  zeroize_NUM(&ent->Num);
5166 
5168  NULL, NUM_index, NUM_FLAG, &ent->Num);
5169 
5170  ent->valid = true;
5171  }
5172  return ent;
5173 }
static NUMCacheEntry * NUM_cache_getnew(const char *str)
Definition: formatting.c:5072
static NUMCacheEntry * NUM_cache_search(const char *str)
Definition: formatting.c:5131

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

Referenced by NUM_cache().

◆ NUM_cache_getnew()

static NUMCacheEntry * NUM_cache_getnew ( const char *  str)
static

Definition at line 5072 of file formatting.c.

5073 {
5074  NUMCacheEntry *ent;
5075 
5076  /* Ensure we can advance NUMCounter below */
5078 
5079  /*
5080  * If cache is full, remove oldest entry (or recycle first not-valid one)
5081  */
5083  {
5084  NUMCacheEntry *old = NUMCache[0];
5085 
5086 #ifdef DEBUG_TO_FROM_CHAR
5087  elog(DEBUG_elog_output, "Cache is full (%d)", n_NUMCache);
5088 #endif
5089  if (old->valid)
5090  {
5091  for (int i = 1; i < NUM_CACHE_ENTRIES; i++)
5092  {
5093  ent = NUMCache[i];
5094  if (!ent->valid)
5095  {
5096  old = ent;
5097  break;
5098  }
5099  if (ent->age < old->age)
5100  old = ent;
5101  }
5102  }
5103 #ifdef DEBUG_TO_FROM_CHAR
5104  elog(DEBUG_elog_output, "OLD: \"%s\" AGE: %d", old->str, old->age);
5105 #endif
5106  old->valid = false;
5107  strlcpy(old->str, str, NUM_CACHE_SIZE + 1);
5108  old->age = (++NUMCounter);
5109  /* caller is expected to fill format and Num, then set valid */
5110  return old;
5111  }
5112  else
5113  {
5114 #ifdef DEBUG_TO_FROM_CHAR
5115  elog(DEBUG_elog_output, "NEW (%d)", n_NUMCache);
5116 #endif
5117  Assert(NUMCache[n_NUMCache] == NULL);
5118  NUMCache[n_NUMCache] = ent = (NUMCacheEntry *)
5120  ent->valid = false;
5121  strlcpy(ent->str, str, NUM_CACHE_SIZE + 1);
5122  ent->age = (++NUMCounter);
5123  /* caller is expected to fill format and Num, then set valid */
5124  ++n_NUMCache;
5125  return ent;
5126  }
5127 }
static NUMCacheEntry * NUMCache[NUM_CACHE_ENTRIES]
Definition: formatting.c:392
#define NUM_CACHE_ENTRIES
Definition: formatting.c:366
static void NUM_prevent_counter_overflow(void)
Definition: formatting.c:5060
static int NUMCounter
Definition: formatting.c:394
static int n_NUMCache
Definition: formatting.c:393
char str[NUM_CACHE_SIZE+1]
Definition: formatting.c:380

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

5132 {
5133  /* Ensure we can advance NUMCounter below */
5135 
5136  for (int i = 0; i < n_NUMCache; i++)
5137  {
5138  NUMCacheEntry *ent = NUMCache[i];
5139 
5140  if (ent->valid && strcmp(ent->str, str) == 0)
5141  {
5142  ent->age = (++NUMCounter);
5143  return ent;
5144  }
5145  }
5146 
5147  return NULL;
5148 }

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

Referenced by NUM_cache_fetch().

◆ NUM_eat_non_data_chars()

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

Definition at line 5810 of file formatting.c.

5811 {
5812  while (n-- > 0)
5813  {
5814  if (OVERLOAD_TEST)
5815  break; /* end of input */
5816  if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
5817  break; /* it's a data character */
5818  Np->inout_p += pg_mblen(Np->inout_p);
5819  }
5820 }
#define OVERLOAD_TEST
Definition: formatting.c:5397
char * inout_p
Definition: formatting.c:1015

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

Referenced by NUM_processor().

◆ NUM_numpart_from_char()

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

Definition at line 5405 of file formatting.c.

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

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

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

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

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

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

5061 {
5062  if (NUMCounter >= (INT_MAX - 1))
5063  {
5064  for (int i = 0; i < n_NUMCache; i++)
5065  NUMCache[i]->age >>= 1;
5066  NUMCounter >>= 1;
5067  }
5068 }

References i, n_NUMCache, NUMCache, and NUMCounter.

Referenced by NUM_cache_getnew(), and NUM_cache_search().

◆ NUM_processor()

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

Definition at line 5823 of file formatting.c.

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

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_F_BRACKET, NUM_F_FILLMODE, NUM_F_ROMAN, 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, 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 1153 of file formatting.c.

1154 {
1155  if (n->type != NODE_TYPE_ACTION)
1156  return;
1157 
1158  if (IS_EEEE(num) && n->key->id != NUM_E)
1159  ereport(ERROR,
1160  (errcode(ERRCODE_SYNTAX_ERROR),
1161  errmsg("\"EEEE\" must be the last pattern used")));
1162 
1163  switch (n->key->id)
1164  {
1165  case NUM_9:
1166  if (IS_BRACKET(num))
1167  ereport(ERROR,
1168  (errcode(ERRCODE_SYNTAX_ERROR),
1169  errmsg("\"9\" must be ahead of \"PR\"")));
1170  if (IS_MULTI(num))
1171  {
1172  ++num->multi;
1173  break;
1174  }
1175  if (IS_DECIMAL(num))
1176  ++num->post;
1177  else
1178  ++num->pre;
1179  break;
1180 
1181  case NUM_0:
1182  if (IS_BRACKET(num))
1183  ereport(ERROR,
1184  (errcode(ERRCODE_SYNTAX_ERROR),
1185  errmsg("\"0\" must be ahead of \"PR\"")));
1186  if (!IS_ZERO(num) && !IS_DECIMAL(num))
1187  {
1188  num->flag |= NUM_F_ZERO;
1189  num->zero_start = num->pre + 1;
1190  }
1191  if (!IS_DECIMAL(num))
1192  ++num->pre;
1193  else
1194  ++num->post;
1195 
1196  num->zero_end = num->pre + num->post;
1197  break;
1198 
1199  case NUM_B:
1200  if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num)))
1201  num->flag |= NUM_F_BLANK;
1202  break;
1203 
1204  case NUM_D:
1205  num->flag |= NUM_F_LDECIMAL;
1206  num->need_locale = true;
1207  /* FALLTHROUGH */
1208  case NUM_DEC:
1209  if (IS_DECIMAL(num))
1210  ereport(ERROR,
1211  (errcode(ERRCODE_SYNTAX_ERROR),
1212  errmsg("multiple decimal points")));
1213  if (IS_MULTI(num))
1214  ereport(ERROR,
1215  (errcode(ERRCODE_SYNTAX_ERROR),
1216  errmsg("cannot use \"V\" and decimal point together")));
1217  num->flag |= NUM_F_DECIMAL;
1218  break;
1219 
1220  case NUM_FM:
1221  num->flag |= NUM_F_FILLMODE;
1222  break;
1223 
1224  case NUM_S:
1225  if (IS_LSIGN(num))
1226  ereport(ERROR,
1227  (errcode(ERRCODE_SYNTAX_ERROR),
1228  errmsg("cannot use \"S\" twice")));
1229  if (IS_PLUS(num) || IS_MINUS(num) || IS_BRACKET(num))
1230  ereport(ERROR,
1231  (errcode(ERRCODE_SYNTAX_ERROR),
1232  errmsg("cannot use \"S\" and \"PL\"/\"MI\"/\"SG\"/\"PR\" together")));
1233  if (!IS_DECIMAL(num))
1234  {
1235  num->lsign = NUM_LSIGN_PRE;
1236  num->pre_lsign_num = num->pre;
1237  num->need_locale = true;
1238  num->flag |= NUM_F_LSIGN;
1239  }
1240  else if (num->lsign == NUM_LSIGN_NONE)
1241  {
1242  num->lsign = NUM_LSIGN_POST;
1243  num->need_locale = true;
1244  num->flag |= NUM_F_LSIGN;
1245  }
1246  break;
1247 
1248  case NUM_MI:
1249  if (IS_LSIGN(num))
1250  ereport(ERROR,
1251  (errcode(ERRCODE_SYNTAX_ERROR),
1252  errmsg("cannot use \"S\" and \"MI\" together")));
1253  num->flag |= NUM_F_MINUS;
1254  if (IS_DECIMAL(num))
1255  num->flag |= NUM_F_MINUS_POST;
1256  break;
1257 
1258  case NUM_PL:
1259  if (IS_LSIGN(num))
1260  ereport(ERROR,
1261  (errcode(ERRCODE_SYNTAX_ERROR),
1262  errmsg("cannot use \"S\" and \"PL\" together")));
1263  num->flag |= NUM_F_PLUS;
1264  if (IS_DECIMAL(num))
1265  num->flag |= NUM_F_PLUS_POST;
1266  break;
1267 
1268  case NUM_SG:
1269  if (IS_LSIGN(num))
1270  ereport(ERROR,
1271  (errcode(ERRCODE_SYNTAX_ERROR),
1272  errmsg("cannot use \"S\" and \"SG\" together")));
1273  num->flag |= NUM_F_MINUS;
1274  num->flag |= NUM_F_PLUS;
1275  break;
1276 
1277  case NUM_PR:
1278  if (IS_LSIGN(num) || IS_PLUS(num) || IS_MINUS(num))
1279  ereport(ERROR,
1280  (errcode(ERRCODE_SYNTAX_ERROR),
1281  errmsg("cannot use \"PR\" and \"S\"/\"PL\"/\"MI\"/\"SG\" together")));
1282  num->flag |= NUM_F_BRACKET;
1283  break;
1284 
1285  case NUM_rn:
1286  case NUM_RN:
1287  num->flag |= NUM_F_ROMAN;
1288  break;
1289 
1290  case NUM_L:
1291  case NUM_G:
1292  num->need_locale = true;
1293  break;
1294 
1295  case NUM_V:
1296  if (IS_DECIMAL(num))
1297  ereport(ERROR,
1298  (errcode(ERRCODE_SYNTAX_ERROR),
1299  errmsg("cannot use \"V\" and decimal point together")));
1300  num->flag |= NUM_F_MULTI;
1301  break;
1302 
1303  case NUM_E:
1304  if (IS_EEEE(num))
1305  ereport(ERROR,
1306  (errcode(ERRCODE_SYNTAX_ERROR),
1307  errmsg("cannot use \"EEEE\" twice")));
1308  if (IS_BLANK(num) || IS_FILLMODE(num) || IS_LSIGN(num) ||
1309  IS_BRACKET(num) || IS_MINUS(num) || IS_PLUS(num) ||
1310  IS_ROMAN(num) || IS_MULTI(num))
1311  ereport(ERROR,
1312  (errcode(ERRCODE_SYNTAX_ERROR),
1313  errmsg("\"EEEE\" is incompatible with other formats"),
1314  errdetail("\"EEEE\" may only be used together with digit and decimal point patterns.")));
1315  num->flag |= NUM_F_EEEE;
1316  break;
1317  }
1318 }
#define NUM_F_MINUS
Definition: formatting.c:308
#define NUM_F_DECIMAL
Definition: formatting.c:301
#define NUM_F_BLANK
Definition: formatting.c:304
#define NUM_LSIGN_NONE
Definition: formatting.c:318
#define IS_BLANK(_f)
Definition: formatting.c:327
#define NUM_F_MINUS_POST
Definition: formatting.c:313
#define NUM_F_LDECIMAL
Definition: formatting.c:302
#define NUM_F_PLUS_POST
Definition: formatting.c:312
#define NUM_F_MULTI
Definition: formatting.c:311
#define NUM_F_EEEE
Definition: formatting.c:314
#define NUM_F_ZERO
Definition: formatting.c:303
#define NUM_F_LSIGN
Definition: formatting.c:306
#define NUM_F_PLUS
Definition: formatting.c:309

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

6403 {
6405  text *fmt = PG_GETARG_TEXT_PP(1);
6406  NUMDesc Num;
6407  FormatNode *format;
6408  text *result;
6409  bool shouldFree;
6410  int out_pre_spaces = 0,
6411  sign = 0;
6412  char *numstr,
6413  *orgnum,
6414  *p;
6415  Numeric x;
6416 
6418 
6419  /*
6420  * On DateType depend part (numeric)
6421  */
6422  if (IS_ROMAN(&Num))
6423  {
6426  Int32GetDatum(0)));
6427  numstr =
6429  NumericGetDatum(x))));
6430  }
6431  else if (IS_EEEE(&Num))
6432  {
6433  orgnum = numeric_out_sci(value, Num.post);
6434 
6435  /*
6436  * numeric_out_sci() does not emit a sign for positive numbers. We
6437  * need to add a space in this case so that positive and negative
6438  * numbers are aligned. Also must check for NaN/infinity cases, which
6439  * we handle the same way as in float8_to_char.
6440  */
6441  if (strcmp(orgnum, "NaN") == 0 ||
6442  strcmp(orgnum, "Infinity") == 0 ||
6443  strcmp(orgnum, "-Infinity") == 0)
6444  {
6445  /*
6446  * Allow 6 characters for the leading sign, the decimal point,
6447  * "e", the exponent's sign and two exponent digits.
6448  */
6449  numstr = (char *) palloc(Num.pre + Num.post + 7);
6450  fill_str(numstr, '#', Num.pre + Num.post + 6);
6451  *numstr = ' ';
6452  *(numstr + Num.pre + 1) = '.';
6453  }
6454  else if (*orgnum != '-')
6455  {
6456  numstr = (char *) palloc(strlen(orgnum) + 2);
6457  *numstr = ' ';
6458  strcpy(numstr + 1, orgnum);
6459  }
6460  else
6461  {
6462  numstr = orgnum;
6463  }
6464  }
6465  else
6466  {
6467  int numstr_pre_len;
6468  Numeric val = value;
6469 
6470  if (IS_MULTI(&Num))
6471  {
6472  Numeric a = int64_to_numeric(10);
6474 
6476  NumericGetDatum(a),
6477  NumericGetDatum(b)));
6480  NumericGetDatum(x)));
6481  Num.pre += Num.multi;
6482  }
6483 
6486  Int32GetDatum(Num.post)));
6488  NumericGetDatum(x)));
6489 
6490  if (*orgnum == '-')
6491  {
6492  sign = '-';
6493  numstr = orgnum + 1;
6494  }
6495  else
6496  {
6497  sign = '+';
6498  numstr = orgnum;
6499  }
6500 
6501  if ((p = strchr(numstr, '.')))
6502  numstr_pre_len = p - numstr;
6503  else
6504  numstr_pre_len = strlen(numstr);
6505 
6506  /* needs padding? */
6507  if (numstr_pre_len < Num.pre)
6508  out_pre_spaces = Num.pre - numstr_pre_len;
6509  /* overflowed prefix digit format? */
6510  else if (numstr_pre_len > Num.pre)
6511  {
6512  numstr = (char *) palloc(Num.pre + Num.post + 2);
6513  fill_str(numstr, '#', Num.pre + Num.post + 1);
6514  *(numstr + Num.pre) = '.';
6515  }
6516  }
Datum numeric_round(PG_FUNCTION_ARGS)
Definition: numeric.c:1534
Datum numeric_power(PG_FUNCTION_ARGS)
Definition: numeric.c:3935
Datum numeric_int4(PG_FUNCTION_ARGS)
Definition: numeric.c:4447
Datum numeric_out(PG_FUNCTION_ARGS)
Definition: numeric.c:807
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition: numeric.c:3003
int b
Definition: isn.c:70
int a
Definition: isn.c:69
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:61
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:78
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:73

References a, b, DatumGetCString(), DatumGetInt32(), DatumGetNumeric(), DirectFunctionCall1, DirectFunctionCall2, fill_str(), fmt, format, Int32GetDatum(), int64_to_numeric(), int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, numeric_int4(), numeric_mul(), numeric_out(), numeric_out_sci(), numeric_power(), numeric_round(), NumericGetDatum(), palloc(), PG_GETARG_NUMERIC, PG_GETARG_TEXT_PP, 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 6339 of file formatting.c.

6344 {
6346  text *fmt = PG_GETARG_TEXT_PP(1);
6347  NUMDesc Num;
6348  Datum result;
6349  FormatNode *format;
6350  char *numstr;
6351  bool shouldFree;
6352  int len = 0;
6353  int scale,
6354  precision;
6355 
6357 
6358  if (len <= 0 || len >= INT_MAX / NUM_MAX_ITEM_SIZ)
6359  PG_RETURN_NULL();
6360 
6361  format = NUM_cache(len, &Num, fmt, &shouldFree);
6362 
6363  numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
6364 
6365  NUM_processor(format, &Num, VARDATA_ANY(value), numstr,
6366  VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
6367 
6368  scale = Num.post;
6369  precision = Num.pre + Num.multi + scale;
6370 
6371  if (shouldFree)
6372  pfree(format);
6373 
6375  CStringGetDatum(numstr),
6377  Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
6378 
6379  if (IS_MULTI(&Num))
6380  {
6381  Numeric x;
6382  Numeric a = int64_to_numeric(10);
6383  Numeric b = int64_to_numeric(-Num.multi);
6384 
6386  NumericGetDatum(a),
6387  NumericGetDatum(b)));
6389  result,
6390  NumericGetDatum(x));
6391  }
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:628
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
int scale
Definition: pgbench.c:181
uintptr_t Datum
Definition: postgres.h:64
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
#define VARDATA_ANY(PTR)
Definition: varatt.h:324

References a, b, CStringGetDatum(), DatumGetNumeric(), DirectFunctionCall2, DirectFunctionCall3, fmt, 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 4455 of file formatting.c.

4458 {
4459  struct pg_tm tm;
4460  struct fmt_tz ftz;
4461  fsec_t fsec;
4462  int fprec;
4463  uint32 flags;
4464 
4465  if (!do_to_timestamp(date_txt, fmt, collid, strict,
4466  &tm, &fsec, &ftz, &fprec, &flags, escontext))
4467  return (Datum) 0;
4468 
4469  *typmod = fprec ? fprec : -1; /* fractional part precision */
4470 
4471  if (flags & DCH_DATED)
4472  {
4473  if (flags & DCH_TIMED)
4474  {
4475  if (flags & DCH_ZONED)
4476  {
4477  TimestampTz result;
4478 
4479  if (ftz.has_tz)
4480  {
4481  *tz = ftz.gmtoffset;
4482  }
4483  else
4484  {
4485  /*
4486  * Time zone is present in format string, but not in input
4487  * string. Assuming do_to_timestamp() triggers no error
4488  * this should be possible only in non-strict case.
4489  */
4490  Assert(!strict);
4491 
4492  ereturn(escontext, (Datum) 0,
4493  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4494  errmsg("missing time zone in input string for type timestamptz")));
4495  }
4496 
4497  if (tm2timestamp(&tm, fsec, tz, &result) != 0)
4498  ereturn(escontext, (Datum) 0,
4499  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4500  errmsg("timestamptz out of range")));
4501 
4502  AdjustTimestampForTypmod(&result, *typmod, escontext);
4503 
4504  *typid = TIMESTAMPTZOID;
4505  return TimestampTzGetDatum(result);
4506  }
4507  else
4508  {
4509  Timestamp result;
4510 
4511  if (tm2timestamp(&tm, fsec, NULL, &result) != 0)
4512  ereturn(escontext, (Datum) 0,
4513  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4514  errmsg("timestamp out of range")));
4515 
4516  AdjustTimestampForTypmod(&result, *typmod, escontext);
4517 
4518  *typid = TIMESTAMPOID;
4519  return TimestampGetDatum(result);
4520  }
4521  }
4522  else
4523  {
4524  if (flags & DCH_ZONED)
4525  {
4526  ereturn(escontext, (Datum) 0,
4527  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4528  errmsg("datetime format is zoned but not timed")));
4529  }
4530  else
4531  {
4532  DateADT result;
4533 
4534  /* Prevent overflow in Julian-day routines */
4536  ereturn(escontext, (Datum) 0,
4537  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4538  errmsg("date out of range: \"%s\"",
4539  text_to_cstring(date_txt))));
4540 
4541  result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) -
4543 
4544  /* Now check for just-out-of-range dates */
4545  if (!IS_VALID_DATE(result))
4546  ereturn(escontext, (Datum) 0,
4547  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4548  errmsg("date out of range: \"%s\"",
4549  text_to_cstring(date_txt))));
4550 
4551  *typid = DATEOID;
4552  return DateADTGetDatum(result);
4553  }
4554  }
4555  }
4556  else if (flags & DCH_TIMED)
4557  {
4558  if (flags & DCH_ZONED)
4559  {
4560  TimeTzADT *result = palloc(sizeof(TimeTzADT));
4561 
4562  if (ftz.has_tz)
4563  {
4564  *tz = ftz.gmtoffset;
4565  }
4566  else
4567  {
4568  /*
4569  * Time zone is present in format string, but not in input
4570  * string. Assuming do_to_timestamp() triggers no error this
4571  * should be possible only in non-strict case.
4572  */
4573  Assert(!strict);
4574 
4575  ereturn(escontext, (Datum) 0,
4576  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4577  errmsg("missing time zone in input string for type timetz")));
4578  }
4579 
4580  if (tm2timetz(&tm, fsec, *tz, result) != 0)
4581  ereturn(escontext, (Datum) 0,
4582  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4583  errmsg("timetz out of range")));
4584 
4585  AdjustTimeForTypmod(&result->time, *typmod);
4586 
4587  *typid = TIMETZOID;
4588  return TimeTzADTPGetDatum(result);
4589  }
4590  else
4591  {
4592  TimeADT result;
4593 
4594  if (tm2time(&tm, fsec, &result) != 0)
4595  ereturn(escontext, (Datum) 0,
4596  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4597  errmsg("time out of range")));
4598 
4599  AdjustTimeForTypmod(&result, *typmod);
4600 
4601  *typid = TIMEOID;
4602  return TimeADTGetDatum(result);
4603  }
4604  }
4605  else
4606  {
4607  ereturn(escontext, (Datum) 0,
4608  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
4609  errmsg("datetime format is not dated and not timed")));
4610  }
4611 }
bool AdjustTimestampForTypmod(Timestamp *time, int32 typmod, Node *escontext)
Definition: timestamp.c:366
int tm2timestamp(struct pg_tm *tm, fsec_t fsec, int *tzp, Timestamp *result)
Definition: timestamp.c:1997
unsigned int uint32
Definition: c.h:506
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:1416
int tm2timetz(struct pg_tm *tm, fsec_t fsec, int tz, TimeTzADT *result)
Definition: date.c:2263
void AdjustTimeForTypmod(TimeADT *time, int32 typmod)
Definition: date.c:1645
static Datum DateADTGetDatum(DateADT X)
Definition: date.h:72
int32 DateADT
Definition: date.h:23
static Datum TimeTzADTPGetDatum(const TimeTzADT *X)
Definition: date.h:84
int64 TimeADT
Definition: date.h:25
static Datum TimeADTGetDatum(TimeADT X)
Definition: date.h:78
static bool do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext)
Definition: formatting.c:4681
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, fmt_tz::gmtoffset, fmt_tz::has_tz, IS_VALID_DATE, IS_VALID_JULIAN, palloc(), POSTGRES_EPOCH_JDATE, text_to_cstring(), TimeTzADT::time, TimeADTGetDatum(), TimestampGetDatum(), TimestampTzGetDatum(), TimeTzADTPGetDatum(), tm, tm2time(), tm2timestamp(), tm2timetz(), pg_tm::tm_mday, pg_tm::tm_mon, and pg_tm::tm_year.

Referenced by executeDateTimeMethod().

◆ parse_format()

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

Definition at line 1328 of file formatting.c.

1330 {
1331  FormatNode *n;
1332 
1333 #ifdef DEBUG_TO_FROM_CHAR
1334  elog(DEBUG_elog_output, "to_char/number(): run parser");
1335 #endif
1336 
1337  n = node;
1338 
1339  while (*str)
1340  {
1341  int suffix = 0;
1342  const KeySuffix *s;
1343 
1344  /*
1345  * Prefix
1346  */
1347  if ((flags & DCH_FLAG) &&
1348  (s = suff_search(str, suf, SUFFTYPE_PREFIX)) != NULL)
1349  {
1350  suffix |= s->id;
1351  if (s->len)
1352  str += s->len;
1353  }
1354 
1355  /*
1356  * Keyword
1357  */
1358  if (*str && (n->key = index_seq_search(str, kw, index)) != NULL)
1359  {
1360  n->type = NODE_TYPE_ACTION;
1361  n->suffix = suffix;
1362  if (n->key->len)
1363  str += n->key->len;
1364 
1365  /*
1366  * NUM version: Prepare global NUMDesc struct
1367  */
1368  if (flags & NUM_FLAG)
1369  NUMDesc_prepare(Num, n);
1370 
1371  /*
1372  * Postfix
1373  */
1374  if ((flags & DCH_FLAG) && *str &&
1375  (s = suff_search(str, suf, SUFFTYPE_POSTFIX)) != NULL)
1376  {
1377  n->suffix |= s->id;
1378  if (s->len)
1379  str += s->len;
1380  }
1381 
1382  n++;
1383  }
1384  else if (*str)
1385  {
1386  int chlen;
1387 
1388  if ((flags & STD_FLAG) && *str != '"')
1389  {
1390  /*
1391  * Standard mode, allow only following separators: "-./,':; ".
1392  * However, we support double quotes even in standard mode
1393  * (see below). This is our extension of standard mode.
1394  */
1395  if (strchr("-./,':; ", *str) == NULL)
1396  ereport(ERROR,
1397  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
1398  errmsg("invalid datetime format separator: \"%s\"",
1399  pnstrdup(str, pg_mblen(str)))));
1400 
1401  if (*str == ' ')
1402  n->type = NODE_TYPE_SPACE;
1403  else
1405 
1406  n->character[0] = *str;
1407  n->character[1] = '\0';
1408  n->key = NULL;
1409  n->suffix = 0;
1410  n++;
1411  str++;
1412  }
1413  else if (*str == '"')
1414  {
1415  /*
1416  * Process double-quoted literal string, if any
1417  */
1418  str++;
1419  while (*str)
1420  {
1421  if (*str == '"')
1422  {
1423  str++;
1424  break;
1425  }
1426  /* backslash quotes the next character, if any */
1427  if (*str == '\\' && *(str + 1))
1428  str++;
1429  chlen = pg_mblen(str);
1430  n->type = NODE_TYPE_CHAR;
1431  memcpy(n->character, str, chlen);
1432  n->character[chlen] = '\0';
1433  n->key = NULL;
1434  n->suffix = 0;
1435  n++;
1436  str += chlen;
1437  }
1438  }
1439  else
1440  {
1441  /*
1442  * Outside double-quoted strings, backslash is only special if
1443  * it immediately precedes a double quote.
1444  */
1445  if (*str == '\\' && *(str + 1) == '"')
1446  str++;
1447  chlen = pg_mblen(str);
1448 
1449  if ((flags & DCH_FLAG) && is_separator_char(str))
1451  else if (isspace((unsigned char) *str))
1452  n->type = NODE_TYPE_SPACE;
1453  else
1454  n->type = NODE_TYPE_CHAR;
1455 
1456  memcpy(n->character, str, chlen);
1457  n->character[chlen] = '\0';
1458  n->key = NULL;
1459  n->suffix = 0;
1460  n++;
1461  str += chlen;
1462  }
1463  }
1464  }
1465 
1466  n->type = NODE_TYPE_END;
1467  n->suffix = 0;
1468 }
static void NUMDesc_prepare(NUMDesc *num, FormatNode *n)
Definition: formatting.c:1153
static const KeySuffix * suff_search(const char *str, const KeySuffix *suf, int type)
Definition: formatting.c:1123
static const KeyWord * index_seq_search(const char *str, const KeyWord *kw, const int *index)
Definition: formatting.c:1099
#define SUFFTYPE_PREFIX
Definition: formatting.c:167
#define SUFFTYPE_POSTFIX
Definition: formatting.c:168

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

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

◆ seq_search_ascii()

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

Definition at line 2578 of file formatting.c.

2579 {
2580  unsigned char firstc;
2581  const char *const *a;
2582 
2583  *len = 0;
2584 
2585  /* empty string can't match anything */
2586  if (!*name)
2587  return -1;
2588 
2589  /* we handle first char specially to gain some speed */
2590  firstc = pg_ascii_tolower((unsigned char) *name);
2591 
2592  for (a = array; *a != NULL; a++)
2593  {
2594  const char *p;
2595  const char *n;
2596 
2597  /* compare first chars */
2598  if (pg_ascii_tolower((unsigned char) **a) != firstc)
2599  continue;
2600 
2601  /* compare rest of string */
2602  for (p = *a + 1, n = name + 1;; p++, n++)
2603  {
2604  /* return success if we matched whole array entry */
2605  if (*p == '\0')
2606  {
2607  *len = n - name;
2608  return a - array;
2609  }
2610  /* else, must have another character in "name" ... */
2611  if (*n == '\0')
2612  break;
2613  /* ... and it must match */
2614  if (pg_ascii_tolower((unsigned char) *p) !=
2615  pg_ascii_tolower((unsigned char) *n))
2616  break;
2617  }
2618  }
2619 
2620  return -1;
2621 }
const char * name

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

Referenced by from_char_seq_search().

◆ seq_search_localized()

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

Definition at line 2635 of file formatting.c.

2636 {
2637  char **a;
2638  char *upper_name;
2639  char *lower_name;
2640 
2641  *len = 0;
2642 
2643  /* empty string can't match anything */
2644  if (!*name)
2645  return -1;
2646 
2647  /*
2648  * The case-folding processing done below is fairly expensive, so before
2649  * doing that, make a quick pass to see if there is an exact match.
2650  */
2651  for (a = array; *a != NULL; a++)
2652  {
2653  int element_len = strlen(*a);
2654 
2655  if (strncmp(name, *a, element_len) == 0)
2656  {
2657  *len = element_len;
2658  return a - array;
2659  }
2660  }
2661 
2662  /*
2663  * Fold to upper case, then to lower case, so that we can match reliably
2664  * even in languages in which case conversions are not injective.
2665  */
2666  upper_name = str_toupper(unconstify(char *, name), strlen(name), collid);
2667  lower_name = str_tolower(upper_name, strlen(upper_name), collid);
2668  pfree(upper_name);
2669 
2670  for (a = array; *a != NULL; a++)
2671  {
2672  char *upper_element;
2673  char *lower_element;
2674  int element_len;
2675 
2676  /* Likewise upper/lower-case array element */
2677  upper_element = str_toupper(*a, strlen(*a), collid);
2678  lower_element = str_tolower(upper_element, strlen(upper_element),
2679  collid);
2680  pfree(upper_element);
2681  element_len = strlen(lower_element);
2682 
2683  /* Match? */
2684  if (strncmp(lower_name, lower_element, element_len) == 0)
2685  {
2686  *len = element_len;
2687  pfree(lower_element);
2688  pfree(lower_name);
2689  return a - array;
2690  }
2691  pfree(lower_element);
2692  }
2693 
2694  pfree(lower_name);
2695  return -1;
2696 }
#define unconstify(underlying_type, expr)
Definition: c.h:1245
char * str_toupper(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1784
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1636

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

Referenced by from_char_seq_search().

◆ str_initcap()

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

Definition at line 1973 of file formatting.c.

1974 {
1975  char *result;
1976  int wasalnum = false;
1977 
1978  if (!buff)
1979  return NULL;
1980 
1981  if (!OidIsValid(collid))
1982  {
1983  /*
1984  * This typically means that the parser could not resolve a conflict
1985  * of implicit collations, so report it that way.
1986  */
1987  ereport(ERROR,
1988  (errcode(ERRCODE_INDETERMINATE_COLLATION),
1989  errmsg("could not determine which collation to use for %s function",
1990  "initcap()"),
1991  errhint("Use the COLLATE clause to set the collation explicitly.")));
1992  }
1993 
1994  /* C/POSIX collations use this path regardless of database encoding */
1995  if (lc_ctype_is_c(collid))
1996  {
1997  result = asc_initcap(buff, nbytes);
1998  }
1999  else
2000  {
2001  pg_locale_t mylocale;
2002 
2003  mylocale = pg_newlocale_from_collation(collid);
2004 
2005 #ifdef USE_ICU
2006  if (mylocale && mylocale->provider == COLLPROVIDER_ICU)
2007  {
2008  int32_t len_uchar,
2009  len_conv;
2010  UChar *buff_uchar;
2011  UChar *buff_conv;
2012 
2013  len_uchar = icu_to_uchar(&buff_uchar, buff, nbytes);
2014  len_conv = icu_convert_case(u_strToTitle_default_BI, mylocale,
2015  &buff_conv, buff_uchar, len_uchar);
2016  icu_from_uchar(&result, buff_conv, len_conv);
2017  pfree(buff_uchar);
2018  pfree(buff_conv);
2019  }
2020  else
2021 #endif
2022  if (mylocale && mylocale->provider == COLLPROVIDER_BUILTIN)
2023  {
2024  const char *src = buff;
2025  size_t srclen = nbytes;
2026  size_t dstsize;
2027  char *dst;
2028  size_t needed;
2029  struct WordBoundaryState wbstate = {
2030  .str = src,
2031  .len = srclen,
2032  .offset = 0,
2033  .init = false,
2034  .prev_alnum = false,
2035  };
2036 
2038 
2039  /* first try buffer of equal size plus terminating NUL */
2040  dstsize = srclen + 1;
2041  dst = palloc(dstsize);
2042 
2043  needed = unicode_strtitle(dst, dstsize, src, srclen,
2044  initcap_wbnext, &wbstate);
2045  if (needed + 1 > dstsize)
2046  {
2047  /* reset iterator */
2048  wbstate.offset = 0;
2049  wbstate.init = false;
2050 
2051  /* grow buffer if needed and retry */
2052  dstsize = needed + 1;
2053  dst = repalloc(dst, dstsize);
2054  needed = unicode_strtitle(dst, dstsize, src, srclen,
2055  initcap_wbnext, &wbstate);
2056  Assert(needed + 1 == dstsize);
2057  }
2058 
2059  result = dst;
2060  }
2061  else
2062  {
2063  Assert(!mylocale || mylocale->provider == COLLPROVIDER_LIBC);
2064 
2066  {
2067  wchar_t *workspace;
2068  size_t curr_char;
2069  size_t result_size;
2070 
2071  /* Overflow paranoia */
2072  if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
2073  ereport(ERROR,
2074  (errcode(ERRCODE_OUT_OF_MEMORY),
2075  errmsg("out of memory")));
2076 
2077  /* Output workspace cannot have more codes than input bytes */
2078  workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
2079 
2080  char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
2081 
2082  for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
2083  {
2084  if (mylocale)
2085  {
2086  if (wasalnum)
2087  workspace[curr_char] = towlower_l(workspace[curr_char], mylocale->info.lt);
2088  else
2089  workspace[curr_char] = towupper_l(workspace[curr_char], mylocale->info.lt);
2090  wasalnum = iswalnum_l(workspace[curr_char], mylocale->info.lt);
2091  }
2092  else
2093  {
2094  if (wasalnum)
2095  workspace[curr_char] = towlower(workspace[curr_char]);
2096  else
2097  workspace[curr_char] = towupper(workspace[curr_char]);
2098  wasalnum = iswalnum(workspace[curr_char]);
2099  }
2100  }
2101 
2102  /*
2103  * Make result large enough; case change might change number
2104  * of bytes
2105  */
2106  result_size = curr_char * pg_database_encoding_max_length() + 1;
2107  result = palloc(result_size);
2108 
2109  wchar2char(result, workspace, result_size, mylocale);
2110  pfree(workspace);
2111  }
2112  else
2113  {
2114  char *p;
2115 
2116  result = pnstrdup(buff, nbytes);
2117 
2118  /*
2119  * Note: we assume that toupper_l()/tolower_l() will not be so
2120  * broken as to need guard tests. When using the default
2121  * collation, we apply the traditional Postgres behavior that
2122  * forces ASCII-style treatment of I/i, but in non-default
2123  * collations you get exactly what the collation says.
2124  */
2125  for (p = result; *p; p++)
2126  {
2127  if (mylocale)
2128  {
2129  if (wasalnum)
2130  *p = tolower_l((unsigned char) *p, mylocale->info.lt);
2131  else
2132  *p = toupper_l((unsigned char) *p, mylocale->info.lt);
2133  wasalnum = isalnum_l((unsigned char) *p, mylocale->info.lt);
2134  }
2135  else
2136  {
2137  if (wasalnum)
2138  *p = pg_tolower((unsigned char) *p);
2139  else
2140  *p = pg_toupper((unsigned char) *p);
2141  wasalnum = isalnum((unsigned char) *p);
2142  }
2143  }
2144  }
2145  }
2146  }
2147 
2148  return result;
2149 }
#define OidIsValid(objectId)
Definition: c.h:775
char * asc_initcap(const char *buff, size_t nbytes)
Definition: formatting.c:2204
static size_t initcap_wbnext(void *state)
Definition: formatting.c:1939
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
int pg_database_encoding_max_length(void)
Definition: mbutils.c:1546
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1540
size_t wchar2char(char *to, const wchar_t *from, size_t tolen, pg_locale_t locale)
Definition: pg_locale.c:3065
pg_locale_t pg_newlocale_from_collation(Oid collid)
Definition: pg_locale.c:1551
bool lc_ctype_is_c(Oid collation)
Definition: pg_locale.c:1384
size_t char2wchar(wchar_t *to, size_t tolen, const char *from, size_t fromlen, pg_locale_t locale)
Definition: pg_locale.c:3121
@ PG_UTF8
Definition: pg_wchar.h:232
unsigned char pg_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:105
unsigned char pg_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:122
locale_t lt
Definition: pg_locale.h:83
union pg_locale_struct::@151 info
size_t unicode_strtitle(char *dst, size_t dstsize, const char *src, ssize_t srclen, WordBoundaryNext wbnext, void *wbstate)
Definition: unicode_case.c:100
#define toupper_l
Definition: win32_port.h:426
#define iswalnum_l
Definition: win32_port.h:434
#define towupper_l
Definition: win32_port.h:428
#define towlower_l
Definition: win32_port.h:427
#define tolower_l
Definition: win32_port.h:425
#define isalnum_l
Definition: win32_port.h:433

References asc_initcap(), Assert, char2wchar(), collid, ereport, errcode(), errhint(), errmsg(), ERROR, GetDatabaseEncoding(), pg_locale_struct::info, WordBoundaryState::init, initcap_wbnext(), isalnum_l, iswalnum_l, lc_ctype_is_c(), pg_locale_struct::lt, WordBoundaryState::offset, OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_tolower(), pg_toupper(), PG_UTF8, pnstrdup(), pg_locale_struct::provider, repalloc(), WordBoundaryState::str, tolower_l, toupper_l, towlower_l, towupper_l, unicode_strtitle(), and wchar2char().

Referenced by initcap(), and str_initcap_z().

◆ str_initcap_z()

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

Definition at line 2247 of file formatting.c.

2248 {
2249  return str_initcap(buff, strlen(buff), collid);
2250 }
char * str_initcap(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1973

References collid, and str_initcap().

Referenced by DCH_to_char().

◆ str_numth()

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

Definition at line 1561 of file formatting.c.

1562 {
1563  if (dest != num)
1564  strcpy(dest, num);
1565  strcat(dest, get_th(num, type));
1566  return dest;
1567 }

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

1637 {
1638  char *result;
1639 
1640  if (!buff)
1641  return NULL;
1642 
1643  if (!OidIsValid(collid))
1644  {
1645  /*
1646  * This typically means that the parser could not resolve a conflict
1647  * of implicit collations, so report it that way.
1648  */
1649  ereport(ERROR,
1650  (errcode(ERRCODE_INDETERMINATE_COLLATION),
1651  errmsg("could not determine which collation to use for %s function",
1652  "lower()"),
1653  errhint("Use the COLLATE clause to set the collation explicitly.")));
1654  }
1655 
1656  /* C/POSIX collations use this path regardless of database encoding */
1657  if (lc_ctype_is_c(collid))
1658  {
1659  result = asc_tolower(buff, nbytes);
1660  }
1661  else
1662  {
1663  pg_locale_t mylocale;
1664 
1665  mylocale = pg_newlocale_from_collation(collid);
1666 
1667 #ifdef USE_ICU
1668  if (mylocale && mylocale->provider == COLLPROVIDER_ICU)
1669  {
1670  int32_t len_uchar;
1671  int32_t len_conv;
1672  UChar *buff_uchar;
1673  UChar *buff_conv;
1674 
1675  len_uchar = icu_to_uchar(&buff_uchar, buff, nbytes);
1676  len_conv = icu_convert_case(u_strToLower, mylocale,
1677  &buff_conv, buff_uchar, len_uchar);
1678  icu_from_uchar(&result, buff_conv, len_conv);
1679  pfree(buff_uchar);
1680  pfree(buff_conv);
1681  }
1682  else
1683 #endif
1684  if (mylocale && mylocale->provider == COLLPROVIDER_BUILTIN)
1685  {
1686  const char *src = buff;
1687  size_t srclen = nbytes;
1688  size_t dstsize;
1689  char *dst;
1690  size_t needed;
1691 
1693 
1694  /* first try buffer of equal size plus terminating NUL */
1695  dstsize = srclen + 1;
1696  dst = palloc(dstsize);
1697 
1698  needed = unicode_strlower(dst, dstsize, src, srclen);
1699  if (needed + 1 > dstsize)
1700  {
1701  /* grow buffer if needed and retry */
1702  dstsize = needed + 1;
1703  dst = repalloc(dst, dstsize);
1704  needed = unicode_strlower(dst, dstsize, src, srclen);
1705  Assert(needed + 1 == dstsize);
1706  }
1707 
1708  Assert(dst[needed] == '\0');
1709  result = dst;
1710  }
1711  else
1712  {
1713  Assert(!mylocale || mylocale->provider == COLLPROVIDER_LIBC);
1714 
1716  {
1717  wchar_t *workspace;
1718  size_t curr_char;
1719  size_t result_size;
1720 
1721  /* Overflow paranoia */
1722  if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1723  ereport(ERROR,
1724  (errcode(ERRCODE_OUT_OF_MEMORY),
1725  errmsg("out of memory")));
1726 
1727  /* Output workspace cannot have more codes than input bytes */
1728  workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1729 
1730  char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1731 
1732  for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1733  {
1734  if (mylocale)
1735  workspace[curr_char] = towlower_l(workspace[curr_char], mylocale->info.lt);
1736  else
1737  workspace[curr_char] = towlower(workspace[curr_char]);
1738  }
1739 
1740  /*
1741  * Make result large enough; case change might change number
1742  * of bytes
1743  */
1744  result_size = curr_char * pg_database_encoding_max_length() + 1;
1745  result = palloc(result_size);
1746 
1747  wchar2char(result, workspace, result_size, mylocale);
1748  pfree(workspace);
1749  }
1750  else
1751  {
1752  char *p;
1753 
1754  result = pnstrdup(buff, nbytes);
1755 
1756  /*
1757  * Note: we assume that tolower_l() will not be so broken as
1758  * to need an isupper_l() guard test. When using the default
1759  * collation, we apply the traditional Postgres behavior that
1760  * forces ASCII-style treatment of I/i, but in non-default
1761  * collations you get exactly what the collation says.
1762  */
1763  for (p = result; *p; p++)
1764  {
1765  if (mylocale)
1766  *p = tolower_l((unsigned char) *p, mylocale->info.lt);
1767  else
1768  *p = pg_tolower((unsigned char) *p);
1769  }
1770  }
1771  }
1772  }
1773 
1774  return result;
1775 }
size_t unicode_strlower(char *dst, size_t dstsize, const char *src, ssize_t srclen)
Definition: unicode_case.c:69

References asc_tolower(), Assert, char2wchar(), collid, ereport, errcode(), errhint(), errmsg(), ERROR, GetDatabaseEncoding(), pg_locale_struct::info, lc_ctype_is_c(), pg_locale_struct::lt, OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_tolower(), PG_UTF8, pnstrdup(), pg_locale_struct::provider, repalloc(), tolower_l, towlower_l, unicode_strlower(), and wchar2char().

Referenced by citext_eq(), citext_hash(), citext_hash_extended(), citext_ne(), citextcmp(), internal_citext_pattern_cmp(), lower(), ltree_strncasecmp(), seq_search_localized(), and str_tolower_z().

◆ str_tolower_z()

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

Definition at line 2235 of file formatting.c.

2236 {
2237  return str_tolower(buff, strlen(buff), collid);
2238 }

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

1785 {
1786  char *result;
1787 
1788  if (!buff)
1789  return NULL;
1790 
1791  if (!OidIsValid(collid))
1792  {
1793  /*
1794  * This typically means that the parser could not resolve a conflict
1795  * of implicit collations, so report it that way.
1796  */
1797  ereport(ERROR,
1798  (errcode(ERRCODE_INDETERMINATE_COLLATION),
1799  errmsg("could not determine which collation to use for %s function",
1800  "upper()"),
1801  errhint("Use the COLLATE clause to set the collation explicitly.")));
1802  }
1803 
1804  /* C/POSIX collations use this path regardless of database encoding */
1805  if (lc_ctype_is_c(collid))
1806  {
1807  result = asc_toupper(buff, nbytes);
1808  }
1809  else
1810  {
1811  pg_locale_t mylocale;
1812 
1813  mylocale = pg_newlocale_from_collation(collid);
1814 
1815 #ifdef USE_ICU
1816  if (mylocale && mylocale->provider == COLLPROVIDER_ICU)
1817  {
1818  int32_t len_uchar,
1819  len_conv;
1820  UChar *buff_uchar;
1821  UChar *buff_conv;
1822 
1823  len_uchar = icu_to_uchar(&buff_uchar, buff, nbytes);
1824  len_conv = icu_convert_case(u_strToUpper, mylocale,
1825  &buff_conv, buff_uchar, len_uchar);
1826  icu_from_uchar(&result, buff_conv, len_conv);
1827  pfree(buff_uchar);
1828  pfree(buff_conv);
1829  }
1830  else
1831 #endif
1832  if (mylocale && mylocale->provider == COLLPROVIDER_BUILTIN)
1833  {
1834  const char *src = buff;
1835  size_t srclen = nbytes;
1836  size_t dstsize;
1837  char *dst;
1838  size_t needed;
1839 
1841 
1842  /* first try buffer of equal size plus terminating NUL */
1843  dstsize = srclen + 1;
1844  dst = palloc(dstsize);
1845 
1846  needed = unicode_strupper(dst, dstsize, src, srclen);
1847  if (needed + 1 > dstsize)
1848  {
1849  /* grow buffer if needed and retry */
1850  dstsize = needed + 1;
1851  dst = repalloc(dst, dstsize);
1852  needed = unicode_strupper(dst, dstsize, src, srclen);
1853  Assert(needed + 1 == dstsize);
1854  }
1855 
1856  Assert(dst[needed] == '\0');
1857  result = dst;
1858  }
1859  else
1860  {
1861  Assert(!mylocale || mylocale->provider == COLLPROVIDER_LIBC);
1862 
1864  {
1865  wchar_t *workspace;
1866  size_t curr_char;
1867  size_t result_size;
1868 
1869  /* Overflow paranoia */
1870  if ((nbytes + 1) > (INT_MAX / sizeof(wchar_t)))
1871  ereport(ERROR,
1872  (errcode(ERRCODE_OUT_OF_MEMORY),
1873  errmsg("out of memory")));
1874 
1875  /* Output workspace cannot have more codes than input bytes */
1876  workspace = (wchar_t *) palloc((nbytes + 1) * sizeof(wchar_t));
1877 
1878  char2wchar(workspace, nbytes + 1, buff, nbytes, mylocale);
1879 
1880  for (curr_char = 0; workspace[curr_char] != 0; curr_char++)
1881  {
1882  if (mylocale)
1883  workspace[curr_char] = towupper_l(workspace[curr_char], mylocale->info.lt);
1884  else
1885  workspace[curr_char] = towupper(workspace[curr_char]);
1886  }
1887 
1888  /*
1889  * Make result large enough; case change might change number
1890  * of bytes
1891  */
1892  result_size = curr_char * pg_database_encoding_max_length() + 1;
1893  result = palloc(result_size);
1894 
1895  wchar2char(result, workspace, result_size, mylocale);
1896  pfree(workspace);
1897  }
1898  else
1899  {
1900  char *p;
1901 
1902  result = pnstrdup(buff, nbytes);
1903 
1904  /*
1905  * Note: we assume that toupper_l() will not be so broken as
1906  * to need an islower_l() guard test. When using the default
1907  * collation, we apply the traditional Postgres behavior that
1908  * forces ASCII-style treatment of I/i, but in non-default
1909  * collations you get exactly what the collation says.
1910  */
1911  for (p = result; *p; p++)
1912  {
1913  if (mylocale)
1914  *p = toupper_l((unsigned char) *p, mylocale->info.lt);
1915  else
1916  *p = pg_toupper((unsigned char) *p);
1917  }
1918  }
1919  }
1920  }
1921 
1922  return result;
1923 }
size_t unicode_strupper(char *dst, size_t dstsize, const char *src, ssize_t srclen)
Definition: unicode_case.c:124

References asc_toupper(), Assert, char2wchar(), collid, ereport, errcode(), errhint(), errmsg(), ERROR, GetDatabaseEncoding(), pg_locale_struct::info, lc_ctype_is_c(), pg_locale_struct::lt, OidIsValid, palloc(), pfree(), pg_database_encoding_max_length(), pg_newlocale_from_collation(), pg_toupper(), PG_UTF8, pnstrdup(), pg_locale_struct::provider, repalloc(), toupper_l, towupper_l, unicode_strupper(), and wchar2char().

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

2242 {
2243  return str_toupper(buff, strlen(buff), collid);
2244 }

References collid, and str_toupper().

Referenced by DCH_to_char().

◆ strspace_len()

static int strspace_len ( const char *  str)
static

Definition at line 2378 of file formatting.c.

2379 {
2380  int len = 0;
2381 
2382  while (*str && isspace((unsigned char) *str))
2383  {
2384  str++;
2385  len++;
2386  }
2387  return len;
2388 }

References len, and str.

Referenced by from_char_parse_int_len().

◆ suff_search()

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

Definition at line 1123 of file formatting.c.

1124 {
1125  const KeySuffix *s;
1126 
1127  for (s = suf; s->name != NULL; s++)
1128  {
1129  if (s->type != type)
1130  continue;
1131 
1132  if (strncmp(str, s->name, s->len) == 0)
1133  return s;
1134  }
1135  return NULL;
1136 }
const char * name
Definition: formatting.c:124

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

Referenced by parse_format().

◆ timestamp_to_char()

Datum timestamp_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4250 of file formatting.c.

4251 {
4253  text *fmt = PG_GETARG_TEXT_PP(1),
4254  *res;
4255  TmToChar tmtc;
4256  struct pg_tm tt;
4257  struct fmt_tm *tm;
4258  int thisdate;
4259 
4260  if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
4261  PG_RETURN_NULL();
4262 
4263  ZERO_tmtc(&tmtc);
4264  tm = tmtcTm(&tmtc);
4265 
4266  if (timestamp2tm(dt, NULL, &tt, &tmtcFsec(&tmtc), NULL, NULL) != 0)
4267  ereport(ERROR,
4268  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4269  errmsg("timestamp out of range")));
4270 
4271  /* calculate wday and yday, because timestamp2tm doesn't */
4272  thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
4273  tt.tm_wday = (thisdate + 1) % 7;
4274  tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
4275 
4276  COPY_tm(tm, &tt);
4277 
4278  if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
4279  PG_RETURN_NULL();
4280 
4282 }
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition: timestamp.c:1901
#define TIMESTAMP_NOT_FINITE(j)
Definition: timestamp.h:169
#define tmtcFsec(_X)
Definition: formatting.c:491
#define COPY_tm(_DST, _SRC)
Definition: formatting.c:494
#define PG_GETARG_TIMESTAMP(n)
Definition: timestamp.h:63

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, fmt, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, 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 4285 of file formatting.c.

4286 {
4288  text *fmt = PG_GETARG_TEXT_PP(1),
4289  *res;
4290  TmToChar tmtc;
4291  int tz;
4292  struct pg_tm tt;
4293  struct fmt_tm *tm;
4294  int thisdate;
4295 
4296  if (VARSIZE_ANY_EXHDR(fmt) <= 0 || TIMESTAMP_NOT_FINITE(dt))
4297  PG_RETURN_NULL();
4298 
4299  ZERO_tmtc(&tmtc);
4300  tm = tmtcTm(&tmtc);
4301 
4302  if (timestamp2tm(dt, &tz, &tt, &tmtcFsec(&tmtc), &tmtcTzn(&tmtc), NULL) != 0)
4303  ereport(ERROR,
4304  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4305  errmsg("timestamp out of range")));
4306 
4307  /* calculate wday and yday, because timestamp2tm doesn't */
4308  thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
4309  tt.tm_wday = (thisdate + 1) % 7;
4310  tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
4311 
4312  COPY_tm(tm, &tt);
4313 
4314  if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
4315  PG_RETURN_NULL();
4316 
4318 }

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg(), ERROR, fmt, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, res, 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 4407 of file formatting.c.

4408 {
4409  text *date_txt = PG_GETARG_TEXT_PP(0);
4410  text *fmt = PG_GETARG_TEXT_PP(1);
4412  DateADT result;
4413  struct pg_tm tm;
4414  struct fmt_tz ftz;
4415  fsec_t fsec;
4416 
4417  do_to_timestamp(date_txt, fmt, collid, false,
4418  &tm, &fsec, &ftz, NULL, NULL, NULL);
4419 
4420  /* Prevent overflow in Julian-day routines */
4422  ereport(ERROR,
4423  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4424  errmsg("date out of range: \"%s\"",
4425  text_to_cstring(date_txt))));
4426 
4428 
4429  /* Now check for just-out-of-range dates */
4430  if (!IS_VALID_DATE(result))
4431  ereport(ERROR,
4432  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4433  errmsg("date out of range: \"%s\"",
4434  text_to_cstring(date_txt))));
4435 
4436  PG_RETURN_DATEADT(result);
4437 }
#define PG_RETURN_DATEADT(x)
Definition: date.h:93
unsigned int Oid
Definition: postgres_ext.h:31

References collid, date2j(), do_to_timestamp(), ereport, errcode(), errmsg(), ERROR, fmt, 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 4368 of file formatting.c.

4369 {
4370  text *date_txt = PG_GETARG_TEXT_PP(0);
4371  text *fmt = PG_GETARG_TEXT_PP(1);
4373  Timestamp result;
4374  int tz;
4375  struct pg_tm tm;
4376  struct fmt_tz ftz;
4377  fsec_t fsec;
4378  int fprec;
4379 
4380  do_to_timestamp(date_txt, fmt, collid, false,
4381  &tm, &fsec, &ftz, &fprec, NULL, NULL);
4382 
4383  /* Use the specified time zone, if any. */
4384  if (ftz.has_tz)
4385  tz = ftz.gmtoffset;
4386  else
4388 
4389  if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
4390  ereport(ERROR,
4391  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
4392  errmsg("timestamp out of range")));
4393 
4394  /* Use the specified fractional precision, if any. */
4395  if (fprec)
4396  AdjustTimestampForTypmod(&result, fprec, NULL);
4397 
4398  PG_RETURN_TIMESTAMP(result);
4399 }
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition: datetime.c:1585
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, fmt_tz::gmtoffset, fmt_tz::has_tz, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_TIMESTAMP, session_timezone, tm, and tm2timestamp().

Variable Documentation

◆ adbc_strings

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

Definition at line 216 of file formatting.c.

Referenced by DCH_from_char().

◆ adbc_strings_long

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

Definition at line 217 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings

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

Definition at line 243 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings_long

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

Definition at line 244 of file formatting.c.

Referenced by DCH_from_char().

◆ days_short

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

Definition at line 183 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ DCH_index

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

Definition at line 948 of file formatting.c.

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

◆ DCH_keywords

const KeyWord DCH_keywords[]
static

◆ DCH_suff

const KeySuffix DCH_suff[]
static
Initial value:
= {
{NULL, 0, 0, 0}
}
#define DCH_S_FM
Definition: formatting.c:542
#define DCH_S_th
Definition: formatting.c:544
#define DCH_S_TH
Definition: formatting.c:543
#define DCH_S_SP
Definition: formatting.c:545
#define DCH_S_TM
Definition: formatting.c:546

Definition at line 568 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 387 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 389 of file formatting.c.

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

◆ months_full

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

Definition at line 178 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ n_DCHCache

int n_DCHCache = 0
static

Definition at line 388 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 393 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 972 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUM_keywords

const KeyWord NUM_keywords[]
static

Definition at line 900 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUMCache

NUMCacheEntry* NUMCache[NUM_CACHE_ENTRIES]
static

Definition at line 392 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 394 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 270 of file formatting.c.

Referenced by get_th().

◆ numth

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

Definition at line 271 of file formatting.c.

Referenced by get_th().

◆ rm1

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

Definition at line 262 of file formatting.c.

Referenced by int_to_roman().

◆ rm10

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

Definition at line 263 of file formatting.c.

Referenced by int_to_roman().

◆ rm100

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

Definition at line 264 of file formatting.c.

Referenced by int_to_roman().

◆ rm_months_lower

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

Definition at line 255 of file formatting.c.

Referenced by DCH_from_char(), and DCH_to_char().

◆ rm_months_upper

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

Definition at line 252 of file formatting.c.

Referenced by DCH_to_char().