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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

typedef struct TmToChar TmToChar
 
typedef struct NUMProc NUMProc
 

Enumerations

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

Functions

static bool IS_SUFFIX_TH (uint8 _s)
 
static bool IS_SUFFIX_th (uint8 _s)
 
static bool IS_SUFFIX_THth (uint8 _s)
 
static enum TH_Case SUFFIX_TH_TYPE (uint8 _s)
 
static bool IS_SUFFIX_FM (uint8 _s)
 
static bool IS_SUFFIX_TM (uint8 _s)
 
static const KeyWordindex_seq_search (const char *str, const KeyWord *kw, const int *index)
 
static const KeySuffixsuff_search (const char *str, const KeySuffix *suf, enum KeySuffixType type)
 
static bool is_separator_char (const char *str)
 
static void NUMDesc_prepare (NUMDesc *num, FormatNode *n)
 
static void parse_format (FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, uint32 flags, NUMDesc *Num)
 
static void DCH_to_char (FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
 
static void DCH_from_char (FormatNode *node, const char *in, TmFromChar *out, Oid collid, bool std, Node *escontext)
 
static const charget_th (const char *num, enum TH_Case type)
 
static charstr_numth (char *dest, const char *num, enum TH_Case type)
 
static int adjust_partial_year_to_2020 (int year)
 
static size_t strspace_len (const char *str)
 
static bool from_char_set_mode (TmFromChar *tmfc, const FromCharDateMode mode, Node *escontext)
 
static bool from_char_set_int (int *dest, const int value, const FormatNode *node, Node *escontext)
 
static int from_char_parse_int_len (int *dest, const char **src, const size_t len, FormatNode *node, Node *escontext)
 
static int from_char_parse_int (int *dest, const char **src, FormatNode *node, Node *escontext)
 
static int seq_search_ascii (const char *name, const char *const *array, size_t *len)
 
static int seq_search_localized (const char *name, char **array, size_t *len, Oid collid)
 
static bool from_char_seq_search (int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, Node *escontext)
 
static bool do_to_timestamp (const text *date_txt, const text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext)
 
static void fill_str (char *str, int c, int max)
 
static FormatNodeNUM_cache (int len, NUMDesc *Num, const text *pars_str, bool *shouldFree)
 
static charint_to_roman (int number)
 
static int roman_to_int (NUMProc *Np, size_t input_len)
 
static void NUM_prepare_locale (NUMProc *Np)
 
static const charget_last_relevant_decnum (const char *num)
 
static void NUM_numpart_from_char (NUMProc *Np, int id, size_t input_len)
 
static void NUM_numpart_to_char (NUMProc *Np, int id)
 
static void NUM_add_locale_symbol (NUMProc *Np, const char *pattern)
 
static charNUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, size_t input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
 
static DCHCacheEntryDCH_cache_getnew (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_search (const char *str, bool std)
 
static DCHCacheEntryDCH_cache_fetch (const char *str, bool std)
 
static NUMCacheEntryNUM_cache_getnew (const char *str)
 
static NUMCacheEntryNUM_cache_search (const char *str)
 
static NUMCacheEntryNUM_cache_fetch (const char *str)
 
charstr_tolower (const char *buff, size_t nbytes, Oid collid)
 
charstr_toupper (const char *buff, size_t nbytes, Oid collid)
 
charstr_initcap (const char *buff, size_t nbytes, Oid collid)
 
charstr_casefold (const char *buff, size_t nbytes, Oid collid)
 
charasc_tolower (const char *buff, size_t nbytes)
 
charasc_toupper (const char *buff, size_t nbytes)
 
charasc_initcap (const char *buff, size_t nbytes)
 
static charstr_tolower_z (const char *buff, Oid collid)
 
static charstr_toupper_z (const char *buff, Oid collid)
 
static charstr_initcap_z (const char *buff, Oid collid)
 
static charasc_tolower_z (const char *buff)
 
static charasc_toupper_z (const char *buff)
 
static bool is_next_separator (FormatNode *n)
 
static void DCH_prevent_counter_overflow (void)
 
static int DCH_datetime_type (FormatNode *node)
 
static textdatetime_to_char_body (TmToChar *tmtc, const text *fmt, bool is_interval, Oid collid)
 
Datum timestamp_to_char (PG_FUNCTION_ARGS)
 
Datum timestamptz_to_char (PG_FUNCTION_ARGS)
 
Datum interval_to_char (PG_FUNCTION_ARGS)
 
Datum to_timestamp (PG_FUNCTION_ARGS)
 
Datum to_date (PG_FUNCTION_ARGS)
 
Datum parse_datetime (text *date_txt, text *fmt, Oid collid, bool strict, Oid *typid, int32 *typmod, int *tz, Node *escontext)
 
bool datetime_format_has_tz (const char *fmt_str)
 
static void NUM_prevent_counter_overflow (void)
 
static void NUM_eat_non_data_chars (NUMProc *Np, int n, size_t input_len)
 
Datum numeric_to_number (PG_FUNCTION_ARGS)
 
Datum numeric_to_char (PG_FUNCTION_ARGS)
 
Datum int4_to_char (PG_FUNCTION_ARGS)
 
Datum int8_to_char (PG_FUNCTION_ARGS)
 
Datum float4_to_char (PG_FUNCTION_ARGS)
 
Datum float8_to_char (PG_FUNCTION_ARGS)
 

Variables

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

Macro Definition Documentation

◆ A_D_STR

#define A_D_STR   "A.D."

Definition at line 187 of file formatting.c.

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 188 of file formatting.c.

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 213 of file formatting.c.

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 214 of file formatting.c.

◆ AD_STR

#define AD_STR   "AD"

Definition at line 189 of file formatting.c.

◆ ad_STR

#define ad_STR   "ad"

Definition at line 190 of file formatting.c.

◆ ADJUST_YEAR

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

Definition at line 185 of file formatting.c.

◆ AM_STR

#define AM_STR   "AM"

Definition at line 215 of file formatting.c.

◆ am_STR

#define am_STR   "am"

Definition at line 216 of file formatting.c.

◆ AMOUNT_TEST

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

Definition at line 1063 of file formatting.c.

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 192 of file formatting.c.

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 193 of file formatting.c.

◆ BC_STR

#define BC_STR   "BC"

Definition at line 194 of file formatting.c.

◆ bc_STR

#define bc_STR   "bc"

Definition at line 195 of file formatting.c.

◆ COPY_tm

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

Definition at line 503 of file formatting.c.

504 { \
505 (_DST)->tm_sec = (_SRC)->tm_sec; \
506 (_DST)->tm_min = (_SRC)->tm_min; \
507 (_DST)->tm_hour = (_SRC)->tm_hour; \
508 (_DST)->tm_mday = (_SRC)->tm_mday; \
509 (_DST)->tm_mon = (_SRC)->tm_mon; \
510 (_DST)->tm_year = (_SRC)->tm_year; \
511 (_DST)->tm_wday = (_SRC)->tm_wday; \
512 (_DST)->tm_yday = (_SRC)->tm_yday; \
513 (_DST)->tm_gmtoff = (_SRC)->tm_gmtoff; \
514} while(0)

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 379 of file formatting.c.

◆ DCH_CACHE_OVERHEAD

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

Definition at line 369 of file formatting.c.

◆ DCH_CACHE_SIZE

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

Definition at line 374 of file formatting.c.

◆ DCH_DATED

#define DCH_DATED   0x01

Definition at line 1053 of file formatting.c.

◆ DCH_FLAG

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

Definition at line 90 of file formatting.c.

◆ DCH_MAX_ITEM_SIZ

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

Definition at line 103 of file formatting.c.

◆ DCH_SUFFIX_FM

#define DCH_SUFFIX_FM   0x01

Definition at line 550 of file formatting.c.

◆ DCH_SUFFIX_SP

#define DCH_SUFFIX_SP   0x08

Definition at line 553 of file formatting.c.

◆ DCH_SUFFIX_TH

#define DCH_SUFFIX_TH   0x02

Definition at line 551 of file formatting.c.

◆ DCH_SUFFIX_th

#define DCH_SUFFIX_th   0x04

Definition at line 552 of file formatting.c.

◆ DCH_SUFFIX_TM

#define DCH_SUFFIX_TM   0x10

Definition at line 554 of file formatting.c.

◆ DCH_TIMED

#define DCH_TIMED   0x02

Definition at line 1054 of file formatting.c.

◆ DCH_to_char_fsec

#define DCH_to_char_fsec (   frac_fmt,
  frac_val 
)
Value:
sprintf(s, frac_fmt, (int) (frac_val)); \
if (IS_SUFFIX_THth(n->suffix)) \
str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); \
s += strlen(s)
static enum TH_Case SUFFIX_TH_TYPE(uint8 _s)
Definition formatting.c:578
static bool IS_SUFFIX_THth(uint8 _s)
Definition formatting.c:572
#define sprintf
Definition port.h:262

◆ DCH_ZONED

#define DCH_ZONED   0x04

Definition at line 1055 of file formatting.c.

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 468 of file formatting.c.

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 467 of file formatting.c.

◆ INVALID_FOR_INTERVAL

#define INVALID_FOR_INTERVAL
Value:
do { \
errmsg("invalid format specification for an interval value"), \
errhint("Intervals are not tied to specific calendar dates."))); \
} while(0)
int errcode(int sqlerrcode)
Definition elog.c:875
int errhint(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
static char * errmsg

Definition at line 534 of file formatting.c.

535 { \
539 errmsg("invalid format specification for an interval value"), \
540 errhint("Intervals are not tied to specific calendar dates."))); \
541} while(0)

◆ IS_BLANK

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

Definition at line 342 of file formatting.c.

◆ IS_BRACKET

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

Definition at line 344 of file formatting.c.

◆ IS_DECIMAL

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

Definition at line 339 of file formatting.c.

◆ IS_EEEE

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

Definition at line 350 of file formatting.c.

◆ IS_FILLMODE

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

Definition at line 343 of file formatting.c.

