PostgreSQL Source Code  git master
formatting.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <unistd.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include "catalog/pg_collation.h"
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datetime.h"
#include "utils/formatting.h"
#include "utils/int8.h"
#include "utils/numeric.h"
#include "utils/pg_locale.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  TmToChar
 
struct  NUMProc
 

Macros

#define DCH_TYPE   1 /* DATE-TIME version */
 
#define NUM_TYPE   2 /* NUMBER version */
 
#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 MAXFLOATWIDTH   60
 
#define MAXDOUBLEWIDTH   500
 
#define NODE_TYPE_END   1
 
#define NODE_TYPE_ACTION   2
 
#define NODE_TYPE_CHAR   3
 
#define SUFFTYPE_PREFIX   1
 
#define SUFFTYPE_POSTFIX   2
 
#define CLOCK_24_HOUR   0
 
#define CLOCK_12_HOUR   1
 
#define ADJUST_YEAR(year, is_interval)   ((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))
 
#define A_D_STR   "A.D."
 
#define a_d_STR   "a.d."
 
#define AD_STR   "AD"
 
#define ad_STR   "ad"
 
#define B_C_STR   "B.C."
 
#define b_c_STR   "b.c."
 
#define BC_STR   "BC"
 
#define bc_STR   "bc"
 
#define A_M_STR   "A.M."
 
#define a_m_STR   "a.m."
 
#define AM_STR   "AM"
 
#define am_STR   "am"
 
#define P_M_STR   "P.M."
 
#define p_m_STR   "p.m."
 
#define PM_STR   "PM"
 
#define pm_STR   "pm"
 
#define ONE_UPPER   1 /* Name */
 
#define ALL_UPPER   2 /* NAME */
 
#define ALL_LOWER   3 /* name */
 
#define FULL_SIZ   0
 
#define MAX_MONTH_LEN   9
 
#define MAX_MON_LEN   3
 
#define MAX_DAY_LEN   9
 
#define MAX_DY_LEN   3
 
#define MAX_RM_LEN   4
 
#define TH_UPPER   1
 
#define TH_LOWER   2
 
#define NUM_F_DECIMAL   (1 << 1)
 
#define NUM_F_LDECIMAL   (1 << 2)
 
#define NUM_F_ZERO   (1 << 3)
 
#define NUM_F_BLANK   (1 << 4)
 
#define NUM_F_FILLMODE   (1 << 5)
 
#define NUM_F_LSIGN   (1 << 6)
 
#define NUM_F_BRACKET   (1 << 7)
 
#define NUM_F_MINUS   (1 << 8)
 
#define NUM_F_PLUS   (1 << 9)
 
#define NUM_F_ROMAN   (1 << 10)
 
#define NUM_F_MULTI   (1 << 11)
 
#define NUM_F_PLUS_POST   (1 << 12)
 
#define NUM_F_MINUS_POST   (1 << 13)
 
#define NUM_F_EEEE   (1 << 14)
 
#define NUM_LSIGN_PRE   (-1)
 
#define NUM_LSIGN_POST   1
 
#define NUM_LSIGN_NONE   0
 
#define IS_DECIMAL(_f)   ((_f)->flag & NUM_F_DECIMAL)
 
#define IS_LDECIMAL(_f)   ((_f)->flag & NUM_F_LDECIMAL)
 
#define IS_ZERO(_f)   ((_f)->flag & NUM_F_ZERO)
 
#define IS_BLANK(_f)   ((_f)->flag & NUM_F_BLANK)
 
#define IS_FILLMODE(_f)   ((_f)->flag & NUM_F_FILLMODE)
 
#define IS_BRACKET(_f)   ((_f)->flag & NUM_F_BRACKET)
 
#define IS_MINUS(_f)   ((_f)->flag & NUM_F_MINUS)
 
#define IS_LSIGN(_f)   ((_f)->flag & NUM_F_LSIGN)
 
#define IS_PLUS(_f)   ((_f)->flag & NUM_F_PLUS)
 
#define IS_ROMAN(_f)   ((_f)->flag & NUM_F_ROMAN)
 
#define IS_MULTI(_f)   ((_f)->flag & NUM_F_MULTI)
 
#define IS_EEEE(_f)   ((_f)->flag & NUM_F_EEEE)
 
#define NUM_CACHE_SIZE   64
 
#define NUM_CACHE_ENTRIES   20
 
#define DCH_CACHE_SIZE   128
 
#define DCH_CACHE_ENTRIES   20
 
#define ZERO_tmfc(_X)   memset(_X, 0, sizeof(TmFromChar))
 
#define DEBUG_TMFC(_X)
 
#define DEBUG_TM(_X)
 
#define tmtcTm(_X)   (&(_X)->tm)
 
#define tmtcTzn(_X)   ((_X)->tzn)
 
#define tmtcFsec(_X)   ((_X)->fsec)
 
#define ZERO_tm(_X)
 
#define ZERO_tmtc(_X)
 
#define INVALID_FOR_INTERVAL
 
#define DCH_S_FM   0x01
 
#define DCH_S_TH   0x02
 
#define DCH_S_th   0x04
 
#define DCH_S_SP   0x08
 
#define DCH_S_TM   0x10
 
#define S_THth(_s)   ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0)
 
#define S_TH(_s)   (((_s) & DCH_S_TH) ? 1 : 0)
 
#define S_th(_s)   (((_s) & DCH_S_th) ? 1 : 0)
 
#define S_TH_TYPE(_s)   (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER)
 
#define S_FM(_s)   (((_s) & DCH_S_FM) ? 1 : 0)
 
#define S_SP(_s)   (((_s) & DCH_S_SP) ? 1 : 0)
 
#define S_TM(_s)   (((_s) & DCH_S_TM) ? 1 : 0)
 
#define TM_SUFFIX_LEN   2
 
#define SKIP_THth(ptr, _suf)
 
#define zeroize_NUM(_n)
 
#define OVERLOAD_TEST   (Np->inout_p >= Np->inout + input_len)
 
#define AMOUNT_TEST(s)   (Np->inout_p <= Np->inout + (input_len - (s)))
 
#define IS_PREDEC_SPACE(_n)
 
#define NUM_TOCHAR_prepare
 
#define NUM_TOCHAR_finish
 

Typedefs

typedef struct TmToChar TmToChar
 
typedef struct NUMProc NUMProc
 

Enumerations

enum  FromCharDateMode { FROM_CHAR_DATE_NONE = 0, FROM_CHAR_DATE_GREGORIAN, FROM_CHAR_DATE_ISOWEEK }
 
enum  DCH_poz {
  DCH_A_D, DCH_A_M, DCH_AD, DCH_AM,
  DCH_B_C, DCH_BC, DCH_CC, DCH_DAY,
  DCH_DDD, DCH_DD, DCH_DY, DCH_Day,
  DCH_Dy, DCH_D, DCH_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_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_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_p_m, DCH_pm, DCH_q, DCH_rm,
  DCH_ssss, DCH_ss, DCH_tz, DCH_us,
  DCH_ww, DCH_w, DCH_y_yyy, DCH_yyyy,
  DCH_yyy, DCH_yy, DCH_y, _DCH_last_
}
 
enum  NUM_poz {
  NUM_COMMA, NUM_DEC, NUM_0, NUM_9,
  NUM_B, NUM_C, NUM_D, NUM_E,
  NUM_FM, NUM_G, NUM_L, NUM_MI,
  NUM_PL, NUM_PR, NUM_RN, NUM_SG,
  NUM_SP, NUM_S, NUM_TH, NUM_V,
  NUM_b, NUM_c, NUM_d, NUM_e,
  NUM_fm, NUM_g, NUM_l, NUM_mi,
  NUM_pl, NUM_pr, NUM_rn, NUM_sg,
  NUM_sp, NUM_s, NUM_th, NUM_v,
  _NUM_last_
}
 

Functions

static const KeyWordindex_seq_search (const char *str, const KeyWord *kw, const int *index)
 
static const KeySuffixsuff_search (const char *str, const KeySuffix *suf, int type)
 
static 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, int ver, 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, char *in, TmFromChar *out)
 
static const char * get_th (char *num, int type)
 
static char * str_numth (char *dest, char *num, int type)
 
static int adjust_partial_year_to_2020 (int year)
 
static int strspace_len (char *str)
 
static void from_char_set_mode (TmFromChar *tmfc, const FromCharDateMode mode)
 
static void from_char_set_int (int *dest, const int value, const FormatNode *node)
 
static int from_char_parse_int_len (int *dest, char **src, const int len, FormatNode *node)
 
static int from_char_parse_int (int *dest, char **src, FormatNode *node)
 
static int seq_search (char *name, const char *const *array, int type, int max, int *len)
 
static int from_char_seq_search (int *dest, char **src, const char *const *array, int type, int max, FormatNode *node)
 
static void do_to_timestamp (text *date_txt, text *fmt, struct pg_tm *tm, fsec_t *fsec)
 
static char * fill_str (char *str, int c, int max)
 
static FormatNodeNUM_cache (int len, NUMDesc *Num, text *pars_str, bool *shouldFree)
 
static char * int_to_roman (int number)
 
static void NUM_prepare_locale (NUMProc *Np)
 
static char * get_last_relevant_decnum (char *num)
 
static void NUM_numpart_from_char (NUMProc *Np, int id, int input_len)
 
static void NUM_numpart_to_char (NUMProc *Np, int id)
 
static char * NUM_processor (FormatNode *node, NUMDesc *Num, char *inout, char *number, int input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid)
 
static DCHCacheEntryDCH_cache_getnew (const char *str)
 
static DCHCacheEntryDCH_cache_search (const char *str)
 
static DCHCacheEntryDCH_cache_fetch (const char *str)
 
static NUMCacheEntryNUM_cache_getnew (const char *str)
 
static NUMCacheEntryNUM_cache_search (const char *str)
 
static NUMCacheEntryNUM_cache_fetch (const char *str)
 
char * str_tolower (const char *buff, size_t nbytes, Oid collid)
 
char * str_toupper (const char *buff, size_t nbytes, Oid collid)
 
char * str_initcap (const char *buff, size_t nbytes, Oid collid)
 
char * asc_tolower (const char *buff, size_t nbytes)
 
char * asc_toupper (const char *buff, size_t nbytes)
 
char * asc_initcap (const char *buff, size_t nbytes)
 
static char * str_tolower_z (const char *buff, Oid collid)
 
static char * str_toupper_z (const char *buff, Oid collid)
 
static char * str_initcap_z (const char *buff, Oid collid)
 
static char * asc_tolower_z (const char *buff)
 
static char * asc_toupper_z (const char *buff)
 
static bool is_next_separator (FormatNode *n)
 
static textdatetime_to_char_body (TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
 
Datum timestamp_to_char (PG_FUNCTION_ARGS)
 
Datum timestamptz_to_char (PG_FUNCTION_ARGS)
 
Datum interval_to_char (PG_FUNCTION_ARGS)
 
Datum to_timestamp (PG_FUNCTION_ARGS)
 
Datum to_date (PG_FUNCTION_ARGS)
 
static void NUM_eat_non_data_chars (NUMProc *Np, int n, int input_len)
 
Datum numeric_to_number (PG_FUNCTION_ARGS)
 
Datum numeric_to_char (PG_FUNCTION_ARGS)
 
Datum int4_to_char (PG_FUNCTION_ARGS)
 
Datum int8_to_char (PG_FUNCTION_ARGS)
 
Datum float4_to_char (PG_FUNCTION_ARGS)
 
Datum float8_to_char (PG_FUNCTION_ARGS)
 

Variables

static const char *const months_full []
 
static const char *const days_short []
 
static const char *const adbc_strings [] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL}
 
static const char *const adbc_strings_long [] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL}
 
static const char *const ampm_strings [] = {am_STR, pm_STR, AM_STR, PM_STR, NULL}
 
static const char *const ampm_strings_long [] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL}
 
static const char *const rm_months_upper []
 
static const char *const rm_months_lower []
 
static const char *const rm1 [] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL}
 
static const char *const rm10 [] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL}
 
static const char *const rm100 [] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL}
 
static const char *const numTH [] = {"ST", "ND", "RD", "TH", NULL}
 
static const char *const numth [] = {"st", "nd", "rd", "th", NULL}
 
static DCHCacheEntry DCHCache [DCH_CACHE_ENTRIES]
 
static int n_DCHCache = 0
 
static int DCHCounter = 0
 
