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

📄 numeric.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 5 页
字号:
	init_var(&result);	set_var_from_str(buf, &result);	res = make_result(&result);	free_var(&result);	PG_RETURN_NUMERIC(res);}Datumnumeric_float4(PG_FUNCTION_ARGS){	Numeric		num = PG_GETARG_NUMERIC(0);	char	   *tmp;	Datum		result;	if (NUMERIC_IS_NAN(num))		PG_RETURN_FLOAT4((float4) NAN);	tmp = DatumGetCString(DirectFunctionCall1(numeric_out,											  NumericGetDatum(num)));	result = DirectFunctionCall1(float4in, CStringGetDatum(tmp));	pfree(tmp);	PG_RETURN_DATUM(result);}Datumtext_numeric(PG_FUNCTION_ARGS){	text	   *str = PG_GETARG_TEXT_P(0);	int			len;	char	   *s;	Datum		result;	len = (VARSIZE(str) - VARHDRSZ);	s = palloc(len + 1);	memcpy(s, VARDATA(str), len);	*(s + len) = '\0';	result = DirectFunctionCall3(numeric_in, CStringGetDatum(s),								 ObjectIdGetDatum(0), Int32GetDatum(-1));	pfree(s);	return result;}Datumnumeric_text(PG_FUNCTION_ARGS){	/* val is numeric, but easier to leave it as Datum */	Datum		val = PG_GETARG_DATUM(0);	char	   *s;	int			len;	text	   *result;	s = DatumGetCString(DirectFunctionCall1(numeric_out, val));	len = strlen(s);	result = (text *) palloc(VARHDRSZ + len);	VARATT_SIZEP(result) = len + VARHDRSZ;	memcpy(VARDATA(result), s, len);	pfree(s);	PG_RETURN_TEXT_P(result);}/* ---------------------------------------------------------------------- * * Aggregate functions * * The transition datatype for all these aggregates is a 3-element array * of Numeric, holding the values N, sum(X), sum(X*X) in that order. * * We represent N as a numeric mainly to avoid having to build a special * datatype; it's unlikely it'd overflow an int4, but ... * * ---------------------------------------------------------------------- */static ArrayType *do_numeric_accum(ArrayType *transarray, Numeric newval){	Datum	   *transdatums;	int			ndatums;	Datum		N,				sumX,				sumX2;	ArrayType  *result;	/* We assume the input is array of numeric */	deconstruct_array(transarray,					  NUMERICOID, -1, false, 'i',					  &transdatums, &ndatums);	if (ndatums != 3)		elog(ERROR, "expected 3-element numeric array");	N = transdatums[0];	sumX = transdatums[1];	sumX2 = transdatums[2];	N = DirectFunctionCall1(numeric_inc, N);	sumX = DirectFunctionCall2(numeric_add, sumX,							   NumericGetDatum(newval));	sumX2 = DirectFunctionCall2(numeric_add, sumX2,								DirectFunctionCall2(numeric_mul,												 NumericGetDatum(newval),											   NumericGetDatum(newval)));	transdatums[0] = N;	transdatums[1] = sumX;	transdatums[2] = sumX2;	result = construct_array(transdatums, 3,							 NUMERICOID, -1, false, 'i');	return result;}Datumnumeric_accum(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Numeric		newval = PG_GETARG_NUMERIC(1);	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));}/* * Integer data types all use Numeric accumulators to share code and * avoid risk of overflow.	For int2 and int4 inputs, Numeric accumulation * is overkill for the N and sum(X) values, but definitely not overkill * for the sum(X*X) value.	Hence, we use int2_accum and int4_accum only * for stddev/variance --- there are faster special-purpose accumulator * routines for SUM and AVG of these datatypes. */Datumint2_accum(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Datum		newval2 = PG_GETARG_DATUM(1);	Numeric		newval;	newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));}Datumint4_accum(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Datum		newval4 = PG_GETARG_DATUM(1);	Numeric		newval;	newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));}Datumint8_accum(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Datum		newval8 = PG_GETARG_DATUM(1);	Numeric		newval;	newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));}Datumnumeric_avg(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Datum	   *transdatums;	int			ndatums;	Numeric		N,				sumX;	/* We assume the input is array of numeric */	deconstruct_array(transarray,					  NUMERICOID, -1, false, 'i',					  &transdatums, &ndatums);	if (ndatums != 3)		elog(ERROR, "expected 3-element numeric array");	N = DatumGetNumeric(transdatums[0]);	sumX = DatumGetNumeric(transdatums[1]);	/* ignore sumX2 */	/* SQL92 defines AVG of no values to be NULL */	/* N is zero iff no digits (cf. numeric_uminus) */	if (N->varlen == NUMERIC_HDRSZ)		PG_RETURN_NULL();	PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,										NumericGetDatum(sumX),										NumericGetDatum(N)));}Datumnumeric_variance(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Datum	   *transdatums;	int			ndatums;	Numeric		N,				sumX,				sumX2,				res;	NumericVar	vN,				vsumX,				vsumX2,				vNminus1;	int			rscale;	/* We assume the input is array of numeric */	deconstruct_array(transarray,					  NUMERICOID, -1, false, 'i',					  &transdatums, &ndatums);	if (ndatums != 3)		elog(ERROR, "expected 3-element numeric array");	N = DatumGetNumeric(transdatums[0]);	sumX = DatumGetNumeric(transdatums[1]);	sumX2 = DatumGetNumeric(transdatums[2]);	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/* Sample variance is undefined when N is 0 or 1, so return NULL */	init_var(&vN);	set_var_from_num(N, &vN);	if (cmp_var(&vN, &const_one) <= 0)	{		free_var(&vN);		PG_RETURN_NULL();	}	init_var(&vNminus1);	sub_var(&vN, &const_one, &vNminus1);	init_var(&vsumX);	set_var_from_num(sumX, &vsumX);	init_var(&vsumX2);	set_var_from_num(sumX2, &vsumX2);	/* compute rscale for mul_var calls */	rscale = vsumX.dscale * 2;	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */	sub_var(&vsumX2, &vsumX, &vsumX2);	/* N * sumX2 - sumX * sumX */	if (cmp_var(&vsumX2, &const_zero) <= 0)	{		/* Watch out for roundoff error producing a negative numerator */		res = make_result(&const_zero);	}	else	{		mul_var(&vN, &vNminus1, &vNminus1, 0);	/* N * (N - 1) */		rscale = select_div_scale(&vsumX2, &vNminus1);		div_var(&vsumX2, &vNminus1, &vsumX, rscale);	/* variance */		res = make_result(&vsumX);	}	free_var(&vN);	free_var(&vNminus1);	free_var(&vsumX);	free_var(&vsumX2);	PG_RETURN_NUMERIC(res);}Datumnumeric_stddev(PG_FUNCTION_ARGS){	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);	Datum	   *transdatums;	int			ndatums;	Numeric		N,				sumX,				sumX2,				res;	NumericVar	vN,				vsumX,				vsumX2,				vNminus1;	int			rscale;	/* We assume the input is array of numeric */	deconstruct_array(transarray,					  NUMERICOID, -1, false, 'i',					  &transdatums, &ndatums);	if (ndatums != 3)		elog(ERROR, "expected 3-element numeric array");	N = DatumGetNumeric(transdatums[0]);	sumX = DatumGetNumeric(transdatums[1]);	sumX2 = DatumGetNumeric(transdatums[2]);	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))		PG_RETURN_NUMERIC(make_result(&const_nan));	/* Sample stddev is undefined when N is 0 or 1, so return NULL */	init_var(&vN);	set_var_from_num(N, &vN);	if (cmp_var(&vN, &const_one) <= 0)	{		free_var(&vN);		PG_RETURN_NULL();	}	init_var(&vNminus1);	sub_var(&vN, &const_one, &vNminus1);	init_var(&vsumX);	set_var_from_num(sumX, &vsumX);	init_var(&vsumX2);	set_var_from_num(sumX2, &vsumX2);	/* compute rscale for mul_var calls */	rscale = vsumX.dscale * 2;	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */	sub_var(&vsumX2, &vsumX, &vsumX2);	/* N * sumX2 - sumX * sumX */	if (cmp_var(&vsumX2, &const_zero) <= 0)	{		/* Watch out for roundoff error producing a negative numerator */		res = make_result(&const_zero);	}	else	{		mul_var(&vN, &vNminus1, &vNminus1, 0);	/* N * (N - 1) */		rscale = select_div_scale(&vsumX2, &vNminus1);		div_var(&vsumX2, &vNminus1, &vsumX, rscale);	/* variance */		sqrt_var(&vsumX, &vsumX, rscale);		/* stddev */		res = make_result(&vsumX);	}	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		oldsum;	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);	}	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		oldsum;	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);	}	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);	}	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 = PG_GETARG_ARRAYTYPE_P_COPY(0);	int16		newval = PG_GETARG_INT16(1);	Int8TransTypeData *transdata;	/*	 * We copied the input array, so it's okay to scribble on it directly.	 */	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 = PG_GETARG_ARRAYTYPE_P_COPY(0);	int32		newval = PG_GETARG_INT32(1);	Int8TransTypeData *transdata;	/*	 * We copied the input array, so it's okay to scribble on it directly.	 */	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 */

⌨️ 快捷键说明

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