◆ IS_LDECIMAL

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

Definition at line 340 of file formatting.c.

◆ IS_LSIGN

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

Definition at line 346 of file formatting.c.

◆ IS_MINUS

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

Definition at line 345 of file formatting.c.

◆ IS_MULTI

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

Definition at line 349 of file formatting.c.

◆ IS_PLUS

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

Definition at line 347 of file formatting.c.

◆ IS_PREDEC_SPACE

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

Definition at line 5526 of file formatting.c.

◆ IS_ROMAN

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

Definition at line 348 of file formatting.c.

◆ IS_VALID_SUB_COMB

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

Definition at line 258 of file formatting.c.

◆ IS_ZERO

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

Definition at line 341 of file formatting.c.

◆ KeyWord_INDEX_FILTER

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

Definition at line 98 of file formatting.c.

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 97 of file formatting.c.

◆ MAX_ROMAN_LEN

#define MAX_ROMAN_LEN   15

Definition at line 278 of file formatting.c.

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 380 of file formatting.c.

◆ NUM_CACHE_OVERHEAD

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

Definition at line 371 of file formatting.c.

◆ NUM_CACHE_SIZE

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

Definition at line 376 of file formatting.c.

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 324 of file formatting.c.

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 327 of file formatting.c.

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 321 of file formatting.c.

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 334 of file formatting.c.

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 325 of file formatting.c.

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 322 of file formatting.c.

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 326 of file formatting.c.

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 328 of file formatting.c.

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 333 of file formatting.c.

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 331 of file formatting.c.

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 329 of file formatting.c.

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 332 of file formatting.c.

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 330 of file formatting.c.

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 323 of file formatting.c.

◆ NUM_FLAG

#define NUM_FLAG   0x2 /* NUMBER flag */

Definition at line 91 of file formatting.c.

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 104 of file formatting.c.

◆ NUM_TOCHAR_finish

#define NUM_TOCHAR_finish
Value:
do { \
size_t len; \
NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \
\
/* \
* 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. \
*/ \
} while (0)
#define VARHDRSZ
Definition c.h:781
uint32 result
#define PG_GET_COLLATION()
Definition fmgr.h:198
char sign
Definition informix.c:693
static char format
const void size_t len
static char * VARDATA(const void *PTR)
Definition varatt.h:305

Definition at line 6244 of file formatting.c.

