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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

typedef struct TmToChar TmToChar
 
typedef struct NUMProc NUMProc
 

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ A_D_STR

#define A_D_STR   "A.D."

Definition at line 196 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 197 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 223 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 224 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 198 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 199 of file formatting.c.

◆ ADJUST_YEAR

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

Definition at line 194 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 225 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 226 of file formatting.c.

◆ AMOUNT_TEST

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

Definition at line 1062 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 201 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 202 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 203 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

Definition at line 204 of file formatting.c.

◆ CLOCK_12_HOUR

#define CLOCK_12_HOUR   1

Definition at line 171 of file formatting.c.

◆ CLOCK_24_HOUR

#define CLOCK_24_HOUR   0

Definition at line 170 of file formatting.c.

◆ COPY_tm

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

Definition at line 520 of file formatting.c.

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 391 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

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

Definition at line 381 of file formatting.c.

◆ DCH_CACHE_SIZE

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

Definition at line 386 of file formatting.c.

◆ DCH_DATED

#define DCH_DATED   0x01

Definition at line 1052 of file formatting.c.

◆ DCH_FLAG

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

Definition at line 99 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

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

Definition at line 114 of file formatting.c.

◆ DCH_S_FM

#define DCH_S_FM   0x01

Definition at line 568 of file formatting.c.

◆ DCH_S_SP

#define DCH_S_SP   0x08

Definition at line 571 of file formatting.c.

◆ DCH_S_TH

#define DCH_S_TH   0x02

Definition at line 569 of file formatting.c.

◆ DCH_S_th

#define DCH_S_th   0x04

Definition at line 570 of file formatting.c.

◆ DCH_S_TM

#define DCH_S_TM   0x10

Definition at line 572 of file formatting.c.

◆ DCH_TIMED

#define DCH_TIMED   0x02

Definition at line 1053 of file formatting.c.

◆ DCH_to_char_fsec

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

◆ DCH_ZONED

#define DCH_ZONED   0x04

Definition at line 1054 of file formatting.c.

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 484 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 483 of file formatting.c.

◆ INVALID_FOR_INTERVAL

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

Definition at line 551 of file formatting.c.

◆ IS_BLANK

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

Definition at line 353 of file formatting.c.

◆ IS_BRACKET

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

Definition at line 355 of file formatting.c.

◆ IS_DECIMAL

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

Definition at line 350 of file formatting.c.

◆ IS_EEEE

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

Definition at line 361 of file formatting.c.

◆ IS_FILLMODE

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

Definition at line 354 of file formatting.c.

◆ IS_LDECIMAL

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

Definition at line 351 of file formatting.c.

◆ IS_LSIGN

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

Definition at line 357 of file formatting.c.

◆ IS_MINUS

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

Definition at line 356 of file formatting.c.

◆ IS_MULTI

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

Definition at line 360 of file formatting.c.

◆ IS_PLUS

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

Definition at line 358 of file formatting.c.

◆ IS_PREDEC_SPACE

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

Definition at line 5590 of file formatting.c.

◆ IS_ROMAN

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

Definition at line 359 of file formatting.c.

◆ IS_VALID_SUB_COMB

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

Definition at line 270 of file formatting.c.

◆ IS_ZERO

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

Definition at line 352 of file formatting.c.

◆ KeyWord_INDEX_FILTER

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

Definition at line 108 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 107 of file formatting.c.

◆ MAX_ROMAN_LEN

#define MAX_ROMAN_LEN   15

Definition at line 290 of file formatting.c.

◆ NODE_TYPE_ACTION

#define NODE_TYPE_ACTION   2

Definition at line 162 of file formatting.c.

◆ NODE_TYPE_CHAR

#define NODE_TYPE_CHAR   3

Definition at line 163 of file formatting.c.

◆ NODE_TYPE_END

#define NODE_TYPE_END   1

Definition at line 161 of file formatting.c.

◆ NODE_TYPE_SEPARATOR

