⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 formatting.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/* ----------------------------------------------------------------------- * formatting.c * * $PostgreSQL: pgsql/src/backend/utils/adt/formatting.c,v 1.101.2.2 2005/12/03 16:45:23 momjian Exp $ * * *	 Portions Copyright (c) 1999-2005, PostgreSQL Global Development Group * * *	 TO_CHAR(); TO_TIMESTAMP(); TO_DATE(); TO_NUMBER(); * *	 The PostgreSQL routines for a timestamp/int/float/numeric formatting, *	 inspired by the Oracle TO_CHAR() / TO_DATE() / TO_NUMBER() routines. * * *	 Cache & Memory: *	Routines use (itself) internal cache for format pictures. * *	The cache uses a static buffers and is persistent across transactions. *	If format-picture is bigger than cache buffer, parser is called always. * *	 NOTE for Number version: *	All in this version is implemented as keywords ( => not used *	suffixes), because a format picture is for *one* item (number) *	only. It not is as a timestamp version, where each keyword (can) *	has suffix. * *	 NOTE for Timestamp routines: *	In this module the POSIX 'struct tm' type is *not* used, but rather *	PgSQL type, which has tm_mon based on one (*non* zero) and *	year *not* based on 1900, but is used full year number. *	Module supports AD / BC / AM / PM. * *	Supported types for to_char(): * *		Timestamp, Numeric, int4, int8, float4, float8 * *	Supported types for reverse conversion: * *		Timestamp	- to_timestamp() *		Date		- to_date() *		Numeric		- to_number() * * *	Karel Zak * * TODO *	- better number building (formatting) / parsing, now it isn't *		  ideal code *	- use Assert() *	- add support for abstime *	- add support for roman number to standard number conversion *	- add support for number spelling *	- add support for string to string formatting (we must be better *	  than Oracle :-), *		to_char('Hello', 'X X X X X') -> 'H e l l o' * * ----------------------------------------------------------------------- *//* ---------- * UnComment me for DEBUG * ---------- *//***#define DEBUG_TO_FROM_CHAR#define DEBUG_elog_output	DEBUG3***/#include "postgres.h"#include <ctype.h>#include <unistd.h>#include <math.h>#include <float.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"/* ---------- * Routines type * ---------- */#define DCH_TYPE		1		/* DATE-TIME version	*/#define NUM_TYPE		2		/* NUMBER version	*//* ---------- * KeyWord Index (ascii from position 32 (' ') to 126 (~)) * ---------- */#define KeyWord_INDEX_SIZE		('~' - ' ')#define KeyWord_INDEX_FILTER(_c)	((_c) <= ' ' || (_c) >= '~' ? 0 : 1)/* ---------- * Maximal length of one node * ---------- */#define DCH_MAX_ITEM_SIZ		9		/* max julian day		*/#define NUM_MAX_ITEM_SIZ		8		/* roman number (RN has 15 chars)	*//* ---------- * More is in float.c * ---------- */#define MAXFLOATWIDTH	64#define MAXDOUBLEWIDTH	128/* ---------- * External (defined in PgSQL datetime.c (timestamp utils)) * ---------- */extern char *months[],			/* month abbreviation	*/		   *days[];				/* full days		*//* ---------- * Format parser structs * ---------- */typedef struct{	char	   *name;			/* suffix string		*/	int			len,			/* suffix length		*/				id,				/* used in node->suffix */				type;			/* prefix / postfix			*/} KeySuffix;typedef struct FormatNode FormatNode;typedef struct{	const char *name;			/* keyword			*/	int			len;			/* keyword length		*/	int			(*action) (int arg, char *inout,		/* action for keyword */								  int suf, bool is_to_char, bool is_interval,									   FormatNode *node, void *data);	int			id;				/* keyword id			*/	bool		isitdigit;		/* is expected output/input digit */} KeyWord;struct FormatNode{	int			type;			/* node type			*/	const KeyWord *key;			/* if node type is KEYWORD	*/	int			character,		/* if node type is CHAR		*/				suffix;			/* keyword suffix		*/};#define NODE_TYPE_END		1#define NODE_TYPE_ACTION	2#define NODE_TYPE_CHAR		3#define SUFFTYPE_PREFIX		1#define SUFFTYPE_POSTFIX	2/* ---------- * Full months * ---------- */static char *months_full[] = {	"January", "February", "March", "April", "May", "June", "July",	"August", "September", "October", "November", "December", NULL};/* ---------- * AC / DC * ---------- *//* *	There is no 0 AD.  Years go from 1 BC to 1 AD, so we make it *	positive and map year == -1 to year zero, and shift all negative *	years up one.  For interval years, we just return the year. */#define ADJUST_YEAR(year, is_interval)	((is_interval) ? (year) : ((year) <= 0 ? -((year) - 1) : (year)))#define BC_STR_ORIG " BC"#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"/* ---------- * AM / PM * ---------- */#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"/* ---------- * Months in roman-numeral * (Must be conversely for seq_search (in FROM_CHAR), because *	'VIII' must be over 'V') * ---------- */static char *rm_months_upper[] ={"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL};static char *rm_months_lower[] ={"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL};/* ---------- * Roman numbers * ---------- */static char *rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL};static char *rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL};static char *rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM", NULL};/* ---------- * Ordinal postfixes * ---------- */static char *numTH[] = {"ST", "ND", "RD", "TH", NULL};static char *numth[] = {"st", "nd", "rd", "th", NULL};/* ---------- * Flags & Options: * ---------- */#define ONE_UPPER	1			/* Name */#define ALL_UPPER	2			/* NAME */#define ALL_LOWER	3			/* name */#define FULL_SIZ	0#define MAX_MON_LEN 3#define MAX_DY_LEN	3#define TH_UPPER	1#define TH_LOWER	2/* ---------- * Flags for DCH version * ---------- */static bool DCH_global_fx = false;/* ---------- * Number description struct * ---------- */typedef struct{	int			pre,			/* (count) numbers before decimal */				post,			/* (count) numbers after decimal  */				lsign,			/* want locales sign		  */				flag,			/* number parameters		  */				pre_lsign_num,	/* tmp value for lsign		  */				multi,			/* multiplier for 'V'		  */				zero_start,		/* position of first zero	  */				zero_end,		/* position of last zero	  */				need_locale;	/* needs it locale		  */} NUMDesc;/* ---------- * Flags for NUMBER version * ---------- */#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_LSIGN_PRE	(-1)#define NUM_LSIGN_POST	1#define NUM_LSIGN_NONE	0/* ---------- * Tests * ---------- */#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)/* ---------- * Format picture cache *	(cache size: *		Number part = NUM_CACHE_SIZE * NUM_CACHE_FIELDS *		Date-time part	= DCH_CACHE_SIZE * DCH_CACHE_FIELDS *	) * ---------- */#define NUM_CACHE_SIZE		64#define NUM_CACHE_FIELDS	16#define DCH_CACHE_SIZE		128#define DCH_CACHE_FIELDS	16typedef struct{	FormatNode	format[DCH_CACHE_SIZE + 1];	char		str[DCH_CACHE_SIZE + 1];	int			age;} DCHCacheEntry;typedef struct{	FormatNode	format[NUM_CACHE_SIZE + 1];	char		str[NUM_CACHE_SIZE + 1];	int			age;	NUMDesc		Num;} NUMCacheEntry;/* global cache for --- date/time part */static DCHCacheEntry DCHCache[DCH_CACHE_FIELDS + 1];static int	n_DCHCache = 0;		/* number of entries */static int	DCHCounter = 0;/* global cache for --- number part */static NUMCacheEntry NUMCache[NUM_CACHE_FIELDS + 1];static NUMCacheEntry *last_NUMCacheEntry;static int	n_NUMCache = 0;		/* number of entries */static int	NUMCounter = 0;#define MAX_INT32	(2147483600)/* ---------- * For char->date/time conversion * ---------- */typedef struct{	int			hh,				am,				pm,				mi,				ss,				ssss,				d,				dd,				ddd,				mm,				ms,				year,				bc,				iw,				ww,				w,				cc,				q,				j,				us,				yysz;			/* is it YY or YYYY ? */} TmFromChar;#define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar))/* ---------- * Debug * ---------- */#ifdef DEBUG_TO_FROM_CHAR#define DEBUG_TMFC(_X) \		elog(DEBUG_elog_output, "TMFC:\nhh %d\nam %d\npm %d\nmi %d\nss %d\nssss %d\nd %d\ndd %d\nddd %d\nmm %d\nms: %d\nyear %d\nbc %d\niw %d\nww %d\nw %d\ncc %d\nq %d\nj %d\nus: %d\nyysz: %d", \			(_X)->hh, (_X)->am, (_X)->pm, (_X)->mi, (_X)->ss, \			(_X)->ssss, (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, \			(_X)->year, (_X)->bc, (_X)->iw, (_X)->ww, (_X)->w, \			(_X)->cc, (_X)->q, (_X)->j, (_X)->us, (_X)->yysz);#define DEBUG_TM(_X) \		elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\			(_X)->tm_sec, (_X)->tm_year,\			(_X)->tm_min, (_X)->tm_wday, (_X)->tm_hour, (_X)->tm_yday,\			(_X)->tm_mday, (_X)->tm_isdst, (_X)->tm_mon)#else#define DEBUG_TMFC(_X)#define DEBUG_TM(_X)#endif/* ---------- * Datetime to char conversion * ---------- */typedef struct TmToChar{	struct pg_tm tm;			/* classic 'tm' struct */	fsec_t		fsec;			/* fractional seconds */	char	   *tzn;			/* timezone */} TmToChar;#define tmtcTm(_X)	(&(_X)->tm)#define tmtcTzn(_X) ((_X)->tzn)#define tmtcFsec(_X)	((_X)->fsec)#define ZERO_tm(_X) \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; \} while(0)#define ZERO_tmtc(_X) \do { \	ZERO_tm( tmtcTm(_X) ); \	tmtcFsec(_X) = 0; \	tmtcTzn(_X) = NULL; \} while(0)/* *	to_char(time) appears to to_char() as an interval, so this check *	is really for interval and time data types. */#define INVALID_FOR_INTERVAL  \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)/***************************************************************************** *			KeyWords definition & action *****************************************************************************/static int dch_global(int arg, char *inout, int suf, bool is_to_char,		   bool is_interval, FormatNode *node, void *data);static int dch_time(int arg, char *inout, int suf, bool is_to_char,		 bool is_interval, FormatNode *node, void *data);static int dch_date(int arg, char *inout, int suf, bool is_to_char,		 bool is_interval, FormatNode *node, void *data);/* ---------- * Suffixes: * ---------- */#define DCH_S_FM	0x01#define DCH_S_TH	0x02#define DCH_S_th	0x04#define DCH_S_SP	0x08/* ---------- * Suffix tests * ---------- */#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)/* ---------- * Suffixes definition for DATE-TIME TO/FROM CHAR * ---------- */static KeySuffix DCH_suff[] = {	{"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX},	{"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX},	{"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX},	{"th", 2, DCH_S_th, SUFFTYPE_POSTFIX},	{"SP", 2, DCH_S_SP, SUFFTYPE_POSTFIX},	/* last */	{NULL, 0, 0, 0}};/* ---------- * Format-pictures (KeyWord). * * The KeyWord field; alphabetic sorted, *BUT* strings alike is sorted *		  complicated -to-> easy: * *	(example: "DDD","DD","Day","D" ) * * (this specific sort needs the algorithm for sequential search for strings, * which not has exact end; -> How keyword is in "HH12blabla" ? - "HH" * or "HH12"? You must first try "HH12", because "HH" is in string, but * it is not good. * * (!) *	 - Position for the keyword is similar as position in the enum DCH/NUM_poz. * (!) * * For fast search is used the 'int index[]', index is ascii table from position * 32 (' ') to 126 (~), in this index is DCH_ / NUM_ enums for each ASCII * position or -1 if char is not used in the KeyWord. Search example for * string "MM": *	1)	see in index to index['M' - 32], *	2)	take keywords position (enum DCH_MM) from index *	3)	run sequential search in keywords[] from this position * * ---------- */typedef enum{	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,						/* global suffix */	DCH_HH24,	DCH_HH12,	DCH_HH,	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_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_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,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -