numeric.c

来自「postgresql8.3.4源码,开源数据库」· C语言 代码 · 共 2,840 行 · 第 1/5 页

C
2,840
字号
			ereport(ERROR,					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),					 errmsg("NUMERIC precision %d must be between 1 and %d",							tl[0], NUMERIC_MAX_PRECISION)));		/* scale defaults to zero */		typmod = (tl[0] << 16) + VARHDRSZ;	}	else	{		ereport(ERROR,				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),				 errmsg("invalid NUMERIC type modifier")));		typmod = 0;				/* keep compiler quiet */	}	PG_RETURN_INT32(typmod);}Datumnumerictypmodout(PG_FUNCTION_ARGS){	int32		typmod = PG_GETARG_INT32(0);	char	   *res = (char *) palloc(64);	if (typmod >= 0)		snprintf(res, 64, "(%d,%d)",				 ((typmod - VARHDRSZ) >> 16) & 0xffff,				 (typmod - VARHDRSZ) & 0xffff);	else		*res = '\0';	PG_RETURN_CSTRING(res);}/* ---------------------------------------------------------------------- * * Sign manipulation, rounding and the like * * ---------------------------------------------------------------------- */Datumnumeric_abs(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Do it the easy way directly on the packed format	 */	res = (Numeric) palloc(VARSIZE(num));	memcpy(res, num, VARSIZE(num));	res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);	PG_RETURN_NUMERIC(res);}Datumnumeric_uminus(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Do it the easy way directly on the packed format	 */	res = (Numeric) palloc(VARSIZE(num));	memcpy(res, num, VARSIZE(num));	/*	 * The packed format is known to be totally zero digit trimmed always. So	 * we can identify a ZERO by the fact that there are no digits at all.	Do	 * nothing to a zero.	 */	if (VARSIZE(num) != NUMERIC_HDRSZ)	{		/* Else, flip the sign */		if (NUMERIC_SIGN(num) == NUMERIC_POS)			res->n_sign_dscale = NUMERIC_NEG | NUMERIC_DSCALE(num);		else			res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);	}	PG_RETURN_NUMERIC(res);}Datumnumeric_uplus(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	res = (Numeric) palloc(VARSIZE(num));	memcpy(res, num, VARSIZE(num));	PG_RETURN_NUMERIC(res);}/* * numeric_sign() - * * returns -1 if the argument is less than 0, 0 if the argument is equal * to 0, and 1 if the argument is greater than zero. */Datumnumeric_sign(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	NumericVar	result;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	init_var(&result);	/*	 * The packed format is known to be totally zero digit trimmed always. So	 * we can identify a ZERO by the fact that there are no digits at all.	 */	if (VARSIZE(num) == 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);	PG_RETURN_NUMERIC(res);}/* * numeric_round() - * *	Round a value to have 'scale' digits after the decimal point. *	We allow negative 'scale', implying rounding before the decimal *	point --- Oracle interprets rounding that way. */Datumnumeric_round(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	int32		scale = PG_GETARG_INT32(1);	Numeric		res;	NumericVar	arg;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Limit the scale value to avoid possible overflow in calculations	 */	scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE);	scale = Min(scale, NUMERIC_MAX_RESULT_SCALE);	/*	 * Unpack the argument and round it at the proper digit position	 */	init_var(&arg);	set_var_from_num(num, &arg);	round_var(&arg, scale);	/* We don't allow negative output dscale */	if (scale < 0)		arg.dscale = 0;	/*	 * Return the rounded result	 */	res = make_result(&arg);	free_var(&arg);	PG_RETURN_NUMERIC(res);}/* * numeric_trunc() - * *	Truncate a value to have 'scale' digits after the decimal point. *	We allow negative 'scale', implying a truncation before the decimal *	point --- Oracle interprets truncation that way. */Datumnumeric_trunc(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	int32		scale = PG_GETARG_INT32(1);	Numeric		res;	NumericVar	arg;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Limit the scale value to avoid possible overflow in calculations	 */	scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE);	scale = Min(scale, NUMERIC_MAX_RESULT_SCALE);	/*	 * Unpack the argument and truncate it at the proper digit position	 */	init_var(&arg);	set_var_from_num(num, &arg);	trunc_var(&arg, scale);	/* We don't allow negative output dscale */	if (scale < 0)		arg.dscale = 0;	/*	 * Return the truncated result	 */	res = make_result(&arg);	free_var(&arg);	PG_RETURN_NUMERIC(res);}/* * numeric_ceil() - * *	Return the smallest integer greater than or equal to the argument */Datumnumeric_ceil(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	NumericVar	result;	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	init_var(&result);	set_var_from_num(num, &result);	ceil_var(&result, &result);	res = make_result(&result);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * numeric_floor() - * *	Return the largest integer equal to or less than the argument */Datumnumeric_floor(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	Numeric		res;	NumericVar	result;	if (NUMERIC_IS_NAN(num))		PG_RETURN_NUMERIC(make_result(&const_nan));	init_var(&result);	set_var_from_num(num, &result);	floor_var(&result, &result);	res = make_result(&result);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * Implements the numeric version of the width_bucket() function * defined by SQL2003. See also width_bucket_float8(). * * 'bound1' and 'bound2' are the lower and upper bounds of the * histogram's range, respectively. 'count' is the number of buckets * in the histogram. width_bucket() returns an integer indicating the * bucket number that 'operand' belongs to in an equiwidth histogram * with the specified characteristics. An operand smaller than the * lower bound is assigned to bucket 0. An operand greater than the * upper bound is assigned to an additional bucket (with number * count+1). We don't allow "NaN" for any of the numeric arguments. */Datumwidth_bucket_numeric(PG_FUNCTION_ARGS){	Numeric		operand = PG_GETARG_NUMERIC(0);	Numeric		bound1 = PG_GETARG_NUMERIC(1);	Numeric		bound2 = PG_GETARG_NUMERIC(2);	int32		count = PG_GETARG_INT32(3);	NumericVar	count_var;	NumericVar	result_var;	int32		result;	if (count <= 0)		ereport(ERROR,				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),				 errmsg("count must be greater than zero")));	if (NUMERIC_IS_NAN(operand) ||		NUMERIC_IS_NAN(bound1) ||		NUMERIC_IS_NAN(bound2))		ereport(ERROR,				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),			  errmsg("operand, lower bound and upper bound cannot be NaN")));	init_var(&result_var);	init_var(&count_var);	/* Convert 'count' to a numeric, for ease of use later */	int8_to_numericvar((int64) count, &count_var);	switch (cmp_numerics(bound1, bound2))	{		case 0:			ereport(ERROR,				(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),				 errmsg("lower bound cannot equal upper bound")));			/* bound1 < bound2 */		case -1:			if (cmp_numerics(operand, bound1) < 0)				set_var_from_var(&const_zero, &result_var);			else if (cmp_numerics(operand, bound2) >= 0)				add_var(&count_var, &const_one, &result_var);			else				compute_bucket(operand, bound1, bound2,							   &count_var, &result_var);			break;			/* bound1 > bound2 */		case 1:			if (cmp_numerics(operand, bound1) > 0)				set_var_from_var(&const_zero, &result_var);			else if (cmp_numerics(operand, bound2) <= 0)				add_var(&count_var, &const_one, &result_var);			else				compute_bucket(operand, bound1, bound2,							   &count_var, &result_var);			break;	}	/* if result exceeds the range of a legal int4, we ereport here */	result = numericvar_to_int4(&result_var);	free_var(&count_var);	free_var(&result_var);	PG_RETURN_INT32(result);}/* * If 'operand' is not outside the bucket range, determine the correct * bucket for it to go. The calculations performed by this function * are derived directly from the SQL2003 spec. */static voidcompute_bucket(Numeric operand, Numeric bound1, Numeric bound2,			   NumericVar *count_var, NumericVar *result_var){	NumericVar	bound1_var;	NumericVar	bound2_var;	NumericVar	operand_var;	init_var(&bound1_var);	init_var(&bound2_var);	init_var(&operand_var);	set_var_from_num(bound1, &bound1_var);	set_var_from_num(bound2, &bound2_var);	set_var_from_num(operand, &operand_var);	if (cmp_var(&bound1_var, &bound2_var) < 0)	{		sub_var(&operand_var, &bound1_var, &operand_var);		sub_var(&bound2_var, &bound1_var, &bound2_var);		div_var(&operand_var, &bound2_var, result_var,				select_div_scale(&operand_var, &bound2_var), true);	}	else	{		sub_var(&bound1_var, &operand_var, &operand_var);		sub_var(&bound1_var, &bound2_var, &bound1_var);		div_var(&operand_var, &bound1_var, result_var,				select_div_scale(&operand_var, &bound1_var), true);	}	mul_var(result_var, count_var, result_var,			result_var->dscale + count_var->dscale);	add_var(result_var, &const_one, result_var);	floor_var(result_var, result_var);	free_var(&bound1_var);	free_var(&bound2_var);	free_var(&operand_var);}/* ---------------------------------------------------------------------- * * Comparison functions * * Note: btree indexes need these routines not to leak memory; therefore, * be careful to free working copies of toasted datums.  Most places don't * need to be so careful. * ---------------------------------------------------------------------- */Datumnumeric_cmp(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	int			result;	result = cmp_numerics(num1, num2);	PG_FREE_IF_COPY(num1, 0);	PG_FREE_IF_COPY(num2, 1);	PG_RETURN_INT32(result);}Datumnumeric_eq(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	bool		result;	result = cmp_numerics(num1, num2) == 0;	PG_FREE_IF_COPY(num1, 0);	PG_FREE_IF_COPY(num2, 1);	PG_RETURN_BOOL(result);}Datumnumeric_ne(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	bool		result;	result = cmp_numerics(num1, num2) != 0;	PG_FREE_IF_COPY(num1, 0);	PG_FREE_IF_COPY(num2, 1);	PG_RETURN_BOOL(result);}Datumnumeric_gt(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	bool		result;	result = cmp_numerics(num1, num2) > 0;	PG_FREE_IF_COPY(num1, 0);	PG_FREE_IF_COPY(num2, 1);	PG_RETURN_BOOL(result);}Datumnumeric_ge(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	bool		result;	result = cmp_numerics(num1, num2) >= 0;	PG_FREE_IF_COPY(num1, 0);	PG_FREE_IF_COPY(num2, 1);	PG_RETURN_BOOL(result);}Datumnumeric_lt(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	bool		result;	result = cmp_numerics(num1, num2) < 0;	PG_FREE_IF_COPY(num1, 0);	PG_FREE_IF_COPY(num2, 1);	PG_RETURN_BOOL(result);}Datumnumeric_le(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	bool		result;	result = cmp_numerics(num1, num2) <= 0;	PG_FREE_IF_COPY(num1, 0);	PG_FREE_IF_COPY(num2, 1);	PG_RETURN_BOOL(result);}static intcmp_numerics(Numeric num1, Numeric num2){	int			result;	/*	 * We consider all NANs to be equal and larger than any non-NAN. This is	 * somewhat arbitrary; the important thing is to have a consistent sort	 * order.	 */	if (NUMERIC_IS_NAN(num1))	{		if (NUMERIC_IS_NAN(num2))			result = 0;			/* NAN = NAN */		else

⌨️ 快捷键说明

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