6245 { \
6246 size_t len; \
6247 \
6248 NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \
6249 \
6251 pfree(format); \
6252 \
6253 /* \
6254 * Convert null-terminated representation of result to standard text. \
6255 * The result is usually much bigger than it needs to be, but there \
6256 * seems little point in realloc'ing it smaller. \

◆ NUM_TOCHAR_prepare

#define NUM_TOCHAR_prepare
Value:
do { \
} while (0)
static FormatNode * NUM_cache(int len, NUMDesc *Num, const text *pars_str, bool *shouldFree)
#define NUM_MAX_ITEM_SIZ
Definition formatting.c:104
void * palloc0(Size size)
Definition mcxt.c:1417
Definition c.h:776
static Size VARSIZE_ANY_EXHDR(const void *PTR)
Definition varatt.h:472
text * cstring_to_text(const char *s)
Definition varlena.c:184

Definition at line 6232 of file formatting.c.

6233 { \
6234 int len = VARSIZE_ANY_EXHDR(fmt); \
6237 result = (text *) palloc0((len * NUM_MAX_ITEM_SIZ) + 1 + VARHDRSZ); \
6238 format = NUM_cache(len, &Num, fmt, &shouldFree); \
6239} while (0)

◆ OVERLOAD_TEST

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

Definition at line 1062 of file formatting.c.

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 218 of file formatting.c.

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 219 of file formatting.c.

◆ PM_STR

#define PM_STR   "PM"

Definition at line 220 of file formatting.c.

◆ pm_STR

#define pm_STR   "pm"

Definition at line 221 of file formatting.c.

◆ ROMAN_VAL

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

Definition at line 266 of file formatting.c.

267 : \
268 (r) == 'V' ? 5 : \
269 (r) == 'X' ? 10 : \
270 (r) == 'L' ? 50 : \
271 (r) == 'C' ? 100 : \
272 (r) == 'D' ? 500 : \
273 (r) == 'M' ? 1000 : 0)

◆ SKIP_THth

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

Definition at line 1992 of file formatting.c.

1993 { \
1995 { \
1996 if (*(ptr)) (ptr) += pg_mblen_cstr(ptr); \
1997 if (*(ptr)) (ptr) += pg_mblen_cstr(ptr); \
1998 } \
1999 } while (0)

◆ STD_FLAG

#define STD_FLAG   0x4 /* STANDARD flag */

Definition at line 92 of file formatting.c.

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 599 of file formatting.c.

◆ tmtcFsec

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

Definition at line 500 of file formatting.c.

◆ tmtcTm

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

Definition at line 498 of file formatting.c.

◆ tmtcTzn

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

Definition at line 499 of file formatting.c.

◆ ZERO_tm

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

Definition at line 517 of file formatting.c.

518 { \
519 memset(_X, 0, sizeof(*(_X))); \
520 (_X)->tm_mday = (_X)->tm_mon = 1; \
521} while(0)

◆ ZERO_tmtc

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

Definition at line 523 of file formatting.c.

524 { \
525 ZERO_tm( tmtcTm(_X) ); \
526 tmtcFsec(_X) = 0; \
527 tmtcTzn(_X) = NULL; \
528} while(0)

Typedef Documentation

◆ NUMProc

◆ TmToChar

Enumeration Type Documentation

◆ DCH_poz

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

Definition at line 640 of file formatting.c.

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

◆ FormatNodeType

Enumerator
NODE_TYPE_END 
NODE_TYPE_ACTION 
NODE_TYPE_CHAR 
NODE_TYPE_SEPARATOR 
NODE_TYPE_SPACE 

Definition at line 147 of file formatting.c.

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

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 131 of file formatting.c.

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

◆ KeySuffixType

Enumerator
SUFFTYPE_PREFIX 
SUFFTYPE_POSTFIX 

Definition at line 111 of file formatting.c.

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

◆ NUM_poz

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

Definition at line 759 of file formatting.c.

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

◆ NUMDesc_lsign

Enumerator
NUM_LSIGN_PRE 
NUM_LSIGN_POST 
NUM_LSIGN_NONE 

Definition at line 295 of file formatting.c.

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

◆ TH_Case

Enumerator
TH_UPPER 
TH_LOWER 

Definition at line 289 of file formatting.c.

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

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2070 of file formatting.c.

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

Referenced by DCH_from_char().

◆ asc_initcap()

char * asc_initcap ( const char buff,
size_t  nbytes 
)

Definition at line 1925 of file formatting.c.

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

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

Referenced by str_initcap().

◆ asc_tolower()

char * asc_tolower ( const char buff,
size_t  nbytes 
)

Definition at line 1881 of file formatting.c.

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

References fb(), pg_ascii_tolower(), pnstrdup(), and result.

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

1974{
1975 return asc_tolower(buff, strlen(buff));
1976}
char * asc_tolower(const char *buff, size_t nbytes)

References asc_tolower(), and fb().

Referenced by DCH_to_char(), and NUM_processor().

◆ asc_toupper()

char * asc_toupper ( const char buff,
size_t  nbytes 
)

Definition at line 1903 of file formatting.c.

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

References fb(), pg_ascii_toupper(), pnstrdup(), and result.

Referenced by asc_toupper_z(), and str_toupper().

◆ asc_toupper_z()

static char * asc_toupper_z ( const char buff)
static

Definition at line 1979 of file formatting.c.

1980{
1981 return asc_toupper(buff, strlen(buff));
1982}
char * asc_toupper(const char *buff, size_t nbytes)

References asc_toupper(), and fb().

Referenced by DCH_to_char().

◆ datetime_format_has_tz()

bool datetime_format_has_tz ( const char fmt_str)

Definition at line 4318 of file formatting.c.

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

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

Referenced by jspIsMutableWalker().

◆ datetime_to_char_body()

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

Definition at line 3889 of file formatting.c.

3890{
3892 char *fmt_str,
3893 *result;
3894 bool incache;
3895 size_t fmt_len;
3896 text *res;
3897
3898 /*
3899 * Convert fmt to C string
3900 */
3903
3904 /*
3905 * Allocate workspace for result as C string
3906 */
3908 *result = '\0';
3909
3910 if (fmt_len > DCH_CACHE_SIZE)
3911 {
3912 /*
3913 * Allocate new memory if format picture is bigger than static cache
3914 * and do not use cache (call parser always)
3915 */
3916 incache = false;
3917
3918 format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3919
3922 }
3923 else
3924 {
3925 /*
3926 * Use cache buffers
3927 */
3929
3930 incache = true;
3931 format = ent->format;
3932 }
3933
3934 /* The real work is here */
3936
3937 if (!incache)
3938 pfree(format);
3939
3940 pfree(fmt_str);
3941
3942 /* convert C-string result to TEXT format */
3943 res = cstring_to_text(result);
3944
3945 pfree(result);
3946 return res;
3947}
Oid collid
static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
#define DCH_MAX_ITEM_SIZ
Definition formatting.c:103
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(), fb(), format, palloc(), parse_format(), pfree(), result, 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 3862 of file formatting.c.

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

References DCH_cache_getnew(), DCH_cache_search(), DCH_FLAG, DCH_index, DCH_keywords, DCH_suff, fb(), parse_format(), STD_FLAG, and str.

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

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

References Assert, DCH_CACHE_ENTRIES, DCH_CACHE_SIZE, DCH_prevent_counter_overflow(), DCHCache, DCHCounter, elog, fb(), i, MemoryContextAllocZero(), n_DCHCache, 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 3841 of file formatting.c.

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

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

Referenced by DCH_cache_fetch().

◆ DCH_datetime_type()

static int DCH_datetime_type ( FormatNode node)
static

Definition at line 3685 of file formatting.c.

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

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

Referenced by datetime_format_has_tz(), and do_to_timestamp().

◆ DCH_from_char()

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

Definition at line 3115 of file formatting.c.

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

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

Referenced by do_to_timestamp().

◆ DCH_prevent_counter_overflow()

static void DCH_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 3671 of file formatting.c.

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

References DCHCache, DCHCounter, fb(), 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 2469 of file formatting.c.

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

Referenced by datetime_to_char_body().

◆ do_to_timestamp()

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

Definition at line 4381 of file formatting.c.

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

References Assert, collid, DateTimeParseError(), DAY, DCH_cache_fetch(), DCH_CACHE_SIZE, DCH_datetime_type(), DCH_FLAG, DCH_from_char(), DCH_index, DCH_keywords, DCH_suff, DEBUG_TM, DEBUG_TMFC, DetermineTimeZoneAbbrevOffset(), DTERR_FIELD_OVERFLOW, DTERR_TZDISP_OVERFLOW, DTK_DATE_M, DTK_M, errcode(), errhint(), errmsg, errsave, fb(), format, FROM_CHAR_DATE_ISOWEEK, fmt_tz::gmtoffset, fmt_tz::has_tz, HOURS_PER_DAY, i, INT64CONST, isleap, isoweek2date(), isoweek2j(), isoweekdate2date(), j2date(), MAX_TZDISP_HOUR, MINS_PER_HOUR, MONTH, MONTHS_PER_YEAR, palloc(), parse_format(), pfree(), pg_add_s32_overflow(), pg_mul_s32_overflow(), pg_sub_s32_overflow(), SECS_PER_HOUR, SECS_PER_MINUTE, SOFT_ERROR_OCCURRED, 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, USECS_PER_SEC, ValidateDate(), VARSIZE_ANY_EXHDR(), x, y, YEAR, and ZERO_tm.

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

◆ fill_str()

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

Definition at line 4816 of file formatting.c.

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

References fb(), and 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 6651 of file formatting.c.

6656{
6659 NUMDesc Num;
6661 text *result;
6662 bool shouldFree;
6663 int out_pre_spaces = 0,
6664 sign = 0;
6665 char *numstr,
6666 *p;
6667
6669
6670 if (IS_ROMAN(&Num))
6671 {
6673
6674 /* See notes in ftoi4() */
6675 value = rint(value);
6676 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6678 intvalue = (int32) value;
6679 else
6682 }
6683 else if (IS_EEEE(&Num))
6684 {
6685 if (isnan(value) || isinf(value))
6686 {
6687 /*
6688 * Allow 6 characters for the leading sign, the decimal point,
6689 * "e", the exponent's sign and two exponent digits.
6690 */
6691 numstr = (char *) palloc(Num.pre + Num.post + 7);
6692 fill_str(numstr, '#', Num.pre + Num.post + 6);
6693 *numstr = ' ';
6694 *(numstr + Num.pre + 1) = '.';
6695 }
6696 else
6697 {
6698 numstr = psprintf("%+.*e", Num.post, value);
6699
6700 /*
6701 * Swap a leading positive sign for a space.
6702 */
6703 if (*numstr == '+')
6704 *numstr = ' ';
6705 }
6706 }
6707 else
6708 {
6709 float4 val = value;
6710 char *orgnum;
6711 size_t numstr_pre_len;
6712
6713 if (IS_MULTI(&Num))
6714 {
6715 float multi = pow((double) 10, (double) Num.multi);
6716
6717 val = value * multi;
6718 Num.pre += Num.multi;
6719 }
6720
6721 orgnum = psprintf("%.0f", fabs(val));
6723
6724 /* adjust post digits to fit max float digits */
6725 if (numstr_pre_len >= FLT_DIG)
6726 Num.post = 0;
6727 else if (numstr_pre_len + Num.post > FLT_DIG)
6728 Num.post = FLT_DIG - numstr_pre_len;
6729 orgnum = psprintf("%.*f", Num.post, val);
6730
6731 if (*orgnum == '-')
6732 { /* < 0 */
6733 sign = '-';
6734 numstr = orgnum + 1;
6735 }
6736 else
6737 {
6738 sign = '+';
6739 numstr = orgnum;
6740 }
6741
6742 if ((p = strchr(numstr, '.')))
6743 numstr_pre_len = p - numstr;
6744 else
6746
6747 /* needs padding? */
6748 if (numstr_pre_len < Num.pre)
6749 out_pre_spaces = Num.pre - numstr_pre_len;
6750 /* overflowed prefix digit format? */
6751 else if (numstr_pre_len > Num.pre)
6752 {
6753 numstr = (char *) palloc(Num.pre + Num.post + 2);
6754 fill_str(numstr, '#', Num.pre + Num.post + 1);
6755 *(numstr + Num.pre) = '.';
6756 }
6757 }
#define FLOAT4_FITS_IN_INT32(num)
Definition c.h:1171
#define PG_INT32_MAX
Definition c.h:673
int32_t int32
Definition c.h:620
float float4
Definition c.h:713
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define PG_GETARG_FLOAT4(n)
Definition fmgr.h:282
static void fill_str(char *str, int c, int max)
#define NUM_TOCHAR_prepare
#define IS_MULTI(_f)
Definition formatting.c:349
#define IS_ROMAN(_f)
Definition formatting.c:348
#define IS_EEEE(_f)
Definition formatting.c:350
static char * int_to_roman(int number)
long val
Definition informix.c:689
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
int multi
Definition formatting.c:312

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

◆ float8_to_char()

Datum float8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6763 of file formatting.c.

6768{
6771 NUMDesc Num;
6773 text *result;
6774 bool shouldFree;
6775 int out_pre_spaces = 0,
6776 sign = 0;
6777 char *numstr,
6778 *p;
6779
6781
6782 if (IS_ROMAN(&Num))
6783 {
6785
6786 /* See notes in dtoi4() */
6787 value = rint(value);
6788 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6790 intvalue = (int32) value;
6791 else
6794 }
6795 else if (IS_EEEE(&Num))
6796 {
6797 if (isnan(value) || isinf(value))
6798 {
6799 /*
6800 * Allow 6 characters for the leading sign, the decimal point,
6801 * "e", the exponent's sign and two exponent digits.
6802 */
6803 numstr = (char *) palloc(Num.pre + Num.post + 7);
6804 fill_str(numstr, '#', Num.pre + Num.post + 6);
6805 *numstr = ' ';
6806 *(numstr + Num.pre + 1) = '.';
6807 }
6808 else
6809 {
6810 numstr = psprintf("%+.*e", Num.post, value);
6811
6812 /*
6813 * Swap a leading positive sign for a space.
6814 */
6815 if (*numstr == '+')
6816 *numstr = ' ';
6817 }
6818 }
6819 else
6820 {
6821 float8 val = value;
6822 char *orgnum;
6823 size_t numstr_pre_len;
6824
6825 if (IS_MULTI(&Num))
6826 {
6827 double multi = pow((double) 10, (double) Num.multi);
6828
6829 val = value * multi;
6830 Num.pre += Num.multi;
6831 }
6832
6833 orgnum = psprintf("%.0f", fabs(val));
6835
6836 /* adjust post digits to fit max double digits */
6837 if (numstr_pre_len >= DBL_DIG)
6838 Num.post = 0;
6839 else if (numstr_pre_len + Num.post > DBL_DIG)
6840 Num.post = DBL_DIG - numstr_pre_len;
6841 orgnum = psprintf("%.*f", Num.post, val);
6842
6843 if (*orgnum == '-')
6844 { /* < 0 */
6845 sign = '-';
6846 numstr = orgnum + 1;
6847 }
6848 else
6849 {
6850 sign = '+';
6851 numstr = orgnum;
6852 }
6853
6854 if ((p = strchr(numstr, '.')))
6855 numstr_pre_len = p - numstr;
6856 else
6858
6859 /* needs padding? */
6860 if (numstr_pre_len < Num.pre)
6861 out_pre_spaces = Num.pre - numstr_pre_len;
6862 /* overflowed prefix digit format? */
6863 else if (numstr_pre_len > Num.pre)
6864 {
6865 numstr = (char *) palloc(Num.pre + Num.post + 2);
6866 fill_str(numstr, '#', Num.pre + Num.post + 1);
6867 *(numstr + Num.pre) = '.';
6868 }
6869 }
#define FLOAT8_FITS_IN_INT32(num)
Definition c.h:1177
double float8
Definition c.h:714
#define PG_GETARG_FLOAT8(n)
Definition fmgr.h:283

References fb(), fill_str(), FLOAT8_FITS_IN_INT32, format, int_to_roman(), IS_EEEE, IS_MULTI, IS_ROMAN, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, palloc(), PG_GETARG_FLOAT8, PG_GETARG_TEXT_PP, PG_INT32_MAX, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, psprintf(), result, 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 2272 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ from_char_parse_int_len()

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

Definition at line 2177 of file formatting.c.

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

References Assert, DCH_MAX_ITEM_SIZ, ereturn, errcode(), errdetail(), errhint(), errmsg, fb(), from_char_set_int(), init, is_next_separator(), IS_SUFFIX_FM(), FormatNode::key, len, KeyWord::name, result, 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 2426 of file formatting.c.

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

References collid, ereturn, errcode(), errdetail(), errmsg, fb(), 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 2142 of file formatting.c.

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

References ereturn, errcode(), errdetail(), errmsg, fb(), 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 2116 of file formatting.c.

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

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

Referenced by DCH_from_char().

◆ get_last_relevant_decnum()

static const char * get_last_relevant_decnum ( const char num)
static

Definition at line 5295 of file formatting.c.

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

References elog, fb(), and result.

Referenced by NUM_processor().

◆ get_th()

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

Definition at line 1556 of file formatting.c.

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

References Assert, ereport, errcode(), errmsg, ERROR, fb(), 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:98
Definition type.h:96

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

6452{
6455 NUMDesc Num;
6457 text *result;
6458 bool shouldFree;
6459 int out_pre_spaces = 0,
6460 sign = 0;
6461 char *numstr,
6462 *orgnum;
6463
6465
6466 /*
6467 * On DateType depend part (int32)
6468 */
6469 if (IS_ROMAN(&Num))
6471 else if (IS_EEEE(&Num))
6472 {
6473 /* we can do it easily because float8 won't lose any precision */
6474 float8 val = (float8) value;
6475
6476 orgnum = (char *) psprintf("%+.*e", Num.post, val);
6477
6478 /*
6479 * Swap a leading positive sign for a space.
6480 */
6481 if (*orgnum == '+')
6482 *orgnum = ' ';
6483
6484 numstr = orgnum;
6485 }
6486 else
6487 {
6488 size_t numstr_pre_len;
6489
6490 if (IS_MULTI(&Num))
6491 {
6493 Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
6494 Num.pre += Num.multi;
6495 }
6496 else
6497 {
6500 }
6501
6502 if (*orgnum == '-')
6503 {
6504 sign = '-';
6505 orgnum++;
6506 }
6507 else
6508 sign = '+';
6509
6511
6512 /* post-decimal digits? Pad out with zeros. */
6513 if (Num.post)
6514 {
6515 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6517 *(numstr + numstr_pre_len) = '.';
6518 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6519 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6520 }
6521 else
6522 numstr = orgnum;
6523
6524 /* needs padding? */
6525 if (numstr_pre_len < Num.pre)
6526 out_pre_spaces = Num.pre - numstr_pre_len;
6527 /* overflowed prefix digit format? */
6528 else if (numstr_pre_len > Num.pre)
6529 {
6530 numstr = (char *) palloc(Num.pre + Num.post + 2);
6531 fill_str(numstr, '#', Num.pre + Num.post + 1);
6532 *(numstr + Num.pre) = '.';
6533 }
6534 }
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
Datum int4out(PG_FUNCTION_ARGS)
Definition int.c:327
static char * DatumGetCString(Datum X)
Definition postgres.h:365
static Datum Int32GetDatum(int32 X)
Definition postgres.h:212

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

◆ int8_to_char()

Datum int8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6540 of file formatting.c.

6545{
6548 NUMDesc Num;
6550 text *result;
6551 bool shouldFree;
6552 int out_pre_spaces = 0,
6553 sign = 0;
6554 char *numstr,
6555 *orgnum;
6556
6558
6559 /*
6560 * On DateType depend part (int64)
6561 */
6562 if (IS_ROMAN(&Num))
6563 {
6565
6566 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6568 intvalue = (int32) value;
6569 else
6572 }
6573 else if (IS_EEEE(&Num))
6574 {
6575 /* to avoid loss of precision, must go via numeric not float8 */
6577 Num.post);
6578
6579 /*
6580 * numeric_out_sci() does not emit a sign for positive numbers. We
6581 * need to add a space in this case so that positive and negative
6582 * numbers are aligned. We don't have to worry about NaN/inf here.
6583 */
6584 if (*orgnum != '-')
6585 {
6586 numstr = (char *) palloc(strlen(orgnum) + 2);
6587 *numstr = ' ';
6588 strcpy(numstr + 1, orgnum);
6589 }
6590 else
6591 {
6592 numstr = orgnum;
6593 }
6594 }
6595 else
6596 {
6597 size_t numstr_pre_len;
6598
6599 if (IS_MULTI(&Num))
6600 {
6601 double multi = pow((double) 10, (double) Num.multi);
6602
6606 Float8GetDatum(multi))));
6607 Num.pre += Num.multi;
6608 }
6609
6612
6613 if (*orgnum == '-')
6614 {
6615 sign = '-';
6616 orgnum++;
6617 }
6618 else
6619 sign = '+';
6620
6622
6623 /* post-decimal digits? Pad out with zeros. */
6624 if (Num.post)
6625 {
6626 numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
6628 *(numstr + numstr_pre_len) = '.';
6629 memset(numstr + numstr_pre_len + 1, '0', Num.post);
6630 *(numstr + numstr_pre_len + Num.post + 1) = '\0';
6631 }
6632 else
6633 numstr = orgnum;
6634
6635 /* needs padding? */
6636 if (numstr_pre_len < Num.pre)
6637 out_pre_spaces = Num.pre - numstr_pre_len;
6638 /* overflowed prefix digit format? */
6639 else if (numstr_pre_len > Num.pre)
6640 {
6641 numstr = (char *) palloc(Num.pre + Num.post + 2);
6642 fill_str(numstr, '#', Num.pre + Num.post + 1);
6643 *(numstr + Num.pre) = '.';
6644 }
6645 }
char * numeric_out_sci(Numeric num, int scale)
Definition numeric.c:975
Numeric int64_to_numeric(int64 val)
Definition numeric.c:4264
int64_t int64
Definition c.h:621
#define PG_INT32_MIN
Definition c.h:672
#define DirectFunctionCall2(func, arg1, arg2)
Definition fmgr.h:686
#define PG_GETARG_INT64(n)
Definition fmgr.h:284
Datum int8out(PG_FUNCTION_ARGS)
Definition int8.c:61
Datum int8mul(PG_FUNCTION_ARGS)
Definition int8.c:490
Datum dtoi8(PG_FUNCTION_ARGS)
Definition int8.c:1297
static Datum Int64GetDatum(int64 X)
Definition postgres.h:426
static int64 DatumGetInt64(Datum X)
Definition postgres.h:416
static Datum Float8GetDatum(float8 X)
Definition postgres.h:515

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

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 5006 of file formatting.c.

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

References Assert, fb(), fill_str(), len, MAX_ROMAN_LEN, palloc(), result, rm1, rm10, rm100, and snprintf.

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

◆ interval_to_char()

Datum interval_to_char ( PG_FUNCTION_ARGS  )

Definition at line 4032 of file formatting.c.

4033{
4036 *res;
4037 TmToChar tmtc;
4038 struct fmt_tm *tm;
4039 struct pg_itm tt,
4040 *itm = &tt;
4041
4044
4045 ZERO_tmtc(&tmtc);
4046 tm = tmtcTm(&tmtc);
4047
4048 interval2itm(*it, itm);
4049 tmtc.fsec = itm->tm_usec;
4050 tm->tm_sec = itm->tm_sec;
4051 tm->tm_min = itm->tm_min;
4052 tm->tm_hour = itm->tm_hour;
4053 tm->tm_mday = itm->tm_mday;
4054 tm->tm_mon = itm->tm_mon;
4055 tm->tm_year = itm->tm_year;
4056
4057 /* wday is meaningless, yday approximates the total span in days */
4059
4060 if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
4062
4063 PG_RETURN_TEXT_P(res);
4064}
void interval2itm(Interval span, struct pg_itm *itm)
Definition timestamp.c:2041
#define INTERVAL_NOT_FINITE(i)
Definition timestamp.h:195
#define DAYS_PER_MONTH
Definition timestamp.h:116
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_RETURN_TEXT_P(x)
Definition fmgr.h:374
static text * datetime_to_char_body(TmToChar *tmtc, const text *fmt, bool is_interval, Oid collid)
#define ZERO_tmtc(_X)
Definition formatting.c:523
int tm_yday
Definition pgtime.h:43
#define PG_GETARG_INTERVAL_P(n)
Definition timestamp.h:65

References datetime_to_char_body(), DAYS_PER_MONTH, fb(), interval2itm(), INTERVAL_NOT_FINITE, MONTHS_PER_YEAR, PG_GET_COLLATION, PG_GETARG_INTERVAL_P, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, tm, pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_yday, pg_tm::tm_year, tmtcTm, VARSIZE_ANY_EXHDR(), and ZERO_tmtc.

◆ is_next_separator()

static bool is_next_separator ( FormatNode n)
static

Definition at line 2037 of file formatting.c.

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

References FormatNode::character, fb(), KeyWord::is_digit, IS_SUFFIX_THth(), FormatNode::key, NODE_TYPE_ACTION, NODE_TYPE_END, FormatNode::suffix, and FormatNode::type.

Referenced by from_char_parse_int_len().

◆ is_separator_char()

static bool is_separator_char ( const char str)
static

Definition at line 1173 of file formatting.c.

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

References str.

Referenced by DCH_from_char(), and parse_format().

◆ IS_SUFFIX_FM()

static bool IS_SUFFIX_FM ( uint8  _s)
inlinestatic

Definition at line 585 of file formatting.c.

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

References DCH_SUFFIX_FM, and fb().

Referenced by DCH_to_char(), and from_char_parse_int_len().

◆ IS_SUFFIX_TH()

static bool IS_SUFFIX_TH ( uint8  _s)
inlinestatic

Definition at line 560 of file formatting.c.

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

References DCH_SUFFIX_TH, and fb().

Referenced by IS_SUFFIX_THth().

◆ IS_SUFFIX_th()

static bool IS_SUFFIX_th ( uint8  _s)
inlinestatic

Definition at line 566 of file formatting.c.

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

References DCH_SUFFIX_th, and fb().

Referenced by IS_SUFFIX_THth().

◆ IS_SUFFIX_THth()

static bool IS_SUFFIX_THth ( uint8  _s)
inlinestatic

Definition at line 572 of file formatting.c.

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

References fb(), IS_SUFFIX_TH(), and IS_SUFFIX_th().

Referenced by DCH_to_char(), and is_next_separator().

◆ IS_SUFFIX_TM()

static bool IS_SUFFIX_TM ( uint8  _s)
inlinestatic

Definition at line 591 of file formatting.c.

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

References DCH_SUFFIX_TM, and fb().

Referenced by DCH_from_char(), and DCH_to_char().

◆ NUM_add_locale_symbol()

static void NUM_add_locale_symbol ( NUMProc Np,
const char pattern 
)
static

Definition at line 5721 of file formatting.c.

5722{
5723 size_t pattern_len = strlen(pattern);
5724
5725 /* Truncate symbol if it's potentially too long */
5729 memcpy(Np->inout_p, pattern, pattern_len);
5730 Np->inout_p += pattern_len;
5731}
#define unlikely(x)
Definition c.h:438
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
int pg_mbcliplen(const char *mbstr, int len, int limit)
Definition mbutils.c:1211

References fb(), memcpy(), NUM_MAX_ITEM_SIZ, pg_mbcliplen(), and unlikely.

Referenced by NUM_numpart_to_char().

◆ NUM_cache()

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

Definition at line 4943 of file formatting.c.

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

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

Referenced by numeric_to_number().

◆ NUM_cache_fetch()

static NUMCacheEntry * NUM_cache_fetch ( const char str)
static

Definition at line 4916 of file formatting.c.

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

References fb(), NUM_cache_getnew(), NUM_cache_search(), NUM_FLAG, NUM_index, NUM_keywords, parse_format(), and str.

Referenced by NUM_cache().

◆ NUM_cache_getnew()

static NUMCacheEntry * NUM_cache_getnew ( const char str)
static

Definition at line 4836 of file formatting.c.

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

References Assert, elog, fb(), i, MemoryContextAllocZero(), n_NUMCache, NUM_CACHE_ENTRIES, NUM_CACHE_SIZE, NUM_prevent_counter_overflow(), NUMCache, NUMCounter, str, strlcpy(), TopMemoryContext, and NUMCacheEntry::valid.

Referenced by NUM_cache_fetch().

◆ NUM_cache_search()

static NUMCacheEntry * NUM_cache_search ( const char str)
static

Definition at line 4895 of file formatting.c.

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

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

Referenced by NUM_cache_fetch().

◆ NUM_eat_non_data_chars()

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

Definition at line 5737 of file formatting.c.

5738{
5739 const char *end = Np->inout + input_len;
5740
5741 while (n-- > 0)
5742 {
5743 if (OVERLOAD_TEST)
5744 break; /* end of input */
5745 if (strchr("0123456789.,+-", *Np->inout_p) != NULL)
5746 break; /* it's a data character */
5747 Np->inout_p += pg_mblen_range(Np->inout_p, end);
5748 }
5749}
#define OVERLOAD_TEST
int pg_mblen_range(const char *mbstr, const char *end)
Definition mbutils.c:1084

References fb(), OVERLOAD_TEST, and pg_mblen_range().

Referenced by NUM_processor().

◆ NUM_numpart_from_char()

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

Definition at line 5322 of file formatting.c.

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

References AMOUNT_TEST, elog, fb(), IS_BRACKET, IS_DECIMAL, IS_LSIGN, IS_MINUS, IS_PLUS, NUM_0, NUM_9, NUM_DEC, NUM_LSIGN_PRE, OVERLOAD_TEST, and x.

Referenced by NUM_processor().

◆ NUM_numpart_to_char()

static void NUM_numpart_to_char ( NUMProc Np,
int  id 
)
static

Definition at line 5536 of file formatting.c.

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

References elog, fb(), IS_BRACKET, IS_DECIMAL, IS_FILLMODE, IS_LSIGN, IS_PREDEC_SPACE, IS_ROMAN, IS_ZERO, NUM_0, NUM_9, NUM_add_locale_symbol(), NUM_D, NUM_DEC, NUM_LSIGN_POST, and NUM_LSIGN_PRE.

Referenced by NUM_processor().

◆ NUM_prepare_locale()

static void NUM_prepare_locale ( NUMProc Np)
static

Definition at line 5214 of file formatting.c.

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

References fb(), IS_LDECIMAL, and PGLC_localeconv().

Referenced by NUM_processor().

◆ NUM_prevent_counter_overflow()

static void NUM_prevent_counter_overflow ( void  )
inlinestatic

Definition at line 4824 of file formatting.c.

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

References fb(), i, n_NUMCache, NUMCache, and NUMCounter.

Referenced by NUM_cache_getnew(), and NUM_cache_search().

◆ NUM_processor()

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

Definition at line 5752 of file formatting.c.

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

References AMOUNT_TEST, asc_tolower_z(), FormatNode::character, elog, ereport, errcode(), errmsg, ERROR, fb(), get_last_relevant_decnum(), get_th(), KeyWord::id, IS_BRACKET, IS_DECIMAL, IS_EEEE, IS_FILLMODE, IS_LSIGN, IS_MINUS, IS_PLUS, IS_ROMAN, IS_ZERO, FormatNode::key, memcpy(), MemSet, Min, NODE_TYPE_ACTION, NODE_TYPE_END, NUM_0, NUM_9, NUM_COMMA, NUM_D, NUM_DEC, NUM_eat_non_data_chars(), NUM_G, NUM_L, NUM_LSIGN_POST, NUM_LSIGN_PRE, NUM_MAX_ITEM_SIZ, NUM_MI, NUM_numpart_from_char(), NUM_numpart_to_char(), NUM_PL, NUM_prepare_locale(), NUM_RN, NUM_rn, NUM_SG, NUM_TH, NUM_th, OVERLOAD_TEST, pg_mbcliplen(), pg_mblen_range(), pg_mbstrlen(), pg_mbstrlen_with_len(), roman_to_int(), sign, sprintf, TH_LOWER, TH_UPPER, FormatNode::type, unlikely, and NUMDesc::zero_start.

Referenced by numeric_to_number().

◆ NUMDesc_prepare()

static void NUMDesc_prepare ( NUMDesc num,
FormatNode n 
)
static

Definition at line 1186 of file formatting.c.

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

References ereport, errcode(), errdetail(), errmsg, ERROR, fb(), NUMDesc::flag, KeyWord::id, IS_BLANK, IS_BRACKET, IS_DECIMAL, IS_EEEE, IS_FILLMODE, IS_LSIGN, IS_MINUS, IS_MULTI, IS_PLUS, IS_ROMAN, IS_ZERO, FormatNode::key, NUMDesc::lsign, NUMDesc::multi, NUMDesc::need_locale, NODE_TYPE_ACTION, NUM_0, NUM_9, NUM_B, NUM_D, NUM_DEC, NUM_E, NUM_F_BLANK, NUM_F_BRACKET, NUM_F_DECIMAL, NUM_F_EEEE, NUM_F_FILLMODE, NUM_F_LDECIMAL, NUM_F_LSIGN, NUM_F_MINUS, NUM_F_MINUS_POST, NUM_F_MULTI, NUM_F_PLUS, NUM_F_PLUS_POST, NUM_F_ROMAN, NUM_F_ZERO, NUM_FM, NUM_G, NUM_L, NUM_LSIGN_NONE, NUM_LSIGN_POST, NUM_LSIGN_PRE, NUM_MI, NUM_PL, NUM_PR, NUM_RN, NUM_rn, NUM_S, NUM_SG, NUM_V, pg_fallthrough, NUMDesc::post, NUMDesc::pre, NUMDesc::pre_lsign_num, FormatNode::type, NUMDesc::zero_end, and NUMDesc::zero_start.

Referenced by parse_format().

◆ numeric_to_char()

Datum numeric_to_char ( PG_FUNCTION_ARGS  )

Definition at line 6320 of file formatting.c.

6325{
6328 NUMDesc Num;
6330 text *result;
6331 bool shouldFree;
6332 int out_pre_spaces = 0,
6333 sign = 0;
6334 char *numstr,
6335 *orgnum,
6336 *p;
6337
6339
6340 /*
6341 * On DateType depend part (numeric)
6342 */
6343 if (IS_ROMAN(&Num))
6344 {
6347
6348 /* Round and convert to int */
6349 intvalue = numeric_int4_safe(value, (Node *) &escontext);
6350 /* On overflow, just use PG_INT32_MAX; int_to_roman will cope */
6351 if (escontext.error_occurred)
6354 }
6355 else if (IS_EEEE(&Num))
6356 {
6358
6359 /*
6360 * numeric_out_sci() does not emit a sign for positive numbers. We
6361 * need to add a space in this case so that positive and negative
6362 * numbers are aligned. Also must check for NaN/infinity cases, which
6363 * we handle the same way as in float8_to_char.
6364 */
6365 if (strcmp(orgnum, "NaN") == 0 ||
6366 strcmp(orgnum, "Infinity") == 0 ||
6367 strcmp(orgnum, "-Infinity") == 0)
6368 {
6369 /*
6370 * Allow 6 characters for the leading sign, the decimal point,
6371 * "e", the exponent's sign and two exponent digits.
6372 */
6373 numstr = (char *) palloc(Num.pre + Num.post + 7);
6374 fill_str(numstr, '#', Num.pre + Num.post + 6);
6375 *numstr = ' ';
6376 *(numstr + Num.pre + 1) = '.';
6377 }
6378 else if (*orgnum != '-')
6379 {
6380 numstr = (char *) palloc(strlen(orgnum) + 2);
6381 *numstr = ' ';
6382 strcpy(numstr + 1, orgnum);
6383 }
6384 else
6385 {
6386 numstr = orgnum;
6387 }
6388 }
6389 else
6390 {
6391 size_t numstr_pre_len;
6392 Numeric val = value;
6393 Numeric x;
6394
6395 if (IS_MULTI(&Num))
6396 {
6399
6402 NumericGetDatum(b)));
6405 NumericGetDatum(x)));
6406 Num.pre += Num.multi;
6407 }
6408
6411 Int32GetDatum(Num.post)));
6413 NumericGetDatum(x)));
6414
6415 if (*orgnum == '-')
6416 {
6417 sign = '-';
6418 numstr = orgnum + 1;
6419 }
6420 else
6421 {
6422 sign = '+';
6423 numstr = orgnum;
6424 }
6425
6426 if ((p = strchr(numstr, '.')))
6427 numstr_pre_len = p - numstr;
6428 else
6430
6431 /* needs padding? */
6432 if (numstr_pre_len < Num.pre)
6433 out_pre_spaces = Num.pre - numstr_pre_len;
6434 /* overflowed prefix digit format? */
6435 else if (numstr_pre_len > Num.pre)
6436 {
6437 numstr = (char *) palloc(Num.pre + Num.post + 2);
6438 fill_str(numstr, '#', Num.pre + Num.post + 1);
6439 *(numstr + Num.pre) = '.';
6440 }
6441 }
Datum numeric_round(PG_FUNCTION_ARGS)
Definition numeric.c:1528
int32 numeric_int4_safe(Numeric num, Node *escontext)
Definition numeric.c:4369
Datum numeric_power(PG_FUNCTION_ARGS)
Definition numeric.c:3916
Datum numeric_out(PG_FUNCTION_ARGS)
Definition numeric.c:799
Datum numeric_mul(PG_FUNCTION_ARGS)
Definition numeric.c:3017
int b
Definition isn.c:74
int a
Definition isn.c:73
static Numeric DatumGetNumeric(Datum X)
Definition numeric.h:64
#define PG_GETARG_NUMERIC(n)
Definition numeric.h:81
static Datum NumericGetDatum(Numeric X)
Definition numeric.h:76
Definition nodes.h:135

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

◆ numeric_to_number()

Datum numeric_to_number ( PG_FUNCTION_ARGS  )

Definition at line 6262 of file formatting.c.

6267{
6270 NUMDesc Num;
6271 Datum result;
6273 char *numstr;
6274 bool shouldFree;
6275 int len = 0;
6276 int scale,
6277 precision;
6278
6280
6283
6284 format = NUM_cache(len, &Num, fmt, &shouldFree);
6285
6286 numstr = (char *) palloc((len * NUM_MAX_ITEM_SIZ) + 1);
6287
6289 VARSIZE_ANY_EXHDR(value), 0, 0, false, PG_GET_COLLATION());
6290
6291 scale = Num.post;
6292 precision = Num.pre + Num.multi + scale;
6293
6294 if (shouldFree)
6295 pfree(format);
6296
6300 Int32GetDatum(((precision << 16) | scale) + VARHDRSZ));
6301
6302 if (IS_MULTI(&Num))
6303 {
6304 Numeric x;
6307
6310 NumericGetDatum(b)));
6312 result,
6314 }
Datum numeric_in(PG_FUNCTION_ARGS)
Definition numeric.c:626
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition fmgr.h:688
static char * NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, char *number, size_t input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
static int scale
Definition pgbench.c:182
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:383
static char * VARDATA_ANY(const void *PTR)
Definition varatt.h:486

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