static NUMCacheEntry NUMCache [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 204 of file formatting.c.

Referenced by DCH_to_char().

◆ a_d_STR

#define a_d_STR   "a.d."

Definition at line 205 of file formatting.c.

Referenced by DCH_to_char().

◆ A_M_STR

#define A_M_STR   "A.M."

Definition at line 231 of file formatting.c.

Referenced by DCH_to_char().

◆ a_m_STR

#define a_m_STR   "a.m."

Definition at line 232 of file formatting.c.

Referenced by DCH_to_char().

◆ AD_STR

#define AD_STR   "AD"

Definition at line 206 of file formatting.c.

Referenced by DCH_to_char().

◆ ad_STR

#define ad_STR   "ad"

Definition at line 207 of file formatting.c.

Referenced by DCH_to_char().

◆ ADJUST_YEAR

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

Definition at line 202 of file formatting.c.

Referenced by DCH_to_char().

◆ ALL_LOWER

#define ALL_LOWER   3 /* name */

Definition at line 287 of file formatting.c.

Referenced by DCH_from_char(), and seq_search().

◆ ALL_UPPER

#define ALL_UPPER   2 /* NAME */

Definition at line 286 of file formatting.c.

Referenced by DCH_from_char(), and seq_search().

◆ AM_STR

#define AM_STR   "AM"

Definition at line 233 of file formatting.c.

Referenced by DCH_to_char().

◆ am_STR

#define am_STR   "am"

Definition at line 234 of file formatting.c.

Referenced by DCH_to_char().

◆ AMOUNT_TEST

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

Definition at line 4292 of file formatting.c.

Referenced by NUM_numpart_from_char(), and NUM_processor().

◆ B_C_STR

#define B_C_STR   "B.C."

Definition at line 209 of file formatting.c.

Referenced by DCH_to_char().

◆ b_c_STR

#define b_c_STR   "b.c."

Definition at line 210 of file formatting.c.

Referenced by DCH_to_char().

◆ BC_STR

#define BC_STR   "BC"

Definition at line 211 of file formatting.c.

Referenced by DCH_to_char().

◆ bc_STR

#define bc_STR   "bc"

Definition at line 212 of file formatting.c.

Referenced by DCH_to_char().

◆ CLOCK_12_HOUR

#define CLOCK_12_HOUR   1

Definition at line 179 of file formatting.c.

Referenced by DCH_from_char(), and do_to_timestamp().

◆ CLOCK_24_HOUR

#define CLOCK_24_HOUR   0

Definition at line 178 of file formatting.c.

◆ DCH_CACHE_ENTRIES

#define DCH_CACHE_ENTRIES   20

Definition at line 373 of file formatting.c.

Referenced by DCH_cache_getnew(), and DCH_cache_search().

◆ DCH_CACHE_SIZE

#define DCH_CACHE_SIZE   128

Definition at line 372 of file formatting.c.

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

◆ DCH_MAX_ITEM_SIZ

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

◆ DCH_S_FM

#define DCH_S_FM   0x01

Definition at line 507 of file formatting.c.

◆ DCH_S_SP

#define DCH_S_SP   0x08

Definition at line 510 of file formatting.c.

◆ DCH_S_TH

#define DCH_S_TH   0x02

Definition at line 508 of file formatting.c.

◆ DCH_S_th

#define DCH_S_th   0x04

Definition at line 509 of file formatting.c.

◆ DCH_S_TM

#define DCH_S_TM   0x10

Definition at line 511 of file formatting.c.

◆ DCH_TYPE

#define DCH_TYPE   1 /* DATE-TIME version */

◆ DEBUG_TM

#define DEBUG_TM (   _X)

Definition at line 453 of file formatting.c.

Referenced by do_to_timestamp().

◆ DEBUG_TMFC

#define DEBUG_TMFC (   _X)

Definition at line 452 of file formatting.c.

Referenced by do_to_timestamp().

◆ FULL_SIZ

#define FULL_SIZ   0

Definition at line 289 of file formatting.c.

◆ INVALID_FOR_INTERVAL

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

Definition at line 490 of file formatting.c.

Referenced by DCH_to_char().

◆ IS_BLANK

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

Definition at line 347 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ IS_BRACKET

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

◆ IS_DECIMAL

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

◆ IS_EEEE

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

◆ IS_FILLMODE

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

Definition at line 348 of file formatting.c.

Referenced by NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().

◆ IS_LDECIMAL

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

Definition at line 345 of file formatting.c.

Referenced by NUM_prepare_locale().

◆ IS_LSIGN

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

◆ IS_MINUS

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

Definition at line 350 of file formatting.c.

Referenced by NUM_numpart_from_char(), NUM_processor(), and NUMDesc_prepare().

◆ IS_MULTI

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

◆ IS_PLUS

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

Definition at line 352 of file formatting.c.

Referenced by NUM_numpart_from_char(), NUM_processor(), and NUMDesc_prepare().

◆ 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:346

Definition at line 4503 of file formatting.c.

Referenced by NUM_numpart_to_char().

◆ IS_ROMAN

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

◆ IS_ZERO

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

Definition at line 346 of file formatting.c.

Referenced by NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().

◆ KeyWord_INDEX_FILTER

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

Definition at line 111 of file formatting.c.

Referenced by index_seq_search().

◆ KeyWord_INDEX_SIZE

#define KeyWord_INDEX_SIZE   ('~' - ' ')

Definition at line 110 of file formatting.c.

◆ MAX_DAY_LEN

#define MAX_DAY_LEN   9

Definition at line 293 of file formatting.c.

Referenced by DCH_from_char().

◆ MAX_DY_LEN

#define MAX_DY_LEN   3

Definition at line 294 of file formatting.c.

Referenced by DCH_from_char().

◆ MAX_MON_LEN

#define MAX_MON_LEN   3

Definition at line 292 of file formatting.c.

Referenced by DCH_from_char().

◆ MAX_MONTH_LEN

#define MAX_MONTH_LEN   9

Definition at line 291 of file formatting.c.

Referenced by DCH_from_char().

◆ MAX_RM_LEN

#define MAX_RM_LEN   4

Definition at line 295 of file formatting.c.

Referenced by DCH_from_char().

◆ MAXDOUBLEWIDTH

#define MAXDOUBLEWIDTH   500

Definition at line 125 of file formatting.c.

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

◆ MAXFLOATWIDTH

#define MAXFLOATWIDTH   60

Definition at line 124 of file formatting.c.

Referenced by float4_to_char().

◆ NODE_TYPE_ACTION

#define NODE_TYPE_ACTION   2

◆ NODE_TYPE_CHAR

#define NODE_TYPE_CHAR   3

Definition at line 173 of file formatting.c.

Referenced by parse_format().

◆ NODE_TYPE_END

#define NODE_TYPE_END   1

◆ NUM_CACHE_ENTRIES

#define NUM_CACHE_ENTRIES   20

Definition at line 371 of file formatting.c.

Referenced by NUM_cache_getnew(), and NUM_cache_search().

◆ NUM_CACHE_SIZE

#define NUM_CACHE_SIZE   64

Definition at line 370 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_getnew().

◆ NUM_F_BLANK

#define NUM_F_BLANK   (1 << 4)

Definition at line 324 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_BRACKET

#define NUM_F_BRACKET   (1 << 7)

Definition at line 327 of file formatting.c.

Referenced by NUM_processor(), and NUMDesc_prepare().

◆ NUM_F_DECIMAL

#define NUM_F_DECIMAL   (1 << 1)

Definition at line 321 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_EEEE

#define NUM_F_EEEE   (1 << 14)

Definition at line 334 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_FILLMODE

#define NUM_F_FILLMODE   (1 << 5)

Definition at line 325 of file formatting.c.

Referenced by NUM_processor(), and NUMDesc_prepare().

◆ NUM_F_LDECIMAL

#define NUM_F_LDECIMAL   (1 << 2)

Definition at line 322 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_LSIGN

#define NUM_F_LSIGN   (1 << 6)

Definition at line 326 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_MINUS

#define NUM_F_MINUS   (1 << 8)

Definition at line 328 of file formatting.c.

Referenced by NUM_processor(), and NUMDesc_prepare().

◆ NUM_F_MINUS_POST

#define NUM_F_MINUS_POST   (1 << 13)

Definition at line 333 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_MULTI

#define NUM_F_MULTI   (1 << 11)

Definition at line 331 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_PLUS

#define NUM_F_PLUS   (1 << 9)

Definition at line 329 of file formatting.c.

Referenced by NUM_processor(), and NUMDesc_prepare().

◆ NUM_F_PLUS_POST

#define NUM_F_PLUS_POST   (1 << 12)

Definition at line 332 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_F_ROMAN

#define NUM_F_ROMAN   (1 << 10)

Definition at line 330 of file formatting.c.

Referenced by NUM_processor(), and NUMDesc_prepare().

◆ NUM_F_ZERO

#define NUM_F_ZERO   (1 << 3)

Definition at line 323 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_LSIGN_NONE

#define NUM_LSIGN_NONE   0

Definition at line 338 of file formatting.c.

Referenced by NUMDesc_prepare().

◆ NUM_LSIGN_POST

#define NUM_LSIGN_POST   1

Definition at line 337 of file formatting.c.

Referenced by NUM_numpart_to_char(), NUM_processor(), and NUMDesc_prepare().

◆ NUM_LSIGN_PRE

#define NUM_LSIGN_PRE   (-1)

◆ NUM_MAX_ITEM_SIZ

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

Definition at line 118 of file formatting.c.

Referenced by numeric_to_number().

◆ NUM_TOCHAR_finish

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

Definition at line 5211 of file formatting.c.

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

◆ NUM_TOCHAR_prepare

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

Definition at line 5198 of file formatting.c.

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

◆ NUM_TYPE

#define NUM_TYPE   2 /* NUMBER version */

Definition at line 104 of file formatting.c.

Referenced by NUM_cache(), NUM_cache_fetch(), and parse_format().

◆ ONE_UPPER

#define ONE_UPPER   1 /* Name */

Definition at line 285 of file formatting.c.

Referenced by DCH_from_char(), and seq_search().

◆ OVERLOAD_TEST

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

Definition at line 4291 of file formatting.c.

Referenced by NUM_eat_non_data_chars(), NUM_numpart_from_char(), and NUM_processor().

◆ P_M_STR

#define P_M_STR   "P.M."

Definition at line 236 of file formatting.c.

Referenced by DCH_to_char().

◆ p_m_STR

#define p_m_STR   "p.m."

Definition at line 237 of file formatting.c.

Referenced by DCH_to_char().

◆ PM_STR

#define PM_STR   "PM"

Definition at line 238 of file formatting.c.

Referenced by DCH_to_char().

◆ pm_STR

#define pm_STR   "pm"

Definition at line 239 of file formatting.c.

Referenced by DCH_to_char().

◆ S_FM

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

Definition at line 523 of file formatting.c.

Referenced by DCH_to_char(), and from_char_parse_int_len().

◆ S_SP

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

Definition at line 524 of file formatting.c.

◆ S_TH

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

Definition at line 518 of file formatting.c.

◆ S_th

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

Definition at line 519 of file formatting.c.

◆ S_TH_TYPE

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

Definition at line 520 of file formatting.c.

Referenced by DCH_to_char().

◆ S_THth

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

Definition at line 517 of file formatting.c.

Referenced by DCH_to_char(), and is_next_separator().

◆ S_TM

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

Definition at line 525 of file formatting.c.

Referenced by DCH_to_char().

◆ SKIP_THth

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

Definition at line 2022 of file formatting.c.

Referenced by DCH_from_char().

◆ SUFFTYPE_POSTFIX

#define SUFFTYPE_POSTFIX   2

Definition at line 176 of file formatting.c.

Referenced by parse_format().

◆ SUFFTYPE_PREFIX

#define SUFFTYPE_PREFIX   1

Definition at line 175 of file formatting.c.

Referenced by parse_format().

◆ TH_LOWER

#define TH_LOWER   2

Definition at line 298 of file formatting.c.

Referenced by NUM_processor().

◆ TH_UPPER

#define TH_UPPER   1

Definition at line 297 of file formatting.c.

Referenced by get_th(), and NUM_processor().

◆ TM_SUFFIX_LEN

#define TM_SUFFIX_LEN   2

Definition at line 531 of file formatting.c.

Referenced by DCH_to_char().

◆ tmtcFsec

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

Definition at line 469 of file formatting.c.

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

◆ tmtcTm

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

Definition at line 467 of file formatting.c.

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

◆ tmtcTzn

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

Definition at line 468 of file formatting.c.

Referenced by DCH_to_char(), and timestamptz_to_char().

◆ ZERO_tm

#define ZERO_tm (   _X)
Value:
do { \
(_X)->tm_sec = (_X)->tm_year = (_X)->tm_min = (_X)->tm_wday = \
(_X)->tm_hour = (_X)->tm_yday = (_X)->tm_isdst = 0; \
(_X)->tm_mday = (_X)->tm_mon = 1; \
(_X)->tm_zone = NULL; \
} while(0)

Definition at line 471 of file formatting.c.

Referenced by do_to_timestamp().

◆ ZERO_tmfc

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

Definition at line 433 of file formatting.c.

Referenced by do_to_timestamp().

◆ ZERO_tmtc

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

Definition at line 479 of file formatting.c.

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

◆ zeroize_NUM

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

Definition at line 3941 of file formatting.c.

Referenced by NUM_cache(), and NUM_cache_fetch().

Typedef Documentation

◆ NUMProc

◆ TmToChar

Enumeration Type Documentation

◆ DCH_poz

enum DCH_poz
Enumerator
DCH_A_D 
DCH_A_M 
DCH_AD 
DCH_AM 
DCH_B_C 
DCH_BC 
DCH_CC 
DCH_DAY 
DCH_DDD 
DCH_DD 
DCH_DY 
DCH_Day 
DCH_Dy 
DCH_D 
DCH_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_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_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_p_m 
DCH_pm 
DCH_q 
DCH_rm 
DCH_ssss 
DCH_ss 
DCH_tz 
DCH_us 
DCH_ww 
DCH_w 
DCH_y_yyy 
DCH_yyyy 
DCH_yyy 
DCH_yy 
DCH_y 
_DCH_last_ 

Definition at line 574 of file formatting.c.

575 {
576  DCH_A_D,
577  DCH_A_M,
578  DCH_AD,
579  DCH_AM,
580  DCH_B_C,
581  DCH_BC,
582  DCH_CC,
583  DCH_DAY,
584  DCH_DDD,
585  DCH_DD,
586  DCH_DY,
587  DCH_Day,
588  DCH_Dy,
589  DCH_D,
590  DCH_FX, /* global suffix */
591  DCH_HH24,
592  DCH_HH12,
593  DCH_HH,
594  DCH_IDDD,
595  DCH_ID,
596  DCH_IW,
597  DCH_IYYY,
598  DCH_IYY,
599  DCH_IY,
600  DCH_I,
601  DCH_J,
602  DCH_MI,
603  DCH_MM,
604  DCH_MONTH,
605  DCH_MON,
606  DCH_MS,
607  DCH_Month,
608  DCH_Mon,
609  DCH_OF,
610  DCH_P_M,
611  DCH_PM,
612  DCH_Q,
613  DCH_RM,
614  DCH_SSSS,
615  DCH_SS,
616  DCH_TZH,
617  DCH_TZM,
618  DCH_TZ,
619  DCH_US,
620  DCH_WW,
621  DCH_W,
622  DCH_Y_YYY,
623  DCH_YYYY,
624  DCH_YYY,
625  DCH_YY,
626  DCH_Y,
627  DCH_a_d,
628  DCH_a_m,
629  DCH_ad,
630  DCH_am,
631  DCH_b_c,
632  DCH_bc,
633  DCH_cc,
634  DCH_day,
635  DCH_ddd,
636  DCH_dd,
637  DCH_dy,
638  DCH_d,
639  DCH_fx,
640  DCH_hh24,
641  DCH_hh12,
642  DCH_hh,
643  DCH_iddd,
644  DCH_id,
645  DCH_iw,
646  DCH_iyyy,
647  DCH_iyy,
648  DCH_iy,
649  DCH_i,
650  DCH_j,
651  DCH_mi,
652  DCH_mm,
653  DCH_month,
654  DCH_mon,
655  DCH_ms,
656  DCH_p_m,
657  DCH_pm,
658  DCH_q,
659  DCH_rm,
660  DCH_ssss,
661  DCH_ss,
662  DCH_tz,
663  DCH_us,
664  DCH_ww,
665  DCH_w,
666  DCH_y_yyy,
667  DCH_yyyy,
668  DCH_yyy,
669  DCH_yy,
670  DCH_y,
671 
672  /* last */
673  _DCH_last_
674 } DCH_poz;
DCH_poz
Definition: formatting.c:574

◆ FromCharDateMode

Enumerator
FROM_CHAR_DATE_NONE 
FROM_CHAR_DATE_GREGORIAN 
FROM_CHAR_DATE_ISOWEEK 

Definition at line 147 of file formatting.c.

148 {
149  FROM_CHAR_DATE_NONE = 0, /* Value does not affect date mode. */
150  FROM_CHAR_DATE_GREGORIAN, /* Gregorian (day, month, year) style date */
151  FROM_CHAR_DATE_ISOWEEK /* ISO 8601 week date */
FromCharDateMode
Definition: formatting.c:147

◆ NUM_poz

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

Definition at line 676 of file formatting.c.

677 {
678  NUM_COMMA,
679  NUM_DEC,
680  NUM_0,
681  NUM_9,
682  NUM_B,
683  NUM_C,
684  NUM_D,
685  NUM_E,
686  NUM_FM,
687  NUM_G,
688  NUM_L,
689  NUM_MI,
690  NUM_PL,
691  NUM_PR,
692  NUM_RN,
693  NUM_SG,
694  NUM_SP,
695  NUM_S,
696  NUM_TH,
697  NUM_V,
698  NUM_b,
699  NUM_c,
700  NUM_d,
701  NUM_e,
702  NUM_fm,
703  NUM_g,
704  NUM_l,
705  NUM_mi,
706  NUM_pl,
707  NUM_pr,
708  NUM_rn,
709  NUM_sg,
710  NUM_sp,
711  NUM_s,
712  NUM_th,
713  NUM_v,
714 
715  /* last */
716  _NUM_last_
717 } NUM_poz;
NUM_poz
Definition: formatting.c:676

Function Documentation

◆ adjust_partial_year_to_2020()

static int adjust_partial_year_to_2020 ( int  year)
static

Definition at line 2103 of file formatting.c.

Referenced by DCH_from_char().

2104 {
2105  /*
2106  * Adjust all dates toward 2020; this is effectively what happens when we
2107  * assume '70' is 1970 and '69' is 2069.
2108  */
2109  /* Force 0-69 into the 2000's */
2110  if (year < 70)
2111  return year + 2000;
2112  /* Force 70-99 into the 1900's */
2113  else if (year < 100)
2114  return year + 1900;
2115  /* Force 100-519 into the 2000's */
2116  else if (year < 520)
2117  return year + 2000;
2118  /* Force 520-999 into the 1000's */
2119  else if (year < 1000)
2120  return year + 1000;
2121  else
2122  return year;
2123 }

◆ asc_initcap()

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

Definition at line 1953 of file formatting.c.

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

Referenced by str_initcap().

1954 {
1955  char *result;
1956  char *p;
1957  int wasalnum = false;
1958 
1959  if (!buff)
1960  return NULL;
1961 
1962  result = pnstrdup(buff, nbytes);
1963 
1964  for (p = result; *p; p++)
1965  {
1966  char c;
1967 
1968  if (wasalnum)
1969  *p = c = pg_ascii_tolower((unsigned char) *p);
1970  else
1971  *p = c = pg_ascii_toupper((unsigned char) *p);
1972  /* we don't trust isalnum() here */
1973  wasalnum = ((c >= 'A' && c <= 'Z') ||
1974  (c >= 'a' && c <= 'z') ||
1975  (c >= '0' && c <= '9'));
1976  }
1977 
1978  return result;
1979 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1074
unsigned char pg_ascii_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:146
unsigned char pg_ascii_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:135
char * c

◆ asc_tolower()

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

Definition at line 1907 of file formatting.c.

References pg_ascii_tolower(), and pnstrdup().

Referenced by asc_tolower_z(), and str_tolower().

1908 {
1909  char *result;
1910  char *p;
1911 
1912  if (!buff)
1913  return NULL;
1914 
1915  result = pnstrdup(buff, nbytes);
1916 
1917  for (p = result; *p; p++)
1918  *p = pg_ascii_tolower((unsigned char) *p);
1919 
1920  return result;
1921 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1074
unsigned char pg_ascii_tolower(unsigned char ch)
Definition: pgstrcasecmp.c:146

◆ asc_tolower_z()

static char* asc_tolower_z ( const char *  buff)
static

Definition at line 2002 of file formatting.c.

References asc_tolower().

Referenced by DCH_to_char(), and NUM_processor().

2003 {
2004  return asc_tolower(buff, strlen(buff));
2005 }
char * asc_tolower(const char *buff, size_t nbytes)
Definition: formatting.c:1907

◆ asc_toupper()

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

Definition at line 1930 of file formatting.c.

References pg_ascii_toupper(), and pnstrdup().

Referenced by asc_toupper_z(), and str_toupper().

1931 {
1932  char *result;
1933  char *p;
1934 
1935  if (!buff)
1936  return NULL;
1937 
1938  result = pnstrdup(buff, nbytes);
1939 
1940  for (p = result; *p; p++)
1941  *p = pg_ascii_toupper((unsigned char) *p);
1942 
1943  return result;
1944 }
char * pnstrdup(const char *in, Size len)
Definition: mcxt.c:1074
unsigned char pg_ascii_toupper(unsigned char ch)
Definition: pgstrcasecmp.c:135

◆ asc_toupper_z()

static char* asc_toupper_z ( const char *  buff)
static

Definition at line 2008 of file formatting.c.

References asc_toupper().

Referenced by DCH_to_char().

2009 {
2010  return asc_toupper(buff, strlen(buff));
2011 }
char * asc_toupper(const char *buff, size_t nbytes)
Definition: formatting.c:1930

◆ datetime_to_char_body()

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

Definition at line 3392 of file formatting.c.

References cstring_to_text(), DCH_cache_fetch(), DCH_CACHE_SIZE, DCH_index, DCH_MAX_ITEM_SIZ, DCH_to_char(), DCH_TYPE, format, DCHCacheEntry::format, palloc(), parse_format(), pfree(), and text_to_cstring().

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

3393 {
3394  FormatNode *format;
3395  char *fmt_str,
3396  *result;
3397  bool incache;
3398  int fmt_len;
3399  text *res;
3400 
3401  /*
3402  * Convert fmt to C string
3403  */
3404  fmt_str = text_to_cstring(fmt);
3405  fmt_len = strlen(fmt_str);
3406 
3407  /*
3408  * Allocate workspace for result as C string
3409  */
3410  result = palloc((fmt_len * DCH_MAX_ITEM_SIZ) + 1);
3411  *result = '\0';
3412 
3413  if (fmt_len > DCH_CACHE_SIZE)
3414  {
3415  /*
3416  * Allocate new memory if format picture is bigger than static cache
3417  * and do not use cache (call parser always)
3418  */
3419  incache = false;
3420 
3421  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3422 
3423  parse_format(format, fmt_str, DCH_keywords,
3424  DCH_suff, DCH_index, DCH_TYPE, NULL);
3425  }
3426  else
3427  {
3428  /*
3429  * Use cache buffers
3430  */
3431  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str);
3432 
3433  incache = true;
3434  format = ent->format;
3435  }
3436 
3437  /* The real work is here */
3438  DCH_to_char(format, is_interval, tmtc, result, collid);
3439 
3440  if (!incache)
3441  pfree(format);
3442 
3443  pfree(fmt_str);
3444 
3445  /* convert C-string result to TEXT format */
3446  res = cstring_to_text(result);
3447 
3448  pfree(result);
3449  return res;
3450 }
static const KeySuffix DCH_suff[]
Definition: formatting.c:533
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:879
void pfree(void *pointer)
Definition: mcxt.c:936
#define DCH_CACHE_SIZE
Definition: formatting.c:372
static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
Definition: formatting.c:1233
static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid)
Definition: formatting.c:2409
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:377
static DCHCacheEntry * DCH_cache_fetch(const char *str)
Definition: formatting.c:3365
#define DCH_TYPE
Definition: formatting.c:103
text * cstring_to_text(const char *s)
Definition: varlena.c:150
char * text_to_cstring(const text *t)
Definition: varlena.c:183
void * palloc(Size size)
Definition: mcxt.c:835
static const KeyWord DCH_keywords[]
Definition: formatting.c:723
Definition: c.h:497
static char format
Definition: pg_basebackup.c:81
#define DCH_MAX_ITEM_SIZ
Definition: formatting.c:117

◆ DCH_cache_fetch()

static DCHCacheEntry * DCH_cache_fetch ( const char *  str)
static

Definition at line 3365 of file formatting.c.

References DCH_cache_getnew(), DCH_cache_search(), DCH_index, DCH_TYPE, DCHCacheEntry::format, parse_format(), and DCHCacheEntry::valid.

Referenced by datetime_to_char_body(), and do_to_timestamp().

3366 {
3367  DCHCacheEntry *ent;
3368 
3369  if ((ent = DCH_cache_search(str)) == NULL)
3370  {
3371  /*
3372  * Not in the cache, must run parser and save a new format-picture to
3373  * the cache. Do not mark the cache entry valid until parsing
3374  * succeeds.
3375  */
3376  ent = DCH_cache_getnew(str);
3377 
3379  DCH_suff, DCH_index, DCH_TYPE, NULL);
3380 
3381  ent->valid = true;
3382  }
3383  return ent;
3384 }
static DCHCacheEntry * DCH_cache_getnew(const char *str)
Definition: formatting.c:3275
static const KeySuffix DCH_suff[]
Definition: formatting.c:533
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:879
static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
Definition: formatting.c:1233
static DCHCacheEntry * DCH_cache_search(const char *str)
Definition: formatting.c:3337
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:377
#define DCH_TYPE
Definition: formatting.c:103
static const KeyWord DCH_keywords[]
Definition: formatting.c:723

◆ DCH_cache_getnew()

static DCHCacheEntry * DCH_cache_getnew ( const char *  str)
static

Definition at line 3275 of file formatting.c.

References DCHCacheEntry::age, DCH_CACHE_ENTRIES, DCH_CACHE_SIZE, DCHCounter, elog, n_DCHCache, DCHCacheEntry::str, StrNCpy, and DCHCacheEntry::valid.

Referenced by DCH_cache_fetch().

3276 {
3277  DCHCacheEntry *ent;
3278 
3279  /* counter overflow check - paranoia? */
3280  if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES))
3281  {
3282  DCHCounter = 0;
3283 
3284  for (ent = DCHCache; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++)
3285  ent->age = (++DCHCounter);
3286  }
3287 
3288  /*
3289  * If cache is full, remove oldest entry (or recycle first not-valid one)
3290  */
3292  {
3293  DCHCacheEntry *old = DCHCache + 0;
3294 
3295 #ifdef DEBUG_TO_FROM_CHAR
3296  elog(DEBUG_elog_output, "cache is full (%d)", n_DCHCache);
3297 #endif
3298  if (old->valid)
3299  {
3300  for (ent = DCHCache + 1; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++)
3301  {
3302  if (!ent->valid)
3303  {
3304  old = ent;
3305  break;
3306  }
3307  if (ent->age < old->age)
3308  old = ent;
3309  }
3310  }
3311 #ifdef DEBUG_TO_FROM_CHAR
3312  elog(DEBUG_elog_output, "OLD: '%s' AGE: %d", old->str, old->age);
3313 #endif
3314  old->valid = false;
3315  StrNCpy(old->str, str, DCH_CACHE_SIZE + 1);
3316  old->age = (++DCHCounter);
3317  /* caller is expected to fill format, then set valid */
3318  return old;
3319  }
3320  else
3321  {
3322 #ifdef DEBUG_TO_FROM_CHAR
3323  elog(DEBUG_elog_output, "NEW (%d)", n_DCHCache);
3324 #endif
3325  ent = DCHCache + n_DCHCache;
3326  ent->valid = false;
3327  StrNCpy(ent->str, str, DCH_CACHE_SIZE + 1);
3328  ent->age = (++DCHCounter);
3329  /* caller is expected to fill format, then set valid */
3330  ++n_DCHCache;
3331  return ent;
3332  }
3333 }
char str[DCH_CACHE_SIZE+1]
Definition: formatting.c:378
#define DCH_CACHE_SIZE
Definition: formatting.c:372
static int n_DCHCache
Definition: formatting.c:394
#define DCH_CACHE_ENTRIES
Definition: formatting.c:373
static DCHCacheEntry DCHCache[DCH_CACHE_ENTRIES]
Definition: formatting.c:393
#define StrNCpy(dst, src, len)
Definition: c.h:850
#define elog
Definition: elog.h:219
static int DCHCounter
Definition: formatting.c:395

