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

📄 numeric.c

📁 postgresql8.3.4源码,开源数据库
💻 C
📖 第 1 页 / 共 3 页
字号:
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/numeric.c,v 1.33 2006/10/04 00:30:12 momjian Exp $ */#include "postgres_fe.h"#include <ctype.h>#include <limits.h>#include "extern.h"#include "pgtypes_error.h"#define Max(x, y)				((x) > (y) ? (x) : (y))#define Min(x, y)				((x) < (y) ? (x) : (y))#define init_var(v)				memset(v,0,sizeof(numeric))#define digitbuf_alloc(size) ((NumericDigit *) pgtypes_alloc(size))#define digitbuf_free(buf)		\	   do { \				 if ((buf) != NULL) \						  free(buf); \		  } while (0)#include "pgtypes_numeric.h"#if 0/* ---------- * apply_typmod() - * *	Do bounds checking and rounding according to the attributes *	typmod field. * ---------- */static intapply_typmod(numeric *var, long typmod){	int			precision;	int			scale;	int			maxweight;	int			i;	/* Do nothing if we have a default typmod (-1) */	if (typmod < (long) (VARHDRSZ))		return (0);	typmod -= VARHDRSZ;	precision = (typmod >> 16) & 0xffff;	scale = typmod & 0xffff;	maxweight = precision - scale;	/* Round to target scale */	i = scale + var->weight + 1;	if (i >= 0 && var->ndigits > i)	{		int			carry = (var->digits[i] > 4) ? 1 : 0;		var->ndigits = i;		while (carry)		{			carry += var->digits[--i];			var->digits[i] = carry % 10;			carry /= 10;		}		if (i < 0)		{			var->digits--;			var->ndigits++;			var->weight++;		}	}	else		var->ndigits = Max(0, Min(i, var->ndigits));	/*	 * Check for overflow - note we can't do this before rounding, because	 * rounding could raise the weight.  Also note that the var's weight could	 * be inflated by leading zeroes, which will be stripped before storage	 * but perhaps might not have been yet. In any case, we must recognize a	 * true zero, whose weight doesn't mean anything.	 */	if (var->weight >= maxweight)	{		/* Determine true weight; and check for all-zero result */		int			tweight = var->weight;		for (i = 0; i < var->ndigits; i++)		{			if (var->digits[i])				break;			tweight--;		}		if (tweight >= maxweight && i < var->ndigits)		{			errno = PGTYPES_NUM_OVERFLOW;			return -1;		}	}	var->rscale = scale;	var->dscale = scale;	return (0);}#endif/* ---------- *	alloc_var() - * *	 Allocate a digit buffer of ndigits digits (plus a spare digit for rounding) * ---------- */static intalloc_var(numeric *var, int ndigits){	digitbuf_free(var->buf);	var->buf = digitbuf_alloc(ndigits + 1);	if (var->buf == NULL)		return -1;	var->buf[0] = 0;	var->digits = var->buf + 1;	var->ndigits = ndigits;	return 0;}numeric *PGTYPESnumeric_new(void){	numeric    *var;	if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)		return NULL;	if (alloc_var(var, 0) < 0)	{		free(var);		return NULL;	}	return var;}decimal *PGTYPESdecimal_new(void){	decimal    *var;	if ((var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)		return NULL;	memset(var, 0, sizeof(decimal));	return var;}/* ---------- * set_var_from_str() * *	Parse a string and put the number into a variable * ---------- */static intset_var_from_str(char *str, char **ptr, numeric *dest){	bool		have_dp = FALSE;	int			i = 0;	errno = 0;	*ptr = str;	while (*(*ptr))	{		if (!isspace((unsigned char) *(*ptr)))			break;		(*ptr)++;	}	if (alloc_var(dest, strlen((*ptr))) < 0)		return -1;	dest->weight = -1;	dest->dscale = 0;	dest->sign = NUMERIC_POS;	switch (*(*ptr))	{		case '+':			dest->sign = NUMERIC_POS;			(*ptr)++;			break;		case '-':			dest->sign = NUMERIC_NEG;			(*ptr)++;			break;	}	if (*(*ptr) == '.')	{		have_dp = TRUE;		(*ptr)++;	}	if (!isdigit((unsigned char) *(*ptr)))	{		errno = PGTYPES_NUM_BAD_NUMERIC;		return -1;	}	while (*(*ptr))	{		if (isdigit((unsigned char) *(*ptr)))		{			dest->digits[i++] = *(*ptr)++ - '0';			if (!have_dp)				dest->weight++;			else				dest->dscale++;		}		else if (*(*ptr) == '.')		{			if (have_dp)			{				errno = PGTYPES_NUM_BAD_NUMERIC;				return -1;			}			have_dp = TRUE;			(*ptr)++;		}		else			break;	}	dest->ndigits = i;	/* Handle exponent, if any */	if (*(*ptr) == 'e' || *(*ptr) == 'E')	{		long		exponent;		char	   *endptr;		(*ptr)++;		exponent = strtol(*ptr, &endptr, 10);		if (endptr == (*ptr))		{			errno = PGTYPES_NUM_BAD_NUMERIC;			return -1;		}		(*ptr) = endptr;		if (exponent > NUMERIC_MAX_PRECISION ||			exponent < -NUMERIC_MAX_PRECISION)		{			errno = PGTYPES_NUM_BAD_NUMERIC;			return -1;		}		dest->weight += (int) exponent;		dest->dscale -= (int) exponent;		if (dest->dscale < 0)			dest->dscale = 0;	}	/* Should be nothing left but spaces */	while (*(*ptr))	{		if (!isspace((unsigned char) *(*ptr)))		{			errno = PGTYPES_NUM_BAD_NUMERIC;			return -1;		}		(*ptr)++;	}	/* Strip any leading zeroes */	while (dest->ndigits > 0 && *(dest->digits) == 0)	{		(dest->digits)++;		(dest->weight)--;		(dest->ndigits)--;	}	if (dest->ndigits == 0)		dest->weight = 0;	dest->rscale = dest->dscale;	return (0);}/* ---------- * get_str_from_var() - * *	Convert a var to text representation (guts of numeric_out). *	CAUTION: var's contents may be modified by rounding! * ---------- */static char *get_str_from_var(numeric *var, int dscale){	char	   *str;	char	   *cp;	int			i;	int			d;	/*	 * Check if we must round up before printing the value and do so.	 */	i = dscale + var->weight + 1;	if (i >= 0 && var->ndigits > i)	{		int			carry = (var->digits[i] > 4) ? 1 : 0;		var->ndigits = i;		while (carry)		{			carry += var->digits[--i];			var->digits[i] = carry % 10;			carry /= 10;		}		if (i < 0)		{			var->digits--;			var->ndigits++;			var->weight++;		}	}	else		var->ndigits = Max(0, Min(i, var->ndigits));	/*	 * Allocate space for the result	 */	if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)		return NULL;	cp = str;	/*	 * Output a dash for negative values	 */	if (var->sign == NUMERIC_NEG)		*cp++ = '-';	/*	 * Output all digits before the decimal point	 */	i = Max(var->weight, 0);	d = 0;	while (i >= 0)	{		if (i <= var->weight && d < var->ndigits)			*cp++ = var->digits[d++] + '0';		else			*cp++ = '0';		i--;	}	/*	 * If requested, output a decimal point and all the digits that follow it.	 */	if (dscale > 0)	{		*cp++ = '.';		while (i >= -dscale)		{			if (i <= var->weight && d < var->ndigits)				*cp++ = var->digits[d++] + '0';			else				*cp++ = '0';			i--;		}	}	/*	 * terminate the string and return it	 */	*cp = '\0';	return str;}numeric *PGTYPESnumeric_from_asc(char *str, char **endptr){	numeric    *value = (numeric *) pgtypes_alloc(sizeof(numeric));	int			ret;	char	   *realptr;	char	  **ptr = (endptr != NULL) ? endptr : &realptr;	if (!value)		return (NULL);	ret = set_var_from_str(str, ptr, value);	if (ret)	{		free(value);		return (NULL);	}	return (value);}char *PGTYPESnumeric_to_asc(numeric *num, int dscale){	numeric    *numcopy = PGTYPESnumeric_new();	char	   *s;	if (dscale < 0)		dscale = num->dscale;	if (PGTYPESnumeric_copy(num, numcopy) < 0)	{		PGTYPESnumeric_free(numcopy);		return NULL;	}	/* get_str_from_var may change its argument */	s = get_str_from_var(numcopy, dscale);	PGTYPESnumeric_free(numcopy);	return (s);}/* ---------- * zero_var() - * *	Set a variable to ZERO. *	Note: rscale and dscale are not touched. * ---------- */static voidzero_var(numeric *var){	digitbuf_free(var->buf);	var->buf = NULL;	var->digits = NULL;	var->ndigits = 0;	var->weight = 0;			/* by convention; doesn't really matter */	var->sign = NUMERIC_POS;	/* anything but NAN... */}voidPGTYPESnumeric_free(numeric *var){	digitbuf_free(var->buf);	free(var);}voidPGTYPESdecimal_free(decimal *var){	free(var);}/* ---------- * cmp_abs() - * *	Compare the absolute values of var1 and var2 *	Returns:	-1 for ABS(var1) < ABS(var2) *				0  for ABS(var1) == ABS(var2) *				1  for ABS(var1) > ABS(var2) * ---------- */static intcmp_abs(numeric *var1, numeric *var2){	int			i1 = 0;	int			i2 = 0;	int			w1 = var1->weight;	int			w2 = var2->weight;	int			stat;	while (w1 > w2 && i1 < var1->ndigits)	{		if (var1->digits[i1++] != 0)			return 1;		w1--;	}	while (w2 > w1 && i2 < var2->ndigits)	{		if (var2->digits[i2++] != 0)			return -1;		w2--;	}	if (w1 == w2)	{		while (i1 < var1->ndigits && i2 < var2->ndigits)		{			stat = var1->digits[i1++] - var2->digits[i2++];			if (stat)			{				if (stat > 0)					return 1;				return -1;			}		}	}	while (i1 < var1->ndigits)	{		if (var1->digits[i1++] != 0)			return 1;	}	while (i2 < var2->ndigits)	{		if (var2->digits[i2++] != 0)			return -1;	}	return 0;}/* ---------- * add_abs() - * *	Add the absolute values of two variables into result. *	result might point to one of the operands without danger. * ---------- */static intadd_abs(numeric *var1, numeric *var2, numeric *result){	NumericDigit *res_buf;	NumericDigit *res_digits;	int			res_ndigits;	int			res_weight;	int			res_rscale;	int			res_dscale;	int			i,				i1,				i2;	int			carry = 0;	/* copy these values into local vars for speed in inner loop */	int			var1ndigits = var1->ndigits;	int			var2ndigits = var2->ndigits;	NumericDigit *var1digits = var1->digits;	NumericDigit *var2digits = var2->digits;	res_weight = Max(var1->weight, var2->weight) + 1;	res_rscale = Max(var1->rscale, var2->rscale);	res_dscale = Max(var1->dscale, var2->dscale);	res_ndigits = res_rscale + res_weight + 1;	if (res_ndigits <= 0)		res_ndigits = 1;	if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)		return -1;	res_digits = res_buf;

⌨️ 快捷键说明

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