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

📄 numeric.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 5 页
字号:
/* ---------- * numeric.c * *	An exact numeric data type for the Postgres database system * *	1998 Jan Wieck * * $Header: /usr/local/cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.16.2.1 1999/08/02 05:24:55 scrappy Exp $ * * ---------- */#include <ctype.h>#include <float.h>#include <math.h>#include <errno.h>#include <sys/types.h>#include "postgres.h"#include "utils/builtins.h"#include "utils/numeric.h"/* ---------- * Uncomment the following to enable compilation of dump_numeric() * and dump_var() and to get a dump of any result produced by make_result(). * ----------#define NUMERIC_DEBUG *//* ---------- * Local definitions * ---------- */#define NUMERIC_MIN_BUFSIZE		2048#define NUMERIC_MAX_FREEBUFS	20#ifndef MIN#define MIN(a,b) (((a)<(b)) ? (a) : (b))#endif#ifndef MAX#define MAX(a,b) (((a)>(b)) ? (a) : (b))#endif#ifndef NAN#define NAN		(0.0/0.0)#endif/* ---------- * Local data types * ---------- */typedef unsigned char NumericDigit;typedef struct NumericDigitBuf{	struct NumericDigitBuf *prev;	struct NumericDigitBuf *next;	int			size;} NumericDigitBuf;typedef struct NumericVar{	int			ndigits;	int			weight;	int			rscale;	int			dscale;	int			sign;	NumericDigitBuf *buf;	NumericDigit *digits;} NumericVar;/* ---------- * Local data * ---------- */static NumericDigitBuf *digitbuf_freelist = NULL;static NumericDigitBuf *digitbuf_usedlist = NULL;static int	digitbuf_nfree = 0;static int	global_rscale = NUMERIC_MIN_RESULT_SCALE;/* ---------- * Some preinitialized variables we need often * ---------- */static NumericDigit const_zero_data[1] = {0};static NumericVar const_zero ={0, 0, 0, 0, NUMERIC_POS, NULL, const_zero_data};static NumericDigit const_one_data[1] = {1};static NumericVar const_one ={1, 0, 0, 0, NUMERIC_POS, NULL, const_one_data};static NumericDigit const_two_data[1] = {2};static NumericVar const_two ={1, 0, 0, 0, NUMERIC_POS, NULL, const_two_data};static NumericVar const_nan ={0, 0, 0, 0, NUMERIC_NAN, NULL, NULL};/* ---------- * Local functions * ---------- */#ifdef NUMERIC_DEBUGstatic void dump_numeric(char *str, Numeric num);static void dump_var(char *str, NumericVar *var);#else#define dump_numeric(s,n)#define dump_var(s,v)#endifstatic NumericDigitBuf *digitbuf_alloc(int size);static void digitbuf_free(NumericDigitBuf *buf);#define init_var(v)		memset(v,0,sizeof(NumericVar))static void free_var(NumericVar *var);static void free_allvars(void);static void set_var_from_str(char *str, NumericVar *dest);static void set_var_from_num(Numeric value, NumericVar *dest);static void set_var_from_var(NumericVar *value, NumericVar *dest);static Numeric make_result(NumericVar *var);static void apply_typmod(NumericVar *var, int32 typmod);static int	cmp_var(NumericVar *var1, NumericVar *var2);static void add_var(NumericVar *var1, NumericVar *var2, NumericVar *result);static void sub_var(NumericVar *var1, NumericVar *var2, NumericVar *result);static void mul_var(NumericVar *var1, NumericVar *var2, NumericVar *result);static void div_var(NumericVar *var1, NumericVar *var2, NumericVar *result);static void mod_var(NumericVar *var1, NumericVar *var2, NumericVar *result);static void ceil_var(NumericVar *var, NumericVar *result);static void floor_var(NumericVar *var, NumericVar *result);static void sqrt_var(NumericVar *arg, NumericVar *result);static void exp_var(NumericVar *arg, NumericVar *result);static void ln_var(NumericVar *arg, NumericVar *result);static void log_var(NumericVar *base, NumericVar *num, NumericVar *result);static void power_var(NumericVar *base, NumericVar *exp, NumericVar *result);static int	cmp_abs(NumericVar *var1, NumericVar *var2);static void add_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);static void sub_abs(NumericVar *var1, NumericVar *var2, NumericVar *result);/* ---------------------------------------------------------------------- * * Input-, output- and rounding-functions * * ---------------------------------------------------------------------- *//* ---------- * numeric_in() - * *	Input function for numeric data type * ---------- */Numericnumeric_in(char *str, int dummy, int32 typmod){	NumericVar	value;	Numeric		res;	/* ----------	 * Check for NULL	 * ----------	 */	if (str == NULL)		return NULL;	if (strcmp(str, "NULL") == 0)		return NULL;	/* ----------	 * Check for NaN	 * ----------	 */	if (strcmp(str, "NaN") == 0)		return make_result(&const_nan);	/* ----------	 * Use set_var_from_str() to parse the input string	 * and return it in the packed DB storage format	 * ----------	 */	init_var(&value);	set_var_from_str(str, &value);	apply_typmod(&value, typmod);	res = make_result(&value);	free_var(&value);	return res;}/* ---------- * numeric_out() - * *	Output function for numeric data type * ---------- */char *numeric_out(Numeric num){	char	   *str;	char	   *cp;	NumericVar	x;	int			i;	int			d;	/* ----------	 * Handle NULL	 * ----------	 */	if (num == NULL)	{		str = palloc(5);		strcpy(str, "NULL");		return str;	}	/* ----------	 * Handle NaN	 * ----------	 */	if (NUMERIC_IS_NAN(num))	{		str = palloc(4);		strcpy(str, "NaN");		return str;	}	/* ----------	 * Get the number in the variable format	 * ----------	 */	init_var(&x);	set_var_from_num(num, &x);	/* ----------	 * Allocate space for the result	 * ----------	 */	str = palloc(x.dscale + MAX(0, x.weight) + 5);	cp = str;	/* ----------	 * Output a dash for negative values	 * ----------	 */	if (x.sign == NUMERIC_NEG)		*cp++ = '-';	/* ----------	 * Check if we must round up before printing the value and	 * do so.	 * ----------	 */	if (x.dscale < x.rscale && (x.dscale + x.weight + 1) < x.ndigits)	{		int			j;		int			carry;		j = x.dscale + x.weight + 1;		carry = (x.digits[j] > 4) ? 1 : 0;		while (carry)		{			j--;			carry += x.digits[j];			x.digits[j] = carry % 10;			carry /= 10;		}		if (j < 0)		{			x.digits--;			x.weight++;		}	}	/* ----------	 * Output all digits before the decimal point	 * ----------	 */	i = MAX(x.weight, 0);	d = 0;	while (i >= 0)	{		if (i <= x.weight && d < x.ndigits)			*cp++ = x.digits[d++] + '0';		else			*cp++ = '0';		i--;	}	/* ----------	 * If requested, output a decimal point and all the digits	 * that follow it.	 * ----------	 */	if (x.dscale > 0)	{		*cp++ = '.';		while (i >= -x.dscale)		{			if (i <= x.weight && d < x.ndigits)				*cp++ = x.digits[d++] + '0';			else				*cp++ = '0';			i--;		}	}	/* ----------	 * Get rid of the variable, terminate the string and return it	 * ----------	 */	free_var(&x);	*cp = '\0';	return str;}/* ---------- * numeric() - * *	This is a special function called by the Postgres database system *	before a value is stored in a tuples attribute. The precision and *	scale of the attribute have to be applied on the value. * ---------- */Numericnumeric(Numeric num, int32 typmod){	Numeric		new;	int32		tmp_typmod;	int			precision;	int			scale;	int			maxweight;	NumericVar	var;	/* ----------	 * Handle NULL	 * ----------	 */	if (num == NULL)		return NULL;	/* ----------	 * Handle NaN	 * ----------	 */	if (NUMERIC_IS_NAN(num))		return make_result(&const_nan);	/* ----------	 * If the value isn't a valid type modifier, simply return a	 * copy of the input value	 * ----------	 */	if (typmod < (int32) (VARHDRSZ))	{		new = (Numeric) palloc(num->varlen);		memcpy(new, num, num->varlen);		return new;	}	/* ----------	 * Get the precision and scale out of the typmod value	 * ----------	 */	tmp_typmod = typmod - VARHDRSZ;	precision = (tmp_typmod >> 16) & 0xffff;	scale = tmp_typmod & 0xffff;	maxweight = precision - scale;	/* ----------	 * If the number is in bounds and due to the present result scale	 * no rounding could be necessary, make a copy of the input and	 * modify it's header fields.	 * ----------	 */	if (num->n_weight < maxweight && scale >= num->n_rscale)	{		new = (Numeric) palloc(num->varlen);		memcpy(new, num, num->varlen);		new->n_rscale = scale;		new->n_sign_dscale = NUMERIC_SIGN(new) |			((uint16) scale & ~NUMERIC_SIGN_MASK);		return new;	}	/* ----------	 * We really need to fiddle with things - unpack the number into	 * a variable and let apply_typmod() do it.	 * ----------	 */	init_var(&var);	set_var_from_num(num, &var);	apply_typmod(&var, typmod);	new = make_result(&var);	free_var(&var);	return new;}/* ---------------------------------------------------------------------- * * Rounding and the like * * ---------------------------------------------------------------------- */Numericnumeric_abs(Numeric num){	Numeric		res;	/* ----------	 * Handle NULL	 * ----------	 */	if (num == NULL)		return NULL;	/* ----------	 * Handle NaN	 * ----------	 */	if (NUMERIC_IS_NAN(num))		return make_result(&const_nan);	/* ----------	 * Do it the easy way directly on the packed format	 * ----------	 */	res = (Numeric) palloc(num->varlen);	memcpy(res, num, num->varlen);	res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);	return res;}Numericnumeric_sign(Numeric num){	Numeric		res;	NumericVar	result;	/* ----------	 * Handle NULL	 * ----------	 */	if (num == NULL)		return NULL;	/* ----------	 * Handle NaN	 * ----------	 */	if (NUMERIC_IS_NAN(num))		return make_result(&const_nan);	init_var(&result);	/* ----------	 * The packed format is known to be totally zero digit trimmed	 * allways. So we can identify a ZERO by the fact that there	 * are no digits at all.	 * ----------	 */	if (num->varlen == NUMERIC_HDRSZ)		set_var_from_var(&const_zero, &result);	else	{		/* ----------		 * And if there are some, we return a copy of ONE		 * with the sign of our argument		 * ----------		 */		set_var_from_var(&const_one, &result);		result.sign = NUMERIC_SIGN(num);	}	res = make_result(&result);	free_var(&result);	return res;}/* ---------- * numeric_round() - * *	Modify rscale and dscale of a number and round it if required. * ---------- */Numericnumeric_round(Numeric num, int32 scale){	int32		typmod;	int			precision;	/* ----------	 * Handle NULL	 * ----------	 */	if (num == NULL)		return NULL;	/* ----------	 * Handle NaN	 * ----------	 */	if (NUMERIC_IS_NAN(num))		return make_result(&const_nan);	/* ----------	 * Check that the requested scale is valid	 * ----------	 */	if (scale < 0 || scale > NUMERIC_MAX_DISPLAY_SCALE)	{		free_allvars();		elog(ERROR, "illegal numeric scale %d - must be between 0 and %d",			 scale, NUMERIC_MAX_DISPLAY_SCALE);	}	/* ----------	 * Let numeric() and in turn apply_typmod() do the job	 * ----------	 */	precision = MAX(0, num->n_weight) + scale;	typmod = (((precision + 2) << 16) | scale) + VARHDRSZ;	return numeric(num, typmod);}/* ---------- * numeric_trunc() - * *	Modify rscale and dscale of a number and cut it if required. * ---------- */Numericnumeric_trunc(Numeric num, int32 scale){	Numeric		res;	NumericVar	arg;	/* ----------	 * Handle NULL	 * ----------	 */	if (num == NULL)		return NULL;	/* ----------	 * Handle NaN	 * ----------	 */	if (NUMERIC_IS_NAN(num))		return make_result(&const_nan);	/* ----------	 * Check that the requested scale is valid	 * ----------	 */	if (scale < 0 || scale > NUMERIC_MAX_DISPLAY_SCALE)	{		free_allvars();		elog(ERROR, "illegal numeric scale %d - must be between 0 and %d",			 scale, NUMERIC_MAX_DISPLAY_SCALE);	}	/* ----------	 * Unpack the argument and truncate it	 * ----------	 */	init_var(&arg);	set_var_from_num(num, &arg);	arg.rscale = scale;	arg.dscale = scale;	arg.ndigits = MIN(arg.ndigits, MAX(0, arg.weight + scale + 1));	while (arg.ndigits > 0 && arg.digits[arg.ndigits - 1] == 0)		arg.ndigits--;	/* ----------	 * Return the truncated result	 * ----------	 */	res = make_result(&arg);	free_var(&arg);	return res;}/* ---------- * numeric_ceil() - * *	Return the smallest integer greater than or equal to the argument * ---------- */Numericnumeric_ceil(Numeric num){	Numeric		res;	NumericVar	result;	if (num == NULL)		return NULL;	if (NUMERIC_IS_NAN(num))		return make_result(&const_nan);	init_var(&result);	set_var_from_num(num, &result);	ceil_var(&result, &result);	result.dscale = 0;	res = make_result(&result);	free_var(&result);	return res;}/* ---------- * numeric_floor() - * *	Return the largest integer equal to or less than the argument * ---------- */Numericnumeric_floor(Numeric num){	Numeric		res;	NumericVar	result;	if (num == NULL)		return NULL;	if (NUMERIC_IS_NAN(num))		return make_result(&const_nan);	init_var(&result);	set_var_from_num(num, &result);	floor_var(&result, &result);	result.dscale = 0;	res = make_result(&result);	free_var(&result);	return res;}/* ---------------------------------------------------------------------- * * Comparision functions * * ---------------------------------------------------------------------- */boolnumeric_eq(Numeric num1, Numeric num2){	int			result;	NumericVar	arg1;	NumericVar	arg2;	if (num1 == NULL || num2 == NULL)		return FALSE;	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		return FALSE;

⌨️ 快捷键说明

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