◆ DCH_cache_search()

static DCHCacheEntry * DCH_cache_search ( const char *  str)
static

Definition at line 3337 of file formatting.c.

References DCHCacheEntry::age, DCH_CACHE_ENTRIES, DCHCounter, i, n_DCHCache, DCHCacheEntry::str, and DCHCacheEntry::valid.

Referenced by DCH_cache_fetch().

3338 {
3339  int i;
3340  DCHCacheEntry *ent;
3341 
3342  /* counter overflow check - paranoia? */
3343  if (DCHCounter >= (INT_MAX - DCH_CACHE_ENTRIES))
3344  {
3345  DCHCounter = 0;
3346 
3347  for (ent = DCHCache; ent < (DCHCache + DCH_CACHE_ENTRIES); ent++)
3348  ent->age = (++DCHCounter);
3349  }
3350 
3351  for (i = 0, ent = DCHCache; i < n_DCHCache; i++, ent++)
3352  {
3353  if (ent->valid && strcmp(ent->str, str) == 0)
3354  {
3355  ent->age = (++DCHCounter);
3356  return ent;
3357  }
3358  }
3359 
3360  return NULL;
3361 }
char str[DCH_CACHE_SIZE+1]
Definition: formatting.c:378
static int n_DCHCache
Definition: formatting.c:394
#define DCH_CACHE_ENTRIES
Definition: formatting.c:373
static DCHCacheEntry DCHCache[DCH_CACHE_ENTRIES]
Definition: formatting.c:393
int i
static int DCHCounter
Definition: formatting.c:395

◆ DCH_from_char()

static void DCH_from_char ( FormatNode node,
char *  in,
TmFromChar out 
)
static

Definition at line 2989 of file formatting.c.

References adbc_strings, adbc_strings_long, adjust_partial_year_to_2020(), ALL_LOWER, ALL_UPPER, ampm_strings, ampm_strings_long, TmFromChar::bc, TmFromChar::cc, TmFromChar::clock, CLOCK_12_HOUR, TmFromChar::d, KeyWord::date_mode, days, 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_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, ereport, errcode(), errmsg(), ERROR, from_char_parse_int(), from_char_parse_int_len(), from_char_seq_search(), from_char_set_int(), from_char_set_mode(), TmFromChar::hh, KeyWord::id, TmFromChar::j, FormatNode::key, KeyWord::len, MAX_DAY_LEN, MAX_DY_LEN, MAX_MON_LEN, MAX_MONTH_LEN, MAX_RM_LEN, TmFromChar::mi, TmFromChar::mm, months, months_full, MONTHS_PER_YEAR, TmFromChar::ms, KeyWord::name, NODE_TYPE_ACTION, NODE_TYPE_END, ONE_UPPER, pg_mblen(), TmFromChar::pm, rm_months_lower, rm_months_upper, SKIP_THth, TmFromChar::ss, TmFromChar::ssss, FormatNode::suffix, FormatNode::type, TmFromChar::tzh, TmFromChar::tzm, TmFromChar::tzsign, TmFromChar::us, value, TmFromChar::w, TmFromChar::ww, TmFromChar::year, and TmFromChar::yysz.

Referenced by do_to_timestamp().