◆ parse_datetime()

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

Definition at line 4157 of file formatting.c.

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

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

Referenced by executeDateTimeMethod().

◆ parse_format()

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

Definition at line 1371 of file formatting.c.

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

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

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

◆ roman_to_int()

static int roman_to_int ( NUMProc Np,
size_t  input_len 
)
static

Definition at line 5065 of file formatting.c.

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

References fb(), i, IS_VALID_SUB_COMB, len, MAX_ROMAN_LEN, OVERLOAD_TEST, pg_ascii_toupper(), result, and ROMAN_VAL.

Referenced by NUM_processor().

◆ seq_search_ascii()

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

Definition at line 2290 of file formatting.c.

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

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

Referenced by from_char_seq_search().

◆ seq_search_localized()

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

Definition at line 2343 of file formatting.c.

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

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

Referenced by from_char_seq_search().

◆ str_casefold()

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

Definition at line 1812 of file formatting.c.

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

References asc_tolower(), Assert, collid, ereport, errcode(), errhint(), errmsg, ERROR, fb(), GetDatabaseEncoding(), OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strfold(), PG_UTF8, repalloc(), and result.

Referenced by casefold().

◆ str_initcap()

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

Definition at line 1748 of file formatting.c.

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

References asc_initcap(), Assert, collid, ereport, errcode(), errhint(), errmsg, ERROR, fb(), OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strtitle(), repalloc(), and result.