#define NODE_TYPE_SEPARATOR   4

Definition at line 164 of file formatting.c.

◆ NODE_TYPE_SPACE

#define NODE_TYPE_SPACE   5

Definition at line 165 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 392 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

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

Definition at line 383 of file formatting.c.

◆ NUM_CACHE_SIZE

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

Definition at line 388 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 330 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 333 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 327 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 340 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 331 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 328 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 332 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 334 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 339 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 337 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 335 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 338 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 336 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 329 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 100 of file formatting.c.

◆ NUM_LSIGN_NONE

#define NUM_LSIGN_NONE   0

Definition at line 344 of file formatting.c.

◆ NUM_LSIGN_POST

#define NUM_LSIGN_POST   1

Definition at line 343 of file formatting.c.

◆ NUM_LSIGN_PRE

#define NUM_LSIGN_PRE   (-1)

Definition at line 342 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 115 of file formatting.c.

◆ NUM_TOCHAR_finish

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

Definition at line 6285 of file formatting.c.

◆ NUM_TOCHAR_prepare

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

Definition at line 6272 of file formatting.c.

◆ OVERLOAD_TEST

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

Definition at line 1061 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 228 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 229 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 230 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

Definition at line 231 of file formatting.c.

◆ ROMAN_VAL

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

Definition at line 278 of file formatting.c.

◆ S_FM

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

Definition at line 584 of file formatting.c.

◆ S_SP

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

Definition at line 585 of file formatting.c.

◆ S_TH

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

Definition at line 579 of file formatting.c.

◆ S_th

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

Definition at line 580 of file formatting.c.

◆ S_TH_TYPE

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

Definition at line 581 of file formatting.c.

◆ S_THth

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

Definition at line 578 of file formatting.c.

◆ S_TM

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

Definition at line 586 of file formatting.c.

◆ SKIP_THth

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

Definition at line 2013 of file formatting.c.

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 101 of file formatting.c.

◆ SUFFTYPE_POSTFIX

#define SUFFTYPE_POSTFIX   2

Definition at line 168 of file formatting.c.

◆ SUFFTYPE_PREFIX

#define SUFFTYPE_PREFIX   1

Definition at line 167 of file formatting.c.

◆ TH_LOWER

#define TH_LOWER   2

Definition at line 304 of file formatting.c.

◆ TH_UPPER

#define TH_UPPER   1

Definition at line 303 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 592 of file formatting.c.

◆ tmtcFsec

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

Definition at line 517 of file formatting.c.

◆ tmtcTm

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

Definition at line 515 of file formatting.c.

◆ tmtcTzn

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

Definition at line 516 of file formatting.c.

◆ ZERO_tm

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

Definition at line 534 of file formatting.c.

◆ ZERO_tmfc

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

Definition at line 458 of file formatting.c.

◆ ZERO_tmtc

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

Definition at line 540 of file formatting.c.

◆ zeroize_NUM

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

Definition at line 4868 of file formatting.c.

Typedef Documentation

◆ NUMProc

typedef struct NUMProc NUMProc

◆ TmToChar

typedef struct TmToChar TmToChar

Enumeration Type Documentation

◆ DCH_poz

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

Definition at line 635 of file formatting.c.

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

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 137 of file formatting.c.

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

◆ NUM_poz

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

Definition at line 754 of file formatting.c.

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

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2094 of file formatting.c.

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

Referenced by DCH_from_char().

◆ asc_initcap()

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

Definition at line 1944 of file formatting.c.

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

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

Referenced by str_initcap().

◆ asc_tolower()

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

Definition at line 1898 of file formatting.c.

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

References pg_ascii_tolower(), and pnstrdup().

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

◆ asc_tolower_z()

static char * asc_tolower_z ( const char *  buff)
static

Definition at line 1993 of file formatting.c.

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

References asc_tolower().

Referenced by DCH_to_char(), and NUM_processor().

◆ asc_toupper()

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