2990 {
2991  FormatNode *n;
2992  char *s;
2993  int len,
2994  value;
2995  bool fx_mode = false;
2996 
2997  for (n = node, s = in; n->type != NODE_TYPE_END && *s != '\0'; n++)
2998  {
2999  if (n->type != NODE_TYPE_ACTION)
3000  {
3001  /*
3002  * Separator, so consume one character from input string. Notice
3003  * we don't insist that the consumed character match the format's
3004  * character.
3005  */
3006  s += pg_mblen(s);
3007  continue;
3008  }
3009 
3010  /* Ignore spaces before fields when not in FX (fixed width) mode */
3011  if (!fx_mode && n->key->id != DCH_FX)
3012  {
3013  while (*s != '\0' && isspace((unsigned char) *s))
3014  s++;
3015  }
3016 
3017  from_char_set_mode(out, n->key->date_mode);
3018 
3019  switch (n->key->id)
3020  {
3021  case DCH_FX:
3022  fx_mode = true;
3023  break;
3024  case DCH_A_M:
3025  case DCH_P_M:
3026  case DCH_a_m:
3027  case DCH_p_m:
3029  ALL_UPPER, n->key->len, n);
3030  from_char_set_int(&out->pm, value % 2, n);
3031  out->clock = CLOCK_12_HOUR;
3032  break;
3033  case DCH_AM:
3034  case DCH_PM:
3035  case DCH_am:
3036  case DCH_pm:
3037  from_char_seq_search(&value, &s, ampm_strings,
3038  ALL_UPPER, n->key->len, n);
3039  from_char_set_int(&out->pm, value % 2, n);
3040  out->clock = CLOCK_12_HOUR;
3041  break;
3042  case DCH_HH:
3043  case DCH_HH12:
3044  from_char_parse_int_len(&out->hh, &s, 2, n);
3045  out->clock = CLOCK_12_HOUR;
3046  SKIP_THth(s, n->suffix);
3047  break;
3048  case DCH_HH24:
3049  from_char_parse_int_len(&out->hh, &s, 2, n);
3050  SKIP_THth(s, n->suffix);
3051  break;
3052  case DCH_MI:
3053  from_char_parse_int(&out->mi, &s, n);
3054  SKIP_THth(s, n->suffix);
3055  break;
3056  case DCH_SS:
3057  from_char_parse_int(&out->ss, &s, n);
3058  SKIP_THth(s, n->suffix);
3059  break;
3060  case DCH_MS: /* millisecond */
3061  len = from_char_parse_int_len(&out->ms, &s, 3, n);
3062 
3063  /*
3064  * 25 is 0.25 and 250 is 0.25 too; 025 is 0.025 and not 0.25
3065  */
3066  out->ms *= len == 1 ? 100 :
3067  len == 2 ? 10 : 1;
3068 
3069  SKIP_THth(s, n->suffix);
3070  break;
3071  case DCH_US: /* microsecond */
3072  len = from_char_parse_int_len(&out->us, &s, 6, n);
3073 
3074  out->us *= len == 1 ? 100000 :
3075  len == 2 ? 10000 :
3076  len == 3 ? 1000 :
3077  len == 4 ? 100 :
3078  len == 5 ? 10 : 1;
3079 
3080  SKIP_THth(s, n->suffix);
3081  break;
3082  case DCH_SSSS:
3083  from_char_parse_int(&out->ssss, &s, n);
3084  SKIP_THth(s, n->suffix);
3085  break;
3086  case DCH_tz:
3087  case DCH_TZ:
3088  case DCH_OF:
3089  ereport(ERROR,
3090  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3091  errmsg("formatting field \"%s\" is only supported in to_char",
3092  n->key->name)));
3093  break;
3094  case DCH_TZH:
3095  out->tzsign = *s == '-' ? -1 : +1;
3096 
3097  if (*s == '+' || *s == '-' || *s == ' ')
3098  s++;
3099 
3100  from_char_parse_int_len(&out->tzh, &s, 2, n);
3101  break;
3102  case DCH_TZM:
3103  /* assign positive timezone sign if TZH was not seen before */
3104  if (!out->tzsign)
3105  out->tzsign = +1;
3106  from_char_parse_int_len(&out->tzm, &s, 2, n);
3107  break;
3108  case DCH_A_D:
3109  case DCH_B_C:
3110  case DCH_a_d:
3111  case DCH_b_c:
3113  ALL_UPPER, n->key->len, n);
3114  from_char_set_int(&out->bc, value % 2, n);
3115  break;
3116  case DCH_AD:
3117  case DCH_BC:
3118  case DCH_ad:
3119  case DCH_bc:
3120  from_char_seq_search(&value, &s, adbc_strings,
3121  ALL_UPPER, n->key->len, n);
3122  from_char_set_int(&out->bc, value % 2, n);
3123  break;
3124  case DCH_MONTH:
3125  case DCH_Month:
3126  case DCH_month:
3128  MAX_MONTH_LEN, n);
3129  from_char_set_int(&out->mm, value + 1, n);
3130  break;
3131  case DCH_MON:
3132  case DCH_Mon:
3133  case DCH_mon:
3134  from_char_seq_search(&value, &s, months, ONE_UPPER,
3135  MAX_MON_LEN, n);
3136  from_char_set_int(&out->mm, value + 1, n);
3137  break;
3138  case DCH_MM:
3139  from_char_parse_int(&out->mm, &s, n);
3140  SKIP_THth(s, n->suffix);
3141  break;
3142  case DCH_DAY:
3143  case DCH_Day:
3144  case DCH_day:
3145  from_char_seq_search(&value, &s, days, ONE_UPPER,
3146  MAX_DAY_LEN, n);
3147  from_char_set_int(&out->d, value, n);
3148  out->d++;
3149  break;
3150  case DCH_DY:
3151  case DCH_Dy:
3152  case DCH_dy:
3153  from_char_seq_search(&value, &s, days, ONE_UPPER,
3154  MAX_DY_LEN, n);
3155  from_char_set_int(&out->d, value, n);
3156  out->d++;
3157  break;
3158  case DCH_DDD:
3159  from_char_parse_int(&out->ddd, &s, n);
3160  SKIP_THth(s, n->suffix);
3161  break;
3162  case DCH_IDDD:
3163  from_char_parse_int_len(&out->ddd, &s, 3, n);
3164  SKIP_THth(s, n->suffix);
3165  break;
3166  case DCH_DD:
3167  from_char_parse_int(&out->dd, &s, n);
3168  SKIP_THth(s, n->suffix);
3169  break;
3170  case DCH_D:
3171  from_char_parse_int(&out->d, &s, n);
3172  SKIP_THth(s, n->suffix);
3173  break;
3174  case DCH_ID:
3175  from_char_parse_int_len(&out->d, &s, 1, n);
3176  /* Shift numbering to match Gregorian where Sunday = 1 */
3177  if (++out->d > 7)
3178  out->d = 1;
3179  SKIP_THth(s, n->suffix);
3180  break;
3181  case DCH_WW:
3182  case DCH_IW:
3183  from_char_parse_int(&out->ww, &s, n);
3184  SKIP_THth(s, n->suffix);
3185  break;
3186  case DCH_Q:
3187 
3188  /*
3189  * We ignore 'Q' when converting to date because it is unclear
3190  * which date in the quarter to use, and some people specify
3191  * both quarter and month, so if it was honored it might
3192  * conflict with the supplied month. That is also why we don't
3193  * throw an error.
3194  *
3195  * We still parse the source string for an integer, but it
3196  * isn't stored anywhere in 'out'.
3197  */
3198  from_char_parse_int((int *) NULL, &s, n);
3199  SKIP_THth(s, n->suffix);
3200  break;
3201  case DCH_CC:
3202  from_char_parse_int(&out->cc, &s, n);
3203  SKIP_THth(s, n->suffix);
3204  break;
3205  case DCH_Y_YYY:
3206  {
3207  int matched,
3208  years,
3209  millennia,
3210  nch;
3211 
3212  matched = sscanf(s, "%d,%03d%n", &millennia, &years, &nch);
3213  if (matched < 2)
3214  ereport(ERROR,
3215  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3216  errmsg("invalid input string for \"Y,YYY\"")));
3217  years += (millennia * 1000);
3218  from_char_set_int(&out->year, years, n);
3219  out->yysz = 4;
3220  s += nch;
3221  SKIP_THth(s, n->suffix);
3222  }
3223  break;
3224  case DCH_YYYY:
3225  case DCH_IYYY:
3226  from_char_parse_int(&out->year, &s, n);
3227  out->yysz = 4;
3228  SKIP_THth(s, n->suffix);
3229  break;
3230  case DCH_YYY:
3231  case DCH_IYY:
3232  if (from_char_parse_int(&out->year, &s, n) < 4)
3233  out->year = adjust_partial_year_to_2020(out->year);
3234  out->yysz = 3;
3235  SKIP_THth(s, n->suffix);
3236  break;
3237  case DCH_YY:
3238  case DCH_IY:
3239  if (from_char_parse_int(&out->year, &s, n) < 4)
3240  out->year = adjust_partial_year_to_2020(out->year);
3241  out->yysz = 2;
3242  SKIP_THth(s, n->suffix);
3243  break;
3244  case DCH_Y:
3245  case DCH_I:
3246  if (from_char_parse_int(&out->year, &s, n) < 4)
3247  out->year = adjust_partial_year_to_2020(out->year);
3248  out->yysz = 1;
3249  SKIP_THth(s, n->suffix);
3250  break;
3251  case DCH_RM:
3253  ALL_UPPER, MAX_RM_LEN, n);
3254  from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
3255  break;
3256  case DCH_rm:
3258  ALL_LOWER, MAX_RM_LEN, n);
3259  from_char_set_int(&out->mm, MONTHS_PER_YEAR - value, n);
3260  break;
3261  case DCH_W:
3262  from_char_parse_int(&out->w, &s, n);
3263  SKIP_THth(s, n->suffix);
3264  break;
3265  case DCH_J:
3266  from_char_parse_int(&out->j, &s, n);
3267  SKIP_THth(s, n->suffix);
3268  break;
3269  }
3270  }
3271 }
#define NODE_TYPE_END
Definition: formatting.c:171
static struct @130 value
const KeyWord * key
Definition: formatting.c:166
static const char *const adbc_strings_long[]
Definition: formatting.c:225
static void from_char_set_int(int *dest, const int value, const FormatNode *node)
Definition: formatting.c:2168
FromCharDateMode date_mode
Definition: formatting.c:160
#define MAX_DY_LEN
Definition: formatting.c:294
int errcode(int sqlerrcode)
Definition: elog.c:575
static const char *const rm_months_upper[]
Definition: formatting.c:260
int id
Definition: formatting.c:158
static const char *const ampm_strings_long[]
Definition: formatting.c:252
static int from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node)
Definition: formatting.c:2201
static const char *const adbc_strings[]
Definition: formatting.c:224
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
#define MAX_MON_LEN
Definition: formatting.c:292
#define ONE_UPPER
Definition: formatting.c:285
const char *const months[]
Definition: datetime.c:66
#define NODE_TYPE_ACTION
Definition: formatting.c:172
#define ERROR
Definition: elog.h:43
static int from_char_seq_search(int *dest, char **src, const char *const *array, int type, int max, FormatNode *node)
Definition: formatting.c:2379
#define SKIP_THth(ptr, _suf)
Definition: formatting.c:2022
const char *const days[]
Definition: datetime.c:69
#define ereport(elevel, rest)
Definition: elog.h:122
#define MAX_RM_LEN
Definition: formatting.c:295
#define CLOCK_12_HOUR
Definition: formatting.c:179
static const char *const ampm_strings[]
Definition: formatting.c:251
const char * name
Definition: formatting.c:156
static const char *const months_full[]
Definition: formatting.c:186
int len
Definition: formatting.c:157
#define ALL_UPPER
Definition: formatting.c:286
static int adjust_partial_year_to_2020(int year)
Definition: formatting.c:2103
int pg_mblen(const char *mbstr)
Definition: mbutils.c:760
#define MAX_MONTH_LEN
Definition: formatting.c:291
static int from_char_parse_int(int *dest, char **src, FormatNode *node)
Definition: formatting.c:2291
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode)
Definition: formatting.c:2146
#define ALL_LOWER
Definition: formatting.c:287
#define MAX_DAY_LEN
Definition: formatting.c:293
static const char *const rm_months_lower[]
Definition: formatting.c:263

◆ DCH_to_char()

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

Definition at line 2409 of file formatting.c.

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, 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_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_TZ, DCH_tz, DCH_TZH, DCH_TZM, DCH_US, DCH_W, DCH_WW, DCH_Y, DCH_Y_YYY, DCH_YY, DCH_YYY, DCH_YYYY, ereport, errcode(), errmsg(), ERROR, TmToChar::fsec, HOURS_PER_DAY, i, KeyWord::id, INVALID_FOR_INTERVAL, FormatNode::key, KeyWord::len, localized_abbrev_days, localized_abbrev_months, localized_full_days, localized_full_months, months, months_full, MONTHS_PER_YEAR, NODE_TYPE_ACTION, NODE_TYPE_END, P_M_STR, p_m_STR, pfree(), PM_STR, pm_STR, rm_months_lower, rm_months_upper, S_FM, S_TH_TYPE, S_THth, S_TM, SECS_PER_HOUR, SECS_PER_MINUTE, generate_unaccent_rules::str, str_initcap_z(), str_numth(), str_tolower_z(), str_toupper_z(), FormatNode::suffix, TmToChar::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().