Referenced by initcap(), and str_initcap_z().

◆ str_initcap_z()

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

Definition at line 1967 of file formatting.c.

1968{
1969 return str_initcap(buff, strlen(buff), collid);
1970}
char * str_initcap(const char *buff, size_t nbytes, Oid collid)

References collid, fb(), and str_initcap().

Referenced by DCH_to_char().

◆ str_numth()

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

Definition at line 1601 of file formatting.c.

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

References fb(), get_th(), and type.

Referenced by DCH_to_char().

◆ str_tolower()

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

Definition at line 1620 of file formatting.c.

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

References asc_tolower(), Assert, collid, ereport, errcode(), errhint(), errmsg, ERROR, fb(), OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strlower(), repalloc(), and result.

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

◆ str_tolower_z()

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

Definition at line 1955 of file formatting.c.

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

References collid, fb(), and str_tolower().

Referenced by DCH_to_char().

◆ str_toupper()

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

Definition at line 1684 of file formatting.c.

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

References asc_toupper(), Assert, collid, ereport, errcode(), errhint(), errmsg, ERROR, fb(), OidIsValid, palloc(), pg_newlocale_from_collation(), pg_strupper(), repalloc(), and result.

Referenced by MakeUpper(), seq_search_localized(), str_toupper_z(), and upper().

◆ str_toupper_z()

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

Definition at line 1961 of file formatting.c.

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

References collid, fb(), and str_toupper().

Referenced by DCH_to_char().

◆ strspace_len()

static size_t strspace_len ( const char str)
static

Definition at line 2094 of file formatting.c.

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

References fb(), len, and str.

Referenced by from_char_parse_int_len().

◆ suff_search()

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

Definition at line 1159 of file formatting.c.

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

References fb(), KeySuffix::name, str, and type.

Referenced by parse_format().

◆ SUFFIX_TH_TYPE()

static enum TH_Case SUFFIX_TH_TYPE ( uint8  _s)
inlinestatic

Definition at line 578 of file formatting.c.

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

References DCH_SUFFIX_TH, fb(), TH_LOWER, and TH_UPPER.

Referenced by DCH_to_char().

◆ timestamp_to_char()

Datum timestamp_to_char ( PG_FUNCTION_ARGS  )

Definition at line 3957 of file formatting.c.

3958{
3961 *res;
3962 TmToChar tmtc;
3963 struct pg_tm tt;
3964 struct fmt_tm *tm;
3965 int thisdate;
3966
3969
3970 ZERO_tmtc(&tmtc);
3971 tm = tmtcTm(&tmtc);
3972
3973 if (timestamp2tm(dt, NULL, &tt, &tmtcFsec(&tmtc), NULL, NULL) != 0)
3974 ereport(ERROR,
3976 errmsg("timestamp out of range")));
3977
3978 /* calculate wday and yday, because timestamp2tm doesn't */
3979 thisdate = date2j(tt.tm_year, tt.tm_mon, tt.tm_mday);
3980 tt.tm_wday = (thisdate + 1) % 7;
3981 tt.tm_yday = thisdate - date2j(tt.tm_year, 1, 1) + 1;
3982
3983 COPY_tm(tm, &tt);
3984
3985 if (!(res = datetime_to_char_body(&tmtc, fmt, false, PG_GET_COLLATION())))
3987
3988 PG_RETURN_TEXT_P(res);
3989}
int timestamp2tm(Timestamp dt, int *tzp, struct pg_tm *tm, fsec_t *fsec, const char **tzn, pg_tz *attimezone)
Definition timestamp.c:1904
#define TIMESTAMP_NOT_FINITE(j)
Definition timestamp.h:169
#define tmtcFsec(_X)
Definition formatting.c:500
#define COPY_tm(_DST, _SRC)
Definition formatting.c:503
#define PG_GETARG_TIMESTAMP(n)
Definition timestamp.h:63

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg, ERROR, fb(), PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, tmtcFsec, tmtcTm, VARSIZE_ANY_EXHDR(), and ZERO_tmtc.

◆ timestamptz_to_char()

Datum timestamptz_to_char ( PG_FUNCTION_ARGS  )

Definition at line 3992 of file formatting.c.

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

References COPY_tm, date2j(), datetime_to_char_body(), ereport, errcode(), errmsg, ERROR, fb(), PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_GETARG_TIMESTAMP, PG_RETURN_NULL, PG_RETURN_TEXT_P, timestamp2tm(), TIMESTAMP_NOT_FINITE, tm, tmtcFsec, tmtcTm, tmtcTzn, VARSIZE_ANY_EXHDR(), and ZERO_tmtc.

◆ to_date()

Datum to_date ( PG_FUNCTION_ARGS  )

Definition at line 4111 of file formatting.c.

4112{
4117 struct pg_tm tm;
4118 struct fmt_tz ftz;
4119 fsec_t fsec;
4120
4122 &tm, &fsec, &ftz, NULL, NULL, NULL);
4123
4124 /* Prevent overflow in Julian-day routines */
4126 ereport(ERROR,
4128 errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
4129
4131
4132 /* Now check for just-out-of-range dates */
4133 if (!IS_VALID_DATE(result))
4134 ereport(ERROR,
4136 errmsg("date out of range: \"%s\"", text_to_cstring(date_txt))));
4137
4139}
#define PG_RETURN_DATEADT(x)
Definition date.h:99
unsigned int Oid

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

◆ to_timestamp()

Datum to_timestamp ( PG_FUNCTION_ARGS  )

Definition at line 4073 of file formatting.c.

4074{
4079 int tz;
4080 struct pg_tm tm;
4081 struct fmt_tz ftz;
4082 fsec_t fsec;
4083 int fprec;
4084
4086 &tm, &fsec, &ftz, &fprec, NULL, NULL);
4087
4088 /* Use the specified time zone, if any. */
4089 if (ftz.has_tz)
4090 tz = ftz.gmtoffset;
4091 else
4093
4094 if (tm2timestamp(&tm, fsec, &tz, &result) != 0)
4095 ereport(ERROR,
4097 errmsg("timestamp out of range")));
4098
4099 /* Use the specified fractional precision, if any. */
4100 if (fprec)
4102
4104}
int DetermineTimeZoneOffset(struct pg_tm *tm, pg_tz *tzp)
Definition datetime.c:1605
PGDLLIMPORT pg_tz * session_timezone
Definition pgtz.c:28
#define PG_RETURN_TIMESTAMP(x)
Definition timestamp.h:67

