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

📄 numeric.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 5 页
字号:
	{		case '0':		case '1':		case '2':		case '3':		case '4':		case '5':		case '6':		case '7':		case '8':		case '9':			dest->sign = NUMERIC_POS;			break;		case '+':			dest->sign = NUMERIC_POS;			cp++;			break;		case '-':			dest->sign = NUMERIC_NEG;			cp++;			break;		case '.':			dest->sign = NUMERIC_POS;			have_dp = TRUE;			cp++;			break;		default:			free_allvars();			elog(ERROR, "Bad numeric input format '%s'", str);	}	if (*cp == '.')	{		if (have_dp)		{			free_allvars();			elog(ERROR, "Bad numeric input format '%s'", str);		}		have_dp = TRUE;		cp++;	}	if (*cp < '0' && *cp > '9')	{		free_allvars();		elog(ERROR, "Bad numeric input format '%s'", str);	}	while (*cp)	{		if (isspace(*cp))			break;		if (*cp == 'e' || *cp == 'E')			break;		switch (*cp)		{			case '0':			case '1':			case '2':			case '3':			case '4':			case '5':			case '6':			case '7':			case '8':			case '9':				dest->digits[i++] = *cp++ - '0';				if (!have_dp)					dest->weight++;				else					dest->dscale++;				break;			case '.':				if (have_dp)				{					free_allvars();					elog(ERROR, "Bad numeric input format '%s'", str);				}				have_dp = TRUE;				cp++;				break;			default:				free_allvars();				elog(ERROR, "Bad numeric input format '%s'", str);		}	}	dest->ndigits = i;	if (*cp == 'e' || *cp == 'E')	{		/* Handle ...Ennn */	}	while (dest->ndigits > 0 && *(dest->digits) == 0)	{		(dest->digits)++;		(dest->weight)--;		(dest->ndigits)--;	}	dest->rscale = dest->dscale;}/* * set_var_from_num() - * *	Parse back the packed db format into a variable * */static voidset_var_from_num(Numeric num, NumericVar *dest){	NumericDigit *digit;	int			i;	int			n;	n = num->varlen - NUMERIC_HDRSZ;	digitbuf_free(dest->buf);	dest->buf = digitbuf_alloc(n * 2 + 2);	digit = ((NumericDigit *) (dest->buf)) + sizeof(NumericDigitBuf);	*digit++ = 0;	*digit++ = 0;	dest->digits = digit;	dest->ndigits = n * 2;	dest->weight = num->n_weight;	dest->rscale = num->n_rscale;	dest->dscale = NUMERIC_DSCALE(num);	dest->sign = NUMERIC_SIGN(num);	for (i = 0; i < n; i++)	{		*digit++ = (num->n_data[i] >> 4) & 0x0f;		*digit++ = num->n_data[i] & 0x0f;	}}/* ---------- * set_var_from_var() - * *	Copy one variable into another * ---------- */static voidset_var_from_var(NumericVar *value, NumericVar *dest){	NumericDigitBuf *newbuf;	NumericDigit *newdigits;	newbuf = digitbuf_alloc(value->ndigits);	newdigits = ((NumericDigit *) newbuf) + sizeof(NumericDigitBuf);	memcpy(newdigits, value->digits, value->ndigits);	digitbuf_free(dest->buf);	memcpy(dest, value, sizeof(NumericVar));	dest->buf = newbuf;	dest->digits = newdigits;}/* ---------- * make_result() - * *	Create the packed db numeric format in palloc()'d memory from *	a variable. * ---------- */static Numericmake_result(NumericVar *var){	Numeric		result;	NumericDigit *digit = var->digits;	int			n;	int			weight = var->weight;	int			sign = var->sign;	int			i,				j;	if (sign == NUMERIC_NAN)	{		result = (Numeric) palloc(NUMERIC_HDRSZ);		result->varlen = NUMERIC_HDRSZ;		result->n_weight = 0;		result->n_rscale = 0;		result->n_sign_dscale = NUMERIC_NAN;		dump_numeric("make_result()", result);		return result;	}	n = MAX(0, MIN(var->ndigits, var->weight + var->rscale + 1));	while (n > 0 && *digit == 0)	{		digit++;		weight--;		n--;	}	while (n > 0 && digit[n - 1] == 0)		n--;	if (n == 0)	{		weight = 0;		sign = NUMERIC_POS;	}	result = (Numeric) palloc(NUMERIC_HDRSZ + (n + 1) / 2);	result->varlen = NUMERIC_HDRSZ + (n + 1) / 2;	result->n_weight = weight;	result->n_rscale = var->rscale;	result->n_sign_dscale = sign | ((uint16) (var->dscale) & ~NUMERIC_SIGN_MASK);	i = 0;	j = 0;	while (j < n)	{		result->n_data[i] = digit[j++] << 4;		if (j < n)			result->n_data[i] |= digit[j++];		i++;	}	dump_numeric("make_result()", result);	return result;}/* ---------- * apply_typmod() - * *	Do bounds checking and rounding according to the attributes *	typmod field. * ---------- */static voidapply_typmod(NumericVar *var, int32 typmod){	int			precision;	int			scale;	int			maxweight;	int			i;	if (typmod < (int32) (VARHDRSZ))		return;	typmod -= VARHDRSZ;	precision = (typmod >> 16) & 0xffff;	scale = typmod & 0xffff;	maxweight = precision - scale;	if (var->weight >= maxweight)	{		free_allvars();		elog(ERROR, "overflow on numeric "			 "ABS(value) >= 10^%d for field with precision %d scale %d",			 var->weight, precision, scale);	}	i = scale + var->weight + 1;	if (i >= 0 && var->ndigits > i)	{		long		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 again - rounding could have raised the	 * weight.	 * ----------	 */	if (var->weight >= maxweight)	{		free_allvars();		elog(ERROR, "overflow on numeric "			 "ABS(value) >= 10^%d for field with precision %d scale %d",			 var->weight, precision, scale);	}	var->rscale = scale;	var->dscale = scale;}/* ---------- * cmp_var() - * *	Compare two values on variable level * ---------- */static intcmp_var(NumericVar *var1, NumericVar *var2){	if (var1->ndigits == 0)	{		if (var2->ndigits == 0)			return 0;		if (var2->sign == NUMERIC_NEG)			return 1;		return -1;	}	if (var2->ndigits == 0)	{		if (var1->sign == NUMERIC_POS)			return 1;		return -1;	}	if (var1->sign == NUMERIC_POS)	{		if (var2->sign == NUMERIC_NEG)			return 1;		return cmp_abs(var1, var2);	}	if (var2->sign == NUMERIC_POS)		return -1;	return cmp_abs(var2, var1);}/* ---------- * add_var() - * *	Full version of add functionality on variable level (handling signs). *	result might point to one of the operands too without danger. * ---------- */static voidadd_var(NumericVar *var1, NumericVar *var2, NumericVar *result){	/* ----------	 * Decide on the signs of the two variables what to do	 * ----------	 */	if (var1->sign == NUMERIC_POS)	{		if (var2->sign == NUMERIC_POS)		{			/* ----------			 * Both are positive			 * result = +(ABS(var1) + ABS(var2))			 * ----------			 */			add_abs(var1, var2, result);			result->sign = NUMERIC_POS;		}		else		{			/* ----------			 * var1 is positive, var2 is negative			 * Must compare absolute values			 * ----------			 */			switch (cmp_abs(var1, var2))			{				case 0: /* ----------												 * ABS(var1) == ABS(var2)												 * result = ZERO												 * ----------												 */					digitbuf_free(result->buf);					result->buf = digitbuf_alloc(0);					result->ndigits = 0;					result->digits = ((NumericDigit *) (result->buf)) +						sizeof(NumericDigitBuf);					result->weight = 0;					result->rscale = MAX(var1->rscale, var2->rscale);					result->dscale = MAX(var1->dscale, var2->dscale);					result->sign = NUMERIC_POS;					break;				case 1: /* ----------												 * ABS(var1) > ABS(var2)												 * result = +(ABS(var1) - ABS(var2))												 * ----------												 */					sub_abs(var1, var2, result);					result->sign = NUMERIC_POS;					break;				case -1:		/* ----------								 * ABS(var1) < ABS(var2)								 * result = -(ABS(var2) - ABS(var1))								 * ----------								 */					sub_abs(var2, var1, result);					result->sign = NUMERIC_NEG;					break;			}		}	}	else	{		if (var2->sign == NUMERIC_POS)		{			/* ----------			 * var1 is negative, var2 is positive			 * Must compare absolute values			 * ----------			 */			switch (cmp_abs(var1, var2))			{				case 0: /* ----------												 * ABS(var1) == ABS(var2)												 * result = ZERO												 * ----------												 */					digitbuf_free(result->buf);					result->buf = digitbuf_alloc(0);					result->ndigits = 0;					result->digits = ((NumericDigit *) (result->buf)) +						sizeof(NumericDigitBuf);					result->weight = 0;					result->rscale = MAX(var1->rscale, var2->rscale);					result->dscale = MAX(var1->dscale, var2->dscale);					result->sign = NUMERIC_POS;					break;				case 1: /* ----------												 * ABS(var1) > ABS(var2)												 * result = -(ABS(var1) - ABS(var2))												 * ----------												 */					sub_abs(var1, var2, result);					result->sign = NUMERIC_NEG;					break;				case -1:		/* ----------								 * ABS(var1) < ABS(var2)								 * result = +(ABS(var2) - ABS(var1))								 * ----------								 */					sub_abs(var2, var1, result);					result->sign = NUMERIC_POS;					break;			}		}		else		{			/* ----------			 * Both are negative			 * result = -(ABS(var1) + ABS(var2))			 * ----------			 */			add_abs(var1, var2, result);			result->sign = NUMERIC_NEG;		}	}}/* ---------- * sub_var() - * *	Full version of sub functionality on variable level (handling signs). *	result might point to one of the operands too without danger. * ---------- */static voidsub_var(NumericVar *var1, NumericVar *var2, NumericVar *result){	/* ----------	 * Decide on the signs of the two variables what to do	 * ----------	 */	if (var1->sign == NUMERIC_POS)	{		if (var2->sign == NUMERIC_NEG)		{			/* ----------			 * var1 is positive, var2 is negative			 * result = +(ABS(var1) + ABS(var2))			 * ----------			 */			add_abs(var1, var2, result);			result->sign = NUMERIC_POS;		}		else		{			/* ----------			 * Both are positive			 * Must compare absolute values			 * ----------			 */			switch (cmp_abs(var1, var2))			{				case 0: /* ----------												 * ABS(var1) == ABS(var2)												 * result = ZERO												 * ----------												 */					digitbuf_free(result->buf);					result->buf = digitbuf_alloc(0);					result->ndigits = 0;					result->digits = ((NumericDigit *) (result->buf)) +						sizeof(NumericDigitBuf);					result->weight = 0;					result->rscale = MAX(var1->rscale, var2->rscale);					result->dscale = MAX(var1->dscale, var2->dscale);					result->sign = NUMERIC_POS;					break;				case 1: /* ----------												 * ABS(var1) > ABS(var2)												 * result = +(ABS(var1) - ABS(var2))												 * ----------												 */					sub_abs(var1, var2, result);					result->sign = NUMERIC_POS;					break;				case -1:		/* ----------								 * ABS(var1) < ABS(var2)								 * result = -(ABS(var2) - ABS(var1))								 * ----------								 */					sub_abs(var2, var1, result);					result->sign = NUMERIC_NEG;					break;			}		}	}	else	{		if (var2->sign == NUMERIC_NEG)		{			/* ----------			 * Both are negative			 * Must compare absolute values			 * ----------			 */			switch (cmp_abs(var1, var2))			{				case 0: /* ----------												 * ABS(var1) == ABS(var2)												 * result = ZERO												 * ----------												 */					digitbuf_free(result->buf);					result->buf = digitbuf_alloc(0);					result->ndigits = 0;					result->digits = ((NumericDigit *) (result->buf)) +						sizeof(NumericDigitBuf);					result->weight = 0;					result->rscale = MAX(var1->rscale, var2->rscale);					result->dscale = MAX(var1->dscale, var2->dscale);					result->sign = NUMERIC_POS;					break;				case 1: /* ----------												 * ABS(var1) > ABS(var2)												 * result = -(ABS(var1) - ABS(var2))												 * ----------												 */					sub_abs(var1, var2, result);					result->sign = NUMERIC_NEG;					break;				case -1:		/* ----------								 * ABS(var1) < ABS(var2)								 * result = +(ABS(var2) - ABS(var1))								 * ----------								 */					sub_abs(var2, var1, result);					result->sign = NUMERIC_POS;					break;			}		}		else		{			/* ----------			 * var1 is negative, var2 is positive			 * result = -(ABS(var1) + ABS(var2))			 * ----------			 */			add_abs(var1, var2, result);			result->sign = NUMERIC_NEG;		}	}}/* ---------- * mul_var() - * *	Multiplication on variable level. Product of var1 * var2 is stored *	in result. * ---------- */static voidmul_var(NumericVar *var1, NumericVar *var2, NumericVar *result){	NumericDigitBuf *res_buf;	NumericDigit *res_digits;	int			res_ndigits;	int			res_weight;	int			res_sign;	int			i,				ri,				i1,				i2;	long		sum = 0;	res_weight = var1->weight + var2->weight + 2;	res_ndigits = var1->ndigits + var2->ndigits + 1;	if (var1->sign == var2->sign)		res_sign = NUMERIC_POS;	else		res_sign = NUMERIC_NEG;	res_buf = digitbuf_alloc(res_ndigits);	res_digits = ((NumericDigit *) res_buf) + sizeof(NumericDigitBuf);	memset(res_digits, 0, res_ndigits);	ri = res_ndigits;	for (i1 = var1->ndigits - 1; i1 >= 0; i1--)	{		sum = 0;		i = --ri;		for (i2 = var2->ndigits - 1; i2 >= 0; i2--)		{			sum = sum + res_digits[i] + var1->digits[i1] * var2->digits[i2];			res_digits[i--] = sum % 10;			sum /= 10;		}		res_digits[i] = sum;	}	i = res_weight + global_rscale + 2;	if (i >= 0 && i < res_ndigits)	{		sum = (res_digits[i] > 4) ? 1 : 0;		res_ndigits = i;		i--;		while (sum)		{			sum += res_digits[i];			res_digits[i--] = sum % 10;			sum /= 10;		}	}	while (res_ndigits > 0 && *res_digits == 0)	{		res_digits++;		res_weight--;		res_ndigits--;	}	while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)		res_ndigits--;	if (res_ndigits == 0)	{		res_sign = NUMERIC_POS;		res_weight = 0;	}	digitbuf_free(result->buf);	result->buf = res_buf;	result->digits = res_digits;	result->ndigits = res_ndigits;	result->weight = res_weight;	result->rscale = global_rscale;	result->sign = res_sign;}/* ---------- * div_var() - * *	Division on variable level. * ----------

⌨️ 快捷键说明

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