2410 {
2411  FormatNode *n;
2412  char *s;
2413  struct pg_tm *tm = &in->tm;
2414  int i;
2415 
2416  /* cache localized days and months */
2418 
2419  s = out;
2420  for (n = node; n->type != NODE_TYPE_END; n++)
2421  {
2422  if (n->type != NODE_TYPE_ACTION)
2423  {
2424  strcpy(s, n->character);
2425  s += strlen(s);
2426  continue;
2427  }
2428 
2429  switch (n->key->id)
2430  {
2431  case DCH_A_M:
2432  case DCH_P_M:
2433  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2434  ? P_M_STR : A_M_STR);
2435  s += strlen(s);
2436  break;
2437  case DCH_AM:
2438  case DCH_PM:
2439  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2440  ? PM_STR : AM_STR);
2441  s += strlen(s);
2442  break;
2443  case DCH_a_m:
2444  case DCH_p_m:
2445  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2446  ? p_m_STR : a_m_STR);
2447  s += strlen(s);
2448  break;
2449  case DCH_am:
2450  case DCH_pm:
2451  strcpy(s, (tm->tm_hour % HOURS_PER_DAY >= HOURS_PER_DAY / 2)
2452  ? pm_STR : am_STR);
2453  s += strlen(s);
2454  break;
2455  case DCH_HH:
2456  case DCH_HH12:
2457 
2458  /*
2459  * display time as shown on a 12-hour clock, even for
2460  * intervals
2461  */
2462  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2463  tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? HOURS_PER_DAY / 2 :
2464  tm->tm_hour % (HOURS_PER_DAY / 2));
2465  if (S_THth(n->suffix))
2466  str_numth(s, s, S_TH_TYPE(n->suffix));
2467  s += strlen(s);
2468  break;
2469  case DCH_HH24:
2470  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3,
2471  tm->tm_hour);
2472  if (S_THth(n->suffix))
2473  str_numth(s, s, S_TH_TYPE(n->suffix));
2474  s += strlen(s);
2475  break;
2476  case DCH_MI:
2477  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3,
2478  tm->tm_min);
2479  if (S_THth(n->suffix))
2480  str_numth(s, s, S_TH_TYPE(n->suffix));
2481  s += strlen(s);
2482  break;
2483  case DCH_SS:
2484  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3,
2485  tm->tm_sec);
2486  if (S_THth(n->suffix))
2487  str_numth(s, s, S_TH_TYPE(n->suffix));
2488  s += strlen(s);
2489  break;
2490  case DCH_MS: /* millisecond */
2491  sprintf(s, "%03d", (int) (in->fsec / INT64CONST(1000)));
2492  if (S_THth(n->suffix))
2493  str_numth(s, s, S_TH_TYPE(n->suffix));
2494  s += strlen(s);
2495  break;
2496  case DCH_US: /* microsecond */
2497  sprintf(s, "%06d", (int) in->fsec);
2498  if (S_THth(n->suffix))
2499  str_numth(s, s, S_TH_TYPE(n->suffix));
2500  s += strlen(s);
2501  break;
2502  case DCH_SSSS:
2503  sprintf(s, "%d", tm->tm_hour * SECS_PER_HOUR +
2504  tm->tm_min * SECS_PER_MINUTE +
2505  tm->tm_sec);
2506  if (S_THth(n->suffix))
2507  str_numth(s, s, S_TH_TYPE(n->suffix));
2508  s += strlen(s);
2509  break;
2510  case DCH_tz:
2512  if (tmtcTzn(in))
2513  {
2514  /* We assume here that timezone names aren't localized */
2515  char *p = asc_tolower_z(tmtcTzn(in));
2516 
2517  strcpy(s, p);
2518  pfree(p);
2519  s += strlen(s);
2520  }
2521  break;
2522  case DCH_TZ:
2524  if (tmtcTzn(in))
2525  {
2526  strcpy(s, tmtcTzn(in));
2527  s += strlen(s);
2528  }
2529  break;
2530  case DCH_TZH:
2532  sprintf(s, "%c%02d",
2533  (tm->tm_gmtoff >= 0) ? '+' : '-',
2534  abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2535  s += strlen(s);
2536  break;
2537  case DCH_TZM:
2539  sprintf(s, "%02d",
2540  (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2541  s += strlen(s);
2542  break;
2543  case DCH_OF:
2545  sprintf(s, "%c%0*d",
2546  (tm->tm_gmtoff >= 0) ? '+' : '-',
2547  S_FM(n->suffix) ? 0 : 2,
2548  abs((int) tm->tm_gmtoff) / SECS_PER_HOUR);
2549  s += strlen(s);
2550  if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0)
2551  {
2552  sprintf(s, ":%02d",
2553  (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR) / SECS_PER_MINUTE);
2554  s += strlen(s);
2555  }
2556  break;
2557  case DCH_A_D:
2558  case DCH_B_C:
2560  strcpy(s, (tm->tm_year <= 0 ? B_C_STR : A_D_STR));
2561  s += strlen(s);
2562  break;
2563  case DCH_AD:
2564  case DCH_BC:
2566  strcpy(s, (tm->tm_year <= 0 ? BC_STR : AD_STR));
2567  s += strlen(s);
2568  break;
2569  case DCH_a_d:
2570  case DCH_b_c:
2572  strcpy(s, (tm->tm_year <= 0 ? b_c_STR : a_d_STR));
2573  s += strlen(s);
2574  break;
2575  case DCH_ad:
2576  case DCH_bc:
2578  strcpy(s, (tm->tm_year <= 0 ? bc_STR : ad_STR));
2579  s += strlen(s);
2580  break;
2581  case DCH_MONTH:
2583  if (!tm->tm_mon)
2584  break;
2585  if (S_TM(n->suffix))
2586  {
2587  char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid);
2588 
2589  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2590  strcpy(s, str);
2591  else
2592  ereport(ERROR,
2593  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2594  errmsg("localized string format value too long")));
2595  }
2596  else
2597  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2598  asc_toupper_z(months_full[tm->tm_mon - 1]));
2599  s += strlen(s);
2600  break;
2601  case DCH_Month:
2603  if (!tm->tm_mon)
2604  break;
2605  if (S_TM(n->suffix))
2606  {
2607  char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid);
2608 
2609  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2610  strcpy(s, str);
2611  else
2612  ereport(ERROR,
2613  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2614  errmsg("localized string format value too long")));
2615  }
2616  else
2617  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2618  months_full[tm->tm_mon - 1]);
2619  s += strlen(s);
2620  break;
2621  case DCH_month:
2623  if (!tm->tm_mon)
2624  break;
2625  if (S_TM(n->suffix))
2626  {
2627  char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid);
2628 
2629  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2630  strcpy(s, str);
2631  else
2632  ereport(ERROR,
2633  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2634  errmsg("localized string format value too long")));
2635  }
2636  else
2637  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2638  asc_tolower_z(months_full[tm->tm_mon - 1]));
2639  s += strlen(s);
2640  break;
2641  case DCH_MON:
2643  if (!tm->tm_mon)
2644  break;
2645  if (S_TM(n->suffix))
2646  {
2647  char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2648 
2649  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2650  strcpy(s, str);
2651  else
2652  ereport(ERROR,
2653  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2654  errmsg("localized string format value too long")));
2655  }
2656  else
2657  strcpy(s, asc_toupper_z(months[tm->tm_mon - 1]));
2658  s += strlen(s);
2659  break;
2660  case DCH_Mon:
2662  if (!tm->tm_mon)
2663  break;
2664  if (S_TM(n->suffix))
2665  {
2666  char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2667 
2668  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2669  strcpy(s, str);
2670  else
2671  ereport(ERROR,
2672  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2673  errmsg("localized string format value too long")));
2674  }
2675  else
2676  strcpy(s, months[tm->tm_mon - 1]);
2677  s += strlen(s);
2678  break;
2679  case DCH_mon:
2681  if (!tm->tm_mon)
2682  break;
2683  if (S_TM(n->suffix))
2684  {
2685  char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid);
2686 
2687  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2688  strcpy(s, str);
2689  else
2690  ereport(ERROR,
2691  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2692  errmsg("localized string format value too long")));
2693  }
2694  else
2695  strcpy(s, asc_tolower_z(months[tm->tm_mon - 1]));
2696  s += strlen(s);
2697  break;
2698  case DCH_MM:
2699  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3,
2700  tm->tm_mon);
2701  if (S_THth(n->suffix))
2702  str_numth(s, s, S_TH_TYPE(n->suffix));
2703  s += strlen(s);
2704  break;
2705  case DCH_DAY:
2707  if (S_TM(n->suffix))
2708  {
2709  char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid);
2710 
2711  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2712  strcpy(s, str);
2713  else
2714  ereport(ERROR,
2715  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2716  errmsg("localized string format value too long")));
2717  }
2718  else
2719  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2720  asc_toupper_z(days[tm->tm_wday]));
2721  s += strlen(s);
2722  break;
2723  case DCH_Day:
2725  if (S_TM(n->suffix))
2726  {
2727  char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid);
2728 
2729  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2730  strcpy(s, str);
2731  else
2732  ereport(ERROR,
2733  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2734  errmsg("localized string format value too long")));
2735  }
2736  else
2737  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2738  days[tm->tm_wday]);
2739  s += strlen(s);
2740  break;
2741  case DCH_day:
2743  if (S_TM(n->suffix))
2744  {
2745  char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid);
2746 
2747  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2748  strcpy(s, str);
2749  else
2750  ereport(ERROR,
2751  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2752  errmsg("localized string format value too long")));
2753  }
2754  else
2755  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9,
2756  asc_tolower_z(days[tm->tm_wday]));
2757  s += strlen(s);
2758  break;
2759  case DCH_DY:
2761  if (S_TM(n->suffix))
2762  {
2763  char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid);
2764 
2765  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2766  strcpy(s, str);
2767  else
2768  ereport(ERROR,
2769  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2770  errmsg("localized string format value too long")));
2771  }
2772  else
2773  strcpy(s, asc_toupper_z(days_short[tm->tm_wday]));
2774  s += strlen(s);
2775  break;
2776  case DCH_Dy:
2778  if (S_TM(n->suffix))
2779  {
2780  char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid);
2781 
2782  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2783  strcpy(s, str);
2784  else
2785  ereport(ERROR,
2786  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2787  errmsg("localized string format value too long")));
2788  }
2789  else
2790  strcpy(s, days_short[tm->tm_wday]);
2791  s += strlen(s);
2792  break;
2793  case DCH_dy:
2795  if (S_TM(n->suffix))
2796  {
2797  char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid);
2798 
2799  if (strlen(str) <= (n->key->len + TM_SUFFIX_LEN) * DCH_MAX_ITEM_SIZ)
2800  strcpy(s, str);
2801  else
2802  ereport(ERROR,
2803  (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
2804  errmsg("localized string format value too long")));
2805  }
2806  else
2807  strcpy(s, asc_tolower_z(days_short[tm->tm_wday]));
2808  s += strlen(s);
2809  break;
2810  case DCH_DDD:
2811  case DCH_IDDD:
2812  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3,
2813  (n->key->id == DCH_DDD) ?
2814  tm->tm_yday :
2815  date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday));
2816  if (S_THth(n->suffix))
2817  str_numth(s, s, S_TH_TYPE(n->suffix));
2818  s += strlen(s);
2819  break;
2820  case DCH_DD:
2821  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday);
2822  if (S_THth(n->suffix))
2823  str_numth(s, s, S_TH_TYPE(n->suffix));
2824  s += strlen(s);
2825  break;
2826  case DCH_D:
2828  sprintf(s, "%d", tm->tm_wday + 1);
2829  if (S_THth(n->suffix))
2830  str_numth(s, s, S_TH_TYPE(n->suffix));
2831  s += strlen(s);
2832  break;
2833  case DCH_ID:
2835  sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday);
2836  if (S_THth(n->suffix))
2837  str_numth(s, s, S_TH_TYPE(n->suffix));
2838  s += strlen(s);
2839  break;
2840  case DCH_WW:
2841  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2842  (tm->tm_yday - 1) / 7 + 1);
2843  if (S_THth(n->suffix))
2844  str_numth(s, s, S_TH_TYPE(n->suffix));
2845  s += strlen(s);
2846  break;
2847  case DCH_IW:
2848  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2,
2849  date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday));
2850  if (S_THth(n->suffix))
2851  str_numth(s, s, S_TH_TYPE(n->suffix));
2852  s += strlen(s);
2853  break;
2854  case DCH_Q:
2855  if (!tm->tm_mon)
2856  break;
2857  sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1);
2858  if (S_THth(n->suffix))
2859  str_numth(s, s, S_TH_TYPE(n->suffix));
2860  s += strlen(s);
2861  break;
2862  case DCH_CC:
2863  if (is_interval) /* straight calculation */
2864  i = tm->tm_year / 100;
2865  else
2866  {
2867  if (tm->tm_year > 0)
2868  /* Century 20 == 1901 - 2000 */
2869  i = (tm->tm_year - 1) / 100 + 1;
2870  else
2871  /* Century 6BC == 600BC - 501BC */
2872  i = tm->tm_year / 100 - 1;
2873  }
2874  if (i <= 99 && i >= -99)
2875  sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i);
2876  else
2877  sprintf(s, "%d", i);
2878  if (S_THth(n->suffix))
2879  str_numth(s, s, S_TH_TYPE(n->suffix));
2880  s += strlen(s);
2881  break;
2882  case DCH_Y_YYY:
2883  i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000;
2884  sprintf(s, "%d,%03d", i,
2885  ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000));
2886  if (S_THth(n->suffix))
2887  str_numth(s, s, S_TH_TYPE(n->suffix));
2888  s += strlen(s);
2889  break;
2890  case DCH_YYYY:
2891  case DCH_IYYY:
2892  sprintf(s, "%0*d",
2893  S_FM(n->suffix) ? 0 :
2894  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5,
2895  (n->key->id == DCH_YYYY ?
2896  ADJUST_YEAR(tm->tm_year, is_interval) :
2898  tm->tm_mon,
2899  tm->tm_mday),
2900  is_interval)));
2901  if (S_THth(n->suffix))
2902  str_numth(s, s, S_TH_TYPE(n->suffix));
2903  s += strlen(s);
2904  break;
2905  case DCH_YYY:
2906  case DCH_IYY:
2907  sprintf(s, "%0*d",
2908  S_FM(n->suffix) ? 0 :
2909  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4,
2910  (n->key->id == DCH_YYY ?
2911  ADJUST_YEAR(tm->tm_year, is_interval) :
2913  tm->tm_mon,
2914  tm->tm_mday),
2915  is_interval)) % 1000);
2916  if (S_THth(n->suffix))
2917  str_numth(s, s, S_TH_TYPE(n->suffix));
2918  s += strlen(s);
2919  break;
2920  case DCH_YY:
2921  case DCH_IY:
2922  sprintf(s, "%0*d",
2923  S_FM(n->suffix) ? 0 :
2924  (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3,
2925  (n->key->id == DCH_YY ?
2926  ADJUST_YEAR(tm->tm_year, is_interval) :
2928  tm->tm_mon,
2929  tm->tm_mday),
2930  is_interval)) % 100);
2931  if (S_THth(n->suffix))
2932  str_numth(s, s, S_TH_TYPE(n->suffix));
2933  s += strlen(s);
2934  break;
2935  case DCH_Y:
2936  case DCH_I:
2937  sprintf(s, "%1d",
2938  (n->key->id == DCH_Y ?
2939  ADJUST_YEAR(tm->tm_year, is_interval) :
2941  tm->tm_mon,
2942  tm->tm_mday),
2943  is_interval)) % 10);
2944  if (S_THth(n->suffix))
2945  str_numth(s, s, S_TH_TYPE(n->suffix));
2946  s += strlen(s);
2947  break;
2948  case DCH_RM:
2949  if (!tm->tm_mon)
2950  break;
2951  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
2953  s += strlen(s);
2954  break;
2955  case DCH_rm:
2956  if (!tm->tm_mon)
2957  break;
2958  sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4,
2960  s += strlen(s);
2961  break;
2962  case DCH_W:
2963  sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1);
2964  if (S_THth(n->suffix))
2965  str_numth(s, s, S_TH_TYPE(n->suffix));
2966  s += strlen(s);
2967  break;
2968  case DCH_J:
2969  sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday));
2970  if (S_THth(n->suffix))
2971  str_numth(s, s, S_TH_TYPE(n->suffix));
2972  s += strlen(s);
2973  break;
2974  }
2975  }
2976 
2977  *s = '\0';
2978 }
#define a_m_STR
Definition: formatting.c:232
#define NODE_TYPE_END
Definition: formatting.c:171
const KeyWord * key
Definition: formatting.c:166
int tm_wday
Definition: pgtime.h:33
#define b_c_STR
Definition: formatting.c:210
#define S_THth(_s)
Definition: formatting.c:517
int tm_hour
Definition: pgtime.h:29
#define BC_STR
Definition: formatting.c:211
#define A_M_STR
Definition: formatting.c:231
static char * str_initcap_z(const char *buff, Oid collid)
Definition: formatting.c:1996
fsec_t fsec
Definition: formatting.c:463
static char * asc_tolower_z(const char *buff)
Definition: formatting.c:2002
#define AD_STR
Definition: formatting.c:206
int errcode(int sqlerrcode)
Definition: elog.c:575
struct pg_tm tm
Definition: formatting.c:462
#define p_m_STR
Definition: formatting.c:237
#define am_STR
Definition: formatting.c:234
static char * str_tolower_z(const char *buff, Oid collid)
Definition: formatting.c:1984
long int tm_gmtoff
Definition: pgtime.h:36
Definition: pgtime.h:25
char * localized_abbrev_months[12]
Definition: pg_locale.c:96
static char * str_numth(char *dest, char *num, int type)
Definition: formatting.c:1435
static const char *const rm_months_upper[]
Definition: formatting.c:260
int id
Definition: formatting.c:158
#define pm_STR
Definition: formatting.c:239
static struct pg_tm tm
Definition: localtime.c:107
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
void pfree(void *pointer)
Definition: mcxt.c:936
const char *const months[]
Definition: datetime.c:66
#define NODE_TYPE_ACTION
Definition: formatting.c:172
#define ERROR
Definition: elog.h:43
char character[MAX_MULTIBYTE_CHAR_LEN+1]
Definition: formatting.c:167
int date2isoweek(int year, int mon, int mday)
Definition: timestamp.c:4092
#define S_FM(_s)
Definition: formatting.c:523
int date2isoyear(int year, int mon, int mday)
Definition: timestamp.c:4146
int tm_mday
Definition: pgtime.h:30
#define HOURS_PER_DAY
Definition: timestamp.h:78
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:88
const char *const days[]
Definition: datetime.c:69
#define A_D_STR
Definition: formatting.c:204
#define a_d_STR
Definition: formatting.c:205
#define ereport(elevel, rest)
Definition: elog.h:122
#define SECS_PER_HOUR
Definition: timestamp.h:87
#define bc_STR
Definition: formatting.c:212
#define S_TH_TYPE(_s)
Definition: formatting.c:520
static const char *const months_full[]
Definition: formatting.c:186
int len
Definition: formatting.c:157
char * localized_full_days[7]
Definition: pg_locale.c:95
int date2j(int y, int m, int d)
Definition: datetime.c:292
#define ad_STR
Definition: formatting.c:207
void cache_locale_time(void)
Definition: pg_locale.c:786
#define P_M_STR
Definition: formatting.c:236
static char * asc_toupper_z(const char *buff)
Definition: formatting.c:2008
#define ADJUST_YEAR(year, is_interval)
Definition: formatting.c:202
#define tmtcTzn(_X)
Definition: formatting.c:468
int tm_year
Definition: pgtime.h:32
int errmsg(const char *fmt,...)
Definition: elog.c:797
static char * str_toupper_z(const char *buff, Oid collid)
Definition: formatting.c:1990
#define INVALID_FOR_INTERVAL
Definition: formatting.c:490
int date2isoyearday(int year, int mon, int mday)
Definition: timestamp.c:4203
int i
#define S_TM(_s)
Definition: formatting.c:525
int tm_yday
Definition: pgtime.h:34
#define PM_STR
Definition: formatting.c:238
#define AM_STR
Definition: formatting.c:233
#define TM_SUFFIX_LEN
Definition: formatting.c:531
int tm_sec
Definition: pgtime.h:27
char * localized_full_months[12]
Definition: pg_locale.c:97
#define DCH_MAX_ITEM_SIZ
Definition: formatting.c:117
char * localized_abbrev_days[7]
Definition: pg_locale.c:94
int tm_min
Definition: pgtime.h:28
static const char *const rm_months_lower[]
Definition: formatting.c:263
static const char *const days_short[]
Definition: formatting.c:191
#define B_C_STR
Definition: formatting.c:209

◆ do_to_timestamp()

static void do_to_timestamp ( text date_txt,
text fmt,
struct pg_tm tm,
fsec_t fsec 
)
static

Definition at line 3642 of file formatting.c.