References AdjustTimestampForTypmod(), collid, DetermineTimeZoneOffset(), do_to_timestamp(), ereport, errcode(), errmsg, ERROR, fb(), PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_TIMESTAMP, result, session_timezone, tm, and tm2timestamp().

Variable Documentation

◆ adbc_strings

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

Definition at line 207 of file formatting.c.

Referenced by DCH_from_char().

◆ adbc_strings_long

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

Definition at line 208 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings

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

Definition at line 233 of file formatting.c.

Referenced by DCH_from_char().

◆ ampm_strings_long

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

Definition at line 234 of file formatting.c.

Referenced by DCH_from_char().

◆ days_short

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

Definition at line 174 of file formatting.c.

174 {
175 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL
176};

Referenced by DCH_from_char(), and DCH_to_char().

◆ DCH_index

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

Definition at line 976 of file formatting.c.

976 {
977/*
9780 1 2 3 4 5 6 7 8 9
979*/
980 /*---- first 0..31 chars are skipped ----*/
981
982 -1, -1, -1, -1, -1, -1, -1, -1,
983 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
984 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
985 -1, -1, -1, -1, -1, DCH_A_D, DCH_B_C, DCH_CC, DCH_DAY, -1,
986 DCH_FF1, -1, DCH_HH24, DCH_IDDD, DCH_J, -1, -1, DCH_MI, -1, DCH_OF,
988 -1, -1, -1, -1, -1, -1, -1, DCH_a_d, DCH_b_c, DCH_cc,
989 DCH_day, -1, DCH_ff1, -1, DCH_hh24, DCH_iddd, DCH_j, -1, -1, DCH_mi,
991 -1, DCH_y_yyy, -1, -1, -1, -1
992
993 /*---- chars over 126 are skipped ----*/
994};

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

◆ DCH_keywords

const KeyWord DCH_keywords[]
static

Definition at line 805 of file formatting.c.

805 {
806/* name, len, id, is_digit, date_mode */
807 {"A.D.", 4, DCH_A_D, false, FROM_CHAR_DATE_NONE}, /* A */
808 {"A.M.", 4, DCH_A_M, false, FROM_CHAR_DATE_NONE},
809 {"AD", 2, DCH_AD, false, FROM_CHAR_DATE_NONE},
810 {"AM", 2, DCH_AM, false, FROM_CHAR_DATE_NONE},
811 {"B.C.", 4, DCH_B_C, false, FROM_CHAR_DATE_NONE}, /* B */
812 {"BC", 2, DCH_BC, false, FROM_CHAR_DATE_NONE},
813 {"CC", 2, DCH_CC, true, FROM_CHAR_DATE_NONE}, /* C */
814 {"DAY", 3, DCH_DAY, false, FROM_CHAR_DATE_NONE}, /* D */
815 {"DDD", 3, DCH_DDD, true, FROM_CHAR_DATE_GREGORIAN},
816 {"DD", 2, DCH_DD, true, FROM_CHAR_DATE_GREGORIAN},
817 {"DY", 2, DCH_DY, false, FROM_CHAR_DATE_NONE},
818 {"Day", 3, DCH_Day, false, FROM_CHAR_DATE_NONE},
819 {"Dy", 2, DCH_Dy, false, FROM_CHAR_DATE_NONE},
820 {"D", 1, DCH_D, true, FROM_CHAR_DATE_GREGORIAN},
821 {"FF1", 3, DCH_FF1, true, FROM_CHAR_DATE_NONE}, /* F */
822 {"FF2", 3, DCH_FF2, true, FROM_CHAR_DATE_NONE},
823 {"FF3", 3, DCH_FF3, true, FROM_CHAR_DATE_NONE},
824 {"FF4", 3, DCH_FF4, true, FROM_CHAR_DATE_NONE},
825 {"FF5", 3, DCH_FF5, true, FROM_CHAR_DATE_NONE},
826 {"FF6", 3, DCH_FF6, true, FROM_CHAR_DATE_NONE},
827 {"FX", 2, DCH_FX, false, FROM_CHAR_DATE_NONE},
828 {"HH24", 4, DCH_HH24, true, FROM_CHAR_DATE_NONE}, /* H */
829 {"HH12", 4, DCH_HH12, true, FROM_CHAR_DATE_NONE},
830 {"HH", 2, DCH_HH, true, FROM_CHAR_DATE_NONE},
831 {"IDDD", 4, DCH_IDDD, true, FROM_CHAR_DATE_ISOWEEK}, /* I */
832 {"ID", 2, DCH_ID, true, FROM_CHAR_DATE_ISOWEEK},
833 {"IW", 2, DCH_IW, true, FROM_CHAR_DATE_ISOWEEK},
834 {"IYYY", 4, DCH_IYYY, true, FROM_CHAR_DATE_ISOWEEK},
835 {"IYY", 3, DCH_IYY, true, FROM_CHAR_DATE_ISOWEEK},
836 {"IY", 2, DCH_IY, true, FROM_CHAR_DATE_ISOWEEK},
837 {"I", 1, DCH_I, true, FROM_CHAR_DATE_ISOWEEK},
838 {"J", 1, DCH_J, true, FROM_CHAR_DATE_NONE}, /* J */
839 {"MI", 2, DCH_MI, true, FROM_CHAR_DATE_NONE}, /* M */
840 {"MM", 2, DCH_MM, true, FROM_CHAR_DATE_GREGORIAN},
841 {"MONTH", 5, DCH_MONTH, false, FROM_CHAR_DATE_GREGORIAN},
842 {"MON", 3, DCH_MON, false, FROM_CHAR_DATE_GREGORIAN},
843 {"MS", 2, DCH_MS, true, FROM_CHAR_DATE_NONE},
844 {"Month", 5, DCH_Month, false, FROM_CHAR_DATE_GREGORIAN},
845 {"Mon", 3, DCH_Mon, false, FROM_CHAR_DATE_GREGORIAN},
846 {"OF", 2, DCH_OF, false, FROM_CHAR_DATE_NONE}, /* O */
847 {"P.M.", 4, DCH_P_M, false, FROM_CHAR_DATE_NONE}, /* P */
848 {"PM", 2, DCH_PM, false, FROM_CHAR_DATE_NONE},
849 {"Q", 1, DCH_Q, true, FROM_CHAR_DATE_NONE}, /* Q */
850 {"RM", 2, DCH_RM, false, FROM_CHAR_DATE_GREGORIAN}, /* R */
851 {"SSSSS", 5, DCH_SSSS, true, FROM_CHAR_DATE_NONE}, /* S */
852 {"SSSS", 4, DCH_SSSS, true, FROM_CHAR_DATE_NONE},
853 {"SS", 2, DCH_SS, true, FROM_CHAR_DATE_NONE},
854 {"TZH", 3, DCH_TZH, false, FROM_CHAR_DATE_NONE}, /* T */
855 {"TZM", 3, DCH_TZM, true, FROM_CHAR_DATE_NONE},
856 {"TZ", 2, DCH_TZ, false, FROM_CHAR_DATE_NONE},
857 {"US", 2, DCH_US, true, FROM_CHAR_DATE_NONE}, /* U */
858 {"WW", 2, DCH_WW, true, FROM_CHAR_DATE_GREGORIAN}, /* W */
859 {"W", 1, DCH_W, true, FROM_CHAR_DATE_GREGORIAN},
860 {"Y,YYY", 5, DCH_Y_YYY, true, FROM_CHAR_DATE_GREGORIAN}, /* Y */
861 {"YYYY", 4, DCH_YYYY, true, FROM_CHAR_DATE_GREGORIAN},
862 {"YYY", 3, DCH_YYY, true, FROM_CHAR_DATE_GREGORIAN},
863 {"YY", 2, DCH_YY, true, FROM_CHAR_DATE_GREGORIAN},
864 {"Y", 1, DCH_Y, true, FROM_CHAR_DATE_GREGORIAN},
865 {"a.d.", 4, DCH_a_d, false, FROM_CHAR_DATE_NONE}, /* a */
866 {"a.m.", 4, DCH_a_m, false, FROM_CHAR_DATE_NONE},
867 {"ad", 2, DCH_ad, false, FROM_CHAR_DATE_NONE},
868 {"am", 2, DCH_am, false, FROM_CHAR_DATE_NONE},
869 {"b.c.", 4, DCH_b_c, false, FROM_CHAR_DATE_NONE}, /* b */
870 {"bc", 2, DCH_bc, false, FROM_CHAR_DATE_NONE},
871 {"cc", 2, DCH_CC, true, FROM_CHAR_DATE_NONE}, /* c */
872 {"day", 3, DCH_day, false, FROM_CHAR_DATE_NONE}, /* d */
873 {"ddd", 3, DCH_DDD, true, FROM_CHAR_DATE_GREGORIAN},
874 {"dd", 2, DCH_DD, true, FROM_CHAR_DATE_GREGORIAN},
875 {"dy", 2, DCH_dy, false, FROM_CHAR_DATE_NONE},
876 {"d", 1, DCH_D, true, FROM_CHAR_DATE_GREGORIAN},
877 {"ff1", 3, DCH_FF1, true, FROM_CHAR_DATE_NONE}, /* f */
878 {"ff2", 3, DCH_FF2, true, FROM_CHAR_DATE_NONE},
879 {"ff3", 3, DCH_FF3, true, FROM_CHAR_DATE_NONE},
880 {"ff4", 3, DCH_FF4, true, FROM_CHAR_DATE_NONE},
881 {"ff5", 3, DCH_FF5, true, FROM_CHAR_DATE_NONE},
882 {"ff6", 3, DCH_FF6, true, FROM_CHAR_DATE_NONE},
883 {"fx", 2, DCH_FX, false, FROM_CHAR_DATE_NONE},
884 {"hh24", 4, DCH_HH24, true, FROM_CHAR_DATE_NONE}, /* h */
885 {"hh12", 4, DCH_HH12, true, FROM_CHAR_DATE_NONE},
886 {"hh", 2, DCH_HH, true, FROM_CHAR_DATE_NONE},
887 {"iddd", 4, DCH_IDDD, true, FROM_CHAR_DATE_ISOWEEK}, /* i */
888 {"id", 2, DCH_ID, true, FROM_CHAR_DATE_ISOWEEK},
889 {"iw", 2, DCH_IW, true, FROM_CHAR_DATE_ISOWEEK},
890 {"iyyy", 4, DCH_IYYY, true, FROM_CHAR_DATE_ISOWEEK},
891 {"iyy", 3, DCH_IYY, true, FROM_CHAR_DATE_ISOWEEK},
892 {"iy", 2, DCH_IY, true, FROM_CHAR_DATE_ISOWEEK},
893 {"i", 1, DCH_I, true, FROM_CHAR_DATE_ISOWEEK},
894 {"j", 1, DCH_J, true, FROM_CHAR_DATE_NONE}, /* j */
895 {"mi", 2, DCH_MI, true, FROM_CHAR_DATE_NONE}, /* m */
896 {"mm", 2, DCH_MM, true, FROM_CHAR_DATE_GREGORIAN},
897 {"month", 5, DCH_month, false, FROM_CHAR_DATE_GREGORIAN},
898 {"mon", 3, DCH_mon, false, FROM_CHAR_DATE_GREGORIAN},
899 {"ms", 2, DCH_MS, true, FROM_CHAR_DATE_NONE},
900 {"of", 2, DCH_OF, false, FROM_CHAR_DATE_NONE}, /* o */
901 {"p.m.", 4, DCH_p_m, false, FROM_CHAR_DATE_NONE}, /* p */
902 {"pm", 2, DCH_pm, false, FROM_CHAR_DATE_NONE},
903 {"q", 1, DCH_Q, true, FROM_CHAR_DATE_NONE}, /* q */
904 {"rm", 2, DCH_rm, false, FROM_CHAR_DATE_GREGORIAN}, /* r */
905 {"sssss", 5, DCH_SSSS, true, FROM_CHAR_DATE_NONE}, /* s */
906 {"ssss", 4, DCH_SSSS, true, FROM_CHAR_DATE_NONE},
907 {"ss", 2, DCH_SS, true, FROM_CHAR_DATE_NONE},
908 {"tzh", 3, DCH_TZH, false, FROM_CHAR_DATE_NONE}, /* t */
909 {"tzm", 3, DCH_TZM, true, FROM_CHAR_DATE_NONE},
910 {"tz", 2, DCH_tz, false, FROM_CHAR_DATE_NONE},
911 {"us", 2, DCH_US, true, FROM_CHAR_DATE_NONE}, /* u */
912 {"ww", 2, DCH_WW, true, FROM_CHAR_DATE_GREGORIAN}, /* w */
913 {"w", 1, DCH_W, true, FROM_CHAR_DATE_GREGORIAN},
914 {"y,yyy", 5, DCH_Y_YYY, true, FROM_CHAR_DATE_GREGORIAN}, /* y */
915 {"yyyy", 4, DCH_YYYY, true, FROM_CHAR_DATE_GREGORIAN},
916 {"yyy", 3, DCH_YYY, true, FROM_CHAR_DATE_GREGORIAN},
917 {"yy", 2, DCH_YY, true, FROM_CHAR_DATE_GREGORIAN},
918 {"y", 1, DCH_Y, true, FROM_CHAR_DATE_GREGORIAN},
919
920 /* last */
921 {NULL, 0, 0, 0, 0}
922};

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

