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

📄 numeric.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	 * nothing to a zero.	 */	if (num->varlen != 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(num->varlen);	memcpy(res, num, num->varlen);	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 (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);	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);}/* * width_bucket_numeric() - * * '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 in for 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). */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")));	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;	}	result = numericvar_to_int4(&result_var);	free_var(&count_var);	free_var(&result_var);	PG_RETURN_INT32(result);}/* * compute_bucket() - * * 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			result = 1;			/* NAN > non-NAN */	}	else if (NUMERIC_IS_NAN(num2))	{		result = -1;			/* non-NAN < NAN */	}	else	{		NumericVar	arg1;		NumericVar	arg2;		init_var(&arg1);		init_var(&arg2);		set_var_from_num(num1, &arg1);		set_var_from_num(num2, &arg2);		result = cmp_var(&arg1, &arg2);		free_var(&arg1);		free_var(&arg2);	}	return result;}/* ---------------------------------------------------------------------- * * Basic arithmetic functions * * ---------------------------------------------------------------------- *//* * numeric_add() - * *	Add two numerics */Datumnumeric_add(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	NumericVar	arg1;	NumericVar	arg2;	NumericVar	result;	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the values, let add_var() compute the result and return it.	 */	init_var(&arg1);	init_var(&arg2);	init_var(&result);	set_var_from_num(num1, &arg1);	set_var_from_num(num2, &arg2);	add_var(&arg1, &arg2, &result);	res = make_result(&result);	free_var(&arg1);	free_var(&arg2);	free_var(&result);	PG_RETURN_NUMERIC(res);}/* * numeric_sub() - * *	Subtract one numeric from another */Datumnumeric_sub(PG_FUNCTION_ARGS){	Numeric		num1 = PG_GETARG_NUMERIC(0);	Numeric		num2 = PG_GETARG_NUMERIC(1);	NumericVar	arg1;	NumericVar	arg2;	NumericVar	result;	Numeric		res;	/*	 * Handle NaN	 */	if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/*	 * Unpack the values, let sub_var() compute the result and return it.	 */	init_var(&arg1);	init_var(&arg2);	init_var(&result);	set_var_from_num(num1, &arg1);

⌨️ 快捷键说明

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