References TmFromChar::bc, TmFromChar::cc, TmFromChar::clock, CLOCK_12_HOUR, TmFromChar::d, DateTimeParseError(), DAY, DCH_cache_fetch(), DCH_CACHE_SIZE, DCH_from_char(), DCH_index, DCH_TYPE, TmFromChar::dd, TmFromChar::ddd, DEBUG_TM, DEBUG_TMFC, DTERR_FIELD_OVERFLOW, DTERR_TZDISP_OVERFLOW, DTK_DATE_M, DTK_M, ereport, errcode(), errhint(), errmsg(), ERROR, format, DCHCacheEntry::format, FROM_CHAR_DATE_ISOWEEK, TmFromChar::hh, HOURS_PER_DAY, i, isleap, isoweek2date(), isoweek2j(), isoweekdate2date(), TmFromChar::j, j2date(), MAX_TZDISP_HOUR, TmFromChar::mi, MINS_PER_HOUR, TmFromChar::mm, TmFromChar::mode, MONTH, MONTHS_PER_YEAR, TmFromChar::ms, palloc(), parse_format(), pfree(), TmFromChar::pm, SECS_PER_HOUR, SECS_PER_MINUTE, snprintf(), TmFromChar::ss, TmFromChar::ssss, text_to_cstring(), pg_tm::tm_hour, pg_tm::tm_mday, pg_tm::tm_min, pg_tm::tm_mon, pg_tm::tm_sec, pg_tm::tm_year, pg_tm::tm_zone, TmFromChar::tzh, TmFromChar::tzm, TmFromChar::tzsign, TmFromChar::us, USECS_PER_SEC, ValidateDate(), VARSIZE_ANY_EXHDR, TmFromChar::w, TmFromChar::ww, YEAR, TmFromChar::year, TmFromChar::yysz, ZERO_tm, and ZERO_tmfc.

Referenced by to_date(), and to_timestamp().

3644 {
3645  FormatNode *format;
3646  TmFromChar tmfc;
3647  int fmt_len;
3648  char *date_str;
3649  int fmask;
3650 
3651  date_str = text_to_cstring(date_txt);
3652 
3653  ZERO_tmfc(&tmfc);
3654  ZERO_tm(tm);
3655  *fsec = 0;
3656  fmask = 0; /* bit mask for ValidateDate() */
3657 
3658  fmt_len = VARSIZE_ANY_EXHDR(fmt);
3659 
3660  if (fmt_len)
3661  {
3662  char *fmt_str;
3663  bool incache;
3664 
3665  fmt_str = text_to_cstring(fmt);
3666 
3667  if (fmt_len > DCH_CACHE_SIZE)
3668  {
3669  /*
3670  * Allocate new memory if format picture is bigger than static
3671  * cache and do not use cache (call parser always)
3672  */
3673  incache = false;
3674 
3675  format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
3676 
3677  parse_format(format, fmt_str, DCH_keywords,
3678  DCH_suff, DCH_index, DCH_TYPE, NULL);
3679  }
3680  else
3681  {
3682  /*
3683  * Use cache buffers
3684  */
3685  DCHCacheEntry *ent = DCH_cache_fetch(fmt_str);
3686 
3687  incache = true;
3688  format = ent->format;
3689  }
3690 
3691 #ifdef DEBUG_TO_FROM_CHAR
3692  /* dump_node(format, fmt_len); */
3693  /* dump_index(DCH_keywords, DCH_index); */
3694 #endif
3695 
3696  DCH_from_char(format, date_str, &tmfc);
3697 
3698  pfree(fmt_str);
3699  if (!incache)
3700  pfree(format);
3701  }
3702 
3703  DEBUG_TMFC(&tmfc);
3704 
3705  /*
3706  * Convert to_date/to_timestamp input fields to standard 'tm'
3707  */
3708  if (tmfc.ssss)
3709  {
3710  int x = tmfc.ssss;
3711 
3712  tm->tm_hour = x / SECS_PER_HOUR;
3713  x %= SECS_PER_HOUR;
3714  tm->tm_min = x / SECS_PER_MINUTE;
3715  x %= SECS_PER_MINUTE;
3716  tm->tm_sec = x;
3717  }
3718 
3719  if (tmfc.ss)
3720  tm->tm_sec = tmfc.ss;
3721  if (tmfc.mi)
3722  tm->tm_min = tmfc.mi;
3723  if (tmfc.hh)
3724  tm->tm_hour = tmfc.hh;
3725 
3726  if (tmfc.clock == CLOCK_12_HOUR)
3727  {
3728  if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2)
3729  ereport(ERROR,
3730  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3731  errmsg("hour \"%d\" is invalid for the 12-hour clock",
3732  tm->tm_hour),
3733  errhint("Use the 24-hour clock, or give an hour between 1 and 12.")));
3734 
3735  if (tmfc.pm && tm->tm_hour < HOURS_PER_DAY / 2)
3736  tm->tm_hour += HOURS_PER_DAY / 2;
3737  else if (!tmfc.pm && tm->tm_hour == HOURS_PER_DAY / 2)
3738  tm->tm_hour = 0;
3739  }
3740 
3741  if (tmfc.year)
3742  {
3743  /*
3744  * If CC and YY (or Y) are provided, use YY as 2 low-order digits for
3745  * the year in the given century. Keep in mind that the 21st century
3746  * AD runs from 2001-2100, not 2000-2099; 6th century BC runs from
3747  * 600BC to 501BC.
3748  */
3749  if (tmfc.cc && tmfc.yysz <= 2)
3750  {
3751  if (tmfc.bc)
3752  tmfc.cc = -tmfc.cc;
3753  tm->tm_year = tmfc.year % 100;
3754  if (tm->tm_year)
3755  {
3756  if (tmfc.cc >= 0)
3757  tm->tm_year += (tmfc.cc - 1) * 100;
3758  else
3759  tm->tm_year = (tmfc.cc + 1) * 100 - tm->tm_year + 1;
3760  }
3761  else
3762  {
3763  /* find century year for dates ending in "00" */
3764  tm->tm_year = tmfc.cc * 100 + ((tmfc.cc >= 0) ? 0 : 1);
3765  }
3766  }
3767  else
3768  {
3769  /* If a 4-digit year is provided, we use that and ignore CC. */
3770  tm->tm_year = tmfc.year;
3771  if (tmfc.bc && tm->tm_year > 0)
3772  tm->tm_year = -(tm->tm_year - 1);
3773  }
3774  fmask |= DTK_M(YEAR);
3775  }
3776  else if (tmfc.cc)
3777  {
3778  /* use first year of century */
3779  if (tmfc.bc)
3780  tmfc.cc = -tmfc.cc;
3781  if (tmfc.cc >= 0)
3782  /* +1 because 21st century started in 2001 */
3783  tm->tm_year = (tmfc.cc - 1) * 100 + 1;
3784  else
3785  /* +1 because year == 599 is 600 BC */
3786  tm->tm_year = tmfc.cc * 100 + 1;
3787  fmask |= DTK_M(YEAR);
3788  }
3789 
3790  if (tmfc.j)
3791  {
3792  j2date(tmfc.j, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3793  fmask |= DTK_DATE_M;
3794  }
3795 
3796  if (tmfc.ww)
3797  {
3798  if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
3799  {
3800  /*
3801  * If tmfc.d is not set, then the date is left at the beginning of
3802  * the ISO week (Monday).
3803  */
3804  if (tmfc.d)
3805  isoweekdate2date(tmfc.ww, tmfc.d, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3806  else
3807  isoweek2date(tmfc.ww, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3808  fmask |= DTK_DATE_M;
3809  }
3810  else
3811  tmfc.ddd = (tmfc.ww - 1) * 7 + 1;
3812  }
3813 
3814  if (tmfc.w)
3815  tmfc.dd = (tmfc.w - 1) * 7 + 1;
3816  if (tmfc.dd)
3817  {
3818  tm->tm_mday = tmfc.dd;
3819  fmask |= DTK_M(DAY);
3820  }
3821  if (tmfc.mm)
3822  {
3823  tm->tm_mon = tmfc.mm;
3824  fmask |= DTK_M(MONTH);
3825  }
3826 
3827  if (tmfc.ddd && (tm->tm_mon <= 1 || tm->tm_mday <= 1))
3828  {
3829  /*
3830  * The month and day field have not been set, so we use the
3831  * day-of-year field to populate them. Depending on the date mode,
3832  * this field may be interpreted as a Gregorian day-of-year, or an ISO
3833  * week date day-of-year.
3834  */
3835 
3836  if (!tm->tm_year && !tmfc.bc)
3837  ereport(ERROR,
3838  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
3839  errmsg("cannot calculate day of year without year information")));
3840 
3841  if (tmfc.mode == FROM_CHAR_DATE_ISOWEEK)
3842  {
3843  int j0; /* zeroth day of the ISO year, in Julian */
3844 
3845  j0 = isoweek2j(tm->tm_year, 1) - 1;
3846 
3847  j2date(j0 + tmfc.ddd, &tm->tm_year, &tm->tm_mon, &tm->tm_mday);
3848  fmask |= DTK_DATE_M;
3849  }
3850  else
3851  {
3852  const int *y;
3853  int i;
3854 
3855  static const int ysum[2][13] = {
3856  {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
3857  {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
3858 
3859  y = ysum[isleap(tm->tm_year)];
3860 
3861  for (i = 1; i <= MONTHS_PER_YEAR; i++)
3862  {
3863  if (tmfc.ddd <= y[i])
3864  break;
3865  }
3866  if (tm->tm_mon <= 1)
3867  tm->tm_mon = i;
3868 
3869  if (tm->tm_mday <= 1)
3870  tm->tm_mday = tmfc.ddd - y[i - 1];
3871 
3872  fmask |= DTK_M(MONTH) | DTK_M(DAY);
3873  }
3874  }
3875 
3876  if (tmfc.ms)
3877  *fsec += tmfc.ms * 1000;
3878  if (tmfc.us)
3879  *fsec += tmfc.us;
3880 
3881  /* Range-check date fields according to bit mask computed above */
3882  if (fmask != 0)
3883  {
3884  /* We already dealt with AD/BC, so pass isjulian = true */
3885  int dterr = ValidateDate(fmask, true, false, false, tm);
3886 
3887  if (dterr != 0)
3888  {
3889  /*
3890  * Force the error to be DTERR_FIELD_OVERFLOW even if ValidateDate
3891  * said DTERR_MD_FIELD_OVERFLOW, because we don't want to print an
3892  * irrelevant hint about datestyle.
3893  */
3894  DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp");
3895  }
3896  }
3897 
3898  /* Range-check time fields too */
3899  if (tm->tm_hour < 0 || tm->tm_hour >= HOURS_PER_DAY ||
3900  tm->tm_min < 0 || tm->tm_min >= MINS_PER_HOUR ||
3901  tm->tm_sec < 0 || tm->tm_sec >= SECS_PER_MINUTE ||
3902  *fsec < INT64CONST(0) || *fsec >= USECS_PER_SEC)
3903  DateTimeParseError(DTERR_FIELD_OVERFLOW, date_str, "timestamp");
3904 
3905  /* Save parsed time-zone into tm->tm_zone if it was specified */
3906  if (tmfc.tzsign)
3907  {
3908  char *tz;
3909 
3910  if (tmfc.tzh < 0 || tmfc.tzh > MAX_TZDISP_HOUR ||
3911  tmfc.tzm < 0 || tmfc.tzm >= MINS_PER_HOUR)
3912  DateTimeParseError(DTERR_TZDISP_OVERFLOW, date_str, "timestamp");
3913 
3914  tz = palloc(7);
3915 
3916  snprintf(tz, 7, "%c%02d:%02d",
3917  tmfc.tzsign > 0 ? '+' : '-', tmfc.tzh, tmfc.tzm);
3918 
3919  tm->tm_zone = tz;
3920  }
3921 
3922  DEBUG_TM(tm);
3923 
3924  pfree(date_str);
3925 }
#define DEBUG_TM(_X)
Definition: formatting.c:453
#define DAY
Definition: datetime.h:94
int errhint(const char *fmt,...)
Definition: elog.c:987
void DateTimeParseError(int dterr, const char *str, const char *datatype)
Definition: datetime.c:3765
#define USECS_PER_SEC
Definition: timestamp.h:94
#define YEAR
Definition: datetime.h:93
int tm_hour
Definition: pgtime.h:29
#define isleap(y)
Definition: datetime.h:273
static const KeySuffix DCH_suff[]
Definition: formatting.c:533
static const int DCH_index[KeyWord_INDEX_SIZE]
Definition: formatting.c:879
int errcode(int sqlerrcode)
Definition: elog.c:575
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
void isoweekdate2date(int isoweek, int wday, int *year, int *mon, int *mday)
Definition: timestamp.c:4074
static void DCH_from_char(FormatNode *node, char *in, TmFromChar *out)
Definition: formatting.c:2989
FromCharDateMode mode
Definition: formatting.c:408
#define DTK_DATE_M
Definition: datetime.h:194
#define MINS_PER_HOUR
Definition: timestamp.h:89
#define MAX_TZDISP_HOUR
Definition: timestamp.h:103
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
void pfree(void *pointer)
Definition: mcxt.c:936
#define DCH_CACHE_SIZE
Definition: formatting.c:372
#define ERROR
Definition: elog.h:43
#define DTERR_FIELD_OVERFLOW
Definition: datetime.h:283
static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, const KeySuffix *suf, const int *index, int ver, NUMDesc *Num)
Definition: formatting.c:1233
int tm_mday
Definition: pgtime.h:30
#define HOURS_PER_DAY
Definition: timestamp.h:78
int tm_mon
Definition: pgtime.h:31
#define SECS_PER_MINUTE
Definition: timestamp.h:88
FormatNode format[DCH_CACHE_SIZE+1]
Definition: formatting.c:377
static DCHCacheEntry * DCH_cache_fetch(const char *str)
Definition: formatting.c:3365
const char * tm_zone
Definition: pgtime.h:37
#define ereport(elevel, rest)
Definition: elog.h:122
void j2date(int jd, int *year, int *month, int *day)
Definition: datetime.c:317
#define SECS_PER_HOUR
Definition: timestamp.h:87
#define CLOCK_12_HOUR
Definition: formatting.c:179
#define MONTH
Definition: datetime.h:92
#define DCH_TYPE
Definition: formatting.c:103
#define DTERR_TZDISP_OVERFLOW
Definition: datetime.h:286
void isoweek2date(int woy, int *year, int *mon, int *mday)
Definition: timestamp.c:4061
#define ZERO_tmfc(_X)
Definition: formatting.c:433
int isoweek2j(int year, int week)
Definition: timestamp.c:4041
#define DEBUG_TMFC(_X)
Definition: formatting.c:452
char * text_to_cstring(const text *t)
Definition: varlena.c:183
int tm_year
Definition: pgtime.h:32
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
void * palloc(Size size)
Definition: mcxt.c:835
int errmsg(const char *fmt,...)
Definition: elog.c:797
static const KeyWord DCH_keywords[]
Definition: formatting.c:723
int i
#define DTK_M(t)
Definition: datetime.h:190
static char format
Definition: pg_basebackup.c:81
int tm_sec
Definition: pgtime.h:27
#define ZERO_tm(_X)
Definition: formatting.c:471
int tm_min
Definition: pgtime.h:28
int ValidateDate(int fmask, bool isjulian, bool is2digits, bool bc, struct pg_tm *tm)
Definition: datetime.c:2479

◆ fill_str()

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

Definition at line 3934 of file formatting.c.

References generate_unaccent_rules::str.

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

3935 {
3936  memset(str, c, max);
3937  *(str + max) = '\0';
3938  return str;
3939 }
char * c

◆ float4_to_char()

Datum float4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 5624 of file formatting.c.

References fill_str(), format, int_to_roman(), IS_EEEE, is_infinite(), IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, MAXFLOATWIDTH, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, palloc(), PG_GETARG_FLOAT4, PG_GETARG_TEXT_PP, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, rint(), sign, snprintf(), val, and value.

5625 {
5627  text *fmt = PG_GETARG_TEXT_PP(1);
5628  NUMDesc Num;
5629  FormatNode *format;
5630  text *result;
5631  bool shouldFree;
5632  int out_pre_spaces = 0,
5633  sign = 0;
5634  char *numstr,
5635  *orgnum,
5636  *p;
5637 
5639 
5640  if (IS_ROMAN(&Num))
5641  numstr = orgnum = int_to_roman((int) rint(value));
5642  else if (IS_EEEE(&Num))
5643  {
5644  numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5645  if (isnan(value) || is_infinite(value))
5646  {
5647  /*
5648  * Allow 6 characters for the leading sign, the decimal point,
5649  * "e", the exponent's sign and two exponent digits.
5650  */
5651  numstr = (char *) palloc(Num.pre + Num.post + 7);
5652  fill_str(numstr, '#', Num.pre + Num.post + 6);
5653  *numstr = ' ';
5654  *(numstr + Num.pre + 1) = '.';
5655  }
5656  else
5657  {
5658  snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5659 
5660  /*
5661  * Swap a leading positive sign for a space.
5662  */
5663  if (*orgnum == '+')
5664  *orgnum = ' ';
5665 
5666  numstr = orgnum;
5667  }
5668  }
5669  else
5670  {
5671  float4 val = value;
5672  int numstr_pre_len;
5673 
5674  if (IS_MULTI(&Num))
5675  {
5676  float multi = pow((double) 10, (double) Num.multi);
5677 
5678  val = value * multi;
5679  Num.pre += Num.multi;
5680  }
5681 
5682  orgnum = (char *) palloc(MAXFLOATWIDTH + 1);
5683  snprintf(orgnum, MAXFLOATWIDTH + 1, "%.0f", fabs(val));
5684  numstr_pre_len = strlen(orgnum);
5685 
5686  /* adjust post digits to fit max float digits */
5687  if (numstr_pre_len >= FLT_DIG)
5688  Num.post = 0;
5689  else if (numstr_pre_len + Num.post > FLT_DIG)
5690  Num.post = FLT_DIG - numstr_pre_len;
5691  snprintf(orgnum, MAXFLOATWIDTH + 1, "%.*f", Num.post, val);
5692 
5693  if (*orgnum == '-')
5694  { /* < 0 */
5695  sign = '-';
5696  numstr = orgnum + 1;
5697  }
5698  else
5699  {
5700  sign = '+';
5701  numstr = orgnum;
5702  }
5703 
5704  if ((p = strchr(numstr, '.')))
5705  numstr_pre_len = p - numstr;
5706  else
5707  numstr_pre_len = strlen(numstr);
5708 
5709  /* needs padding? */
5710  if (numstr_pre_len < Num.pre)
5711  out_pre_spaces = Num.pre - numstr_pre_len;
5712  /* overflowed prefix digit format? */
5713  else if (numstr_pre_len > Num.pre)
5714  {
5715  numstr = (char *) palloc(Num.pre + Num.post + 2);
5716  fill_str(numstr, '#', Num.pre + Num.post + 1);
5717  *(numstr + Num.pre) = '.';
5718  }
5719  }
5720 
5722  PG_RETURN_TEXT_P(result);
5723 }
#define MAXDOUBLEWIDTH
Definition: formatting.c:125
static struct @130 value
#define IS_EEEE(_f)
Definition: formatting.c:355
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define MAXFLOATWIDTH
Definition: formatting.c:124
#define NUM_TOCHAR_finish
Definition: formatting.c:5211
#define IS_ROMAN(_f)
Definition: formatting.c:353
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define NUM_TOCHAR_prepare
Definition: formatting.c:5198
#define IS_MULTI(_f)
Definition: formatting.c:354
char sign
Definition: informix.c:693
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:3934
static char * int_to_roman(int number)
Definition: formatting.c:4132
int pre
Definition: formatting.c:306
double rint(double x)
Definition: rint.c:22
#define PG_GETARG_FLOAT4(n)
Definition: fmgr.h:245
float float4
Definition: c.h:438
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:331
int post
Definition: formatting.c:306
int is_infinite(double val)
Definition: float.c:200
void * palloc(Size size)
Definition: mcxt.c:835
int multi
Definition: formatting.c:306
Definition: c.h:497
static char format
Definition: pg_basebackup.c:81
long val
Definition: informix.c:689

◆ float8_to_char()

Datum float8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 5730 of file formatting.c.

References fill_str(), format, int_to_roman(), IS_EEEE, is_infinite(), IS_MULTI, IS_ROMAN, MAXDOUBLEWIDTH, NUMDesc::multi, NUM_TOCHAR_finish, NUM_TOCHAR_prepare, palloc(), PG_GETARG_FLOAT8, PG_GETARG_TEXT_PP, PG_RETURN_TEXT_P, NUMDesc::post, NUMDesc::pre, rint(), sign, snprintf(), val, and value.

5731 {
5733  text *fmt = PG_GETARG_TEXT_PP(1);
5734  NUMDesc Num;
5735  FormatNode *format;
5736  text *result;
5737  bool shouldFree;
5738  int out_pre_spaces = 0,
5739  sign = 0;
5740  char *numstr,
5741  *orgnum,
5742  *p;
5743 
5745 
5746  if (IS_ROMAN(&Num))
5747  numstr = orgnum = int_to_roman((int) rint(value));
5748  else if (IS_EEEE(&Num))
5749  {
5750  numstr = orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5751  if (isnan(value) || is_infinite(value))
5752  {
5753  /*
5754  * Allow 6 characters for the leading sign, the decimal point,
5755  * "e", the exponent's sign and two exponent digits.
5756  */
5757  numstr = (char *) palloc(Num.pre + Num.post + 7);
5758  fill_str(numstr, '#', Num.pre + Num.post + 6);
5759  *numstr = ' ';
5760  *(numstr + Num.pre + 1) = '.';
5761  }
5762  else
5763  {
5764  snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, value);
5765 
5766  /*
5767  * Swap a leading positive sign for a space.
5768  */
5769  if (*orgnum == '+')
5770  *orgnum = ' ';
5771 
5772  numstr = orgnum;
5773  }
5774  }
5775  else
5776  {
5777  float8 val = value;
5778  int numstr_pre_len;
5779 
5780  if (IS_MULTI(&Num))
5781  {
5782  double multi = pow((double) 10, (double) Num.multi);
5783 
5784  val = value * multi;
5785  Num.pre += Num.multi;
5786  }
5787  orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5788  numstr_pre_len = snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.0f", fabs(val));
5789 
5790  /* adjust post digits to fit max double digits */
5791  if (numstr_pre_len >= DBL_DIG)
5792  Num.post = 0;
5793  else if (numstr_pre_len + Num.post > DBL_DIG)
5794  Num.post = DBL_DIG - numstr_pre_len;
5795  snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%.*f", Num.post, val);
5796 
5797  if (*orgnum == '-')
5798  { /* < 0 */
5799  sign = '-';
5800  numstr = orgnum + 1;
5801  }
5802  else
5803  {
5804  sign = '+';
5805  numstr = orgnum;
5806  }
5807 
5808  if ((p = strchr(numstr, '.')))
5809  numstr_pre_len = p - numstr;
5810  else
5811  numstr_pre_len = strlen(numstr);
5812 
5813  /* needs padding? */
5814  if (numstr_pre_len < Num.pre)
5815  out_pre_spaces = Num.pre - numstr_pre_len;
5816  /* overflowed prefix digit format? */
5817  else if (numstr_pre_len > Num.pre)
5818  {
5819  numstr = (char *) palloc(Num.pre + Num.post + 2);
5820  fill_str(numstr, '#', Num.pre + Num.post + 1);
5821  *(numstr + Num.pre) = '.';
5822  }
5823  }
5824 
5826  PG_RETURN_TEXT_P(result);
5827 }
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:246
#define MAXDOUBLEWIDTH
Definition: formatting.c:125
static struct @130 value
#define IS_EEEE(_f)
Definition: formatting.c:355
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define NUM_TOCHAR_finish
Definition: formatting.c:5211
#define IS_ROMAN(_f)
Definition: formatting.c:353
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define NUM_TOCHAR_prepare
Definition: formatting.c:5198
double float8
Definition: c.h:439
#define IS_MULTI(_f)
Definition: formatting.c:354
char sign
Definition: informix.c:693
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:3934
static char * int_to_roman(int number)
Definition: formatting.c:4132
int pre
Definition: formatting.c:306
double rint(double x)
Definition: rint.c:22
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:331
int post
Definition: formatting.c:306
int is_infinite(double val)
Definition: float.c:200
void * palloc(Size size)
Definition: mcxt.c:835
int multi
Definition: formatting.c:306
Definition: c.h:497
static char format
Definition: pg_basebackup.c:81
long val
Definition: informix.c:689

◆ from_char_parse_int()

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

Definition at line 2291 of file formatting.c.

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

Referenced by DCH_from_char().

2292 {
2293  return from_char_parse_int_len(dest, src, node->key->len, node);
2294 }
const KeyWord * key
Definition: formatting.c:166
static int from_char_parse_int_len(int *dest, char **src, const int len, FormatNode *node)
Definition: formatting.c:2201
int len
Definition: formatting.c:157

◆ from_char_parse_int_len()

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

Definition at line 2201 of file formatting.c.

References Assert, DCH_MAX_ITEM_SIZ, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, from_char_set_int(), is_next_separator(), FormatNode::key, KeyWord::name, S_FM, strlcpy(), strspace_len(), and FormatNode::suffix.

Referenced by DCH_from_char(), and from_char_parse_int().

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

◆ from_char_seq_search()

static int from_char_seq_search ( int *  dest,
char **  src,
const char *const *  array,
int  type,
int  max,
FormatNode node 
)
static

Definition at line 2379 of file formatting.c.

References Assert, DCH_MAX_ITEM_SIZ, ereport, errcode(), errdetail(), errmsg(), ERROR, FormatNode::key, KeyWord::name, seq_search(), and strlcpy().

Referenced by DCH_from_char().

2381 {
2382  int len;
2383 
2384  *dest = seq_search(*src, array, type, max, &len);
2385  if (len <= 0)
2386  {
2387  char copy[DCH_MAX_ITEM_SIZ + 1];
2388 
2389  Assert(max <= DCH_MAX_ITEM_SIZ);
2390  strlcpy(copy, *src, max + 1);
2391 
2392  ereport(ERROR,
2393  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2394  errmsg("invalid value \"%s\" for \"%s\"",
2395  copy, node->key->name),
2396  errdetail("The given value did not match any of the allowed "
2397  "values for this field.")));
2398  }
2399  *src += len;
2400  return len;
2401 }
const KeyWord * key
Definition: formatting.c:166
static int seq_search(char *name, const char *const *array, int type, int max, int *len)
Definition: formatting.c:2301
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
const char * name
Definition: formatting.c:156
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
#define Assert(condition)
Definition: c.h:680
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define DCH_MAX_ITEM_SIZ
Definition: formatting.c:117

◆ from_char_set_int()

static void from_char_set_int ( int *  dest,
const int  value,
const FormatNode node 
)
static

Definition at line 2168 of file formatting.c.

References ereport, errcode(), errdetail(), errmsg(), ERROR, FormatNode::key, KeyWord::name, and value.

Referenced by DCH_from_char(), and from_char_parse_int_len().

2169 {
2170  if (*dest != 0 && *dest != value)
2171  ereport(ERROR,
2172  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2173  errmsg("conflicting values for \"%s\" field in formatting string",
2174  node->key->name),
2175  errdetail("This value contradicts a previous setting for "
2176  "the same field type.")));
2177  *dest = value;
2178 }
static struct @130 value
const KeyWord * key
Definition: formatting.c:166
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define ereport(elevel, rest)
Definition: elog.h:122
const char * name
Definition: formatting.c:156
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ from_char_set_mode()