◆ DCH_suff

const KeySuffix DCH_suff[]
static
Initial value:

Definition at line 601 of file formatting.c.

601 {
602 {"FM", 2, DCH_SUFFIX_FM, SUFFTYPE_PREFIX},
603 {"fm", 2, DCH_SUFFIX_FM, SUFFTYPE_PREFIX},
605 {"tm", 2, DCH_SUFFIX_TM, SUFFTYPE_PREFIX},
609 /* last */
610 {NULL, 0, 0, 0}
611};

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

◆ DCHCache

DCHCacheEntry* DCHCache[DCH_CACHE_ENTRIES]
static

Definition at line 401 of file formatting.c.

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

◆ DCHCounter

int DCHCounter = 0
static

Definition at line 403 of file formatting.c.

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

◆ months_full

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

Definition at line 169 of file formatting.c.

169 {
170 "January", "February", "March", "April", "May", "June", "July",
171 "August", "September", "October", "November", "December", NULL
172};

Referenced by DCH_from_char(), and DCH_to_char().

◆ n_DCHCache

int n_DCHCache = 0
static

Definition at line 402 of file formatting.c.

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

◆ n_NUMCache

int n_NUMCache = 0
static

Definition at line 407 of file formatting.c.

Referenced by NUM_cache_getnew(), NUM_cache_search(), and NUM_prevent_counter_overflow().

◆ NUM_index

const int NUM_index[KeyWord_INDEX_SIZE]
static
Initial value:
= {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
-1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
-1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
-1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
-1, -1, -1, -1, -1, -1
}

Definition at line 999 of file formatting.c.

999 {
1000/*
10010 1 2 3 4 5 6 7 8 9
1002*/
1003 /*---- first 0..31 chars are skipped ----*/
1004
1005 -1, -1, -1, -1, -1, -1, -1, -1,
1006 -1, -1, -1, -1, NUM_COMMA, -1, NUM_DEC, -1, NUM_0, -1,
1007 -1, -1, -1, -1, -1, -1, -1, NUM_9, -1, -1,
1008 -1, -1, -1, -1, -1, -1, NUM_B, NUM_C, NUM_D, NUM_E,
1009 NUM_FM, NUM_G, -1, -1, -1, -1, NUM_L, NUM_MI, -1, -1,
1010 NUM_PL, -1, NUM_RN, NUM_SG, NUM_TH, -1, NUM_V, -1, -1, -1,
1011 -1, -1, -1, -1, -1, -1, -1, -1, NUM_b, NUM_c,
1012 NUM_d, NUM_e, NUM_fm, NUM_g, -1, -1, -1, -1, NUM_l, NUM_mi,
1013 -1, -1, NUM_pl, -1, NUM_rn, NUM_sg, NUM_th, -1, NUM_v, -1,
1014 -1, -1, -1, -1, -1, -1
1015
1016 /*---- chars over 126 are skipped ----*/
1017};

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUM_keywords

const KeyWord NUM_keywords[]
static

Definition at line 929 of file formatting.c.

929 {
930/* name, len, id is in Index */
931 {",", 1, NUM_COMMA}, /* , */
932 {".", 1, NUM_DEC}, /* . */
933 {"0", 1, NUM_0}, /* 0 */
934 {"9", 1, NUM_9}, /* 9 */
935 {"B", 1, NUM_B}, /* B */
936 {"C", 1, NUM_C}, /* C */
937 {"D", 1, NUM_D}, /* D */
938 {"EEEE", 4, NUM_E}, /* E */
939 {"FM", 2, NUM_FM}, /* F */
940 {"G", 1, NUM_G}, /* G */
941 {"L", 1, NUM_L}, /* L */
942 {"MI", 2, NUM_MI}, /* M */
943 {"PL", 2, NUM_PL}, /* P */
944 {"PR", 2, NUM_PR},
945 {"RN", 2, NUM_RN}, /* R */
946 {"SG", 2, NUM_SG}, /* S */
947 {"SP", 2, NUM_SP},
948 {"S", 1, NUM_S},
949 {"TH", 2, NUM_TH}, /* T */
950 {"V", 1, NUM_V}, /* V */
951 {"b", 1, NUM_B}, /* b */
952 {"c", 1, NUM_C}, /* c */
953 {"d", 1, NUM_D}, /* d */
954 {"eeee", 4, NUM_E}, /* e */
955 {"fm", 2, NUM_FM}, /* f */
956 {"g", 1, NUM_G}, /* g */
957 {"l", 1, NUM_L}, /* l */
958 {"mi", 2, NUM_MI}, /* m */
959 {"pl", 2, NUM_PL}, /* p */
960 {"pr", 2, NUM_PR},
961 {"rn", 2, NUM_rn}, /* r */
962 {"sg", 2, NUM_SG}, /* s */
963 {"sp", 2, NUM_SP},
964 {"s", 1, NUM_S},
965 {"th", 2, NUM_th}, /* t */
966 {"v", 1, NUM_V}, /* v */
967
968 /* last */
969 {NULL, 0, 0}
970};

Referenced by NUM_cache(), and NUM_cache_fetch().

◆ NUMCache

NUMCacheEntry* NUMCache[NUM_CACHE_ENTRIES]
static

Definition at line 406 of file formatting.c.

Referenced by NUM_cache_getnew(), NUM_cache_search(), and NUM_prevent_counter_overflow().

◆ NUMCounter

int NUMCounter = 0
static

Definition at line 408 of file formatting.c.

Referenced by NUM_cache_getnew(), NUM_cache_search(), and NUM_prevent_counter_overflow().

◆ numTH

const char* const numTH[] = {"ST", "ND", "RD", "TH", NULL}
static

Definition at line 283 of file formatting.c.

283{"ST", "ND", "RD", "TH", NULL};

Referenced by get_th().

◆ numth

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

Definition at line 284 of file formatting.c.

284{"st", "nd", "rd", "th", NULL};

Referenced by get_th().

◆ rm1

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

Definition at line 250 of file formatting.c.

250{"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};

Referenced by int_to_roman().

◆ rm10

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

Definition at line 251 of file formatting.c.

251{"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};

Referenced by int_to_roman().

◆ rm100

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

Definition at line 252 of file formatting.c.

252{"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};

Referenced by int_to_roman().

◆ rm_months_lower

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

Definition at line 244 of file formatting.c.

245{"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};

Referenced by DCH_from_char(), and DCH_to_char().

◆ rm_months_upper

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

Definition at line 241 of file formatting.c.

242{"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};

Referenced by DCH_to_char().