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

📄 numeric.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	free_var(&vN);	free_var(&vNminus1);	free_var(&vsumX);	free_var(&vsumX2);	PG_RETURN_NUMERIC(res);}/* * SUM transition functions for integer datatypes. * * To avoid overflow, we use accumulators wider than the input datatype. * A Numeric accumulator is needed for int8 input; for int4 and int2 * inputs, we use int8 accumulators which should be sufficient for practical * purposes.  (The latter two therefore don't really belong in this file, * but we keep them here anyway.) * * Because SQL92 defines the SUM() of no values to be NULL, not zero, * the initial condition of the transition data value needs to be NULL. This * means we can't rely on ExecAgg to automatically insert the first non-null * data value into the transition data: it doesn't know how to do the type * conversion.	The upshot is that these routines have to be marked non-strict * and handle substitution of the first non-null input themselves. */Datumint2_sum(PG_FUNCTION_ARGS){	int64		newval;	if (PG_ARGISNULL(0))	{		/* No non-null input seen so far... */		if (PG_ARGISNULL(1))			PG_RETURN_NULL();	/* still no non-null */		/* This is the first non-null input. */		newval = (int64) PG_GETARG_INT16(1);		PG_RETURN_INT64(newval);	}	/*	 * If we're invoked by nodeAgg, we can cheat and modify out first	 * parameter in-place to avoid palloc overhead. If not, we need to return	 * the new value of the transition variable.	 */	if (fcinfo->context && IsA(fcinfo->context, AggState))	{		int64	   *oldsum = (int64 *) PG_GETARG_POINTER(0);		/* Leave the running sum unchanged in the new input is null */		if (!PG_ARGISNULL(1))			*oldsum = *oldsum + (int64) PG_GETARG_INT16(1);		PG_RETURN_POINTER(oldsum);	}	else	{		int64		oldsum = PG_GETARG_INT64(0);		/* Leave sum unchanged if new input is null. */		if (PG_ARGISNULL(1))			PG_RETURN_INT64(oldsum);		/* OK to do the addition. */		newval = oldsum + (int64) PG_GETARG_INT16(1);		PG_RETURN_INT64(newval);	}}Datumint4_sum(PG_FUNCTION_ARGS){	int64		newval;	if (PG_ARGISNULL(0))	{		/* No non-null input seen so far... */		if (PG_ARGISNULL(1))			PG_RETURN_NULL();	/* still no non-null */		/* This is the first non-null input. */		newval = (int64) PG_GETARG_INT32(1);		PG_RETURN_INT64(newval);	}	/*	 * If we're invoked by nodeAgg, we can cheat and modify out first	 * parameter in-place to avoid palloc overhead. If not, we need to return	 * the new value of the transition variable.	 */	if (fcinfo->context && IsA(fcinfo->context, AggState))	{		int64	   *oldsum = (int64 *) PG_GETARG_POINTER(0);		/* Leave the running sum unchanged in the new input is null */		if (!PG_ARGISNULL(1))			*oldsum = *oldsum + (int64) PG_GETARG_INT32(1);		PG_RETURN_POINTER(oldsum);	}	else	{		int64		oldsum = PG_GETARG_INT64(0);		/* Leave sum unchanged if new input is null. */		if (PG_ARGISNULL(1))			PG_RETURN_INT64(oldsum);		/* OK to do the addition. */		newval = oldsum + (int64) PG_GETARG_INT32(1);		PG_RETURN_INT64(newval);	}}Datumint8_sum(PG_FUNCTION_ARGS){	Numeric		oldsum;	Datum		newval;	if (PG_ARGISNULL(0))	{		/* No non-null input seen so far... */		if (PG_ARGISNULL(1))			PG_RETURN_NULL();	/* still no non-null */		/* This is the first non-null input. */		newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));		PG_RETURN_DATUM(newval);	}	/*	 * Note that we cannot special-case the nodeAgg case here, as we do for	 * int2_sum and int4_sum: numeric is of variable size, so we cannot modify	 * our first parameter in-place.	 */	oldsum = PG_GETARG_NUMERIC(0);	/* Leave sum unchanged if new input is null. */	if (PG_ARGISNULL(1))		PG_RETURN_NUMERIC(oldsum);	/* OK to do the addition. */	newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));	PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,										NumericGetDatum(oldsum), newval));}/* * Routines for avg(int2) and avg(int4).  The transition datatype * is a two-element int8 array, holding count and sum. */typedef struct Int8TransTypeData{#ifndef INT64_IS_BUSTED	int64		count;	int64		sum;#else	/* "int64" isn't really 64 bits, so fake up properly-aligned fields */	int32		count;	int32		pad1;	int32		sum;	int32		pad2;#endif} Int8TransTypeData;Datumint2_avg_accum(PG_FUNCTION_ARGS){	ArrayType  *transarray;	int16		newval = PG_GETARG_INT16(1);	Int8TransTypeData *transdata;	/*	 * If we're invoked by nodeAgg, we can cheat and modify our first	 * parameter in-place to reduce palloc overhead. Otherwise we need to make	 * a copy of it before scribbling on it.	 */	if (fcinfo->context && IsA(fcinfo->context, AggState))		transarray = PG_GETARG_ARRAYTYPE_P(0);	else		transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);	if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))		elog(ERROR, "expected 2-element int8 array");	transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);	transdata->count++;	transdata->sum += newval;	PG_RETURN_ARRAYTYPE_P(transarray);}Datumint4_avg_accum(PG_FUNCTION_ARGS){	ArrayType  *transarray;	int32		newval = PG_GETARG_INT32(1);	Int8TransTypeData *transdata;	/*	 * If we're invoked by nodeAgg, we can cheat and modify our first	 * parameter in-place to reduce palloc overhead. Otherwise we need to make	 * a copy of it before scribbling on it.	 */	if (fcinfo->context && IsA(fcinfo->context, AggState))		transarray = PG_GETARG_ARRAYTYPE_P(0);	else		transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);	if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))		elog(ERROR, "expected 2-element int8 array");	transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);	transdata->count++;	transdata->sum += newval;	PG_RETURN_ARRAYTYPE_P(transarray);}Datumint8_avg(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Int8TransTypeData *transdata;	Datum		countd,				sumd;	if (ARR_SIZE(transarray) != ARR_OVERHEAD(1) + sizeof(Int8TransTypeData))		elog(ERROR, "expected 2-element int8 array");	transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);	/* SQL92 defines AVG of no values to be NULL */	if (transdata->count == 0)		PG_RETURN_NULL();	countd = DirectFunctionCall1(int8_numeric,								 Int64GetDatumFast(transdata->count));	sumd = DirectFunctionCall1(int8_numeric,							   Int64GetDatumFast(transdata->sum));	PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));}/* ---------------------------------------------------------------------- * * Debug support * * ---------------------------------------------------------------------- */#ifdef NUMERIC_DEBUG/* * dump_numeric() - Dump a value in the db storage format for debugging */static voiddump_numeric(const char *str, Numeric num){	NumericDigit *digits = (NumericDigit *) num->n_data;	int			ndigits;	int			i;	ndigits = (num->varlen - NUMERIC_HDRSZ) / sizeof(NumericDigit);	printf("%s: NUMERIC w=%d d=%d ", str, num->n_weight, NUMERIC_DSCALE(num));	switch (NUMERIC_SIGN(num))	{		case NUMERIC_POS:			printf("POS");			break;		case NUMERIC_NEG:			printf("NEG");			break;		case NUMERIC_NAN:			printf("NaN");			break;		default:			printf("SIGN=0x%x", NUMERIC_SIGN(num));			break;	}	for (i = 0; i < ndigits; i++)		printf(" %0*d", DEC_DIGITS, digits[i]);	printf("\n");}/* * dump_var() - Dump a value in the variable format for debugging */static voiddump_var(const char *str, NumericVar *var){	int			i;	printf("%s: VAR w=%d d=%d ", str, var->weight, var->dscale);	switch (var->sign)	{		case NUMERIC_POS:			printf("POS");			break;		case NUMERIC_NEG:			printf("NEG");			break;		case NUMERIC_NAN:			printf("NaN");			break;		default:			printf("SIGN=0x%x", var->sign);			break;	}	for (i = 0; i < var->ndigits; i++)		printf(" %0*d", DEC_DIGITS, var->digits[i]);	printf("\n");}#endif   /* NUMERIC_DEBUG *//* ---------------------------------------------------------------------- * * Local functions follow * * In general, these do not support NaNs --- callers must eliminate * the possibility of NaN first.  (make_result() is an exception.) * * ---------------------------------------------------------------------- *//* * alloc_var() - * *	Allocate a digit buffer of ndigits digits (plus a spare digit for rounding) */static voidalloc_var(NumericVar *var, int ndigits){	digitbuf_free(var->buf);	var->buf = digitbuf_alloc(ndigits + 1);	var->buf[0] = 0;			/* spare digit for rounding */	var->digits = var->buf + 1;	var->ndigits = ndigits;}/* * free_var() - * *	Return the digit buffer of a variable to the free pool */static voidfree_var(NumericVar *var){	digitbuf_free(var->buf);	var->buf = NULL;	var->digits = NULL;	var->sign = NUMERIC_NAN;}/* * zero_var() - * *	Set a variable to ZERO. *	Note: its dscale is not touched. */static voidzero_var(NumericVar *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... */}/* * set_var_from_str() * *	Parse a string and put the number into a variable */static voidset_var_from_str(const char *str, NumericVar *dest){	const char *cp = str;	bool		have_dp = FALSE;	int			i;	unsigned char *decdigits;	int			sign = NUMERIC_POS;	int			dweight = -1;	int			ddigits;	int			dscale = 0;	int			weight;	int			ndigits;	int			offset;	NumericDigit *digits;	/*	 * We first parse the string to extract decimal digits and determine the	 * correct decimal weight.	Then convert to NBASE representation.	 */	/* skip leading spaces */	while (*cp)	{		if (!isspace((unsigned char) *cp))			break;		cp++;	}	switch (*cp)	{		case '+':			sign = NUMERIC_POS;			cp++;			break;		case '-':			sign = NUMERIC_NEG;			cp++;			break;	}	if (*cp == '.')	{		have_dp = TRUE;		cp++;	}	if (!isdigit((unsigned char) *cp))		ereport(ERROR,				(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),			  errmsg("invalid input syntax for type numeric: \"%s\"", str)));	decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2);	/* leading padding for digit alignment later */	memset(decdigits, 0, DEC_DIGITS);	i = DEC_DIGITS;	while (*cp)	{		if (isdigit((unsigned char) *cp))		{			decdigits[i++] = *cp++ - '0';			if (!have_dp)				dweight++;			else				dscale++;		}		else if (*cp == '.')		{			if (have_dp)				ereport(ERROR,						(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					  errmsg("invalid input syntax for type numeric: \"%s\"",							 str)));			have_dp = TRUE;			cp++;		}		else			break;	}	ddigits = i - DEC_DIGITS;	/* trailing padding for digit alignment later */	memset(decdigits + i, 0, DEC_DIGITS - 1);	/* Handle exponent, if any */	if (*cp == 'e' || *cp == 'E')	{		long		exponent;		char	   *endptr;		cp++;		exponent = strtol(cp, &endptr, 10);		if (endptr == cp)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("invalid input syntax for type numeric: \"%s\"",							str)));		cp = endptr;		if (exponent > NUMERIC_MAX_PRECISION ||			exponent < -NUMERIC_MAX_PRECISION)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("invalid input syntax for type numeric: \"%s\"",							str)));		dweight += (int) exponent;		dscale -= (int) exponent;		if (dscale < 0)			dscale = 0;	}	/* Should be nothing left but spaces */	while (*cp)	{		if (!isspace((unsigned char) *cp))			ereport(ERROR,					(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),					 errmsg("invalid input syntax for type numeric: \"%s\"",							str)));		cp++;	}	/*	 * Okay, convert pure-decimal representation to base NBASE.  First we need	 * to determine the converted weight and ndigits.  offset is the number of	 * decimal zeroes to insert before the first given digit to have a	 * correctly aligned first NBASE digit.	 */	if (dweight >= 0)		weight = (dweight + 1 + DEC_DIGITS - 1) / DEC_DIGITS - 1;	else		weight = -((-dweight - 1) / DEC_DIGITS + 1);	offset = (weight + 1) * DEC_DIGITS - (dweight + 1);	ndigits = (ddigits + offset + DEC_DIGITS - 1) / DEC_DIGITS;	alloc_var(dest, ndigits);	dest->sign = sign;	dest->weight = weight;	dest->dscale = dscale;	i = DEC_DIGITS - offset;	digits = dest->digits;	while (ndigits-- > 0)	{#if DEC_DIGITS == 4		*digits++ = ((decdigits[i] * 10 + decdigits[i + 1]) * 10 +					 decdigits[i + 2]) * 10 + decdigits[i + 3];#elif DEC_DIGITS == 2		*digits++ = decdigits[i] * 10 + decdigits[i + 1];#elif DEC_DIGITS == 1		*digits++ = decdigits[i];#else#error unsupported NBASE#endif		i += DEC_DIGITS;	}	pfree(decdigits);	/* Strip any leading/trailing zeroes, and normalize weight if zero */	strip_var(dest);}/* * set_var_from_num() - * *	Convert the packed db format into a variable */static voidset_var_from_num(Numeric num, NumericVar *dest){	int			ndigits;	ndigits = (num->varlen - NUMERIC_HDRSZ) / sizeof(NumericDigit);	alloc_var(dest, ndigits);	dest->weight = num->n_weight;	dest->sign = NUMERIC_SIGN(num);

⌨️ 快捷键说明

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