static void from_char_set_mode ( TmFromChar tmfc,
const FromCharDateMode  mode 
)
static

Definition at line 2146 of file formatting.c.

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

Referenced by DCH_from_char().

2147 {
2148  if (mode != FROM_CHAR_DATE_NONE)
2149  {
2150  if (tmfc->mode == FROM_CHAR_DATE_NONE)
2151  tmfc->mode = mode;
2152  else if (tmfc->mode != mode)
2153  ereport(ERROR,
2154  (errcode(ERRCODE_INVALID_DATETIME_FORMAT),
2155  errmsg("invalid combination of date conventions"),
2156  errhint("Do not mix Gregorian and ISO week date "
2157  "conventions in a formatting template.")));
2158  }
2159 }
int errhint(const char *fmt,...)
Definition: elog.c:987
int errcode(int sqlerrcode)
Definition: elog.c:575
FromCharDateMode mode
Definition: formatting.c:408
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ get_last_relevant_decnum()

static char * get_last_relevant_decnum ( char *  num)
static

Definition at line 4263 of file formatting.c.

References elog.

Referenced by NUM_processor().

4264 {
4265  char *result,
4266  *p = strchr(num, '.');
4267 
4268 #ifdef DEBUG_TO_FROM_CHAR
4269  elog(DEBUG_elog_output, "get_last_relevant_decnum()");
4270 #endif
4271 
4272  if (!p)
4273  return NULL;
4274 
4275  result = p;
4276 
4277  while (*(++p))
4278  {
4279  if (*p != '0')
4280  result = p;
4281  }
4282 
4283  return result;
4284 }
#define elog
Definition: elog.h:219

◆ get_th()

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

Definition at line 1389 of file formatting.c.

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

Referenced by NUM_processor(), and str_numth().

1390 {
1391  int len = strlen(num),
1392  last,
1393  seclast;
1394 
1395  last = *(num + (len - 1));
1396  if (!isdigit((unsigned char) last))
1397  ereport(ERROR,
1398  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1399  errmsg("\"%s\" is not a number", num)));
1400 
1401  /*
1402  * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get
1403  * 'ST/st', 'ND/nd', 'RD/rd', respectively
1404  */
1405  if ((len > 1) && ((seclast = num[len - 2]) == '1'))
1406  last = 0;
1407 
1408  switch (last)
1409  {
1410  case '1':
1411  if (type == TH_UPPER)
1412  return numTH[0];
1413  return numth[0];
1414  case '2':
1415  if (type == TH_UPPER)
1416  return numTH[1];
1417  return numth[1];
1418  case '3':
1419  if (type == TH_UPPER)
1420  return numTH[2];
1421  return numth[2];
1422  default:
1423  if (type == TH_UPPER)
1424  return numTH[3];
1425  return numth[3];
1426  }
1427 }
int errcode(int sqlerrcode)
Definition: elog.c:575
static const char *const numTH[]
Definition: formatting.c:278
#define TH_UPPER
Definition: formatting.c:297
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
static const char *const numth[]
Definition: formatting.c:279
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ index_seq_search()

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

Definition at line 1014 of file formatting.c.

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

Referenced by parse_format().

1015 {
1016  int poz;
1017 
1018  if (!KeyWord_INDEX_FILTER(*str))
1019  return NULL;
1020 
1021  if ((poz = *(index + (*str - ' '))) > -1)
1022  {
1023  const KeyWord *k = kw + poz;
1024 
1025  do
1026  {
1027  if (strncmp(str, k->name, k->len) == 0)
1028  return k;
1029  k++;
1030  if (!k->name)
1031  return NULL;
1032  } while (*str == *k->name);
1033  }
1034  return NULL;
1035 }
Definition: type.h:89
const char * name
Definition: formatting.c:156
int len
Definition: formatting.c:157
#define KeyWord_INDEX_FILTER(_c)
Definition: formatting.c:111

◆ int4_to_char()

Datum int4_to_char ( PG_FUNCTION_ARGS  )

Definition at line 5419 of file formatting.c.

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