Definition at line 1921 of file formatting.c.

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

References pg_ascii_toupper(), and pnstrdup().

Referenced by asc_toupper_z(), and str_toupper().

◆ asc_toupper_z()

static char * asc_toupper_z ( const char *  buff)
static

Definition at line 1999 of file formatting.c.

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

References asc_toupper().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char *  fmt_str)

Definition at line 4365 of file formatting.c.

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

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

Referenced by jspIsMutableWalker().

◆ datetime_to_char_body()

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

Definition at line 3928 of file formatting.c.

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

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

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

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

◆ DCH_cache_getnew()

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

Definition at line 3820 of file formatting.c.

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

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

Referenced by DCH_cache_fetch().

◆ DCH_cache_search()

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

Definition at line 3880 of file formatting.c.

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

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

Referenced by DCH_cache_fetch().

◆ DCH_datetime_type()

static int DCH_datetime_type ( FormatNode node)
static

Definition at line 3723 of file formatting.c.

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

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

Referenced by datetime_format_has_tz(), and do_to_timestamp().

◆ DCH_from_char()

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

Definition at line 3152 of file formatting.c.

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

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

Referenced by do_to_timestamp().

◆ DCH_prevent_counter_overflow()

static void DCH_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 3709 of file formatting.c.

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

References DCHCache, DCHCounter, i, and n_DCHCache.

Referenced by DCH_cache_getnew(), and DCH_cache_search().

◆ DCH_to_char()

static void DCH_to_char ( FormatNode node,
bool  is_interval,
TmToChar in,
char *  out,
Oid  collid 
)
static

Definition at line 2505 of file formatting.c.

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

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

Referenced by datetime_to_char_body().

◆ do_to_timestamp()

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

Definition at line 4428 of file formatting.c.

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

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

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

◆ fill_str()

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

Definition at line 4861 of file formatting.c.

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

References str.

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

◆ float4_to_char()

Datum float4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6697 of file formatting.c.

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

References fill_str(), FLOAT4_FITS_IN_INT32, 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_INT32_MAX, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, psprintf(), sign, val, and value.

◆ float8_to_char()

Datum float8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6810 of file formatting.c.

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

References fill_str(), FLOAT8_FITS_IN_INT32, 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_INT32_MAX, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, psprintf(), sign, val, and value.

◆ from_char_parse_int()

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

Definition at line 2300 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ from_char_parse_int_len()

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

Definition at line 2203 of file formatting.c.

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

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

Referenced by DCH_from_char(), and from_char_parse_int().

◆ from_char_seq_search()

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

Definition at line 2459 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ from_char_set_int()

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

Definition at line 2167 of file formatting.c.

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

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

Referenced by DCH_from_char(), and from_char_parse_int_len().

◆ from_char_set_mode()

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

Definition at line 2140 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

static char * get_last_relevant_decnum ( char *  num)
static

Definition at line 5358 of file formatting.c.

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

References elog.

Referenced by NUM_processor().

◆ get_th()

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

Definition at line 1563 of file formatting.c.

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

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

Referenced by NUM_processor(), and str_numth().

◆ index_seq_search()

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

Definition at line 1135 of file formatting.c.

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

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

Referenced by parse_format().

◆ int4_to_char()

Datum int4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6491 of file formatting.c.

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

References DatumGetCString(), DirectFunctionCall1, fill_str(), 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 6585 of file formatting.c.

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

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

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 5066 of file formatting.c.

5067{
5068 int len,
5069 num;
5070 char *p,
5071 *result,
5072 numstr[12];
5073
5074 result = (char *) palloc(MAX_ROMAN_LEN + 1);
5075 *result = '\0';
5076
5077 /*
5078 * This range limit is the same as in Oracle(TM). The difficulty with
5079 * handling 4000 or more is that we'd need to use more than 3 "M"'s, and
5080 * more than 3 of the same digit isn't considered a valid Roman string.
5081 */
5082