5420 {
5422  text *fmt = PG_GETARG_TEXT_PP(1);
5423  NUMDesc Num;
5424  FormatNode *format;
5425  text *result;
5426  bool shouldFree;
5427  int out_pre_spaces = 0,
5428  sign = 0;
5429  char *numstr,
5430  *orgnum;
5431 
5433 
5434  /*
5435  * On DateType depend part (int32)
5436  */
5437  if (IS_ROMAN(&Num))
5438  numstr = orgnum = int_to_roman(value);
5439  else if (IS_EEEE(&Num))
5440  {
5441  /* we can do it easily because float8 won't lose any precision */
5442  float8 val = (float8) value;
5443 
5444  orgnum = (char *) palloc(MAXDOUBLEWIDTH + 1);
5445  snprintf(orgnum, MAXDOUBLEWIDTH + 1, "%+.*e", Num.post, val);
5446 
5447  /*
5448  * Swap a leading positive sign for a space.
5449  */
5450  if (*orgnum == '+')
5451  *orgnum = ' ';
5452 
5453  numstr = orgnum;
5454  }
5455  else
5456  {
5457  int numstr_pre_len;
5458 
5459  if (IS_MULTI(&Num))
5460  {
5462  Int32GetDatum(value * ((int32) pow((double) 10, (double) Num.multi)))));
5463  Num.pre += Num.multi;
5464  }
5465  else
5466  {
5468  Int32GetDatum(value)));
5469  }
5470 
5471  if (*orgnum == '-')
5472  {
5473  sign = '-';
5474  orgnum++;
5475  }
5476  else
5477  sign = '+';
5478 
5479  numstr_pre_len = strlen(orgnum);
5480 
5481  /* post-decimal digits? Pad out with zeros. */
5482  if (Num.post)
5483  {
5484  numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
5485  strcpy(numstr, orgnum);
5486  *(numstr + numstr_pre_len) = '.';
5487  memset(numstr + numstr_pre_len + 1, '0', Num.post);
5488  *(numstr + numstr_pre_len + Num.post + 1) = '\0';
5489  }
5490  else
5491  numstr = orgnum;
5492 
5493  /* needs padding? */
5494  if (numstr_pre_len < Num.pre)
5495  out_pre_spaces = Num.pre - numstr_pre_len;
5496  /* overflowed prefix digit format? */
5497  else if (numstr_pre_len > Num.pre)
5498  {
5499  numstr = (char *) palloc(Num.pre + Num.post + 2);
5500  fill_str(numstr, '#', Num.pre + Num.post + 1);
5501  *(numstr + Num.pre) = '.';
5502  }
5503  }
5504 
5506  PG_RETURN_TEXT_P(result);
5507 }
#define PG_GETARG_INT32(n)
Definition: fmgr.h:234
#define MAXDOUBLEWIDTH
Definition: formatting.c:125
static struct @130 value
#define IS_EEEE(_f)
Definition: formatting.c:355
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
#define NUM_TOCHAR_finish
Definition: formatting.c:5211
#define IS_ROMAN(_f)
Definition: formatting.c:353
signed int int32
Definition: c.h:294
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define NUM_TOCHAR_prepare
Definition: formatting.c:5198
double float8
Definition: c.h:439
#define DatumGetCString(X)
Definition: postgres.h:572
#define IS_MULTI(_f)
Definition: formatting.c:354
char sign
Definition: informix.c:693
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:3934
static char * int_to_roman(int number)
Definition: formatting.c:4132
int pre
Definition: formatting.c:306
Datum int4out(PG_FUNCTION_ARGS)
Definition: int.c:275
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:331
int post
Definition: formatting.c:306
#define Int32GetDatum(X)
Definition: postgres.h:485
void * palloc(Size size)
Definition: mcxt.c:835
int multi
Definition: formatting.c:306
Definition: c.h:497
static char format
Definition: pg_basebackup.c:81
long val
Definition: informix.c:689

◆ int8_to_char()

Datum int8_to_char ( PG_FUNCTION_ARGS  )

Definition at line 5514 of file formatting.c.

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

5515 {
5516  int64 value = PG_GETARG_INT64(0);
5517  text *fmt = PG_GETARG_TEXT_PP(1);
5518  NUMDesc Num;
5519  FormatNode *format;
5520  text *result;
5521  bool shouldFree;
5522  int out_pre_spaces = 0,
5523  sign = 0;
5524  char *numstr,
5525  *orgnum;
5526 
5528 
5529  /*
5530  * On DateType depend part (int32)
5531  */
5532  if (IS_ROMAN(&Num))
5533  {
5534  /* Currently don't support int8 conversion to roman... */
5535  numstr = orgnum = int_to_roman(DatumGetInt32(
5537  }
5538  else if (IS_EEEE(&Num))
5539  {
5540  /* to avoid loss of precision, must go via numeric not float8 */
5541  Numeric val;
5542 
5544  Int64GetDatum(value)));
5545  orgnum = numeric_out_sci(val, Num.post);
5546 
5547  /*
5548  * numeric_out_sci() does not emit a sign for positive numbers. We
5549  * need to add a space in this case so that positive and negative
5550  * numbers are aligned. We don't have to worry about NaN here.
5551  */
5552  if (*orgnum != '-')
5553  {
5554  numstr = (char *) palloc(strlen(orgnum) + 2);
5555  *numstr = ' ';
5556  strcpy(numstr + 1, orgnum);
5557  }
5558  else
5559  {
5560  numstr = orgnum;
5561  }
5562  }
5563  else
5564  {
5565  int numstr_pre_len;
5566 
5567  if (IS_MULTI(&Num))
5568  {
5569  double multi = pow((double) 10, (double) Num.multi);
5570 
5572  Int64GetDatum(value),
5574  Float8GetDatum(multi))));
5575  Num.pre += Num.multi;
5576  }
5577 
5579  Int64GetDatum(value)));
5580 
5581  if (*orgnum == '-')
5582  {
5583  sign = '-';
5584  orgnum++;
5585  }
5586  else
5587  sign = '+';
5588 
5589  numstr_pre_len = strlen(orgnum);
5590 
5591  /* post-decimal digits? Pad out with zeros. */
5592  if (Num.post)
5593  {
5594  numstr = (char *) palloc(numstr_pre_len + Num.post + 2);
5595  strcpy(numstr, orgnum);
5596  *(numstr + numstr_pre_len) = '.';
5597  memset(numstr + numstr_pre_len + 1, '0', Num.post);
5598  *(numstr + numstr_pre_len + Num.post + 1) = '\0';
5599  }
5600  else
5601  numstr = orgnum;
5602 
5603  /* needs padding? */
5604  if (numstr_pre_len < Num.pre)
5605  out_pre_spaces = Num.pre - numstr_pre_len;
5606  /* overflowed prefix digit format? */
5607  else if (numstr_pre_len > Num.pre)
5608  {
5609  numstr = (char *) palloc(Num.pre + Num.post + 2);
5610  fill_str(numstr, '#', Num.pre + Num.post + 1);
5611  *(numstr + Num.pre) = '.';
5612  }
5613  }
5614 
5616  PG_RETURN_TEXT_P(result);
5617 }
static struct @130 value
#define DatumGetInt32(X)
Definition: postgres.h:478
#define IS_EEEE(_f)
Definition: formatting.c:355
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
#define NUM_TOCHAR_finish
Definition: formatting.c:5211
#define IS_ROMAN(_f)
Definition: formatting.c:353
Datum int8_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:3039
Datum Float8GetDatum(float8 X)
Definition: fmgr.c:1810
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define NUM_TOCHAR_prepare
Definition: formatting.c:5198
#define DatumGetCString(X)
Definition: postgres.h:572
#define IS_MULTI(_f)
Definition: formatting.c:354
#define DatumGetInt64(X)
Definition: postgres.h:613
char sign
Definition: informix.c:693
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:3934
Datum int8mul(PG_FUNCTION_ARGS)
Definition: int8.c:528
static char * int_to_roman(int number)
Definition: formatting.c:4132
Datum dtoi8(PG_FUNCTION_ARGS)
Definition: int8.c:1165
int pre
Definition: formatting.c:306
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1786
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:331
int post
Definition: formatting.c:306
#define DatumGetNumeric(X)
Definition: numeric.h:49
Datum int84(PG_FUNCTION_ARGS)
Definition: int8.c:1117
void * palloc(Size size)
Definition: mcxt.c:835
int multi
Definition: formatting.c:306
Definition: c.h:497
static char format
Definition: pg_basebackup.c:81
char * numeric_out_sci(Numeric num, int scale)
Definition: numeric.c:730
#define PG_GETARG_INT64(n)
Definition: fmgr.h:247
long val
Definition: informix.c:689
Datum int8out(PG_FUNCTION_ARGS)
Definition: int8.c:146
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:587

◆ int_to_roman()

static char * int_to_roman ( int  number)
static

Definition at line 4132 of file formatting.c.

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

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

4133 {
4134  int len = 0,
4135  num = 0;
4136  char *p = NULL,
4137  *result,
4138  numstr[5];
4139 
4140  result = (char *) palloc(16);
4141  *result = '\0';
4142 
4143  if (number > 3999 || number < 1)
4144  {
4145  fill_str(result, '#', 15);
4146  return result;
4147  }
4148  len = snprintf(numstr, sizeof(numstr), "%d", number);
4149 
4150  for (p = numstr; *p != '\0'; p++, --len)
4151  {
4152  num = *p - 49; /* 48 ascii + 1 */
4153  if (num < 0)
4154  continue;
4155 
4156  if (len > 3)
4157  {
4158  while (num-- != -1)
4159  strcat(result, "M");
4160  }
4161  else
4162  {
4163  if (len == 3)
4164  strcat(result, rm100[num]);
4165  else if (len == 2)
4166  strcat(result, rm10[num]);
4167  else if (len == 1)
4168  strcat(result, rm1[num]);
4169  }
4170  }
4171  return result;
4172 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static const char *const rm10[]
Definition: formatting.c:271
static const char *const rm1[]
Definition: formatting.c:270
static char * fill_str(char *str, int c, int max)
Definition: formatting.c:3934
static const char *const rm100[]
Definition: formatting.c:272
void * palloc(Size size)
Definition: mcxt.c:835

◆ interval_to_char()

Datum interval_to_char ( PG_FUNCTION_ARGS  )

Definition at line 3529 of file formatting.c.

References datetime_to_char_body(), DAYS_PER_MONTH, interval2tm(), MONTHS_PER_YEAR, PG_GET_COLLATION, PG_GETARG_INTERVAL_P, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, TmToChar::tm, pg_tm::tm_mday, pg_tm::tm_mon, pg_tm::tm_yday, pg_tm::tm_year, tmtcFsec, tmtcTm, VARSIZE_ANY_EXHDR, and ZERO_tmtc.

3530 {
3531  Interval *it = PG_GETARG_INTERVAL_P(0);
3532  text *fmt = PG_GETARG_TEXT_PP(1),
3533  *res;
3534  TmToChar tmtc;
3535  struct pg_tm *tm;
3536 
3537  if (VARSIZE_ANY_EXHDR(fmt) <= 0)
3538  PG_RETURN_NULL();
3539 
3540  ZERO_tmtc(&tmtc);
3541  tm = tmtcTm(&tmtc);
3542 
3543  if (interval2tm(*it, tm, &tmtcFsec(&tmtc)) != 0)
3544  PG_RETURN_NULL();
3545 
3546  /* wday is meaningless, yday approximates the total span in days */
3547  tm->tm_yday = (tm->tm_year * MONTHS_PER_YEAR + tm->tm_mon) * DAYS_PER_MONTH + tm->tm_mday;
3548 
3549  if (!(res = datetime_to_char_body(&tmtc, fmt, true, PG_GET_COLLATION())))
3550  PG_RETURN_NULL();
3551 
3552  PG_RETURN_TEXT_P(res);
3553 }
#define PG_GETARG_INTERVAL_P(n)
Definition: timestamp.h:37
static text * datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid)
Definition: formatting.c:3392
#define ZERO_tmtc(_X)
Definition: formatting.c:479
Definition: pgtime.h:25
#define PG_GET_COLLATION()
Definition: fmgr.h:163
#define tmtcFsec(_X)
Definition: formatting.c:469
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
static struct pg_tm tm
Definition: localtime.c:107
#define MONTHS_PER_YEAR
Definition: timestamp.h:69
int interval2tm(Interval span, struct pg_tm *tm, fsec_t *fsec)
Definition: timestamp.c:1902
int tm_mday
Definition: pgtime.h:30
int tm_mon
Definition: pgtime.h:31
#define DAYS_PER_MONTH
Definition: timestamp.h:77
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:331
int tm_year
Definition: pgtime.h:32
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
int tm_yday
Definition: pgtime.h:34
Definition: c.h:497
#define tmtcTm(_X)
Definition: formatting.c:467
#define PG_RETURN_NULL()
Definition: fmgr.h:305

◆ is_next_separator()

static bool is_next_separator ( FormatNode n)
static

Definition at line 2070 of file formatting.c.

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

Referenced by from_char_parse_int_len().

2071 {
2072  if (n->type == NODE_TYPE_END)
2073  return false;
2074 
2075  if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix))
2076  return true;
2077 
2078  /*
2079  * Next node
2080  */
2081  n++;
2082 
2083  /* end of format string is treated like a non-digit separator */
2084  if (n->type == NODE_TYPE_END)
2085  return true;
2086 
2087  if (n->type == NODE_TYPE_ACTION)
2088  {
2089  if (n->key->is_digit)
2090  return false;
2091 
2092  return true;
2093  }
2094  else if (n->character[1] == '\0' &&
2095  isdigit((unsigned char) n->character[0]))
2096  return false;
2097 
2098  return true; /* some non-digit input (separator) */
2099 }
#define NODE_TYPE_END
Definition: formatting.c:171
const KeyWord * key
Definition: formatting.c:166
#define S_THth(_s)
Definition: formatting.c:517
#define NODE_TYPE_ACTION
Definition: formatting.c:172
char character[MAX_MULTIBYTE_CHAR_LEN+1]
Definition: formatting.c:167
bool is_digit
Definition: formatting.c:159

◆ NUM_cache()

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

Definition at line 4074 of file formatting.c.

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

Referenced by numeric_to_number().

4075 {
4076  FormatNode *format = NULL;
4077  char *str;
4078 
4079  str = text_to_cstring(pars_str);
4080 
4081  if (len > NUM_CACHE_SIZE)
4082  {
4083  /*
4084  * Allocate new memory if format picture is bigger than static cache
4085  * and do not use cache (call parser always)
4086  */
4087  format = (FormatNode *) palloc((len + 1) * sizeof(FormatNode));
4088 
4089  *shouldFree = true;
4090 
4091  zeroize_NUM(Num);
4092 
4093  parse_format(format, str, NUM_keywords,
4094  NULL, NUM_index, NUM_TYPE, Num);
4095  }
4096  else
4097  {
4098  /*
4099  * Use cache buffers
4100  */
4101  NUMCacheEntry *ent = NUM_cache_fetch(str);
4102 
4103  *shouldFree = false;
4104 
4105  format = ent->format;
4106 
4107  /*
4108  * Copy cache to used struct
4109  */
4110  Num->flag = ent->Num.flag;
4111  Num->lsign = ent->Num.lsign;
4112  Num->pre = ent->Num.pre;
4113  Num->post = ent->Num.post;
4114  Num->pre_lsign_num = ent->Num.pre_lsign_num;
4115  Num->need_locale = ent->Num.need_locale;
4116  Num->multi = ent->Num.multi;
4117  Num->zero_start = ent->Num.zero_start;
4118  Num->zero_end = ent->Num.zero_end;
4119  }
4120 
4121 #ifdef DEBUG_TO_FROM_CHAR
4122  /* dump_node(format, len); */
4123  dump_index(NUM_keywords, NUM_index);
4124 #endif
4125 
4126  pfree(str);
4127  return format;
4128 }
NUMDesc Num
Definition: formatting.c:389
int need_locale
Definition: formatting.c:306