patch implementing the multi-argument aggregates (SOC project)

Started by Sergey E. Koposovover 19 years ago7 messages
#1Sergey E. Koposov
math@sai.msu.ru
1 attachment(s)

Hello All,

Since the feature freeze is in a few days, I'm sending the first iteration
of my patch implementing the multi-argument aggregates (PolyArgAgg) (SOC
project)

I currently fully enabled the creation and usage of PolyArgAggs, like this

CREATE OR REPLACE FUNCTION sum2_trans (anyelement, anyelement,anyelement)
RETURNS anyelement
AS 'SELECT $1+$2+$3;'
LANGUAGE SQL;

CREATE AGGREGATE sum2( anyelement,anyelement)
(SFUNC=sum2_trans,
STYPE=anyelement,
INITCOND=0);

postgres=# select * from xx;
a | b | c
---+---+-----
1 | 2 | 1.2
2 | 3 | 2.3
3 | 4 | 3.4
4 | 5 | 3.4
(4 rows)

postgres=# select sum2(a,b) from xx;
sum2
------
24
(1 row)

postgres=# select sum2(a,b) from xx group by c;
sum2
------
3
16
5
(3 rows)

Also I implemented the full set of PolyArgAggs from SQL 2003

REGR_SXX(), REGR_SYY(), REGR_SXY(), REGR_AVGX(), REGR_AVGY(), REGR_R2(),
CORR(), COVAR_POP(),COVAR_SAMP(), REGR_SLOPE(), REGR_INTERCEPT(),
REGR_COUNT()

Example:
template1=# select regr_r2(pronamespace::int::numeric,prolang::int::numeric) from pg_proc;
regr_r2
------------------------
0.14226915125082682802
(1 row)

template1=# select regr_r2(pronamespace::int,prolang::int) from pg_proc;
regr_r2
-------------------
0.142269151250827
(1 row)

template1=# select regr_count(pronamespace::int,prolang::int) from pg_proc;
regr_count
------------
1956
(1 row)

The existing regression tests are working.

What is still missing:
1) The additional regression tests testing the PolyArgAggs.
2) There is a couple of moments in the PG core related part of patch,
where I'm not completely sure that I'm doing the right thing...
(they are commented in the special way in the patch (if somebody can
clarify them for me, I would be happy))

Any comments are very welcome.

Regards,
Sergey

*******************************************************************
Sergey E. Koposov
Max Planck Institute for Astronomy/Sternberg Astronomical Institute
Tel: +49-6221-528-349
Web: http://lnfm1.sai.msu.ru/~math
E-mail: math@sai.msu.ru

Attachments:

PolyArgAggs.difftext/plain; charset=US-ASCII; name=PolyArgAggs.diffDownload
Index: src/backend/catalog/pg_aggregate.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v
retrieving revision 1.81
diff -c -r1.81 pg_aggregate.c
*** src/backend/catalog/pg_aggregate.c	14 Jul 2006 14:52:17 -0000	1.81
--- src/backend/catalog/pg_aggregate.c	24 Jul 2006 09:34:14 -0000
***************
*** 42,48 ****
  void
  AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid aggBaseType,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
--- 42,49 ----
  void
  AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid *aggBaseTypeArray,
! 				int numArgs,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
***************
*** 59,71 ****
  	Oid			sortop = InvalidOid;	/* can be omitted */
  	Oid			rettype;
  	Oid			finaltype;
! 	Oid			fnArgs[2];		/* we only deal with 1- and 2-arg fns */
  	int			nargs_transfn;
  	Oid			procOid;
  	TupleDesc	tupDesc;
  	int			i;
  	ObjectAddress myself,
  				referenced;
  
  	/* sanity checks (caller should have caught these) */
  	if (!aggName)
--- 60,74 ----
  	Oid			sortop = InvalidOid;	/* can be omitted */
  	Oid			rettype;
  	Oid			finaltype;
! 	Oid			*fnArgs;
  	int			nargs_transfn;
  	Oid			procOid;
  	TupleDesc	tupDesc;
  	int			i;
  	ObjectAddress myself,
  				referenced;
+ 	bool		hasAnyArrElOids = false,/* ANYARRAYOID or ANYELEMENTOID */
+ 				hasAnyOids = false;		/* ANYOID */
  
  	/* sanity checks (caller should have caught these) */
  	if (!aggName)
***************
*** 74,99 ****
  	if (!aggtransfnName)
  		elog(ERROR, "aggregate must have a transition function");
  
  	/*
  	 * If transtype is polymorphic, basetype must be polymorphic also; else we
  	 * will have no way to deduce the actual transtype.
  	 */
! 	if ((aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID) &&
! 		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  				 errmsg("cannot determine transition data type"),
  			errdetail("An aggregate using \"anyarray\" or \"anyelement\" as "
  				"transition type must have one of them as its base type.")));
  
  	/* handle transfn */
  	fnArgs[0] = aggTransType;
! 	if (aggBaseType == ANYOID)
  		nargs_transfn = 1;
  	else
  	{
! 		fnArgs[1] = aggBaseType;
! 		nargs_transfn = 2;
  	}
  	transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
  								  &rettype);
--- 77,135 ----
  	if (!aggtransfnName)
  		elog(ERROR, "aggregate must have a transition function");
  
+ 	for(i = 0 ; i < numArgs ; i++)
+ 	{
+ 		if ((aggBaseTypeArray[i] == ANYARRAYOID) ||
+ 			(aggBaseTypeArray[i] == ANYELEMENTOID))
+ 		{
+ 			hasAnyArrElOids = true;
+ 		}
+ 		else if (aggBaseTypeArray[i] == ANYOID)
+ 		{
+ 			hasAnyOids = true;
+ 		}
+ 	}
+ 
  	/*
  	 * If transtype is polymorphic, basetype must be polymorphic also; else we
  	 * will have no way to deduce the actual transtype.
  	 */
! 	if ((!hasAnyArrElOids) &&
! 		(aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID))
! 	{
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  				 errmsg("cannot determine transition data type"),
  			errdetail("An aggregate using \"anyarray\" or \"anyelement\" as "
  				"transition type must have one of them as its base type.")));
+ 	}
+ 
+ 	/* 
+ 	 * Currently I disallow the ANYOID types in multi-argument aggregates
+ 	 * Just because I don't see any sense in that ,and because the standart
+ 	 * (if I understand correctly) doesn't allow "*" arguments in polyArgAggs
+ 	 */
+ 	 
+ 	 if ((hasAnyOids) && (numArgs > 1))
+ 	 {
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 				 errmsg("The ANYOID types are not allowed in multi argument aggregates")));
+ 
+ 	 }
  
  	/* handle transfn */
+ 	fnArgs = palloc((numArgs + 1) * sizeof(Oid));
  	fnArgs[0] = aggTransType;
! 	if (aggBaseTypeArray[0] == ANYOID)
  		nargs_transfn = 1;
  	else
  	{
! 		for(i = 1 ; i <= numArgs; i++)
! 		{
! 			fnArgs[i] = aggBaseTypeArray[i - 1];
! 		}
! 		nargs_transfn = numArgs + 1;
  	}
  	transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
  								  &rettype);
***************
*** 129,135 ****
  	 */
  	if (proc->proisstrict && agginitval == NULL)
  	{
! 		if (!IsBinaryCoercible(aggBaseType, aggTransType))
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
--- 165,171 ----
  	 */
  	if (proc->proisstrict && agginitval == NULL)
  	{
! 		if (!IsBinaryCoercible(aggBaseTypeArray[0], aggTransType))
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
***************
*** 160,167 ****
  	 * that itself violates the rule against polymorphic result with no
  	 * polymorphic input.)
  	 */
! 	if ((finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID) &&
! 		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
  		ereport(ERROR,
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("cannot determine result data type"),
--- 196,203 ----
  	 * that itself violates the rule against polymorphic result with no
  	 * polymorphic input.)
  	 */
! 	if ((!hasAnyArrElOids)&&
! 		(finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID))
  		ereport(ERROR,
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("cannot determine result data type"),
***************
*** 170,184 ****
  
  	/* handle sortop, if supplied */
  	if (aggsortopName)
  		sortop = LookupOperName(NULL, aggsortopName,
! 								aggBaseType, aggBaseType,
  								false, -1);
! 
  	/*
  	 * Everything looks okay.  Try to create the pg_proc entry for the
  	 * aggregate.  (This could fail if there's already a conflicting entry.)
  	 */
! 	fnArgs[0] = aggBaseType;
  
  	procOid = ProcedureCreate(aggName,
  							  aggNamespace,
--- 206,228 ----
  
  	/* handle sortop, if supplied */
  	if (aggsortopName)
+ 	{
+ 		if (numArgs != 1)
+ 		{
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 					errmsg("The sort operator cannot be used in"
+ 					" multi argument aggregates")));
+ 		} 
  		sortop = LookupOperName(NULL, aggsortopName,
! 								aggBaseTypeArray[0], aggBaseTypeArray[0],
  								false, -1);
! 	}
  	/*
  	 * Everything looks okay.  Try to create the pg_proc entry for the
  	 * aggregate.  (This could fail if there's already a conflicting entry.)
  	 */
! 
  
  	procOid = ProcedureCreate(aggName,
  							  aggNamespace,
***************
*** 195,201 ****
  							  false,	/* isStrict (not needed for agg) */
  							  PROVOLATILE_IMMUTABLE,	/* volatility (not
  														 * needed for agg) */
! 							  buildoidvector(fnArgs, 1),		/* paramTypes */
  							  PointerGetDatum(NULL),	/* allParamTypes */
  							  PointerGetDatum(NULL),	/* parameterModes */
  							  PointerGetDatum(NULL));	/* parameterNames */
--- 239,246 ----
  							  false,	/* isStrict (not needed for agg) */
  							  PROVOLATILE_IMMUTABLE,	/* volatility (not
  														 * needed for agg) */
! 							  buildoidvector(aggBaseTypeArray,
! 							  				 numArgs),	/* paramTypes */
  							  PointerGetDatum(NULL),	/* allParamTypes */
  							  PointerGetDatum(NULL),	/* parameterModes */
  							  PointerGetDatum(NULL));	/* parameterNames */
***************
*** 279,284 ****
--- 324,331 ----
  	Oid		   *true_oid_array;
  	FuncDetailCode fdresult;
  	AclResult	aclresult;
+ 	int			i;
+ 	bool		allANY = true;
  
  	/*
  	 * func_get_detail looks up the function in the catalogs, does
***************
*** 302,315 ****
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("function %s returns a set",
  						func_signature_string(fnName, nargs, input_types))));
  
  	/*
  	 * If the given type(s) are all polymorphic, there's nothing we can check.
  	 * Otherwise, enforce consistency, and possibly refine the result type.
  	 */
! 	if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) &&
! 		(nargs == 1 ||
! 		 (input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID)))
  	{
  		/* nothing to check here */
  	}
--- 349,370 ----
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("function %s returns a set",
  						func_signature_string(fnName, nargs, input_types))));
+ 	
+ 	for (i = 0; i < nargs ; i++)
+ 	{
+ 		if (input_types[i] != ANYARRAYOID &&
+ 			input_types[i] != ANYELEMENTOID)
+ 		{
+ 			allANY = false;
+ 			break;
+ 		}
+ 	}
  
  	/*
  	 * If the given type(s) are all polymorphic, there's nothing we can check.
  	 * Otherwise, enforce consistency, and possibly refine the result type.
  	 */
! 	if (allANY)
  	{
  		/* nothing to check here */
  	}
***************
*** 325,346 ****
  	 * func_get_detail will find functions requiring run-time argument type
  	 * coercion, but nodeAgg.c isn't prepared to deal with that
  	 */
! 	if (true_oid_array[0] != ANYARRAYOID &&
! 		true_oid_array[0] != ANYELEMENTOID &&
! 		!IsBinaryCoercible(input_types[0], true_oid_array[0]))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_DATATYPE_MISMATCH),
! 				 errmsg("function %s requires run-time type coercion",
! 					 func_signature_string(fnName, nargs, true_oid_array))));
! 
! 	if (nargs == 2 &&
! 		true_oid_array[1] != ANYARRAYOID &&
! 		true_oid_array[1] != ANYELEMENTOID &&
! 		!IsBinaryCoercible(input_types[1], true_oid_array[1]))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_DATATYPE_MISMATCH),
! 				 errmsg("function %s requires run-time type coercion",
! 					 func_signature_string(fnName, nargs, true_oid_array))));
  
  	/* Check aggregate creator has permission to call the function */
  	aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
--- 380,402 ----
  	 * func_get_detail will find functions requiring run-time argument type
  	 * coercion, but nodeAgg.c isn't prepared to deal with that
  	 */
! 	/* KS 
! 	 * I don't really understand that stuff with type coercion 
! 	 * And It's not clear that it is enough that the first argument type 
! 	 * is coercible with the transType ... 
! 	 */
! 	for (i = 0; i < nargs; i++)
! 	{
! 		if (true_oid_array[i] != ANYARRAYOID &&
! 			true_oid_array[i] != ANYELEMENTOID &&
! 			!IsBinaryCoercible(input_types[i], true_oid_array[i]))
! 		{
! 			ereport(ERROR,
! 					(errcode(ERRCODE_DATATYPE_MISMATCH),
! 					 errmsg("function %s requires run-time type coercion",
! 						 func_signature_string(fnName, nargs, true_oid_array))));
! 		}
! 	}
  
  	/* Check aggregate creator has permission to call the function */
  	aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
Index: src/backend/commands/aggregatecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v
retrieving revision 1.37
diff -c -r1.37 aggregatecmds.c
*** src/backend/commands/aggregatecmds.c	14 Jul 2006 14:52:18 -0000	1.37
--- src/backend/commands/aggregatecmds.c	24 Jul 2006 09:34:15 -0000
***************
*** 57,65 ****
  	TypeName   *baseType = NULL;
  	TypeName   *transType = NULL;
  	char	   *initval = NULL;
! 	Oid			baseTypeId;
  	Oid			transTypeId;
  	ListCell   *pl;
  
  	/* Convert list of names to a name and namespace */
  	aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
--- 57,66 ----
  	TypeName   *baseType = NULL;
  	TypeName   *transType = NULL;
  	char	   *initval = NULL;
! 	Oid			*baseTypeIdArray;
  	Oid			transTypeId;
  	ListCell   *pl;
+ 	int 		numArgs;
  
  	/* Convert list of names to a name and namespace */
  	aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
***************
*** 131,140 ****
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("aggregate input type must be specified")));
  
  		if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
! 			baseTypeId = ANYOID;
  		else
! 			baseTypeId = typenameTypeId(NULL, baseType);
  	}
  	else
  	{
--- 132,143 ----
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("aggregate input type must be specified")));
  
+ 		baseTypeIdArray  = palloc(sizeof(Oid)*1);
  		if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
! 			baseTypeIdArray[0] = ANYOID;
  		else
! 			baseTypeIdArray[0] = typenameTypeId(NULL, baseType);
! 		numArgs = 1;
  	}
  	else
  	{
***************
*** 147,168 ****
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("basetype is redundant with aggregate input type specification")));
  
  		if (args == NIL)
  		{
  			/* special case for agg(*) */
! 			baseTypeId = ANYOID;
! 		}
! 		else if (list_length(args) != 1)
! 		{
! 			/* temporarily reject > 1 arg */
! 			ereport(ERROR,
! 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 					 errmsg("aggregates can have only one input")));
! 			baseTypeId = InvalidOid;	/* keep compiler quiet */
  		}
  		else
  		{
! 			baseTypeId = typenameTypeId(NULL, (TypeName *) linitial(args));
  		}
  	}
  
--- 150,178 ----
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("basetype is redundant with aggregate input type specification")));
  
+ 		/** KS TO check 
+ 		 * I removed the check for length of the list (args)==1
+ 		 * but probably I should check that the length!=0  (I don't know)
+ 		 */
  		if (args == NIL)
  		{
  			/* special case for agg(*) */
! 			baseTypeIdArray  = palloc(sizeof(Oid)*1);
! 			baseTypeIdArray[0] = ANYOID;
! 			numArgs = 1;
  		}
  		else
  		{
! 			int i = 0;
! 			ListCell *lc;
! 			TypeName *curTypeName;
! 			baseTypeIdArray  = palloc(sizeof(Oid)*list_length(args));
! 			foreach (lc, args)
! 			{
! 				curTypeName = lfirst(lc);
! 				baseTypeIdArray[i++] = typenameTypeId(NULL, curTypeName);
! 			}
! 			numArgs = i;
  		}
  	}
  
***************
*** 187,193 ****
  	 */
  	AggregateCreate(aggName,	/* aggregate name */
  					aggNamespace,		/* namespace */
! 					baseTypeId, /* type of data being aggregated */
  					transfuncName,		/* step function name */
  					finalfuncName,		/* final function name */
  					sortoperatorName,	/* sort operator name */
--- 197,204 ----
  	 */
  	AggregateCreate(aggName,	/* aggregate name */
  					aggNamespace,		/* namespace */
! 					baseTypeIdArray, /* type of data being aggregated */
! 					numArgs,
  					transfuncName,		/* step function name */
  					finalfuncName,		/* final function name */
  					sortoperatorName,	/* sort operator name */
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/execQual.c,v
retrieving revision 1.192
diff -c -r1.192 execQual.c
*** src/backend/executor/execQual.c	14 Jul 2006 14:52:19 -0000	1.192
--- src/backend/executor/execQual.c	24 Jul 2006 09:34:20 -0000
***************
*** 3174,3180 ****
  					aggstate->aggs = lcons(astate, aggstate->aggs);
  					naggs = ++aggstate->numaggs;
  
! 					astate->target = ExecInitExpr(aggref->target, parent);
  
  					/*
  					 * Complain if the aggregate's argument contains any
--- 3174,3181 ----
  					aggstate->aggs = lcons(astate, aggstate->aggs);
  					naggs = ++aggstate->numaggs;
  
! 					astate->args = (List *) ExecInitExpr((Expr *)aggref->args,
! 														 parent);
  
  					/*
  					 * Complain if the aggregate's argument contains any
Index: src/backend/executor/nodeAgg.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/nodeAgg.c,v
retrieving revision 1.144
diff -c -r1.144 nodeAgg.c
*** src/backend/executor/nodeAgg.c	14 Jul 2006 14:52:19 -0000	1.144
--- src/backend/executor/nodeAgg.c	24 Jul 2006 09:34:20 -0000
***************
*** 123,128 ****
--- 123,137 ----
  	Oid			inputType;
  	Oid			sortOperator;
  
+ 	int			numArguments;
+ 
+ 	/* 
+ 	 * The preallocated arrays used to store the arguments of Aggs
+ 	 * and the isNull flags.
+ 	 */
+ 	Datum		*newArgValArray;
+ 	bool		*isNullArray;
+ 
  	/*
  	 * fmgr lookup data for input type's equality operator --- only set/used
  	 * when aggregate has DISTINCT flag.
***************
*** 214,220 ****
  static void advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							Datum newVal, bool isNull);
  static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup);
  static void process_sorted_aggregate(AggState *aggstate,
  						 AggStatePerAgg peraggstate,
--- 223,230 ----
  static void advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							Datum *newValArray,
! 							bool *isNullArray, int numArguments);
  static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup);
  static void process_sorted_aggregate(AggState *aggstate,
  						 AggStatePerAgg peraggstate,
***************
*** 322,331 ****
  advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							Datum newVal, bool isNull)
  {
  	FunctionCallInfoData fcinfo;
  	MemoryContext oldContext;
  
  	if (peraggstate->transfn.fn_strict)
  	{
--- 332,344 ----
  advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							Datum *newArgValArray, bool *isNullArray,
! 							int numArguments)
  {
  	FunctionCallInfoData fcinfo;
  	MemoryContext oldContext;
+ 	Datum newComputedTransValue;
+ 	int i;
  
  	if (peraggstate->transfn.fn_strict)
  	{
***************
*** 333,340 ****
  		 * For a strict transfn, nothing happens at a NULL input tuple; we
  		 * just keep the prior transValue.
  		 */
! 		if (isNull)
! 			return;
  		if (pergroupstate->noTransValue)
  		{
  			/*
--- 346,356 ----
  		 * For a strict transfn, nothing happens at a NULL input tuple; we
  		 * just keep the prior transValue.
  		 */
! 		for (i = 0; (i < numArguments); i++)
! 		{
! 			if (isNullArray[i])
! 				return;
! 		}
  		if (pergroupstate->noTransValue)
  		{
  			/*
***************
*** 347,353 ****
  			 * do not need to pfree the old transValue, since it's NULL.
  			 */
  			oldContext = MemoryContextSwitchTo(aggstate->aggcontext);
! 			pergroupstate->transValue = datumCopy(newVal,
  												  peraggstate->transtypeByVal,
  												  peraggstate->transtypeLen);
  			pergroupstate->transValueIsNull = false;
--- 363,369 ----
  			 * do not need to pfree the old transValue, since it's NULL.
  			 */
  			oldContext = MemoryContextSwitchTo(aggstate->aggcontext);
! 			pergroupstate->transValue = datumCopy(newArgValArray[0],
  												  peraggstate->transtypeByVal,
  												  peraggstate->transtypeLen);
  			pergroupstate->transValueIsNull = false;
***************
*** 373,386 ****
  	/*
  	 * OK to call the transition function
  	 */
! 	InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn), 2,
! 							 (void *) aggstate, NULL);
  	fcinfo.arg[0] = pergroupstate->transValue;
  	fcinfo.argnull[0] = pergroupstate->transValueIsNull;
! 	fcinfo.arg[1] = newVal;
! 	fcinfo.argnull[1] = isNull;
  
! 	newVal = FunctionCallInvoke(&fcinfo);
  
  	/*
  	 * If pass-by-ref datatype, must copy the new value into aggcontext and
--- 389,406 ----
  	/*
  	 * OK to call the transition function
  	 */
! 	InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn),
! 							 1 + numArguments, (void *) aggstate,
! 							 NULL);
  	fcinfo.arg[0] = pergroupstate->transValue;
  	fcinfo.argnull[0] = pergroupstate->transValueIsNull;
! 	for(i = 1; i <= numArguments; i++)
! 	{
! 		fcinfo.arg[i] = newArgValArray[i - 1];
! 		fcinfo.argnull[i] = isNullArray[i - 1];
! 	}
  
! 	newComputedTransValue = FunctionCallInvoke(&fcinfo);
  
  	/*
  	 * If pass-by-ref datatype, must copy the new value into aggcontext and
***************
*** 388,399 ****
  	 * first input, we don't need to do anything.
  	 */
  	if (!peraggstate->transtypeByVal &&
! 		DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
  	{
  		if (!fcinfo.isnull)
  		{
  			MemoryContextSwitchTo(aggstate->aggcontext);
! 			newVal = datumCopy(newVal,
  							   peraggstate->transtypeByVal,
  							   peraggstate->transtypeLen);
  		}
--- 408,419 ----
  	 * first input, we don't need to do anything.
  	 */
  	if (!peraggstate->transtypeByVal &&
! 		DatumGetPointer(newComputedTransValue) != DatumGetPointer(pergroupstate->transValue))
  	{
  		if (!fcinfo.isnull)
  		{
  			MemoryContextSwitchTo(aggstate->aggcontext);
! 			newComputedTransValue = datumCopy(newComputedTransValue,
  							   peraggstate->transtypeByVal,
  							   peraggstate->transtypeLen);
  		}
***************
*** 401,407 ****
  			pfree(DatumGetPointer(pergroupstate->transValue));
  	}
  
! 	pergroupstate->transValue = newVal;
  	pergroupstate->transValueIsNull = fcinfo.isnull;
  
  	MemoryContextSwitchTo(oldContext);
--- 421,427 ----
  			pfree(DatumGetPointer(pergroupstate->transValue));
  	}
  
! 	pergroupstate->transValue = newComputedTransValue;
  	pergroupstate->transValueIsNull = fcinfo.isnull;
  
  	MemoryContextSwitchTo(oldContext);
***************
*** 419,449 ****
  advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
  {
  	ExprContext *econtext = aggstate->tmpcontext;
  	int			aggno;
  
  	for (aggno = 0; aggno < aggstate->numaggs; aggno++)
  	{
! 		AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
! 		AggStatePerGroup pergroupstate = &pergroup[aggno];
! 		AggrefExprState *aggrefstate = peraggstate->aggrefstate;
! 		Aggref	   *aggref = peraggstate->aggref;
! 		Datum		newVal;
! 		bool		isNull;
! 
! 		newVal = ExecEvalExprSwitchContext(aggrefstate->target, econtext,
! 										   &isNull, NULL);
  
  		if (aggref->aggdistinct)
  		{
  			/* in DISTINCT mode, we may ignore nulls */
! 			if (isNull)
  				continue;
! 			tuplesort_putdatum(peraggstate->sortstate, newVal, isNull);
  		}
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										newVal, isNull);
  		}
  	}
  }
--- 439,494 ----
  advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
  {
  	ExprContext *econtext = aggstate->tmpcontext;
+ 	Datum		*newArgValArray;
+ 	bool		*isNullArray;
  	int			aggno;
  
  	for (aggno = 0; aggno < aggstate->numaggs; aggno++)
  	{
! 		AggStatePerAgg		peraggstate = &aggstate->peragg[aggno];
! 		AggStatePerGroup	pergroupstate = &pergroup[aggno];
! 		AggrefExprState		*aggrefstate = peraggstate->aggrefstate;
! 		Aggref				*aggref = peraggstate->aggref;
! 		int					i, numArguments;
! 		ListCell			*arg;
! 		MemoryContext		oldContext;
! 		
! 		newArgValArray = peraggstate->newArgValArray;
! 		isNullArray = peraggstate->isNullArray;
! 		numArguments = peraggstate->numArguments;
! 		
! 		i = 0;
! 
! 
! 		/* Switch first to the per-tuple memory context of the expression */
! 		oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
! 		
! 		foreach(arg, aggrefstate->args)
! 		{
! 			ExprState  *argstate = (ExprState *) lfirst(arg);
! 			newArgValArray[i] = ExecEvalExpr(argstate, econtext,
! 											 isNullArray + i, NULL);
! 			i++;
! 		}
! 		
! 		/* Switch back */
! 		MemoryContextSwitchTo(oldContext);
  
  		if (aggref->aggdistinct)
  		{
+ 			/* We use one-argument aggs when in DISTINCT mode */
+ 			
  			/* in DISTINCT mode, we may ignore nulls */
! 			if (isNullArray[0])
  				continue;
! 			tuplesort_putdatum(peraggstate->sortstate, newArgValArray[0],
! 							   isNullArray[0]);
  		}
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										newArgValArray, isNullArray,
! 										numArguments);
  		}
  	}
  }
***************
*** 504,510 ****
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										newVal, false);
  			/* forget the old value, if any */
  			if (haveOldVal && !peraggstate->inputtypeByVal)
  				pfree(DatumGetPointer(oldVal));
--- 549,555 ----
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										&newVal, &isNull, 1);
  			/* forget the old value, if any */
  			if (haveOldVal && !peraggstate->inputtypeByVal)
  				pfree(DatumGetPointer(oldVal));
***************
*** 1120,1125 ****
--- 1165,1172 ----
  	int			numaggs,
  				aggno;
  	ListCell   *l;
+ 	Oid			*inputTypeArray = 0;
+ 
  
  	/* check for unsupported flags */
  	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
***************
*** 1286,1292 ****
  		AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
  		Aggref	   *aggref = (Aggref *) aggrefstate->xprstate.expr;
  		AggStatePerAgg peraggstate;
- 		Oid			inputType;
  		HeapTuple	aggTuple;
  		Form_pg_aggregate aggform;
  		Oid			aggtranstype;
--- 1333,1338 ----
***************
*** 1297,1306 ****
--- 1343,1360 ----
  				   *finalfnexpr;
  		Datum		textInitVal;
  		int			i;
+ 		int         numArguments;
+ 		ListCell    *curArgument;
+ 		
  
  		/* Planner should have assigned aggregate to correct level */
  		Assert(aggref->agglevelsup == 0);
  
+ 		
+ 		/* KS XXX Probably it should work even for polyArgAggs, but
+ 		 * it shoud be checked -- I'm not sure that the 
+ 		 * equal(aggref, aggref) works fine for the polyArgAggs
+ 		 */
  		/* Look for a previous duplicate aggregate */
  		for (i = 0; i <= aggno; i++)
  		{
***************
*** 1324,1336 ****
  		/* Fill in the peraggstate data */
  		peraggstate->aggrefstate = aggrefstate;
  		peraggstate->aggref = aggref;
  
  		/*
  		 * Get actual datatype of the input.  We need this because it may be
  		 * different from the agg's declared input type, when the agg accepts
  		 * ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT.
  		 */
! 		inputType = exprType((Node *) aggref->target);
  
  		aggTuple = SearchSysCache(AGGFNOID,
  								  ObjectIdGetDatum(aggref->aggfnoid),
--- 1378,1415 ----
  		/* Fill in the peraggstate data */
  		peraggstate->aggrefstate = aggrefstate;
  		peraggstate->aggref = aggref;
+ 		
+ 		numArguments = list_length(aggref->args);
+ 		peraggstate->numArguments = numArguments;
+ 		if (!inputTypeArray)
+ 		{
+ 			inputTypeArray = (Oid *) palloc(sizeof(Oid) * numArguments);
+ 		}
+ 		else
+ 		{   
+ 			inputTypeArray = (Oid *) repalloc(inputTypeArray,
+ 											  numArguments * sizeof(Oid));
+ 		}
+ 		
+ 		/* Preallocate the arrays for storing the arguments of the Aggs
+ 		 * and the isNull flags
+ 		 */
+ 		peraggstate->newArgValArray = (Datum *) palloc(sizeof(Datum) *
+ 													   numArguments);
+ 		peraggstate->isNullArray = (bool *) palloc(sizeof(bool) *
+ 													numArguments);
  
  		/*
  		 * Get actual datatype of the input.  We need this because it may be
  		 * different from the agg's declared input type, when the agg accepts
  		 * ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT.
  		 */
! 		i = 0;
! 		foreach(curArgument, aggref->args)
! 		{
! 			inputTypeArray[i++] = exprType((Node *) lfirst(curArgument));
! 		}
! 
  
  		aggTuple = SearchSysCache(AGGFNOID,
  								  ObjectIdGetDatum(aggref->aggfnoid),
***************
*** 1384,1403 ****
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *agg_arg_types;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &agg_arg_types, &agg_nargs);
! 			Assert(agg_nargs == 1);
! 			aggtranstype = resolve_generic_type(aggtranstype,
! 												inputType,
! 												agg_arg_types[0]);
! 			pfree(agg_arg_types);
  		}
  
  		/* build expression trees using actual argument & result types */
! 		build_aggregate_fnexprs(inputType,
  								aggtranstype,
  								aggref->aggtype,
  								transfn_oid,
--- 1463,1482 ----
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *declaredArgTypes;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &declaredArgTypes, &agg_nargs);
! 			aggtranstype = enforce_generic_type_consistency(inputTypeArray,
! 															declaredArgTypes,
! 															agg_nargs,
! 															aggtranstype);
! 			pfree(declaredArgTypes);
  		}
  
  		/* build expression trees using actual argument & result types */
! 		build_aggregate_fnexprs(inputTypeArray,
  								aggtranstype,
  								aggref->aggtype,
  								transfn_oid,
***************
*** 1444,1450 ****
  		 */
  		if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
  		{
! 			if (!IsBinaryCoercible(inputType, aggtranstype))
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  						 errmsg("aggregate %u needs to have compatible input type and transition type",
--- 1523,1529 ----
  		 */
  		if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
  		{
! 			if (!IsBinaryCoercible(inputTypeArray[0], aggtranstype))
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  						 errmsg("aggregate %u needs to have compatible input type and transition type",
***************
*** 1457,1476 ****
  
  			/* We don't implement DISTINCT aggs in the HASHED case */
  			Assert(node->aggstrategy != AGG_HASHED);
  
! 			peraggstate->inputType = inputType;
! 			get_typlenbyval(inputType,
  							&peraggstate->inputtypeLen,
  							&peraggstate->inputtypeByVal);
  
! 			eq_function = equality_oper_funcid(inputType);
  			fmgr_info(eq_function, &(peraggstate->equalfn));
! 			peraggstate->sortOperator = ordering_oper_opid(inputType);
  			peraggstate->sortstate = NULL;
  		}
  
  		ReleaseSysCache(aggTuple);
  	}
  
  	/* Update numaggs to match number of unique aggregates found */
  	aggstate->numaggs = aggno + 1;
--- 1536,1565 ----
  
  			/* We don't implement DISTINCT aggs in the HASHED case */
  			Assert(node->aggstrategy != AGG_HASHED);
+ 			
+ 			/* We don't implement the DISTINCT aggs for the aggs having
+ 			 * more than one argument
+ 			 */ 
+ 			Assert(numArguments == 1);
  
! 			peraggstate->inputType = inputTypeArray[0];
! 			get_typlenbyval(inputTypeArray[0],
  							&peraggstate->inputtypeLen,
  							&peraggstate->inputtypeByVal);
  
! 			eq_function = equality_oper_funcid(inputTypeArray[0]);
  			fmgr_info(eq_function, &(peraggstate->equalfn));
! 			peraggstate->sortOperator = ordering_oper_opid(inputTypeArray[0]);
  			peraggstate->sortstate = NULL;
  		}
  
  		ReleaseSysCache(aggTuple);
  	}
+ 	
+ 	if (inputTypeArray)
+ 	{
+ 		pfree(inputTypeArray);
+ 	}
  
  	/* Update numaggs to match number of unique aggregates found */
  	aggstate->numaggs = aggno + 1;
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.343
diff -c -r1.343 copyfuncs.c
*** src/backend/nodes/copyfuncs.c	14 Jul 2006 14:52:19 -0000	1.343
--- src/backend/nodes/copyfuncs.c	24 Jul 2006 09:34:23 -0000
***************
*** 743,749 ****
  
  	COPY_SCALAR_FIELD(aggfnoid);
  	COPY_SCALAR_FIELD(aggtype);
! 	COPY_NODE_FIELD(target);
  	COPY_SCALAR_FIELD(agglevelsup);
  	COPY_SCALAR_FIELD(aggstar);
  	COPY_SCALAR_FIELD(aggdistinct);
--- 743,749 ----
  
  	COPY_SCALAR_FIELD(aggfnoid);
  	COPY_SCALAR_FIELD(aggtype);
! 	COPY_NODE_FIELD(args);
  	COPY_SCALAR_FIELD(agglevelsup);
  	COPY_SCALAR_FIELD(aggstar);
  	COPY_SCALAR_FIELD(aggdistinct);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.277
diff -c -r1.277 equalfuncs.c
*** src/backend/nodes/equalfuncs.c	14 Jul 2006 14:52:20 -0000	1.277
--- src/backend/nodes/equalfuncs.c	24 Jul 2006 09:34:23 -0000
***************
*** 156,162 ****
  {
  	COMPARE_SCALAR_FIELD(aggfnoid);
  	COMPARE_SCALAR_FIELD(aggtype);
! 	COMPARE_NODE_FIELD(target);
  	COMPARE_SCALAR_FIELD(agglevelsup);
  	COMPARE_SCALAR_FIELD(aggstar);
  	COMPARE_SCALAR_FIELD(aggdistinct);
--- 156,162 ----
  {
  	COMPARE_SCALAR_FIELD(aggfnoid);
  	COMPARE_SCALAR_FIELD(aggtype);
! 	COMPARE_NODE_FIELD(args);
  	COMPARE_SCALAR_FIELD(agglevelsup);
  	COMPARE_SCALAR_FIELD(aggstar);
  	COMPARE_SCALAR_FIELD(aggdistinct);
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.278
diff -c -r1.278 outfuncs.c
*** src/backend/nodes/outfuncs.c	14 Jul 2006 14:52:20 -0000	1.278
--- src/backend/nodes/outfuncs.c	24 Jul 2006 09:34:23 -0000
***************
*** 635,641 ****
  
  	WRITE_OID_FIELD(aggfnoid);
  	WRITE_OID_FIELD(aggtype);
! 	WRITE_NODE_FIELD(target);
  	WRITE_UINT_FIELD(agglevelsup);
  	WRITE_BOOL_FIELD(aggstar);
  	WRITE_BOOL_FIELD(aggdistinct);
--- 635,641 ----
  
  	WRITE_OID_FIELD(aggfnoid);
  	WRITE_OID_FIELD(aggtype);
! 	WRITE_NODE_FIELD(args);
  	WRITE_UINT_FIELD(agglevelsup);
  	WRITE_BOOL_FIELD(aggstar);
  	WRITE_BOOL_FIELD(aggdistinct);
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/readfuncs.c,v
retrieving revision 1.191
diff -c -r1.191 readfuncs.c
*** src/backend/nodes/readfuncs.c	3 Jul 2006 22:45:39 -0000	1.191
--- src/backend/nodes/readfuncs.c	24 Jul 2006 09:34:23 -0000
***************
*** 348,354 ****
  
  	READ_OID_FIELD(aggfnoid);
  	READ_OID_FIELD(aggtype);
! 	READ_NODE_FIELD(target);
  	READ_UINT_FIELD(agglevelsup);
  	READ_BOOL_FIELD(aggstar);
  	READ_BOOL_FIELD(aggdistinct);
--- 348,354 ----
  
  	READ_OID_FIELD(aggfnoid);
  	READ_OID_FIELD(aggtype);
! 	READ_NODE_FIELD(args);
  	READ_UINT_FIELD(agglevelsup);
  	READ_BOOL_FIELD(aggstar);
  	READ_BOOL_FIELD(aggdistinct);
Index: src/backend/optimizer/plan/planagg.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/plan/planagg.c,v
retrieving revision 1.18
diff -c -r1.18 planagg.c
*** src/backend/optimizer/plan/planagg.c	14 Jul 2006 14:52:20 -0000	1.18
--- src/backend/optimizer/plan/planagg.c	24 Jul 2006 09:34:27 -0000
***************
*** 219,224 ****
--- 219,225 ----
  		Oid			aggsortop;
  		MinMaxAggInfo *info;
  		ListCell   *l;
+ 		Expr		*curTarget;
  
  		Assert(aggref->agglevelsup == 0);
  		if (aggref->aggstar)
***************
*** 228,233 ****
--- 229,237 ----
  		aggsortop = fetch_agg_sort_op(aggref->aggfnoid);
  		if (!OidIsValid(aggsortop))
  			return true;		/* not a MIN/MAX aggregate */
+ 		
+ 		/* Here we should have only one arg aggs... Isn't it ? */
+ 		curTarget = linitial(aggref->args);
  
  		/*
  		 * Check whether it's already in the list, and add it if not.
***************
*** 236,249 ****
  		{
  			info = (MinMaxAggInfo *) lfirst(l);
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, aggref->target))
  				return false;
  		}
  
  		info = (MinMaxAggInfo *) palloc0(sizeof(MinMaxAggInfo));
  		info->aggfnoid = aggref->aggfnoid;
  		info->aggsortop = aggsortop;
! 		info->target = aggref->target;
  
  		*context = lappend(*context, info);
  
--- 240,253 ----
  		{
  			info = (MinMaxAggInfo *) lfirst(l);
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, curTarget))
  				return false;
  		}
  
  		info = (MinMaxAggInfo *) palloc0(sizeof(MinMaxAggInfo));
  		info->aggfnoid = aggref->aggfnoid;
  		info->aggsortop = aggsortop;
! 		info->target = curTarget;
  
  		*context = lappend(*context, info);
  
***************
*** 520,532 ****
  	{
  		Aggref	   *aggref = (Aggref *) node;
  		ListCell   *l;
  
  		foreach(l, *context)
  		{
  			MinMaxAggInfo *info = (MinMaxAggInfo *) lfirst(l);
  
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, aggref->target))
  				return (Node *) info->param;
  		}
  		elog(ERROR, "failed to re-find aggregate info record");
--- 524,537 ----
  	{
  		Aggref	   *aggref = (Aggref *) node;
  		ListCell   *l;
+ 		Expr		*curTarget = linitial(aggref->args);
  
  		foreach(l, *context)
  		{
  			MinMaxAggInfo *info = (MinMaxAggInfo *) lfirst(l);
  
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, curTarget))
  				return (Node *) info->param;
  		}
  		elog(ERROR, "failed to re-find aggregate info record");
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.214
diff -c -r1.214 clauses.c
*** src/backend/optimizer/util/clauses.c	14 Jul 2006 14:52:21 -0000	1.214
--- src/backend/optimizer/util/clauses.c	24 Jul 2006 09:34:28 -0000
***************
*** 397,413 ****
  	if (IsA(node, Aggref))
  	{
  		Aggref	   *aggref = (Aggref *) node;
! 		Oid			inputType;
  		HeapTuple	aggTuple;
  		Form_pg_aggregate aggform;
  		Oid			aggtranstype;
! 
  		Assert(aggref->agglevelsup == 0);
  		counts->numAggs++;
  		if (aggref->aggdistinct)
  			counts->numDistinctAggs++;
  
! 		inputType = exprType((Node *) aggref->target);
  
  		/* fetch aggregate transition datatype from pg_aggregate */
  		aggTuple = SearchSysCache(AGGFNOID,
--- 397,425 ----
  	if (IsA(node, Aggref))
  	{
  		Aggref	   *aggref = (Aggref *) node;
! 		Oid			*inputTypeArray;
  		HeapTuple	aggTuple;
  		Form_pg_aggregate aggform;
  		Oid			aggtranstype;
! 		int			numArguments;
! 		int			i;
! 		ListCell	*curArgument;
! 		
  		Assert(aggref->agglevelsup == 0);
  		counts->numAggs++;
  		if (aggref->aggdistinct)
  			counts->numDistinctAggs++;
  
! 		numArguments = list_length(aggref->args);
! 
! 		inputTypeArray = (Oid *) palloc(sizeof(Oid) * numArguments);
! 		
! 		i = 0;
! 		foreach(curArgument, aggref->args)
! 		{
! 			inputTypeArray[i++] = exprType((Node *) lfirst(curArgument));
! 		}
! 		
  
  		/* fetch aggregate transition datatype from pg_aggregate */
  		aggTuple = SearchSysCache(AGGFNOID,
***************
*** 424,439 ****
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *agg_arg_types;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &agg_arg_types, &agg_nargs);
! 			Assert(agg_nargs == 1);
! 			aggtranstype = resolve_generic_type(aggtranstype,
! 												inputType,
! 												agg_arg_types[0]);
! 			pfree(agg_arg_types);
  		}
  
  		/*
--- 436,452 ----
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *declaredArgTypes;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &declaredArgTypes, &agg_nargs);
! 			/* To be thought about what to do with resolve_generic_type */
! 			aggtranstype = enforce_generic_type_consistency(inputTypeArray,
! 															declaredArgTypes,
! 															agg_nargs,
! 															aggtranstype);
! 			pfree(declaredArgTypes);
  		}
  
  		/*
***************
*** 452,459 ****
  			 * same typmod (same width) as well.  This works for cases like
  			 * MAX/MIN and is probably somewhat reasonable otherwise.
  			 */
! 			if (aggtranstype == inputType)
! 				aggtranstypmod = exprTypmod((Node *) aggref->target);
  			else
  				aggtranstypmod = -1;
  
--- 465,472 ----
  			 * same typmod (same width) as well.  This works for cases like
  			 * MAX/MIN and is probably somewhat reasonable otherwise.
  			 */
! 			if (aggtranstype == inputTypeArray[0])
! 				aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
  			else
  				aggtranstypmod = -1;
  
***************
*** 467,477 ****
  		 * Complain if the aggregate's argument contains any aggregates;
  		 * nested agg functions are semantically nonsensical.
  		 */
- 		if (contain_agg_clause((Node *) aggref->target))
- 			ereport(ERROR,
- 					(errcode(ERRCODE_GROUPING_ERROR),
- 					 errmsg("aggregate function calls may not be nested")));
  
  		/*
  		 * Having checked that, we need not recurse into the argument.
  		 */
--- 480,495 ----
  		 * Complain if the aggregate's argument contains any aggregates;
  		 * nested agg functions are semantically nonsensical.
  		 */
  
+ 		foreach(curArgument, aggref->args)
+ 		{
+ 			if (contain_agg_clause((Node *) lfirst(curArgument)))
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_GROUPING_ERROR),
+ 						 errmsg("aggregate function calls may not be nested")));
+ 		}
+ 		
+ 		pfree(inputTypeArray);
  		/*
  		 * Having checked that, we need not recurse into the argument.
  		 */
***************
*** 3026,3032 ****
  			/* primitive node types with no expression subnodes */
  			break;
  		case T_Aggref:
! 			return walker(((Aggref *) node)->target, context);
  		case T_ArrayRef:
  			{
  				ArrayRef   *aref = (ArrayRef *) node;
--- 3044,3057 ----
  			/* primitive node types with no expression subnodes */
  			break;
  		case T_Aggref:
! 			{
! 				Aggref   *aggref = (Aggref *) node;
! 
! 				if (expression_tree_walker((Node *) aggref->args,
! 										   walker, context))
! 					return true;
! 			}
! 			break;
  		case T_ArrayRef:
  			{
  				ArrayRef   *aref = (ArrayRef *) node;
***************
*** 3448,3454 ****
  				Aggref	   *newnode;
  
  				FLATCOPY(newnode, aggref, Aggref);
! 				MUTATE(newnode->target, aggref->target, Expr *);
  				return (Node *) newnode;
  			}
  			break;
--- 3473,3479 ----
  				Aggref	   *newnode;
  
  				FLATCOPY(newnode, aggref, Aggref);
! 				MUTATE(newnode->args, aggref->args, List *);
  				return (Node *) newnode;
  			}
  			break;
Index: src/backend/parser/parse_agg.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_agg.c,v
retrieving revision 1.72
diff -c -r1.72 parse_agg.c
*** src/backend/parser/parse_agg.c	14 Jul 2006 14:52:21 -0000	1.72
--- src/backend/parser/parse_agg.c	24 Jul 2006 09:34:30 -0000
***************
*** 51,84 ****
  void
  transformAggregateCall(ParseState *pstate, Aggref *agg)
  {
! 	int			min_varlevel;
! 
! 	/*
! 	 * The aggregate's level is the same as the level of the lowest-level
! 	 * variable or aggregate in its argument; or if it contains no variables
! 	 * at all, we presume it to be local.
! 	 */
! 	min_varlevel = find_minimum_var_level((Node *) agg->target);
! 
! 	/*
! 	 * An aggregate can't directly contain another aggregate call of the same
! 	 * level (though outer aggs are okay).	We can skip this check if we
! 	 * didn't find any local vars or aggs.
! 	 */
! 	if (min_varlevel == 0)
  	{
! 		if (checkExprHasAggs((Node *) agg->target))
! 			ereport(ERROR,
! 					(errcode(ERRCODE_GROUPING_ERROR),
! 					 errmsg("aggregate function calls may not be nested")));
  	}
  
! 	if (min_varlevel < 0)
! 		min_varlevel = 0;
! 	agg->agglevelsup = min_varlevel;
  
  	/* Mark the correct pstate as having aggregates */
! 	while (min_varlevel-- > 0)
  		pstate = pstate->parentParseState;
  	pstate->p_hasAggs = true;
  }
--- 51,98 ----
  void
  transformAggregateCall(ParseState *pstate, Aggref *agg)
  {
! 	int			minVarLevel,
! 				minMinVarLevel = -1;
! 	ListCell	*curArgument;
! 	foreach(curArgument, agg->args)
  	{
! 		Node	*curNode = (Node *)lfirst(curArgument);
! 		/*
! 		 * The aggregate's level is the same as the level of the lowest-level
! 		 * variable or aggregate in its argument; or if it contains no variables
! 		 * at all, we presume it to be local.
! 		 */
! 		minVarLevel = find_minimum_var_level(curNode);
! 	
! 		/*
! 		 * An aggregate can't directly contain another aggregate call of the same
! 		 * level (though outer aggs are okay).	We can skip this check if we
! 		 * didn't find any local vars or aggs.
! 		 */
! 		if (minVarLevel == 0)
! 		{
! 			if (checkExprHasAggs(curNode))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_GROUPING_ERROR),
! 						 errmsg("aggregate function calls may not be nested")));
! 		}
! 		
! /* KS XXX !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!  * !!!!!!!!!!!!!!!Very important!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!  * that logic should be fixed... I don't understand currently how I should
!  * update the minMinVarLevel. Should it be the minimum value among minVarLevels
!  * of different arguments or maximum value among minVarLevels or something else... 
!  * Currently it is just the minVarLevel of the last argument....
!  */	
! 		minMinVarLevel = minVarLevel;
  	}
  
! 	if (minMinVarLevel < 0)
! 		minMinVarLevel = 0;
! 	agg->agglevelsup = minMinVarLevel;
  
  	/* Mark the correct pstate as having aggregates */
! 	while (minMinVarLevel-- > 0)
  		pstate = pstate->parentParseState;
  	pstate->p_hasAggs = true;
  }
***************
*** 371,377 ****
   * *finalfnexpr.  The latter is set to NULL if there's no finalfn.
   */
  void
! build_aggregate_fnexprs(Oid agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
--- 385,391 ----
   * *finalfnexpr.  The latter is set to NULL if there's no finalfn.
   */
  void
! build_aggregate_fnexprs(Oid *agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
***************
*** 379,392 ****
  						Expr **transfnexpr,
  						Expr **finalfnexpr)
  {
! 	int			transfn_nargs;
  	Param	   *arg0;
  	Param	   *arg1;
  	List	   *args;
  
  	/* get the transition function arg count */
  	transfn_nargs = get_func_nargs(transfn_oid);
! 
  	/*
  	 * Build arg list to use in the transfn FuncExpr node. We really only care
  	 * that transfn can discover the actual argument types at runtime using
--- 393,409 ----
  						Expr **transfnexpr,
  						Expr **finalfnexpr)
  {
! 	int			transfn_nargs,
! 				aggfn_nargs,
! 				i;
  	Param	   *arg0;
  	Param	   *arg1;
  	List	   *args;
  
  	/* get the transition function arg count */
  	transfn_nargs = get_func_nargs(transfn_oid);
! 	aggfn_nargs = transfn_nargs - 1;
! 	
  	/*
  	 * Build arg list to use in the transfn FuncExpr node. We really only care
  	 * that transfn can discover the actual argument types at runtime using
***************
*** 398,403 ****
--- 415,432 ----
  	arg0->paramid = -1;
  	arg0->paramtype = agg_state_type;
  
+     args = list_make1(arg0);
+ 
+     for(i = 0; i < aggfn_nargs; i++)
+     {
+         arg1 = makeNode(Param);
+         arg1->paramkind = PARAM_EXEC;
+         arg1->paramid = -1;
+         arg1->paramtype = agg_input_type[i];
+         lappend(args, arg1);
+     }
+ 
+ /*
  	if (transfn_nargs == 2)
  	{
  		arg1 = makeNode(Param);
***************
*** 409,415 ****
  	}
  	else
  		args = list_make1(arg0);
! 
  	*transfnexpr = (Expr *) makeFuncExpr(transfn_oid,
  										 agg_state_type,
  										 args,
--- 438,444 ----
  	}
  	else
  		args = list_make1(arg0);
! */
  	*transfnexpr = (Expr *) makeFuncExpr(transfn_oid,
  										 agg_state_type,
  										 args,
Index: src/backend/parser/parse_func.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_func.c,v
retrieving revision 1.188
diff -c -r1.188 parse_func.c
*** src/backend/parser/parse_func.c	14 Jul 2006 14:52:22 -0000	1.188
--- src/backend/parser/parse_func.c	24 Jul 2006 09:34:30 -0000
***************
*** 259,267 ****
  
  		aggref->aggfnoid = funcid;
  		aggref->aggtype = rettype;
! 		aggref->target = linitial(fargs);
  		aggref->aggstar = agg_star;
  		aggref->aggdistinct = agg_distinct;
  
  		/* parse_agg.c does additional aggregate-specific processing */
  		transformAggregateCall(pstate, aggref);
--- 259,285 ----
  
  		aggref->aggfnoid = funcid;
  		aggref->aggtype = rettype;
! 		aggref->args = fargs;
  		aggref->aggstar = agg_star;
  		aggref->aggdistinct = agg_distinct;
+ 		
+ 		/* From my understanding of the SQL standart the DISTINCT keyword
+ 		 * can be used only in one-argument aggregates
+ 		 * And '*' cannot be used in multi-arg. aggregates
+ 		 */
+ 		if (list_length(fargs) > 1)
+ 		{
+ 			if (agg_distinct)
+ 			{
+ 				elog(ERROR, "It is not allowed to use DISTINCT keyword "
+ 					 "with aggregates with more than one argument");
+ 			}
+ 			if (agg_star)
+ 			{
+ 				elog(ERROR, "It is not allowed to use * arguments"
+ 					 "with aggregates with more than one argument");			
+ 			}
+ 		}
  
  		/* parse_agg.c does additional aggregate-specific processing */
  		transformAggregateCall(pstate, aggref);
Index: src/backend/utils/adt/float.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/float.c,v
retrieving revision 1.127
diff -c -r1.127 float.c
*** src/backend/utils/adt/float.c	14 Jul 2006 14:52:24 -0000	1.127
--- src/backend/utils/adt/float.c	24 Jul 2006 09:34:55 -0000
***************
*** 1878,1895 ****
   */
  
  static float8 *
! check_float8_array(ArrayType *transarray, const char *caller)
  {
  	/*
! 	 * We expect the input to be a 3-element float array; verify that. We
  	 * don't need to use deconstruct_array() since the array data is just
! 	 * going to look like a C array of 3 float8 values.
  	 */
  	if (ARR_NDIM(transarray) != 1 ||
! 		ARR_DIMS(transarray)[0] != 3 ||
  		ARR_HASNULL(transarray) ||
  		ARR_ELEMTYPE(transarray) != FLOAT8OID)
! 		elog(ERROR, "%s: expected 3-element float8 array", caller);
  	return (float8 *) ARR_DATA_PTR(transarray);
  }
  
--- 1878,1895 ----
   */
  
  static float8 *
! check_float8_array(ArrayType *transarray, const char *caller, int nelts)
  {
  	/*
! 	 * We expect the input to be a nelts-element float array; verify that. We
  	 * don't need to use deconstruct_array() since the array data is just
! 	 * going to look like a C array of nelts float8 values.
  	 */
  	if (ARR_NDIM(transarray) != 1 ||
! 		ARR_DIMS(transarray)[0] != nelts ||
  		ARR_HASNULL(transarray) ||
  		ARR_ELEMTYPE(transarray) != FLOAT8OID)
! 		elog(ERROR, "%s: expected %d-element float8 array", caller, nelts);
  	return (float8 *) ARR_DATA_PTR(transarray);
  }
  
***************
*** 1903,1909 ****
  				sumX,
  				sumX2;
  
! 	transvalues = check_float8_array(transarray, "float8_accum");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 1903,1909 ----
  				sumX,
  				sumX2;
  
! 	transvalues = check_float8_array(transarray, "float8_accum", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 1953,1959 ****
  				sumX2,
  				newval;
  
! 	transvalues = check_float8_array(transarray, "float4_accum");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 1953,1959 ----
  				sumX2,
  				newval;
  
! 	transvalues = check_float8_array(transarray, "float4_accum", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2003,2009 ****
  	float8		N,
  				sumX;
  
! 	transvalues = check_float8_array(transarray, "float8_avg");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	/* ignore sumX2 */
--- 2003,2009 ----
  	float8		N,
  				sumX;
  
! 	transvalues = check_float8_array(transarray, "float8_avg", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	/* ignore sumX2 */
***************
*** 2025,2031 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_pop");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2025,2031 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2053,2059 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_samp");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2053,2059 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2081,2087 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_pop");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2081,2087 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2109,2115 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_samp");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2109,2115 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2127,2132 ****
--- 2127,3003 ----
  	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
  }
  
+ Datum float8_regr_count_accum(PG_FUNCTION_ARGS)
+ {
+ 	int64 i = PG_GETARG_INT64(0);
+ 	if (PG_ARGISNULL(1)||PG_ARGISNULL(2))
+ 	{
+ 		PG_RETURN_INT64(i);
+ 	}
+ 	else
+ 	{
+ 		PG_RETURN_INT64(i+1);
+ 	}
+ }
+ 
+ Datum float4_regr_sxx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX,
+ 				sumX2;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_sxx_accum", 3);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 	sumX2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ Datum float4_regr_avgx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_avgx_accum", 2);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_avgx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_avgx_accum", 2);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float4_regr_avgy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_avgy_accum", 2);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_avgy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_avgy_accum", 2);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_avg(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sum,
+ 				numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_avg", 2);
+ 	N = transvalues[0];
+ 	sum = transvalues[1];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = sum;
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float8_regr_sxx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX,
+ 				sumX2;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxx_accum", 3);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 	sumX2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_sxx(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX,
+ 				sumX2,
+ 				numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 3);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumX2 - sumX * sumX;
+ 
+ 	/* Watch out for roundoff error producing a negative numerator */
+ 	if (numerator <= 0.0)
+ 		PG_RETURN_FLOAT8(0.0);
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float4_regr_syy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY,
+ 				sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_syy_accum", 3);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 	sumY2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 	sumY2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 		transvalues[2] = sumY2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 		transdatums[2] = Float8GetDatumFast(sumY2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_syy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY,
+ 				sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_syy_accum", 3);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 	sumY2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 	sumY2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 		transvalues[2] = sumY2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 		transdatums[2] = Float8GetDatumFast(sumY2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_syy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY,
+ 				sumY2,
+ 				numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_syy", 3);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 	sumY2 = transvalues[2];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumY2 - sumY * sumY;
+ 
+ 	/* Watch out for roundoff error producing a negative numerator */
+ 	if (numerator <= 0.0)
+ 		PG_RETURN_FLOAT8(0.0);
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float4_regr_sxy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT4(2);
+ 	float8		newvalY = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_sxy_accum", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumY;
+ 		transvalues[3] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[4];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumY);
+ 		transdatums[3] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 4,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float4_regr_all_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT4(2);
+ 	float8		newvalY = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, sumX2, sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_sxy_accum", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 	sumX2 += newvalX * newvalX;
+ 	sumY2 += newvalY * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 		transvalues[3] = sumY;
+ 		transvalues[4] = sumY2;
+ 		transvalues[5] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[6];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 		transdatums[3] = Float8GetDatumFast(sumY);
+ 		transdatums[4] = Float8GetDatumFast(sumY2);
+ 		transdatums[5] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 6,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ Datum float8_regr_all_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT8(2);
+ 	float8		newvalY = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, sumX2, sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_sxy_accum", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 	sumX2 += newvalX * newvalX;
+ 	sumY2 += newvalY * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 		transvalues[3] = sumY;
+ 		transvalues[4] = sumY2;
+ 		transvalues[5] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[6];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 		transdatums[3] = Float8GetDatumFast(sumY);
+ 		transdatums[4] = Float8GetDatumFast(sumY2);
+ 		transdatums[5] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 6,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_sxy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT8(2);
+ 	float8		newvalY = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxy_accum", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumY;
+ 		transvalues[3] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[4];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumY);
+ 		transdatums[3] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 4,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_sxy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxy", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumXY - sumX * sumY;
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float8_covar_pop(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxy", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumXY - sumX * sumY;
+ 
+ 	PG_RETURN_FLOAT8( numerator / (N * N));
+ }
+ 
+ 
+ Datum float8_covar_samp(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxy", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	/* if N is <=1  we should return NULL */
+ 	if (N < 2.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumXY - sumX * sumY;
+ 
+ 	PG_RETURN_FLOAT8( numerator / (N * (N - 1)));
+ }
+ 
+ 
+ Datum float8_corr(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorY, numeratorXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_corr", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorY = N * sumY2 - sumY * sumY;
+ 	numeratorXY = N * sumXY - sumX * sumY;
+ 	if ((numeratorX <= 0) && (numeratorY <= 0))
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( sqrt (numeratorXY * numeratorXY /
+ 		(numeratorX * numeratorY)));
+ }
+ 
+ Datum float8_regr_r2(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorY, numeratorXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_r2", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorY = N * sumY2 - sumY * sumY;
+ 	numeratorXY = N * sumXY - sumX * sumY;
+ 	if ((numeratorX <= 0) && (numeratorY <= 0))
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( numeratorXY * numeratorXY /
+ 		(numeratorX * numeratorY));
+ }
+ 
+ Datum float8_regr_slope(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_slope", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4]; /* will be ignored */
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorXY = N * sumXY - sumX * sumY;
+ 	if (numeratorX <= 0)
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( numeratorXY / numeratorX );
+ }
+ 
+ Datum float8_regr_intercept(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorXXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_intercept", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4]; /* will be ignored */
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
+ 	if (numeratorX <= 0)
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( numeratorXXY / numeratorX );
+ }
+ 
  
  /*
   *		====================================
Index: src/backend/utils/adt/numeric.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/numeric.c,v
retrieving revision 1.94
diff -c -r1.94 numeric.c
*** src/backend/utils/adt/numeric.c	14 Jul 2006 05:28:28 -0000	1.94
--- src/backend/utils/adt/numeric.c	24 Jul 2006 09:34:56 -0000
***************
*** 2106,2111 ****
--- 2106,2358 ----
  	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
  }
  
+ Datum numeric_regr_avgx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N,
+ 				sumX;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 2)
+ 		elog(ERROR, "expected 2-element numeric array");
+ 	N = transdatums[0];
+ 	sumX = transdatums[1];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumX = DirectFunctionCall2(numeric_add, sumX,
+ 							   NumericGetDatum(newvalX));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 
+ 	outputarray = construct_array(transdatums, 2,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ Datum numeric_regr_avgy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N, sumY;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 2)
+ 		elog(ERROR, "expected 2-element numeric array");
+ 	N = transdatums[0];
+ 	sumY = transdatums[1];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumY;
+ 
+ 	outputarray = construct_array(transdatums, 2,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ Datum numeric_regr_sxx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N,
+ 				sumX,
+ 				sumX2;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &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(newvalX));
+ 	sumX2 = DirectFunctionCall2(numeric_add, sumX2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalX)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 	transdatums[2] = sumX2;
+ 
+ 	outputarray = construct_array(transdatums, 3,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ Datum numeric_regr_syy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N,
+ 				sumY,
+ 				sumY2;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 3)
+ 		elog(ERROR, "expected 3-element numeric array");
+ 	N = transdatums[0];
+ 	sumY = transdatums[1];
+ 	sumY2 = transdatums[2];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY));
+ 	sumY2 = DirectFunctionCall2(numeric_add, sumY2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalY),
+ 													NumericGetDatum(newvalY)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumY;
+ 	transdatums[2] = sumY2;
+ 
+ 	outputarray = construct_array(transdatums, 3,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ Datum numeric_regr_sxy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N, sumX, sumY, sumXY;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = transdatums[0];
+ 	sumX = transdatums[1];
+ 	sumY = transdatums[2];
+ 	sumXY = transdatums[3];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumX = DirectFunctionCall2(numeric_add, sumX,
+ 							   NumericGetDatum(newvalX));
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY));
+ 	sumXY = DirectFunctionCall2(numeric_add, sumXY,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalY)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 	transdatums[2] = sumY;
+ 	transdatums[3] = sumXY;
+ 
+ 	outputarray = construct_array(transdatums, 4,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ Datum numeric_regr_all_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N, sumX, sumX2, sumY,  sumY2, sumXY;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = transdatums[0];
+ 	sumX = transdatums[1];
+ 	sumX2 = transdatums[2];
+ 	sumY = transdatums[3];
+ 	sumY2 = transdatums[4];
+ 	sumXY = transdatums[5];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 
+ /* Probably can and should be optimized to not repeat 
+  * NumericGetDatum several times */
+ 	sumX = DirectFunctionCall2(numeric_add, sumX,
+ 							   NumericGetDatum(newvalX));
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY)); 
+ 	sumXY = DirectFunctionCall2(numeric_add, sumXY,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalY)));
+ 	sumX2 = DirectFunctionCall2(numeric_add, sumX2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalX)));
+ 	sumY2 = DirectFunctionCall2(numeric_add, sumY2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalY),
+ 													NumericGetDatum(newvalY)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 	transdatums[2] = sumX2;
+ 	transdatums[3] = sumY;
+ 	transdatums[4] = sumY2;
+ 	transdatums[5] = sumXY;
+ 
+ 	outputarray = construct_array(transdatums, 6,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ 
+ 
  /*
   * Integer data types all use Numeric accumulators to share code and
   * avoid risk of overflow.	For int2 and int4 inputs, Numeric accumulation
***************
*** 2151,2156 ****
--- 2398,2416 ----
  	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
  }
  
+ Datum numeric_regr_count_accum(PG_FUNCTION_ARGS)
+ {
+ 	int64 i = PG_GETARG_INT64(0);
+ 	if (PG_ARGISNULL(1)||PG_ARGISNULL(2))
+ 	{
+ 		PG_RETURN_INT64(i);
+ 	}
+ 	else
+ 	{
+ 		PG_RETURN_INT64(i+1);
+ 	}
+ }
+ 
  Datum
  numeric_avg(PG_FUNCTION_ARGS)
  {
***************
*** 2283,2288 ****
--- 2543,3392 ----
  	return res;
  }
  
+ Datum numeric_regr_avg(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N,
+ 				sum;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 2)
+ 		elog(ERROR, "expected 2-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sum = DatumGetNumeric(transdatums[1]);
+ 
+ 	/* 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(sum),
+ 										NumericGetDatum(N)));
+ }
+ 
+ 
+ Datum numeric_regr_sxx(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N,
+ 				sumX,
+ 				sumX2,
+ 				res;
+ 	NumericVar	vN,
+ 				vsumX,
+ 				vsumX2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &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));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	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
+ 	{
+ 		rscale = select_div_scale(&vsumX2, &vN);
+ 		div_var(&vsumX2, &vN, &vsumX, rscale, true);
+ 
+ 		res = make_result(&vsumX);
+ 	}
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumX2);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_regr_syy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N,
+ 				sumY,
+ 				sumY2,
+ 				res;
+ 	NumericVar	vN,
+ 				vsumY,
+ 				vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 3)
+ 		elog(ERROR, "expected 3-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumY = DatumGetNumeric(transdatums[1]);
+ 	sumY2 = DatumGetNumeric(transdatums[2]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumY2))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumY.dscale * 2;
+ 
+ 	mul_var(&vsumY, &vsumY, &vsumY, rscale);	/* vsumY = sumY * sumY */
+ 	mul_var(&vN, &vsumY2, &vsumY2, rscale);		/* vsumY2 = N * sumY2 */
+ 	sub_var(&vsumY2, &vsumY, &vsumY2);			/* N * sumY2 - sumY * sumY */
+ 
+ 	if (cmp_var(&vsumY2, &const_zero) <= 0)
+ 	{
+ 		/* Watch out for roundoff error producing a negative numerator */
+ 		res = make_result(&const_zero);
+ 	}
+ 	else
+ 	{
+ 		rscale = select_div_scale(&vsumY2, &vN);
+ 		div_var(&vsumY2, &vN, &vsumY, rscale, true);	/* variance */
+ 
+ 		res = make_result(&vsumY);
+ 	}
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumY);
+ 	free_var(&vsumY2);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_regr_sxy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumY = DatumGetNumeric(transdatums[2]);
+ 	sumXY = DatumGetNumeric(transdatums[3]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vsumY, rscale);	/* vsumY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vsumY, &vsumXY);			/* N * sumXY - sumX * sumY */
+ 
+ 	rscale = select_div_scale(&vsumXY, &vN);
+ 	div_var(&vsumXY, &vN, &vsumY, rscale, true);	/* variance */
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_covar_samp(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vNminus1;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumY = DatumGetNumeric(transdatums[2]);
+ 	sumXY = DatumGetNumeric(transdatums[3]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 	init_var(&vNminus1);
+ 	sub_var(&vN, &const_one, &vNminus1);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vNminus1, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vNminus1);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vsumY, rscale);	/* vsumY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vsumY, &vsumXY);			/* N * sumXY - sumX * sumY */
+ 
+ 	mul_var(&vN, &vNminus1, &vNminus1, 0);				/* N * (N - 1) */
+ 	rscale = select_div_scale(&vsumXY, &vNminus1);
+ 	div_var(&vsumXY, &vNminus1, &vsumY, rscale, true);
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vNminus1);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_covar_pop(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumY = DatumGetNumeric(transdatums[2]);
+ 	sumXY = DatumGetNumeric(transdatums[3]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vsumY, rscale);	/* vsumY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vsumY, &vsumXY);			/* N * sumXY - sumX * sumY */
+ 
+ 	mul_var(&vN, &vN, &vN, 0);				/* N * N */
+ 	rscale = select_div_scale(&vsumXY, &vN);
+ 	div_var(&vsumXY, &vN, &vsumY, rscale, true);
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_corr(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 	
+ 	mul_var(&vsumX, &vsumY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vtmpXY, &vsumXY);			/* vsumXY = N * sumXY - sumX * sumY */
+ 	
+ 	rscale = vsumXY.dscale * 2;
+ 	mul_var(&vsumXY, &vsumXY, &vsumXY, rscale);
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 
+ 	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */
+ 	sub_var(&vsumX2, &vsumX, &vsumX2);			/* vsumX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = 2 * vsumY.dscale;
+ 
+ 	mul_var(&vsumY, &vsumY, &vsumY, rscale);	/* vsumY = sumY * sumY */
+ 	mul_var(&vN, &vsumY2, &vsumY2, rscale);		/* vsumY2 = N * sumY2 */
+ 	sub_var(&vsumY2, &vsumY, &vsumY2);			/* vsumY2 = N * sumY2 - sumY * sumY */
+ 
+ 	if (cmp_var(&vsumY2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 	rscale = vsumY2.dscale + vsumX2.dscale;
+ 	mul_var(&vsumX2, &vsumY2, &vsumY2, rscale);	/* vsumY2 = sumX2 * sumY2 */
+ 
+ 	rscale = select_div_scale(&vsumXY, &vsumY2);
+ 	div_var(&vsumXY, &vsumY2, &vsumY, rscale, true);	/* variance */
+ 
+ 	sqrt_var(&vsumY, &vsumY, rscale);
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_regr_r2(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vtmpXY, &vsumXY);			/* vtmpXY = N * sumXY - sumX * sumY */
+ 
+ 	rscale = vsumXY.dscale * 2;
+ 	mul_var(&vsumXY, &vsumXY, &vsumXY, rscale);
+ 
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 
+ 	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */
+ 	sub_var(&vsumX2, &vsumX, &vsumX2);			/* vsumX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = 2 * vsumY.dscale;
+ 
+ 	mul_var(&vsumY, &vsumY, &vsumY, rscale);	/* vsumY = sumY * sumY */
+ 	mul_var(&vN, &vsumY2, &vsumY2, rscale);		/* vsumY2 = N * sumY2 */
+ 	sub_var(&vsumY2, &vsumY, &vsumY2);			/* vsumY2 = N * sumY2 - sumY * sumY */
+ 
+ 	if (cmp_var(&vsumY2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = vsumY2.dscale + vsumX2.dscale;
+ 	mul_var(&vsumX2, &vsumY2, &vsumY2, rscale);	/* vsumY2 = sumX2 * sumY2 */
+ 
+ 	rscale = select_div_scale(&vsumXY, &vsumY2);
+ 	div_var(&vsumXY, &vsumY2, &vsumY, rscale, true);	/* variance */
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_regr_slope(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vtmpXY, &vsumXY);			/* vtmpXY = N * sumXY - sumX * sumY */
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 
+ 	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */
+ 	sub_var(&vsumX2, &vsumX, &vsumX2);			/* vsumX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = select_div_scale(&vsumXY, &vsumX2);
+ 	div_var(&vsumXY, &vsumX2, &vsumX, rscale, true);	/* variance */
+ 
+ 	res = make_result(&vsumX);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_regr_intercept(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2, vtmpX, vtmpX2, vtmpY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 	init_var(&vtmpX2);
+ 	init_var(&vtmpY2);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumXY.dscale;
+ 	mul_var(&vsumX, &vsumXY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumXY */
+ 	rscale = vsumY.dscale + vsumX2.dscale;
+ 	mul_var(&vsumY, &vsumX2, &vtmpY2, rscale);		/* vtmpY2 = vsumY * sumX2 */
+ 	sub_var(&vtmpY2, &vtmpXY, &vtmpXY);			/* vtmpXY = vsumY * sumX2 - sumX * sumXY */
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 	mul_var(&vsumX, &vsumX, &vtmpX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vtmpX2, rscale);		/* vtmpX2 = N * sumX2 */
+ 	sub_var(&vtmpX2, &vtmpX, &vtmpX2);			/* vtmpX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vtmpX2);
+ 		free_var(&vtmpY2);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);	
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 	rscale = select_div_scale(&vtmpXY, &vtmpX2);
+ 	div_var(&vtmpXY, &vtmpX2, &vsumX, rscale, true);
+ 
+ 	res = make_result(&vsumX);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vtmpX2);
+ 	free_var(&vtmpY2);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
  Datum
  numeric_var_samp(PG_FUNCTION_ARGS)
  {
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.228
diff -c -r1.228 ruleutils.c
*** src/backend/utils/adt/ruleutils.c	14 Jul 2006 14:52:24 -0000	1.228
--- src/backend/utils/adt/ruleutils.c	24 Jul 2006 09:35:13 -0000
***************
*** 3880,3894 ****
  get_agg_expr(Aggref *aggref, deparse_context *context)
  {
  	StringInfo	buf = context->buf;
! 	Oid			argtype = exprType((Node *) aggref->target);
  
  	appendStringInfo(buf, "%s(%s",
! 					 generate_function_name(aggref->aggfnoid, 1, &argtype),
  					 aggref->aggdistinct ? "DISTINCT " : "");
  	if (aggref->aggstar)
  		appendStringInfo(buf, "*");
  	else
! 		get_rule_expr((Node *) aggref->target, context, true);
  	appendStringInfoChar(buf, ')');
  }
  
--- 3880,3908 ----
  get_agg_expr(Aggref *aggref, deparse_context *context)
  {
  	StringInfo	buf = context->buf;
! 	Oid			argtypes[FUNC_MAX_ARGS];
! 	int			nargs;
! 	ListCell   *l;
! 
! 	nargs = 0;
! 	foreach(l, aggref->args)
! 	{
! 		if (nargs >= FUNC_MAX_ARGS)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! 					 errmsg("too many arguments")));
! 		argtypes[nargs] = exprType((Node *) lfirst(l));
! 		nargs++;
! 	}
  
  	appendStringInfo(buf, "%s(%s",
! 					 generate_function_name(aggref->aggfnoid, nargs, argtypes),
  					 aggref->aggdistinct ? "DISTINCT " : "");
+ 	/* aggstar can be set only in one-argument aggregates */
  	if (aggref->aggstar)
  		appendStringInfo(buf, "*");
  	else
! 		get_rule_expr((Node *) aggref->args, context, true);
  	appendStringInfoChar(buf, ')');
  }
  
Index: src/include/catalog/pg_aggregate.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_aggregate.h,v
retrieving revision 1.55
diff -c -r1.55 pg_aggregate.h
*** src/include/catalog/pg_aggregate.h	21 Jul 2006 20:51:33 -0000	1.55
--- src/include/catalog/pg_aggregate.h	24 Jul 2006 09:36:12 -0000
***************
*** 194,199 ****
--- 194,240 ----
  DATA(insert ( 2158	float8_accum	float8_stddev_samp	0	1022	"{0,0,0}" ));
  DATA(insert ( 2159	numeric_accum	numeric_stddev_samp	0	1231	"{0,0,0}" ));
  
+ DATA(insert ( 2800	numeric_regr_count_accum	-	0	20	0 ));
+ DATA(insert ( 2801	float8_regr_count_accum	-	0	20	0 ));
+ DATA(insert ( 2802	float4_regr_sxx_accum	float8_regr_sxx	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2803	float4_regr_syy_accum	float8_regr_syy	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2804	float4_regr_sxy_accum	float8_regr_sxy	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2805	float4_regr_avgx_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ DATA(insert ( 2806	float4_regr_avgy_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ 
+ DATA(insert ( 2807	float8_regr_sxx_accum	float8_regr_sxx	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2808	float8_regr_syy_accum	float8_regr_syy	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2809	float8_regr_sxy_accum	float8_regr_sxy	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2810	float8_regr_avgx_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ DATA(insert ( 2811	float8_regr_avgy_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ 
+ DATA(insert ( 2812	numeric_regr_sxx_accum	numeric_regr_sxx	0	1231	"{0,0,0}" ));
+ DATA(insert ( 2813	numeric_regr_syy_accum	numeric_regr_syy	0	1231	"{0,0,0}" ));
+ DATA(insert ( 2814	numeric_regr_sxy_accum	numeric_regr_sxy	0	1231	"{0,0,0,0}" ));
+ DATA(insert ( 2815	numeric_regr_avgx_accum	numeric_regr_avg	0	1231	"{0,0}" ));
+ DATA(insert ( 2816	numeric_regr_avgy_accum	numeric_regr_avg	0	1231	"{0,0}" ));
+ 
+ DATA(insert ( 2817	float4_regr_sxy_accum	float8_covar_pop	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2818	float8_regr_sxy_accum	float8_covar_pop	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2819	numeric_regr_sxy_accum	numeric_covar_pop	0	1231	"{0,0,0,0}" ));
+ DATA(insert ( 2820	float4_regr_sxy_accum	float8_covar_samp	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2821	float8_regr_sxy_accum	float8_covar_samp	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2822	numeric_regr_sxy_accum	numeric_covar_samp	0	1231	"{0,0,0,0}" ));
+ 
+ DATA(insert ( 2823	float4_regr_all_accum	float8_corr	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2824	float8_regr_all_accum	float8_corr	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2825	numeric_regr_all_accum	numeric_corr	0	1231	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2826	float4_regr_all_accum	float8_regr_r2	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2827	float8_regr_all_accum	float8_regr_r2	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2828	numeric_regr_all_accum	numeric_regr_r2	0	1231	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2829	float4_regr_all_accum	float8_regr_slope	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2830	float8_regr_all_accum	float8_regr_slope	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2831	numeric_regr_all_accum	numeric_regr_slope	0	1231	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2832	float4_regr_all_accum	float8_regr_intercept	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2833	float8_regr_all_accum	float8_regr_intercept	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2834	numeric_regr_all_accum	numeric_regr_intercept	0	1231	"{0,0,0,0,0,0}" ));
+ 
+ 
  /* boolean-and and boolean-or */
  DATA(insert ( 2517	booland_statefunc	-			0	16		_null_ ));
  DATA(insert ( 2518	boolor_statefunc	-			0	16		_null_ ));
***************
*** 214,220 ****
   */
  extern void AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid aggBaseType,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
--- 255,262 ----
   */
  extern void AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid *aggBaseTypeArray,
! 				int numArgs,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.416
diff -c -r1.416 pg_proc.h
*** src/include/catalog/pg_proc.h	21 Jul 2006 20:51:33 -0000	1.416
--- src/include/catalog/pg_proc.h	24 Jul 2006 09:36:13 -0000
***************
*** 2728,2733 ****
--- 2728,2827 ----
  DESCR("AVG(int4) transition function");
  DATA(insert OID = 1964 (  int8_avg		   PGNSP PGUID 12 f f t f i 1 1700 "1016" _null_ _null_ _null_	int8_avg - _null_ ));
  DESCR("AVG(int) aggregate final function");
+ DATA(insert OID = 2850 (  numeric_regr_count_accum	   PGNSP PGUID 12 f f t f i 3 20 "20 1700 1700" _null_ _null_ _null_ numeric_regr_count_accum - _null_ ));
+ DESCR("REGR_COUNT(numeric) transition function");
+ DATA(insert OID = 2851 (  float8_regr_count_accum	   PGNSP PGUID 12 f f t f i 3 20 "20 701 701" _null_ _null_ _null_ float8_regr_count_accum - _null_ ));
+ DESCR("REGR_COUNT(double, double) transition function");
+ DATA(insert OID = 2852 (  float4_regr_sxx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_sxx_accum - _null_ ));
+ DESCR("REGR_SXX(float, float) aggregate transition function");
+ DATA(insert OID = 2853 (  float4_regr_syy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_syy_accum - _null_ ));
+ DESCR("REGR_SYY(float, float) aggregate transition function");
+ DATA(insert OID = 2854 (  float4_regr_sxy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_sxy_accum - _null_ ));
+ DESCR("REGR_SXY(float, float) aggregate transition function");
+ DATA(insert OID = 2855 (  float4_regr_avgx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_avgx_accum - _null_ ));
+ DESCR("REGR_AVGX(float, float) aggregate transition function");
+ DATA(insert OID = 2856 (  float4_regr_avgy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_avgy_accum - _null_ ));
+ DESCR("REGR_AVGY(float, float) aggregate transition function");
+ DATA(insert OID = 2857 (  float8_regr_sxx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_sxx_accum - _null_ ));
+ DESCR("REGR_SXX(double, double) aggregate transition function");
+ DATA(insert OID = 2858 (  float8_regr_syy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_syy_accum - _null_ ));
+ DESCR("REGR_SYY(double, double) aggregate transition function");
+ DATA(insert OID = 2859 (  float8_regr_sxy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_sxy_accum - _null_ ));
+ DESCR("REGR_SXY(double, double) aggregate transition function");
+ DATA(insert OID = 2860 (  float8_regr_avgx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_avgx_accum - _null_ ));
+ DESCR("REGR_AVGX(float, float) aggregate transition function");
+ DATA(insert OID = 2861 (  float8_regr_avgy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_avgy_accum - _null_ ));
+ DESCR("REGR_AVGY(float, float) aggregate transition function");
+ DATA(insert OID = 2862 (  numeric_regr_sxx_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_sxx_accum - _null_ ));
+ DESCR("REGR_SXX(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2863 (  numeric_regr_syy_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_syy_accum - _null_ ));
+ DESCR("REGR_SYY(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2864 (  numeric_regr_sxy_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_sxy_accum - _null_ ));
+ DESCR("REGR_SXY(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2865 (  numeric_regr_avgx_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_avgx_accum - _null_ ));
+ DESCR("REGR_AVGX(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2866 (  numeric_regr_avgy_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_avgy_accum - _null_ ));
+ DESCR("REGR_AVGY(numeric, numeric) aggregate transition function");
+ 
+ DATA(insert OID = 2867 (  float8_regr_sxx	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_sxx - _null_ ));
+ DESCR("REGR_SXX(double, double) aggregate final function");
+ DATA(insert OID = 2868 (  float8_regr_syy	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_syy - _null_ ));
+ DESCR("REGR_SYY(double, double) aggregate final function");
+ DATA(insert OID = 2869 (  float8_regr_sxy	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_sxy - _null_ ));
+ DESCR("REGR_SXY(double, double) aggregate final function");
+ DATA(insert OID = 2870 (  float8_regr_avg	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_avg - _null_ ));
+ DESCR("REGR_AVGX(double, double) AND REGR_AVGY(double,double) aggregate final function");
+ 
+ DATA(insert OID = 2871 (  numeric_regr_sxx	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_sxx - _null_ ));
+ DESCR("REGR_SXX(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2872 (  numeric_regr_syy	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_syy - _null_ ));
+ DESCR("REGR_SYY(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2873 (  numeric_regr_sxy	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_sxy - _null_ ));
+ DESCR("REGR_SXY(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2874 (  numeric_regr_avg	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_avg - _null_ ));
+ DESCR("REGR_AVGX(numeric, numeric) AND REGR_AVGY(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2875 (  float8_covar_samp	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_covar_samp - _null_ ));
+ DESCR("COVAR_SAMP(float8, float8) aggregate final function");
+ DATA(insert OID = 2876 (  numeric_covar_samp	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_covar_samp - _null_ ));
+ DESCR("COVAR_SAMP(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2877 (  float8_covar_pop	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_covar_pop - _null_ ));
+ DESCR("COVAR_POP(float8, float8) aggregate final function");
+ DATA(insert OID = 2878 (  numeric_covar_pop	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_covar_pop - _null_ ));
+ DESCR("COVAR_POP(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2879 (  float4_regr_all_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_all_accum - _null_ ));
+ DESCR("REGR_...(float4, float4) aggregate transition function");
+ DATA(insert OID = 2880 (  float8_regr_all_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_all_accum - _null_ ));
+ DESCR("REGR_...(float8, float8) aggregate transition function");
+ DATA(insert OID = 2881 (  numeric_regr_all_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_all_accum - _null_ ));
+ DESCR("REGR_...(numeric, numeric) aggregate transition function");
+ 
+ DATA(insert OID = 2882 (  float4_corr	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_corr - _null_ ));
+ DESCR("CORR(float4, float4) aggregate final function");
+ DATA(insert OID = 2883 (  float4_regr_r2	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_r2 - _null_ ));
+ DESCR("REGR_R2(float4, float4) aggregate final function");
+ DATA(insert OID = 2884 (  float4_regr_slope	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_slope - _null_ ));
+ DESCR("REGR_SLOPE(float4, float4) aggregate final function");
+ DATA(insert OID = 2885 (  float4_regr_intercept	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_intercept - _null_ ));
+ DESCR("REGR_INTERCEPT(float4, float4) aggregate final function");
+ 
+ DATA(insert OID = 2886 (  float8_corr	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_corr - _null_ ));
+ DESCR("CORR(double, double) aggregate final function");
+ DATA(insert OID = 2887 (  float8_regr_r2	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_r2 - _null_ ));
+ DESCR("REGR_R2(double, double) aggregate final function");
+ DATA(insert OID = 2888 (  float8_regr_slope	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_slope - _null_ ));
+ DESCR("REGR_SLOPE(double, double) aggregate final function");
+ DATA(insert OID = 2889 (  float8_regr_intercept	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_intercept - _null_ ));
+ DESCR("REGR_INTERCEPT(double, double) aggregate final function");
+ 
+ DATA(insert OID = 2890 (  numeric_corr	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_corr - _null_ ));
+ DESCR("CORR(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2891 (  numeric_regr_r2	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_r2 - _null_ ));
+ DESCR("REGR_R2(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2892 (  numeric_regr_slope	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_slope - _null_ ));
+ DESCR("REGR_SLOPE(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2893 (  numeric_regr_intercept	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_intercept - _null_ ));
+ DESCR("REGR_INTERCEPT(numeric, numeric) aggregate final function");
+ 
  
  /* To ASCII conversion */
  DATA(insert OID = 1845 ( to_ascii	PGNSP PGUID 12 f f t f i 1	25 "25" _null_ _null_ _null_	to_ascii_default - _null_ ));
***************
*** 3192,3197 ****
--- 3286,3330 ----
  DATA(insert OID = 2158 (  stddev			PGNSP PGUID 12 t f f f i 1 701 "701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
  DATA(insert OID = 2159 (  stddev			PGNSP PGUID 12 t f f f i 1 1700 "1700" _null_ _null_ _null_ aggregate_dummy - _null_ ));
  
+ DATA(insert OID = 2800 (  regr_count		PGNSP PGUID 12 t f f f i 2 20 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2801 (  regr_count		PGNSP PGUID 12 t f f f i 2 20 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2802 (  regr_sxx		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2803 (  regr_syy		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2804 (  regr_sxy		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2805 (  regr_avgx		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2806 (  regr_avgy		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2807 (  regr_sxx		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2808 (  regr_syy		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2809 (  regr_sxy		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2810 (  regr_avgx		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2811 (  regr_avgy		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2812 (  regr_sxx		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2813 (  regr_syy		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2814 (  regr_sxy		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2815 (  regr_avgx		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2816 (  regr_avgy		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ 
+ DATA(insert OID = 2817 (  covar_pop		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2818 (  covar_pop		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2819 (  covar_pop		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2820 (  covar_samp		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2821 (  covar_samp		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2822 (  covar_samp		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ 
+ DATA(insert OID = 2823 (  corr		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2824 (  corr		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2825 (  corr		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2826 (  regr_r2		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2827 (  regr_r2		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2828 (  regr_r2		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2829 (  regr_slope		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2830 (  regr_slope		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2831 (  regr_slope		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2832 (  regr_intercept		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2833 (  regr_intercept		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2834 (  regr_intercept		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ 
+ 
  DATA(insert OID = 2160 ( text_pattern_lt	 PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_lt - _null_ ));
  DATA(insert OID = 2161 ( text_pattern_le	 PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_le - _null_ ));
  DATA(insert OID = 2162 ( text_pattern_eq	 PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_eq - _null_ ));
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.153
diff -c -r1.153 execnodes.h
*** src/include/nodes/execnodes.h	13 Jul 2006 16:49:19 -0000	1.153
--- src/include/nodes/execnodes.h	24 Jul 2006 09:36:13 -0000
***************
*** 449,455 ****
  typedef struct AggrefExprState
  {
  	ExprState	xprstate;
! 	ExprState  *target;			/* state of my child node */
  	int			aggno;			/* ID number for agg within its plan node */
  } AggrefExprState;
  
--- 449,455 ----
  typedef struct AggrefExprState
  {
  	ExprState	xprstate;
! 	List	   *args;			/* states of argument expressions */
  	int			aggno;			/* ID number for agg within its plan node */
  } AggrefExprState;
  
Index: src/include/nodes/primnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/primnodes.h,v
retrieving revision 1.114
diff -c -r1.114 primnodes.h
*** src/include/nodes/primnodes.h	13 Jul 2006 16:49:19 -0000	1.114
--- src/include/nodes/primnodes.h	24 Jul 2006 09:36:14 -0000
***************
*** 184,190 ****
  	Expr		xpr;
  	Oid			aggfnoid;		/* pg_proc Oid of the aggregate */
  	Oid			aggtype;		/* type Oid of result of the aggregate */
! 	Expr	   *target;			/* expression we are aggregating on */
  	Index		agglevelsup;	/* > 0 if agg belongs to outer query */
  	bool		aggstar;		/* TRUE if argument was really '*' */
  	bool		aggdistinct;	/* TRUE if it's agg(DISTINCT ...) */
--- 184,190 ----
  	Expr		xpr;
  	Oid			aggfnoid;		/* pg_proc Oid of the aggregate */
  	Oid			aggtype;		/* type Oid of result of the aggregate */
! 	List	   *args;			/* arguments to the function */
  	Index		agglevelsup;	/* > 0 if agg belongs to outer query */
  	bool		aggstar;		/* TRUE if argument was really '*' */
  	bool		aggdistinct;	/* TRUE if it's agg(DISTINCT ...) */
Index: src/include/parser/parse_agg.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/parser/parse_agg.h,v
retrieving revision 1.33
diff -c -r1.33 parse_agg.h
*** src/include/parser/parse_agg.h	5 Mar 2006 15:58:57 -0000	1.33
--- src/include/parser/parse_agg.h	24 Jul 2006 09:36:14 -0000
***************
*** 19,25 ****
  
  extern void parseCheckAggregates(ParseState *pstate, Query *qry);
  
! extern void build_aggregate_fnexprs(Oid agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
--- 19,25 ----
  
  extern void parseCheckAggregates(ParseState *pstate, Query *qry);
  
! extern void build_aggregate_fnexprs(Oid *agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
Index: src/include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.280
diff -c -r1.280 builtins.h
*** src/include/utils/builtins.h	21 Jul 2006 20:51:33 -0000	1.280
--- src/include/utils/builtins.h	24 Jul 2006 09:36:14 -0000
***************
*** 368,373 ****
--- 368,389 ----
  extern Datum float84le(PG_FUNCTION_ARGS);
  extern Datum float84gt(PG_FUNCTION_ARGS);
  extern Datum float84ge(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_count_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxx_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_syy_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxy_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_avgx_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_avgy_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_sxx_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_syy_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_sxy_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_avgx_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_avgy_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxx(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_syy(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxy(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_avg(PG_FUNCTION_ARGS);
+ 
  
  /* dbsize.c */
  extern Datum pg_tablespace_size_oid(PG_FUNCTION_ARGS);
***************
*** 836,841 ****
--- 852,885 ----
  extern Datum int4_avg_accum(PG_FUNCTION_ARGS);
  extern Datum int8_avg(PG_FUNCTION_ARGS);
  extern Datum width_bucket_numeric(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_count_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxx_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_syy_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxy_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_avgx_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_avgy_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxx(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_syy(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxy(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_avg(PG_FUNCTION_ARGS);
+ extern Datum numeric_covar_pop(PG_FUNCTION_ARGS);
+ extern Datum numeric_covar_samp(PG_FUNCTION_ARGS);
+ extern Datum float8_covar_pop(PG_FUNCTION_ARGS);
+ extern Datum float8_covar_samp(PG_FUNCTION_ARGS);
+ 
+ extern Datum float4_regr_all_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_all_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_corr(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_r2(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_slope(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_intercept(PG_FUNCTION_ARGS);
+ 
+ extern Datum numeric_regr_all_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_corr(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_r2(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_slope(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_intercept(PG_FUNCTION_ARGS);
+ 
  
  /* ri_triggers.c */
  extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
Index: src/test/regress/expected/opr_sanity.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/opr_sanity.out,v
retrieving revision 1.64
diff -c -r1.64 opr_sanity.out
*** src/test/regress/expected/opr_sanity.out	11 Jul 2006 19:49:14 -0000	1.64
--- src/test/regress/expected/opr_sanity.out	24 Jul 2006 09:36:30 -0000
***************
*** 72,77 ****
--- 72,78 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
+     p1.proisagg = false AND p2.proisagg = false AND
      (p1.prolang != p2.prolang OR
       p1.proisagg != p2.proisagg OR
       p1.prosecdef != p2.prosecdef OR
***************
*** 617,623 ****
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.pronargs != 1 OR p.proretset);
   aggfnoid | proname 
  ----------+---------
  (0 rows)
--- 618,624 ----
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.proretset);
   aggfnoid | proname 
  ----------+---------
  (0 rows)
***************
*** 650,656 ****
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs = 2 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
--- 651,657 ----
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs > 1 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
Index: src/test/regress/sql/opr_sanity.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/opr_sanity.sql,v
retrieving revision 1.50
diff -c -r1.50 opr_sanity.sql
*** src/test/regress/sql/opr_sanity.sql	2 May 2006 11:28:56 -0000	1.50
--- src/test/regress/sql/opr_sanity.sql	24 Jul 2006 09:36:32 -0000
***************
*** 75,80 ****
--- 75,81 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
+     p1.proisagg = false AND p2.proisagg = false AND
      (p1.prolang != p2.prolang OR
       p1.proisagg != p2.proisagg OR
       p1.prosecdef != p2.prosecdef OR
***************
*** 515,521 ****
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.pronargs != 1 OR p.proretset);
  
  -- Make sure there are no proisagg pg_proc entries without matches.
  
--- 516,522 ----
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.proretset);
  
  -- Make sure there are no proisagg pg_proc entries without matches.
  
***************
*** 541,547 ****
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs = 2 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
--- 542,548 ----
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs > 1 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Sergey E. Koposov (#1)
Re: patch implementing the multi-argument aggregates (SOC project)

"Sergey E. Koposov" <math@sai.msu.ru> writes:

Since the feature freeze is in a few days, I'm sending the first iteration
of my patch implementing the multi-argument aggregates (PolyArgAgg) (SOC
project)

This patch is nowhere near ready for submission :-(. Most of the
comments seem to be "I don't know what to do here" ...

A general hint on the polymorphic stuff is that you should be able to
exactly duplicate what's done for polymorphic functions --- or even
better, get rid of the separate code for aggregates and just invoke
the existing logic for functions. (You might need to refactor code
a little bit to separate out the common functionality.)

Instead of copying data inside advance_transition_function, it might
be better for the caller to store the values into the right fields
of a temporary FunctionCallInfoData struct, and just pass that to
advance_transition_function.

The names for the new aggregates seem a bit, how to say, terse and
unfriendly. SQL generally tends to a more verbose style of naming.

regards, tom lane

#3Sergey E. Koposov
math@sai.msu.ru
In reply to: Tom Lane (#2)
Re: patch implementing the multi-argument aggregates (SOC

On Mon, 24 Jul 2006, Tom Lane wrote:

"Sergey E. Koposov" <math@sai.msu.ru> writes:

Since the feature freeze is in a few days, I'm sending the first iteration
of my patch implementing the multi-argument aggregates (PolyArgAgg) (SOC
project)

This patch is nowhere near ready for submission :-(. Most of the

:-(
But now at least I know that...

comments seem to be "I don't know what to do here" ...

No that's not quite true... I have only ~ 2-3 such comments, all others
just express that I marked the places where I've had any little doubts
and which I'll check additionally...

A general hint on the polymorphic stuff is that you should be able to
exactly duplicate what's done for polymorphic functions --- or even
better, get rid of the separate code for aggregates and just invoke
the existing logic for functions. (You might need to refactor code
a little bit to separate out the common functionality.)

Instead of copying data inside advance_transition_function, it might
be better for the caller to store the values into the right fields
of a temporary FunctionCallInfoData struct, and just pass that to
advance_transition_function.

Thank you for the hints, I'll think about them...

The names for the new aggregates seem a bit, how to say, terse and
unfriendly. SQL generally tends to a more verbose style of naming.

The names for the functions came from SQL 2003 standart...

Regards,
Sergey

*******************************************************************
Sergey E. Koposov
Max Planck Institute for Astronomy/Sternberg Astronomical Institute
Tel: +49-6221-528-349
Web: http://lnfm1.sai.msu.ru/~math
E-mail: math@sai.msu.ru

#4Sergey E. Koposov
math@sai.msu.ru
In reply to: Tom Lane (#2)
1 attachment(s)
Re: patch implementing the multi-argument aggregates (SOC

Some small clean-up of the patch...

+ implementing the Tom's idea of minimizing the copying of the data inside
advance_transition_function by using the temporary FunctionCallInfoData
(now the computed arguments of the aggregates are putted directly into
proper fcinfo.args fields, ready for the transition function call).

On Mon, 24 Jul 2006, Tom Lane wrote:

Instead of copying data inside advance_transition_function, it might
be better for the caller to store the values into the right fields
of a temporary FunctionCallInfoData struct, and just pass that to
advance_transition_function.

Regards,
Sergey

*******************************************************************
Sergey E. Koposov
Max Planck Institute for Astronomy/Sternberg Astronomical Institute
Tel: +49-6221-528-349
Web: http://lnfm1.sai.msu.ru/~math
E-mail: math@sai.msu.ru

Attachments:

PolyArgAggs1.difftext/plain; charset=US-ASCII; name=PolyArgAggs1.diffDownload
Index: src/backend/catalog/pg_aggregate.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v
retrieving revision 1.81
diff -c -r1.81 pg_aggregate.c
*** src/backend/catalog/pg_aggregate.c	14 Jul 2006 14:52:17 -0000	1.81
--- src/backend/catalog/pg_aggregate.c	25 Jul 2006 09:12:37 -0000
***************
*** 42,48 ****
  void
  AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid aggBaseType,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
--- 42,49 ----
  void
  AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid *aggBaseTypeArray,
! 				int numArgs,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
***************
*** 59,71 ****
  	Oid			sortop = InvalidOid;	/* can be omitted */
  	Oid			rettype;
  	Oid			finaltype;
! 	Oid			fnArgs[2];		/* we only deal with 1- and 2-arg fns */
  	int			nargs_transfn;
  	Oid			procOid;
  	TupleDesc	tupDesc;
  	int			i;
  	ObjectAddress myself,
  				referenced;
  
  	/* sanity checks (caller should have caught these) */
  	if (!aggName)
--- 60,74 ----
  	Oid			sortop = InvalidOid;	/* can be omitted */
  	Oid			rettype;
  	Oid			finaltype;
! 	Oid			*fnArgs;
  	int			nargs_transfn;
  	Oid			procOid;
  	TupleDesc	tupDesc;
  	int			i;
  	ObjectAddress myself,
  				referenced;
+ 	bool		hasAnyArrElOids = false,/* ANYARRAYOID or ANYELEMENTOID */
+ 				hasAnyOids = false;		/* ANYOID */
  
  	/* sanity checks (caller should have caught these) */
  	if (!aggName)
***************
*** 74,99 ****
  	if (!aggtransfnName)
  		elog(ERROR, "aggregate must have a transition function");
  
  	/*
  	 * If transtype is polymorphic, basetype must be polymorphic also; else we
  	 * will have no way to deduce the actual transtype.
  	 */
! 	if ((aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID) &&
! 		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  				 errmsg("cannot determine transition data type"),
  			errdetail("An aggregate using \"anyarray\" or \"anyelement\" as "
  				"transition type must have one of them as its base type.")));
  
  	/* handle transfn */
  	fnArgs[0] = aggTransType;
! 	if (aggBaseType == ANYOID)
  		nargs_transfn = 1;
  	else
  	{
! 		fnArgs[1] = aggBaseType;
! 		nargs_transfn = 2;
  	}
  	transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
  								  &rettype);
--- 77,135 ----
  	if (!aggtransfnName)
  		elog(ERROR, "aggregate must have a transition function");
  
+ 	for(i = 0 ; i < numArgs ; i++)
+ 	{
+ 		if ((aggBaseTypeArray[i] == ANYARRAYOID) ||
+ 			(aggBaseTypeArray[i] == ANYELEMENTOID))
+ 		{
+ 			hasAnyArrElOids = true;
+ 		}
+ 		else if (aggBaseTypeArray[i] == ANYOID)
+ 		{
+ 			hasAnyOids = true;
+ 		}
+ 	}
+ 
  	/*
  	 * If transtype is polymorphic, basetype must be polymorphic also; else we
  	 * will have no way to deduce the actual transtype.
  	 */
! 	if ((!hasAnyArrElOids) &&
! 		(aggTransType == ANYARRAYOID || aggTransType == ANYELEMENTOID))
! 	{
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  				 errmsg("cannot determine transition data type"),
  			errdetail("An aggregate using \"anyarray\" or \"anyelement\" as "
  				"transition type must have one of them as its base type.")));
+ 	}
+ 
+ 	/* 
+ 	 * Currently I disallow the ANYOID types in multi-argument aggregates
+ 	 * Just because I don't see any sense in that ,and because the standart
+ 	 * (if I understand correctly) doesn't allow "*" arguments in polyArgAggs
+ 	 */
+ 	 
+ 	 if ((hasAnyOids) && (numArgs > 1))
+ 	 {
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 				 errmsg("The ANYOID types are not allowed in multi argument aggregates")));
+ 
+ 	 }
  
  	/* handle transfn */
+ 	fnArgs = palloc((numArgs + 1) * sizeof(Oid));
  	fnArgs[0] = aggTransType;
! 	if (aggBaseTypeArray[0] == ANYOID)
  		nargs_transfn = 1;
  	else
  	{
! 		for(i = 1 ; i <= numArgs; i++)
! 		{
! 			fnArgs[i] = aggBaseTypeArray[i - 1];
! 		}
! 		nargs_transfn = numArgs + 1;
  	}
  	transfn = lookup_agg_function(aggtransfnName, nargs_transfn, fnArgs,
  								  &rettype);
***************
*** 129,135 ****
  	 */
  	if (proc->proisstrict && agginitval == NULL)
  	{
! 		if (!IsBinaryCoercible(aggBaseType, aggTransType))
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
--- 165,171 ----
  	 */
  	if (proc->proisstrict && agginitval == NULL)
  	{
! 		if (!IsBinaryCoercible(aggBaseTypeArray[0], aggTransType))
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("must not omit initial value when transition function is strict and transition type is not compatible with input type")));
***************
*** 160,167 ****
  	 * that itself violates the rule against polymorphic result with no
  	 * polymorphic input.)
  	 */
! 	if ((finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID) &&
! 		!(aggBaseType == ANYARRAYOID || aggBaseType == ANYELEMENTOID))
  		ereport(ERROR,
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("cannot determine result data type"),
--- 196,203 ----
  	 * that itself violates the rule against polymorphic result with no
  	 * polymorphic input.)
  	 */
! 	if ((!hasAnyArrElOids)&&
! 		(finaltype == ANYARRAYOID || finaltype == ANYELEMENTOID))
  		ereport(ERROR,
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("cannot determine result data type"),
***************
*** 170,184 ****
  
  	/* handle sortop, if supplied */
  	if (aggsortopName)
  		sortop = LookupOperName(NULL, aggsortopName,
! 								aggBaseType, aggBaseType,
  								false, -1);
! 
  	/*
  	 * Everything looks okay.  Try to create the pg_proc entry for the
  	 * aggregate.  (This could fail if there's already a conflicting entry.)
  	 */
! 	fnArgs[0] = aggBaseType;
  
  	procOid = ProcedureCreate(aggName,
  							  aggNamespace,
--- 206,228 ----
  
  	/* handle sortop, if supplied */
  	if (aggsortopName)
+ 	{
+ 		if (numArgs != 1)
+ 		{
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
+ 					errmsg("The sort operator cannot be used in"
+ 					" multi argument aggregates")));
+ 		} 
  		sortop = LookupOperName(NULL, aggsortopName,
! 								aggBaseTypeArray[0], aggBaseTypeArray[0],
  								false, -1);
! 	}
  	/*
  	 * Everything looks okay.  Try to create the pg_proc entry for the
  	 * aggregate.  (This could fail if there's already a conflicting entry.)
  	 */
! 
  
  	procOid = ProcedureCreate(aggName,
  							  aggNamespace,
***************
*** 195,201 ****
  							  false,	/* isStrict (not needed for agg) */
  							  PROVOLATILE_IMMUTABLE,	/* volatility (not
  														 * needed for agg) */
! 							  buildoidvector(fnArgs, 1),		/* paramTypes */
  							  PointerGetDatum(NULL),	/* allParamTypes */
  							  PointerGetDatum(NULL),	/* parameterModes */
  							  PointerGetDatum(NULL));	/* parameterNames */
--- 239,246 ----
  							  false,	/* isStrict (not needed for agg) */
  							  PROVOLATILE_IMMUTABLE,	/* volatility (not
  														 * needed for agg) */
! 							  buildoidvector(aggBaseTypeArray,
! 							  				 numArgs),	/* paramTypes */
  							  PointerGetDatum(NULL),	/* allParamTypes */
  							  PointerGetDatum(NULL),	/* parameterModes */
  							  PointerGetDatum(NULL));	/* parameterNames */
***************
*** 279,284 ****
--- 324,331 ----
  	Oid		   *true_oid_array;
  	FuncDetailCode fdresult;
  	AclResult	aclresult;
+ 	int			i;
+ 	bool		allANY = true;
  
  	/*
  	 * func_get_detail looks up the function in the catalogs, does
***************
*** 302,315 ****
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("function %s returns a set",
  						func_signature_string(fnName, nargs, input_types))));
  
  	/*
  	 * If the given type(s) are all polymorphic, there's nothing we can check.
  	 * Otherwise, enforce consistency, and possibly refine the result type.
  	 */
! 	if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) &&
! 		(nargs == 1 ||
! 		 (input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID)))
  	{
  		/* nothing to check here */
  	}
--- 349,370 ----
  				(errcode(ERRCODE_DATATYPE_MISMATCH),
  				 errmsg("function %s returns a set",
  						func_signature_string(fnName, nargs, input_types))));
+ 	
+ 	for (i = 0; i < nargs ; i++)
+ 	{
+ 		if (input_types[i] != ANYARRAYOID &&
+ 			input_types[i] != ANYELEMENTOID)
+ 		{
+ 			allANY = false;
+ 			break;
+ 		}
+ 	}
  
  	/*
  	 * If the given type(s) are all polymorphic, there's nothing we can check.
  	 * Otherwise, enforce consistency, and possibly refine the result type.
  	 */
! 	if (allANY)
  	{
  		/* nothing to check here */
  	}
***************
*** 325,346 ****
  	 * func_get_detail will find functions requiring run-time argument type
  	 * coercion, but nodeAgg.c isn't prepared to deal with that
  	 */
! 	if (true_oid_array[0] != ANYARRAYOID &&
! 		true_oid_array[0] != ANYELEMENTOID &&
! 		!IsBinaryCoercible(input_types[0], true_oid_array[0]))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_DATATYPE_MISMATCH),
! 				 errmsg("function %s requires run-time type coercion",
! 					 func_signature_string(fnName, nargs, true_oid_array))));
! 
! 	if (nargs == 2 &&
! 		true_oid_array[1] != ANYARRAYOID &&
! 		true_oid_array[1] != ANYELEMENTOID &&
! 		!IsBinaryCoercible(input_types[1], true_oid_array[1]))
! 		ereport(ERROR,
! 				(errcode(ERRCODE_DATATYPE_MISMATCH),
! 				 errmsg("function %s requires run-time type coercion",
! 					 func_signature_string(fnName, nargs, true_oid_array))));
  
  	/* Check aggregate creator has permission to call the function */
  	aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
--- 380,397 ----
  	 * func_get_detail will find functions requiring run-time argument type
  	 * coercion, but nodeAgg.c isn't prepared to deal with that
  	 */
! 	for (i = 0; i < nargs; i++)
! 	{
! 		if (true_oid_array[i] != ANYARRAYOID &&
! 			true_oid_array[i] != ANYELEMENTOID &&
! 			!IsBinaryCoercible(input_types[i], true_oid_array[i]))
! 		{
! 			ereport(ERROR,
! 					(errcode(ERRCODE_DATATYPE_MISMATCH),
! 					 errmsg("function %s requires run-time type coercion",
! 						 func_signature_string(fnName, nargs, true_oid_array))));
! 		}
! 	}
  
  	/* Check aggregate creator has permission to call the function */
  	aclresult = pg_proc_aclcheck(fnOid, GetUserId(), ACL_EXECUTE);
Index: src/backend/commands/aggregatecmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v
retrieving revision 1.37
diff -c -r1.37 aggregatecmds.c
*** src/backend/commands/aggregatecmds.c	14 Jul 2006 14:52:18 -0000	1.37
--- src/backend/commands/aggregatecmds.c	25 Jul 2006 09:12:38 -0000
***************
*** 57,65 ****
  	TypeName   *baseType = NULL;
  	TypeName   *transType = NULL;
  	char	   *initval = NULL;
! 	Oid			baseTypeId;
  	Oid			transTypeId;
  	ListCell   *pl;
  
  	/* Convert list of names to a name and namespace */
  	aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
--- 57,66 ----
  	TypeName   *baseType = NULL;
  	TypeName   *transType = NULL;
  	char	   *initval = NULL;
! 	Oid			*baseTypeIdArray;
  	Oid			transTypeId;
  	ListCell   *pl;
+ 	int 		numArgs;
  
  	/* Convert list of names to a name and namespace */
  	aggNamespace = QualifiedNameGetCreationNamespace(name, &aggName);
***************
*** 131,146 ****
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("aggregate input type must be specified")));
  
  		if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
! 			baseTypeId = ANYOID;
  		else
! 			baseTypeId = typenameTypeId(NULL, baseType);
  	}
  	else
  	{
  		/*
! 		 * New style: args is a list of TypeNames.  For the moment, though,
! 		 * we allow at most one.
  		 */
  		if (baseType != NULL)
  			ereport(ERROR,
--- 132,148 ----
  					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  					 errmsg("aggregate input type must be specified")));
  
+ 		baseTypeIdArray  = palloc(sizeof(Oid)*1);
  		if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
! 			baseTypeIdArray[0] = ANYOID;
  		else
! 			baseTypeIdArray[0] = typenameTypeId(NULL, baseType);
! 		numArgs = 1;
  	}
  	else
  	{
  		/*
! 		 * New style: args is a list of TypeNames.
  		 */
  		if (baseType != NULL)
  			ereport(ERROR,
***************
*** 150,168 ****
  		if (args == NIL)
  		{
  			/* special case for agg(*) */
! 			baseTypeId = ANYOID;
! 		}
! 		else if (list_length(args) != 1)
! 		{
! 			/* temporarily reject > 1 arg */
! 			ereport(ERROR,
! 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 					 errmsg("aggregates can have only one input")));
! 			baseTypeId = InvalidOid;	/* keep compiler quiet */
  		}
  		else
  		{
! 			baseTypeId = typenameTypeId(NULL, (TypeName *) linitial(args));
  		}
  	}
  
--- 152,173 ----
  		if (args == NIL)
  		{
  			/* special case for agg(*) */
! 			baseTypeIdArray  = palloc(sizeof(Oid)*1);
! 			baseTypeIdArray[0] = ANYOID;
! 			numArgs = 1;
  		}
  		else
  		{
! 			int i = 0;
! 			ListCell *lc;
! 			TypeName *curTypeName;
! 			baseTypeIdArray  = palloc(sizeof(Oid)*list_length(args));
! 			foreach (lc, args)
! 			{
! 				curTypeName = lfirst(lc);
! 				baseTypeIdArray[i++] = typenameTypeId(NULL, curTypeName);
! 			}
! 			numArgs = i;
  		}
  	}
  
***************
*** 187,193 ****
  	 */
  	AggregateCreate(aggName,	/* aggregate name */
  					aggNamespace,		/* namespace */
! 					baseTypeId, /* type of data being aggregated */
  					transfuncName,		/* step function name */
  					finalfuncName,		/* final function name */
  					sortoperatorName,	/* sort operator name */
--- 192,199 ----
  	 */
  	AggregateCreate(aggName,	/* aggregate name */
  					aggNamespace,		/* namespace */
! 					baseTypeIdArray, /* type of data being aggregated */
! 					numArgs,
  					transfuncName,		/* step function name */
  					finalfuncName,		/* final function name */
  					sortoperatorName,	/* sort operator name */
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/execQual.c,v
retrieving revision 1.192
diff -c -r1.192 execQual.c
*** src/backend/executor/execQual.c	14 Jul 2006 14:52:19 -0000	1.192
--- src/backend/executor/execQual.c	25 Jul 2006 09:12:47 -0000
***************
*** 3174,3180 ****
  					aggstate->aggs = lcons(astate, aggstate->aggs);
  					naggs = ++aggstate->numaggs;
  
! 					astate->target = ExecInitExpr(aggref->target, parent);
  
  					/*
  					 * Complain if the aggregate's argument contains any
--- 3174,3181 ----
  					aggstate->aggs = lcons(astate, aggstate->aggs);
  					naggs = ++aggstate->numaggs;
  
! 					astate->args = (List *) ExecInitExpr((Expr *)aggref->args,
! 														 parent);
  
  					/*
  					 * Complain if the aggregate's argument contains any
Index: src/backend/executor/nodeAgg.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/nodeAgg.c,v
retrieving revision 1.144
diff -c -r1.144 nodeAgg.c
*** src/backend/executor/nodeAgg.c	14 Jul 2006 14:52:19 -0000	1.144
--- src/backend/executor/nodeAgg.c	25 Jul 2006 09:12:47 -0000
***************
*** 123,128 ****
--- 123,137 ----
  	Oid			inputType;
  	Oid			sortOperator;
  
+ 	int			numArguments;
+ 
+ 	/* 
+ 	 * The preallocated arrays used to store the arguments of Aggs
+ 	 * and the isNull flags.
+ 	 */
+ 	Datum		*newArgValArray;
+ 	bool		*isNullArray;
+ 
  	/*
  	 * fmgr lookup data for input type's equality operator --- only set/used
  	 * when aggregate has DISTINCT flag.
***************
*** 214,220 ****
  static void advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							Datum newVal, bool isNull);
  static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup);
  static void process_sorted_aggregate(AggState *aggstate,
  						 AggStatePerAgg peraggstate,
--- 223,230 ----
  static void advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							FunctionCallInfoData *fcinfo,
! 							int numArguments);
  static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup);
  static void process_sorted_aggregate(AggState *aggstate,
  						 AggStatePerAgg peraggstate,
***************
*** 322,331 ****
  advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							Datum newVal, bool isNull)
  {
- 	FunctionCallInfoData fcinfo;
  	MemoryContext oldContext;
  
  	if (peraggstate->transfn.fn_strict)
  	{
--- 332,343 ----
  advance_transition_function(AggState *aggstate,
  							AggStatePerAgg peraggstate,
  							AggStatePerGroup pergroupstate,
! 							FunctionCallInfoData *fcinfo,
! 							int numArguments)
  {
  	MemoryContext oldContext;
+ 	Datum newComputedTransValue;
+ 	int i;
  
  	if (peraggstate->transfn.fn_strict)
  	{
***************
*** 333,340 ****
  		 * For a strict transfn, nothing happens at a NULL input tuple; we
  		 * just keep the prior transValue.
  		 */
! 		if (isNull)
! 			return;
  		if (pergroupstate->noTransValue)
  		{
  			/*
--- 345,355 ----
  		 * For a strict transfn, nothing happens at a NULL input tuple; we
  		 * just keep the prior transValue.
  		 */
! 		for (i = 1; (i <= numArguments); i++)
! 		{
! 			if (fcinfo->argnull[i])
! 				return;
! 		}
  		if (pergroupstate->noTransValue)
  		{
  			/*
***************
*** 347,353 ****
  			 * do not need to pfree the old transValue, since it's NULL.
  			 */
  			oldContext = MemoryContextSwitchTo(aggstate->aggcontext);
! 			pergroupstate->transValue = datumCopy(newVal,
  												  peraggstate->transtypeByVal,
  												  peraggstate->transtypeLen);
  			pergroupstate->transValueIsNull = false;
--- 362,368 ----
  			 * do not need to pfree the old transValue, since it's NULL.
  			 */
  			oldContext = MemoryContextSwitchTo(aggstate->aggcontext);
! 			pergroupstate->transValue = datumCopy(fcinfo->arg[1],
  												  peraggstate->transtypeByVal,
  												  peraggstate->transtypeLen);
  			pergroupstate->transValueIsNull = false;
***************
*** 373,386 ****
  	/*
  	 * OK to call the transition function
  	 */
! 	InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn), 2,
! 							 (void *) aggstate, NULL);
! 	fcinfo.arg[0] = pergroupstate->transValue;
! 	fcinfo.argnull[0] = pergroupstate->transValueIsNull;
! 	fcinfo.arg[1] = newVal;
! 	fcinfo.argnull[1] = isNull;
  
! 	newVal = FunctionCallInvoke(&fcinfo);
  
  	/*
  	 * If pass-by-ref datatype, must copy the new value into aggcontext and
--- 388,397 ----
  	/*
  	 * OK to call the transition function
  	 */
! 	fcinfo->arg[0] = pergroupstate->transValue;
! 	fcinfo->argnull[0] = pergroupstate->transValueIsNull;
  
! 	newComputedTransValue = FunctionCallInvoke(fcinfo);
  
  	/*
  	 * If pass-by-ref datatype, must copy the new value into aggcontext and
***************
*** 388,399 ****
  	 * first input, we don't need to do anything.
  	 */
  	if (!peraggstate->transtypeByVal &&
! 		DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
  	{
! 		if (!fcinfo.isnull)
  		{
  			MemoryContextSwitchTo(aggstate->aggcontext);
! 			newVal = datumCopy(newVal,
  							   peraggstate->transtypeByVal,
  							   peraggstate->transtypeLen);
  		}
--- 399,410 ----
  	 * first input, we don't need to do anything.
  	 */
  	if (!peraggstate->transtypeByVal &&
! 		DatumGetPointer(newComputedTransValue) != DatumGetPointer(pergroupstate->transValue))
  	{
! 		if (!fcinfo->isnull)
  		{
  			MemoryContextSwitchTo(aggstate->aggcontext);
! 			newComputedTransValue = datumCopy(newComputedTransValue,
  							   peraggstate->transtypeByVal,
  							   peraggstate->transtypeLen);
  		}
***************
*** 401,408 ****
  			pfree(DatumGetPointer(pergroupstate->transValue));
  	}
  
! 	pergroupstate->transValue = newVal;
! 	pergroupstate->transValueIsNull = fcinfo.isnull;
  
  	MemoryContextSwitchTo(oldContext);
  }
--- 412,419 ----
  			pfree(DatumGetPointer(pergroupstate->transValue));
  	}
  
! 	pergroupstate->transValue = newComputedTransValue;
! 	pergroupstate->transValueIsNull = fcinfo->isnull;
  
  	MemoryContextSwitchTo(oldContext);
  }
***************
*** 419,449 ****
  advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
  {
  	ExprContext *econtext = aggstate->tmpcontext;
  	int			aggno;
  
  	for (aggno = 0; aggno < aggstate->numaggs; aggno++)
  	{
! 		AggStatePerAgg peraggstate = &aggstate->peragg[aggno];
! 		AggStatePerGroup pergroupstate = &pergroup[aggno];
! 		AggrefExprState *aggrefstate = peraggstate->aggrefstate;
! 		Aggref	   *aggref = peraggstate->aggref;
! 		Datum		newVal;
! 		bool		isNull;
! 
! 		newVal = ExecEvalExprSwitchContext(aggrefstate->target, econtext,
! 										   &isNull, NULL);
  
  		if (aggref->aggdistinct)
  		{
  			/* in DISTINCT mode, we may ignore nulls */
! 			if (isNull)
  				continue;
! 			tuplesort_putdatum(peraggstate->sortstate, newVal, isNull);
  		}
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										newVal, isNull);
  		}
  	}
  }
--- 430,491 ----
  advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
  {
  	ExprContext *econtext = aggstate->tmpcontext;
+ 	Datum		*newArgValArray;
+ 	bool		*isNullArray;
  	int			aggno;
  
  	for (aggno = 0; aggno < aggstate->numaggs; aggno++)
  	{
! 		AggStatePerAgg		peraggstate = &aggstate->peragg[aggno];
! 		AggStatePerGroup	pergroupstate = &pergroup[aggno];
! 		AggrefExprState		*aggrefstate = peraggstate->aggrefstate;
! 		Aggref				*aggref = peraggstate->aggref;
! 		int					i, numArguments;
! 		ListCell			*arg;
! 		MemoryContext		oldContext;
! 		FunctionCallInfoData fcinfo;
! 		
! 		newArgValArray = peraggstate->newArgValArray;
! 		isNullArray = peraggstate->isNullArray;
! 		numArguments = peraggstate->numArguments;
! 		
! 		i = 0;
! 
! 
! 		/* Switch first to the per-tuple memory context of the expression */
! 		oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
! 		
! 		InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn),
! 								 1 + numArguments, (void *) aggstate,
! 								 NULL);
! 		
! 		i = 1;
! 		/* We start from 1, since the 0th arg will be the transition value */
! 		foreach(arg, aggrefstate->args)
! 		{
! 			ExprState  *argstate = (ExprState *) lfirst(arg);
! 			fcinfo.arg[i] = ExecEvalExpr(argstate, econtext,
! 											 fcinfo.argnull + i, NULL);
! 			i++;
! 		}
! 		
! 		/* Switch back */
! 		MemoryContextSwitchTo(oldContext);
  
  		if (aggref->aggdistinct)
  		{
+ 			/* We use one-argument aggs when in DISTINCT mode */
+ 			
  			/* in DISTINCT mode, we may ignore nulls */
! 			if (fcinfo.argnull[1])
  				continue;
! 			tuplesort_putdatum(peraggstate->sortstate, fcinfo.arg[1],
! 							   fcinfo.argnull[1]);
  		}
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										&fcinfo, numArguments);
  		}
  	}
  }
***************
*** 465,475 ****
  	bool		haveOldVal = false;
  	MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
  	MemoryContext oldContext;
! 	Datum		newVal;
! 	bool		isNull;
  
  	tuplesort_performsort(peraggstate->sortstate);
  
  	/*
  	 * Note: if input type is pass-by-ref, the datums returned by the sort are
  	 * freshly palloc'd in the per-query context, so we must be careful to
--- 507,524 ----
  	bool		haveOldVal = false;
  	MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
  	MemoryContext oldContext;
! 	Datum		*newVal;
! 	bool		*isNull;
! 	FunctionCallInfoData fcinfo;
  
  	tuplesort_performsort(peraggstate->sortstate);
  
+ 	InitFunctionCallInfoData(fcinfo, &(peraggstate->transfn),
+ 							 2, (void *) aggstate,
+ 							 NULL);
+ 	newVal = fcinfo.arg + 1;
+ 	isNull = fcinfo.argnull + 1;
+ 
  	/*
  	 * Note: if input type is pass-by-ref, the datums returned by the sort are
  	 * freshly palloc'd in the per-query context, so we must be careful to
***************
*** 477,489 ****
  	 */
  
  	while (tuplesort_getdatum(peraggstate->sortstate, true,
! 							  &newVal, &isNull))
  	{
  		/*
  		 * DISTINCT always suppresses nulls, per SQL spec, regardless of the
  		 * transition function's strictness.
  		 */
! 		if (isNull)
  			continue;
  
  		/*
--- 526,538 ----
  	 */
  
  	while (tuplesort_getdatum(peraggstate->sortstate, true,
! 							  newVal, isNull))
  	{
  		/*
  		 * DISTINCT always suppresses nulls, per SQL spec, regardless of the
  		 * transition function's strictness.
  		 */
! 		if (*isNull)
  			continue;
  
  		/*
***************
*** 495,515 ****
  
  		if (haveOldVal &&
  			DatumGetBool(FunctionCall2(&peraggstate->equalfn,
! 									   oldVal, newVal)))
  		{
  			/* equal to prior, so forget this one */
  			if (!peraggstate->inputtypeByVal)
! 				pfree(DatumGetPointer(newVal));
  		}
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										newVal, false);
  			/* forget the old value, if any */
  			if (haveOldVal && !peraggstate->inputtypeByVal)
  				pfree(DatumGetPointer(oldVal));
  			/* and remember the new one for subsequent equality checks */
! 			oldVal = newVal;
  			haveOldVal = true;
  		}
  
--- 544,564 ----
  
  		if (haveOldVal &&
  			DatumGetBool(FunctionCall2(&peraggstate->equalfn,
! 									   oldVal, *newVal)))
  		{
  			/* equal to prior, so forget this one */
  			if (!peraggstate->inputtypeByVal)
! 				pfree(DatumGetPointer(*newVal));
  		}
  		else
  		{
  			advance_transition_function(aggstate, peraggstate, pergroupstate,
! 										&fcinfo, 1);
  			/* forget the old value, if any */
  			if (haveOldVal && !peraggstate->inputtypeByVal)
  				pfree(DatumGetPointer(oldVal));
  			/* and remember the new one for subsequent equality checks */
! 			oldVal = *newVal;
  			haveOldVal = true;
  		}
  
***************
*** 1120,1125 ****
--- 1169,1176 ----
  	int			numaggs,
  				aggno;
  	ListCell   *l;
+ 	Oid			*inputTypeArray = 0;
+ 
  
  	/* check for unsupported flags */
  	Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
***************
*** 1286,1292 ****
  		AggrefExprState *aggrefstate = (AggrefExprState *) lfirst(l);
  		Aggref	   *aggref = (Aggref *) aggrefstate->xprstate.expr;
  		AggStatePerAgg peraggstate;
- 		Oid			inputType;
  		HeapTuple	aggTuple;
  		Form_pg_aggregate aggform;
  		Oid			aggtranstype;
--- 1337,1342 ----
***************
*** 1297,1306 ****
--- 1347,1364 ----
  				   *finalfnexpr;
  		Datum		textInitVal;
  		int			i;
+ 		int         numArguments;
+ 		ListCell    *curArgument;
+ 		
  
  		/* Planner should have assigned aggregate to correct level */
  		Assert(aggref->agglevelsup == 0);
  
+ 		
+ 		/* KS XXX Probably it should work even for polyArgAggs, but
+ 		 * it shoud be checked -- I'm not sure that the 
+ 		 * equal(aggref, aggref) works fine for the polyArgAggs
+ 		 */
  		/* Look for a previous duplicate aggregate */
  		for (i = 0; i <= aggno; i++)
  		{
***************
*** 1324,1336 ****
  		/* Fill in the peraggstate data */
  		peraggstate->aggrefstate = aggrefstate;
  		peraggstate->aggref = aggref;
  
  		/*
  		 * Get actual datatype of the input.  We need this because it may be
  		 * different from the agg's declared input type, when the agg accepts
  		 * ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT.
  		 */
! 		inputType = exprType((Node *) aggref->target);
  
  		aggTuple = SearchSysCache(AGGFNOID,
  								  ObjectIdGetDatum(aggref->aggfnoid),
--- 1382,1419 ----
  		/* Fill in the peraggstate data */
  		peraggstate->aggrefstate = aggrefstate;
  		peraggstate->aggref = aggref;
+ 		
+ 		numArguments = list_length(aggref->args);
+ 		peraggstate->numArguments = numArguments;
+ 		if (!inputTypeArray)
+ 		{
+ 			inputTypeArray = (Oid *) palloc(sizeof(Oid) * numArguments);
+ 		}
+ 		else
+ 		{   
+ 			inputTypeArray = (Oid *) repalloc(inputTypeArray,
+ 											  numArguments * sizeof(Oid));
+ 		}
+ 		
+ 		/* Preallocate the arrays for storing the arguments of the Aggs
+ 		 * and the isNull flags
+ 		 */
+ 		peraggstate->newArgValArray = (Datum *) palloc(sizeof(Datum) *
+ 													   numArguments);
+ 		peraggstate->isNullArray = (bool *) palloc(sizeof(bool) *
+ 													numArguments);
  
  		/*
  		 * Get actual datatype of the input.  We need this because it may be
  		 * different from the agg's declared input type, when the agg accepts
  		 * ANY (eg, COUNT(*)) or ANYARRAY or ANYELEMENT.
  		 */
! 		i = 0;
! 		foreach(curArgument, aggref->args)
! 		{
! 			inputTypeArray[i++] = exprType((Node *) lfirst(curArgument));
! 		}
! 
  
  		aggTuple = SearchSysCache(AGGFNOID,
  								  ObjectIdGetDatum(aggref->aggfnoid),
***************
*** 1384,1403 ****
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *agg_arg_types;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &agg_arg_types, &agg_nargs);
! 			Assert(agg_nargs == 1);
! 			aggtranstype = resolve_generic_type(aggtranstype,
! 												inputType,
! 												agg_arg_types[0]);
! 			pfree(agg_arg_types);
  		}
  
  		/* build expression trees using actual argument & result types */
! 		build_aggregate_fnexprs(inputType,
  								aggtranstype,
  								aggref->aggtype,
  								transfn_oid,
--- 1467,1486 ----
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *declaredArgTypes;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &declaredArgTypes, &agg_nargs);
! 			aggtranstype = enforce_generic_type_consistency(inputTypeArray,
! 															declaredArgTypes,
! 															agg_nargs,
! 															aggtranstype);
! 			pfree(declaredArgTypes);
  		}
  
  		/* build expression trees using actual argument & result types */
! 		build_aggregate_fnexprs(inputTypeArray,
  								aggtranstype,
  								aggref->aggtype,
  								transfn_oid,
***************
*** 1444,1450 ****
  		 */
  		if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
  		{
! 			if (!IsBinaryCoercible(inputType, aggtranstype))
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  						 errmsg("aggregate %u needs to have compatible input type and transition type",
--- 1527,1533 ----
  		 */
  		if (peraggstate->transfn.fn_strict && peraggstate->initValueIsNull)
  		{
! 			if (!IsBinaryCoercible(inputTypeArray[0], aggtranstype))
  				ereport(ERROR,
  						(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
  						 errmsg("aggregate %u needs to have compatible input type and transition type",
***************
*** 1457,1476 ****
  
  			/* We don't implement DISTINCT aggs in the HASHED case */
  			Assert(node->aggstrategy != AGG_HASHED);
  
! 			peraggstate->inputType = inputType;
! 			get_typlenbyval(inputType,
  							&peraggstate->inputtypeLen,
  							&peraggstate->inputtypeByVal);
  
! 			eq_function = equality_oper_funcid(inputType);
  			fmgr_info(eq_function, &(peraggstate->equalfn));
! 			peraggstate->sortOperator = ordering_oper_opid(inputType);
  			peraggstate->sortstate = NULL;
  		}
  
  		ReleaseSysCache(aggTuple);
  	}
  
  	/* Update numaggs to match number of unique aggregates found */
  	aggstate->numaggs = aggno + 1;
--- 1540,1569 ----
  
  			/* We don't implement DISTINCT aggs in the HASHED case */
  			Assert(node->aggstrategy != AGG_HASHED);
+ 			
+ 			/* We don't implement the DISTINCT aggs for the aggs having
+ 			 * more than one argument
+ 			 */ 
+ 			Assert(numArguments == 1);
  
! 			peraggstate->inputType = inputTypeArray[0];
! 			get_typlenbyval(inputTypeArray[0],
  							&peraggstate->inputtypeLen,
  							&peraggstate->inputtypeByVal);
  
! 			eq_function = equality_oper_funcid(inputTypeArray[0]);
  			fmgr_info(eq_function, &(peraggstate->equalfn));
! 			peraggstate->sortOperator = ordering_oper_opid(inputTypeArray[0]);
  			peraggstate->sortstate = NULL;
  		}
  
  		ReleaseSysCache(aggTuple);
  	}
+ 	
+ 	if (inputTypeArray)
+ 	{
+ 		pfree(inputTypeArray);
+ 	}
  
  	/* Update numaggs to match number of unique aggregates found */
  	aggstate->numaggs = aggno + 1;
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.343
diff -c -r1.343 copyfuncs.c
*** src/backend/nodes/copyfuncs.c	14 Jul 2006 14:52:19 -0000	1.343
--- src/backend/nodes/copyfuncs.c	25 Jul 2006 09:12:49 -0000
***************
*** 743,749 ****
  
  	COPY_SCALAR_FIELD(aggfnoid);
  	COPY_SCALAR_FIELD(aggtype);
! 	COPY_NODE_FIELD(target);
  	COPY_SCALAR_FIELD(agglevelsup);
  	COPY_SCALAR_FIELD(aggstar);
  	COPY_SCALAR_FIELD(aggdistinct);
--- 743,749 ----
  
  	COPY_SCALAR_FIELD(aggfnoid);
  	COPY_SCALAR_FIELD(aggtype);
! 	COPY_NODE_FIELD(args);
  	COPY_SCALAR_FIELD(agglevelsup);
  	COPY_SCALAR_FIELD(aggstar);
  	COPY_SCALAR_FIELD(aggdistinct);
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.277
diff -c -r1.277 equalfuncs.c
*** src/backend/nodes/equalfuncs.c	14 Jul 2006 14:52:20 -0000	1.277
--- src/backend/nodes/equalfuncs.c	25 Jul 2006 09:12:49 -0000
***************
*** 156,162 ****
  {
  	COMPARE_SCALAR_FIELD(aggfnoid);
  	COMPARE_SCALAR_FIELD(aggtype);
! 	COMPARE_NODE_FIELD(target);
  	COMPARE_SCALAR_FIELD(agglevelsup);
  	COMPARE_SCALAR_FIELD(aggstar);
  	COMPARE_SCALAR_FIELD(aggdistinct);
--- 156,162 ----
  {
  	COMPARE_SCALAR_FIELD(aggfnoid);
  	COMPARE_SCALAR_FIELD(aggtype);
! 	COMPARE_NODE_FIELD(args);
  	COMPARE_SCALAR_FIELD(agglevelsup);
  	COMPARE_SCALAR_FIELD(aggstar);
  	COMPARE_SCALAR_FIELD(aggdistinct);
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.278
diff -c -r1.278 outfuncs.c
*** src/backend/nodes/outfuncs.c	14 Jul 2006 14:52:20 -0000	1.278
--- src/backend/nodes/outfuncs.c	25 Jul 2006 09:12:50 -0000
***************
*** 635,641 ****
  
  	WRITE_OID_FIELD(aggfnoid);
  	WRITE_OID_FIELD(aggtype);
! 	WRITE_NODE_FIELD(target);
  	WRITE_UINT_FIELD(agglevelsup);
  	WRITE_BOOL_FIELD(aggstar);
  	WRITE_BOOL_FIELD(aggdistinct);
--- 635,641 ----
  
  	WRITE_OID_FIELD(aggfnoid);
  	WRITE_OID_FIELD(aggtype);
! 	WRITE_NODE_FIELD(args);
  	WRITE_UINT_FIELD(agglevelsup);
  	WRITE_BOOL_FIELD(aggstar);
  	WRITE_BOOL_FIELD(aggdistinct);
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/readfuncs.c,v
retrieving revision 1.191
diff -c -r1.191 readfuncs.c
*** src/backend/nodes/readfuncs.c	3 Jul 2006 22:45:39 -0000	1.191
--- src/backend/nodes/readfuncs.c	25 Jul 2006 09:12:50 -0000
***************
*** 348,354 ****
  
  	READ_OID_FIELD(aggfnoid);
  	READ_OID_FIELD(aggtype);
! 	READ_NODE_FIELD(target);
  	READ_UINT_FIELD(agglevelsup);
  	READ_BOOL_FIELD(aggstar);
  	READ_BOOL_FIELD(aggdistinct);
--- 348,354 ----
  
  	READ_OID_FIELD(aggfnoid);
  	READ_OID_FIELD(aggtype);
! 	READ_NODE_FIELD(args);
  	READ_UINT_FIELD(agglevelsup);
  	READ_BOOL_FIELD(aggstar);
  	READ_BOOL_FIELD(aggdistinct);
Index: src/backend/optimizer/plan/planagg.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/plan/planagg.c,v
retrieving revision 1.18
diff -c -r1.18 planagg.c
*** src/backend/optimizer/plan/planagg.c	14 Jul 2006 14:52:20 -0000	1.18
--- src/backend/optimizer/plan/planagg.c	25 Jul 2006 09:12:51 -0000
***************
*** 219,224 ****
--- 219,225 ----
  		Oid			aggsortop;
  		MinMaxAggInfo *info;
  		ListCell   *l;
+ 		Expr		*curTarget;
  
  		Assert(aggref->agglevelsup == 0);
  		if (aggref->aggstar)
***************
*** 228,233 ****
--- 229,237 ----
  		aggsortop = fetch_agg_sort_op(aggref->aggfnoid);
  		if (!OidIsValid(aggsortop))
  			return true;		/* not a MIN/MAX aggregate */
+ 		
+ 		/* Here we should have only one arg aggs... Isn't it ? */
+ 		curTarget = linitial(aggref->args);
  
  		/*
  		 * Check whether it's already in the list, and add it if not.
***************
*** 236,249 ****
  		{
  			info = (MinMaxAggInfo *) lfirst(l);
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, aggref->target))
  				return false;
  		}
  
  		info = (MinMaxAggInfo *) palloc0(sizeof(MinMaxAggInfo));
  		info->aggfnoid = aggref->aggfnoid;
  		info->aggsortop = aggsortop;
! 		info->target = aggref->target;
  
  		*context = lappend(*context, info);
  
--- 240,253 ----
  		{
  			info = (MinMaxAggInfo *) lfirst(l);
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, curTarget))
  				return false;
  		}
  
  		info = (MinMaxAggInfo *) palloc0(sizeof(MinMaxAggInfo));
  		info->aggfnoid = aggref->aggfnoid;
  		info->aggsortop = aggsortop;
! 		info->target = curTarget;
  
  		*context = lappend(*context, info);
  
***************
*** 520,532 ****
  	{
  		Aggref	   *aggref = (Aggref *) node;
  		ListCell   *l;
  
  		foreach(l, *context)
  		{
  			MinMaxAggInfo *info = (MinMaxAggInfo *) lfirst(l);
  
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, aggref->target))
  				return (Node *) info->param;
  		}
  		elog(ERROR, "failed to re-find aggregate info record");
--- 524,537 ----
  	{
  		Aggref	   *aggref = (Aggref *) node;
  		ListCell   *l;
+ 		Expr		*curTarget = linitial(aggref->args);
  
  		foreach(l, *context)
  		{
  			MinMaxAggInfo *info = (MinMaxAggInfo *) lfirst(l);
  
  			if (info->aggfnoid == aggref->aggfnoid &&
! 				equal(info->target, curTarget))
  				return (Node *) info->param;
  		}
  		elog(ERROR, "failed to re-find aggregate info record");
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.214
diff -c -r1.214 clauses.c
*** src/backend/optimizer/util/clauses.c	14 Jul 2006 14:52:21 -0000	1.214
--- src/backend/optimizer/util/clauses.c	25 Jul 2006 09:12:52 -0000
***************
*** 397,413 ****
  	if (IsA(node, Aggref))
  	{
  		Aggref	   *aggref = (Aggref *) node;
! 		Oid			inputType;
  		HeapTuple	aggTuple;
  		Form_pg_aggregate aggform;
  		Oid			aggtranstype;
! 
  		Assert(aggref->agglevelsup == 0);
  		counts->numAggs++;
  		if (aggref->aggdistinct)
  			counts->numDistinctAggs++;
  
! 		inputType = exprType((Node *) aggref->target);
  
  		/* fetch aggregate transition datatype from pg_aggregate */
  		aggTuple = SearchSysCache(AGGFNOID,
--- 397,425 ----
  	if (IsA(node, Aggref))
  	{
  		Aggref	   *aggref = (Aggref *) node;
! 		Oid			*inputTypeArray;
  		HeapTuple	aggTuple;
  		Form_pg_aggregate aggform;
  		Oid			aggtranstype;
! 		int			numArguments;
! 		int			i;
! 		ListCell	*curArgument;
! 		
  		Assert(aggref->agglevelsup == 0);
  		counts->numAggs++;
  		if (aggref->aggdistinct)
  			counts->numDistinctAggs++;
  
! 		numArguments = list_length(aggref->args);
! 
! 		inputTypeArray = (Oid *) palloc(sizeof(Oid) * numArguments);
! 		
! 		i = 0;
! 		foreach(curArgument, aggref->args)
! 		{
! 			inputTypeArray[i++] = exprType((Node *) lfirst(curArgument));
! 		}
! 		
  
  		/* fetch aggregate transition datatype from pg_aggregate */
  		aggTuple = SearchSysCache(AGGFNOID,
***************
*** 424,439 ****
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *agg_arg_types;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &agg_arg_types, &agg_nargs);
! 			Assert(agg_nargs == 1);
! 			aggtranstype = resolve_generic_type(aggtranstype,
! 												inputType,
! 												agg_arg_types[0]);
! 			pfree(agg_arg_types);
  		}
  
  		/*
--- 436,452 ----
  		if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID)
  		{
  			/* have to fetch the agg's declared input type... */
! 			Oid		   *declaredArgTypes;
  			int			agg_nargs;
  
  			(void) get_func_signature(aggref->aggfnoid,
! 									  &declaredArgTypes, &agg_nargs);
! 			/* To be thought about what to do with resolve_generic_type */
! 			aggtranstype = enforce_generic_type_consistency(inputTypeArray,
! 															declaredArgTypes,
! 															agg_nargs,
! 															aggtranstype);
! 			pfree(declaredArgTypes);
  		}
  
  		/*
***************
*** 452,459 ****
  			 * same typmod (same width) as well.  This works for cases like
  			 * MAX/MIN and is probably somewhat reasonable otherwise.
  			 */
! 			if (aggtranstype == inputType)
! 				aggtranstypmod = exprTypmod((Node *) aggref->target);
  			else
  				aggtranstypmod = -1;
  
--- 465,472 ----
  			 * same typmod (same width) as well.  This works for cases like
  			 * MAX/MIN and is probably somewhat reasonable otherwise.
  			 */
! 			if (aggtranstype == inputTypeArray[0])
! 				aggtranstypmod = exprTypmod((Node *) linitial(aggref->args));
  			else
  				aggtranstypmod = -1;
  
***************
*** 467,477 ****
  		 * Complain if the aggregate's argument contains any aggregates;
  		 * nested agg functions are semantically nonsensical.
  		 */
- 		if (contain_agg_clause((Node *) aggref->target))
- 			ereport(ERROR,
- 					(errcode(ERRCODE_GROUPING_ERROR),
- 					 errmsg("aggregate function calls may not be nested")));
  
  		/*
  		 * Having checked that, we need not recurse into the argument.
  		 */
--- 480,495 ----
  		 * Complain if the aggregate's argument contains any aggregates;
  		 * nested agg functions are semantically nonsensical.
  		 */
  
+ 		foreach(curArgument, aggref->args)
+ 		{
+ 			if (contain_agg_clause((Node *) lfirst(curArgument)))
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_GROUPING_ERROR),
+ 						 errmsg("aggregate function calls may not be nested")));
+ 		}
+ 		
+ 		pfree(inputTypeArray);
  		/*
  		 * Having checked that, we need not recurse into the argument.
  		 */
***************
*** 3026,3032 ****
  			/* primitive node types with no expression subnodes */
  			break;
  		case T_Aggref:
! 			return walker(((Aggref *) node)->target, context);
  		case T_ArrayRef:
  			{
  				ArrayRef   *aref = (ArrayRef *) node;
--- 3044,3057 ----
  			/* primitive node types with no expression subnodes */
  			break;
  		case T_Aggref:
! 			{
! 				Aggref   *aggref = (Aggref *) node;
! 
! 				if (expression_tree_walker((Node *) aggref->args,
! 										   walker, context))
! 					return true;
! 			}
! 			break;
  		case T_ArrayRef:
  			{
  				ArrayRef   *aref = (ArrayRef *) node;
***************
*** 3448,3454 ****
  				Aggref	   *newnode;
  
  				FLATCOPY(newnode, aggref, Aggref);
! 				MUTATE(newnode->target, aggref->target, Expr *);
  				return (Node *) newnode;
  			}
  			break;
--- 3473,3479 ----
  				Aggref	   *newnode;
  
  				FLATCOPY(newnode, aggref, Aggref);
! 				MUTATE(newnode->args, aggref->args, List *);
  				return (Node *) newnode;
  			}
  			break;
Index: src/backend/parser/parse_agg.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_agg.c,v
retrieving revision 1.72
diff -c -r1.72 parse_agg.c
*** src/backend/parser/parse_agg.c	14 Jul 2006 14:52:21 -0000	1.72
--- src/backend/parser/parse_agg.c	25 Jul 2006 09:12:53 -0000
***************
*** 51,84 ****
  void
  transformAggregateCall(ParseState *pstate, Aggref *agg)
  {
! 	int			min_varlevel;
! 
! 	/*
! 	 * The aggregate's level is the same as the level of the lowest-level
! 	 * variable or aggregate in its argument; or if it contains no variables
! 	 * at all, we presume it to be local.
! 	 */
! 	min_varlevel = find_minimum_var_level((Node *) agg->target);
! 
! 	/*
! 	 * An aggregate can't directly contain another aggregate call of the same
! 	 * level (though outer aggs are okay).	We can skip this check if we
! 	 * didn't find any local vars or aggs.
! 	 */
! 	if (min_varlevel == 0)
  	{
! 		if (checkExprHasAggs((Node *) agg->target))
! 			ereport(ERROR,
! 					(errcode(ERRCODE_GROUPING_ERROR),
! 					 errmsg("aggregate function calls may not be nested")));
  	}
  
! 	if (min_varlevel < 0)
! 		min_varlevel = 0;
! 	agg->agglevelsup = min_varlevel;
  
  	/* Mark the correct pstate as having aggregates */
! 	while (min_varlevel-- > 0)
  		pstate = pstate->parentParseState;
  	pstate->p_hasAggs = true;
  }
--- 51,98 ----
  void
  transformAggregateCall(ParseState *pstate, Aggref *agg)
  {
! 	int			minVarLevel,
! 				minMinVarLevel = -1;
! 	ListCell	*curArgument;
! 	foreach(curArgument, agg->args)
  	{
! 		Node	*curNode = (Node *)lfirst(curArgument);
! 		/*
! 		 * The aggregate's level is the same as the level of the lowest-level
! 		 * variable or aggregate in its argument; or if it contains no variables
! 		 * at all, we presume it to be local.
! 		 */
! 		minVarLevel = find_minimum_var_level(curNode);
! 	
! 		/*
! 		 * An aggregate can't directly contain another aggregate call of the same
! 		 * level (though outer aggs are okay).	We can skip this check if we
! 		 * didn't find any local vars or aggs.
! 		 */
! 		if (minVarLevel == 0)
! 		{
! 			if (checkExprHasAggs(curNode))
! 				ereport(ERROR,
! 						(errcode(ERRCODE_GROUPING_ERROR),
! 						 errmsg("aggregate function calls may not be nested")));
! 		}
! 		
! /* KS XXX !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!  * !!!!!!!!!!!!!!!Very important!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!  * that logic should be fixed... I don't understand currently how I should
!  * update the minMinVarLevel. Should it be the minimum value among minVarLevels
!  * of different arguments or maximum value among minVarLevels or something else... 
!  * Currently it is just the minVarLevel of the last argument....
!  */	
! 		minMinVarLevel = minVarLevel;
  	}
  
! 	if (minMinVarLevel < 0)
! 		minMinVarLevel = 0;
! 	agg->agglevelsup = minMinVarLevel;
  
  	/* Mark the correct pstate as having aggregates */
! 	while (minMinVarLevel-- > 0)
  		pstate = pstate->parentParseState;
  	pstate->p_hasAggs = true;
  }
***************
*** 371,377 ****
   * *finalfnexpr.  The latter is set to NULL if there's no finalfn.
   */
  void
! build_aggregate_fnexprs(Oid agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
--- 385,391 ----
   * *finalfnexpr.  The latter is set to NULL if there's no finalfn.
   */
  void
! build_aggregate_fnexprs(Oid *agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
***************
*** 379,392 ****
  						Expr **transfnexpr,
  						Expr **finalfnexpr)
  {
! 	int			transfn_nargs;
  	Param	   *arg0;
  	Param	   *arg1;
  	List	   *args;
  
  	/* get the transition function arg count */
  	transfn_nargs = get_func_nargs(transfn_oid);
! 
  	/*
  	 * Build arg list to use in the transfn FuncExpr node. We really only care
  	 * that transfn can discover the actual argument types at runtime using
--- 393,409 ----
  						Expr **transfnexpr,
  						Expr **finalfnexpr)
  {
! 	int			transfn_nargs,
! 				aggfn_nargs,
! 				i;
  	Param	   *arg0;
  	Param	   *arg1;
  	List	   *args;
  
  	/* get the transition function arg count */
  	transfn_nargs = get_func_nargs(transfn_oid);
! 	aggfn_nargs = transfn_nargs - 1;
! 	
  	/*
  	 * Build arg list to use in the transfn FuncExpr node. We really only care
  	 * that transfn can discover the actual argument types at runtime using
***************
*** 398,403 ****
--- 415,432 ----
  	arg0->paramid = -1;
  	arg0->paramtype = agg_state_type;
  
+     args = list_make1(arg0);
+ 
+     for(i = 0; i < aggfn_nargs; i++)
+     {
+         arg1 = makeNode(Param);
+         arg1->paramkind = PARAM_EXEC;
+         arg1->paramid = -1;
+         arg1->paramtype = agg_input_type[i];
+         lappend(args, arg1);
+     }
+ 
+ /*
  	if (transfn_nargs == 2)
  	{
  		arg1 = makeNode(Param);
***************
*** 409,415 ****
  	}
  	else
  		args = list_make1(arg0);
! 
  	*transfnexpr = (Expr *) makeFuncExpr(transfn_oid,
  										 agg_state_type,
  										 args,
--- 438,444 ----
  	}
  	else
  		args = list_make1(arg0);
! */
  	*transfnexpr = (Expr *) makeFuncExpr(transfn_oid,
  										 agg_state_type,
  										 args,
Index: src/backend/parser/parse_func.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_func.c,v
retrieving revision 1.188
diff -c -r1.188 parse_func.c
*** src/backend/parser/parse_func.c	14 Jul 2006 14:52:22 -0000	1.188
--- src/backend/parser/parse_func.c	25 Jul 2006 09:12:53 -0000
***************
*** 259,267 ****
  
  		aggref->aggfnoid = funcid;
  		aggref->aggtype = rettype;
! 		aggref->target = linitial(fargs);
  		aggref->aggstar = agg_star;
  		aggref->aggdistinct = agg_distinct;
  
  		/* parse_agg.c does additional aggregate-specific processing */
  		transformAggregateCall(pstate, aggref);
--- 259,285 ----
  
  		aggref->aggfnoid = funcid;
  		aggref->aggtype = rettype;
! 		aggref->args = fargs;
  		aggref->aggstar = agg_star;
  		aggref->aggdistinct = agg_distinct;
+ 		
+ 		/* From the current understanding of the SQL standart the 
+ 		 * DISTINCT keyword can be used only in one-argument aggregates
+ 		 * And '*' cannot be used in multi-arg. aggregates
+ 		 */
+ 		if (list_length(fargs) > 1)
+ 		{
+ 			if (agg_distinct)
+ 			{
+ 				elog(ERROR, "It is not allowed to use DISTINCT keyword "
+ 					 "with aggregates with more than one argument");
+ 			}
+ 			if (agg_star)
+ 			{
+ 				elog(ERROR, "It is not allowed to use * arguments"
+ 					 "with aggregates with more than one argument");			
+ 			}
+ 		}
  
  		/* parse_agg.c does additional aggregate-specific processing */
  		transformAggregateCall(pstate, aggref);
Index: src/backend/utils/adt/float.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/float.c,v
retrieving revision 1.127
diff -c -r1.127 float.c
*** src/backend/utils/adt/float.c	14 Jul 2006 14:52:24 -0000	1.127
--- src/backend/utils/adt/float.c	25 Jul 2006 09:13:23 -0000
***************
*** 1878,1895 ****
   */
  
  static float8 *
! check_float8_array(ArrayType *transarray, const char *caller)
  {
  	/*
! 	 * We expect the input to be a 3-element float array; verify that. We
  	 * don't need to use deconstruct_array() since the array data is just
! 	 * going to look like a C array of 3 float8 values.
  	 */
  	if (ARR_NDIM(transarray) != 1 ||
! 		ARR_DIMS(transarray)[0] != 3 ||
  		ARR_HASNULL(transarray) ||
  		ARR_ELEMTYPE(transarray) != FLOAT8OID)
! 		elog(ERROR, "%s: expected 3-element float8 array", caller);
  	return (float8 *) ARR_DATA_PTR(transarray);
  }
  
--- 1878,1895 ----
   */
  
  static float8 *
! check_float8_array(ArrayType *transarray, const char *caller, int nelts)
  {
  	/*
! 	 * We expect the input to be a nelts-element float array; verify that. We
  	 * don't need to use deconstruct_array() since the array data is just
! 	 * going to look like a C array of nelts float8 values.
  	 */
  	if (ARR_NDIM(transarray) != 1 ||
! 		ARR_DIMS(transarray)[0] != nelts ||
  		ARR_HASNULL(transarray) ||
  		ARR_ELEMTYPE(transarray) != FLOAT8OID)
! 		elog(ERROR, "%s: expected %d-element float8 array", caller, nelts);
  	return (float8 *) ARR_DATA_PTR(transarray);
  }
  
***************
*** 1903,1909 ****
  				sumX,
  				sumX2;
  
! 	transvalues = check_float8_array(transarray, "float8_accum");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 1903,1909 ----
  				sumX,
  				sumX2;
  
! 	transvalues = check_float8_array(transarray, "float8_accum", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 1953,1959 ****
  				sumX2,
  				newval;
  
! 	transvalues = check_float8_array(transarray, "float4_accum");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 1953,1959 ----
  				sumX2,
  				newval;
  
! 	transvalues = check_float8_array(transarray, "float4_accum", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2003,2009 ****
  	float8		N,
  				sumX;
  
! 	transvalues = check_float8_array(transarray, "float8_avg");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	/* ignore sumX2 */
--- 2003,2009 ----
  	float8		N,
  				sumX;
  
! 	transvalues = check_float8_array(transarray, "float8_avg", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	/* ignore sumX2 */
***************
*** 2025,2031 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_pop");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2025,2031 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_pop", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2053,2059 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_samp");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2053,2059 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_var_samp", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2081,2087 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_pop");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2081,2087 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_pop", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2109,2115 ****
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_samp");
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
--- 2109,2115 ----
  				sumX2,
  				numerator;
  
! 	transvalues = check_float8_array(transarray, "float8_stddev_samp", 3);
  	N = transvalues[0];
  	sumX = transvalues[1];
  	sumX2 = transvalues[2];
***************
*** 2127,2132 ****
--- 2127,3003 ----
  	PG_RETURN_FLOAT8(sqrt(numerator / (N * (N - 1.0))));
  }
  
+ Datum float8_regr_count_accum(PG_FUNCTION_ARGS)
+ {
+ 	int64 i = PG_GETARG_INT64(0);
+ 	if (PG_ARGISNULL(1)||PG_ARGISNULL(2))
+ 	{
+ 		PG_RETURN_INT64(i);
+ 	}
+ 	else
+ 	{
+ 		PG_RETURN_INT64(i+1);
+ 	}
+ }
+ 
+ Datum float4_regr_sxx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX,
+ 				sumX2;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_sxx_accum", 3);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 	sumX2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ Datum float4_regr_avgx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_avgx_accum", 2);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_avgx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_avgx_accum", 2);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float4_regr_avgy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_avgy_accum", 2);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_avgy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_avgy_accum", 2);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[2];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 
+ 		result = construct_array(transdatums, 2,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_avg(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sum,
+ 				numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_avg", 2);
+ 	N = transvalues[0];
+ 	sum = transvalues[1];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = sum;
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float8_regr_sxx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(2);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX,
+ 				sumX2;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxx_accum", 3);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumX += newval;
+ 	sumX2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_sxx(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumX,
+ 				sumX2,
+ 				numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxx", 3);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumX2 - sumX * sumX;
+ 
+ 	/* Watch out for roundoff error producing a negative numerator */
+ 	if (numerator <= 0.0)
+ 		PG_RETURN_FLOAT8(0.0);
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float4_regr_syy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY,
+ 				sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_syy_accum", 3);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 	sumY2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 	sumY2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 		transvalues[2] = sumY2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 		transdatums[2] = Float8GetDatumFast(sumY2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_syy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newval = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY,
+ 				sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_syy_accum", 3);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 	sumY2 = transvalues[2];
+ 
+ 	N += 1.0;
+ 	sumY += newval;
+ 	sumY2 += newval * newval;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumY;
+ 		transvalues[2] = sumY2;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[3];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumY);
+ 		transdatums[2] = Float8GetDatumFast(sumY2);
+ 
+ 		result = construct_array(transdatums, 3,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_syy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N,
+ 				sumY,
+ 				sumY2,
+ 				numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_syy", 3);
+ 	N = transvalues[0];
+ 	sumY = transvalues[1];
+ 	sumY2 = transvalues[2];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumY2 - sumY * sumY;
+ 
+ 	/* Watch out for roundoff error producing a negative numerator */
+ 	if (numerator <= 0.0)
+ 		PG_RETURN_FLOAT8(0.0);
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float4_regr_sxy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT4(2);
+ 	float8		newvalY = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_sxy_accum", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumY;
+ 		transvalues[3] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[4];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumY);
+ 		transdatums[3] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 4,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float4_regr_all_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT4(2);
+ 	float8		newvalY = PG_GETARG_FLOAT4(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, sumX2, sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float4_regr_all_accum", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 	sumX2 += newvalX * newvalX;
+ 	sumY2 += newvalY * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 		transvalues[3] = sumY;
+ 		transvalues[4] = sumY2;
+ 		transvalues[5] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[6];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 		transdatums[3] = Float8GetDatumFast(sumY);
+ 		transdatums[4] = Float8GetDatumFast(sumY2);
+ 		transdatums[5] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 6,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ Datum float8_regr_all_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT8(2);
+ 	float8		newvalY = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, sumX2, sumY2;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_all_accum", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 	sumX2 += newvalX * newvalX;
+ 	sumY2 += newvalY * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumX2;
+ 		transvalues[3] = sumY;
+ 		transvalues[4] = sumY2;
+ 		transvalues[5] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[6];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumX2);
+ 		transdatums[3] = Float8GetDatumFast(sumY);
+ 		transdatums[4] = Float8GetDatumFast(sumY2);
+ 		transdatums[5] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 6,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ 
+ 
+ Datum float8_regr_sxy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8		newvalX = PG_GETARG_FLOAT8(2);
+ 	float8		newvalY = PG_GETARG_FLOAT8(1);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxy_accum", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	N += 1.0;
+ 	sumX += newvalX;
+ 	sumY += newvalY;
+ 	sumXY += newvalX * newvalY;
+ 
+ 	/*
+ 	 * If we're invoked by nodeAgg, we can cheat and modify our first
+ 	 * parameter in-place to reduce palloc overhead. Otherwise we construct a
+ 	 * new array with the updated transition data and return it.
+ 	 */
+ 	if (fcinfo->context && IsA(fcinfo->context, AggState))
+ 	{
+ 		transvalues[0] = N;
+ 		transvalues[1] = sumX;
+ 		transvalues[2] = sumY;
+ 		transvalues[3] = sumXY;
+ 
+ 		PG_RETURN_ARRAYTYPE_P(transarray);
+ 	}
+ 	else
+ 	{
+ 		Datum		transdatums[4];
+ 		ArrayType  *result;
+ 
+ 		transdatums[0] = Float8GetDatumFast(N);
+ 		transdatums[1] = Float8GetDatumFast(sumX);
+ 		transdatums[2] = Float8GetDatumFast(sumY);
+ 		transdatums[3] = Float8GetDatumFast(sumXY);
+ 
+ 		result = construct_array(transdatums, 4,
+ 								 FLOAT8OID,
+ 							 sizeof(float8), false /* float8 byval */ , 'd');
+ 
+ 		PG_RETURN_ARRAYTYPE_P(result);
+ 	}
+ }
+ 
+ Datum float8_regr_sxy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_sxy", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumXY - sumX * sumY;
+ 
+ 	PG_RETURN_FLOAT8( numerator / N);
+ }
+ 
+ 
+ Datum float8_covar_pop(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_covar_pop", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumXY - sumX * sumY;
+ 
+ 	PG_RETURN_FLOAT8( numerator / (N * N));
+ }
+ 
+ 
+ Datum float8_covar_samp(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumY, sumXY, numerator;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_covar_samp", 4);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumY = transvalues[2];
+ 	sumXY = transvalues[3];
+ 
+ 	/* if N is <=1  we should return NULL */
+ 	if (N < 2.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numerator = N * sumXY - sumX * sumY;
+ 
+ 	PG_RETURN_FLOAT8( numerator / (N * (N - 1)));
+ }
+ 
+ 
+ Datum float8_corr(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorY, numeratorXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_corr", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorY = N * sumY2 - sumY * sumY;
+ 	numeratorXY = N * sumXY - sumX * sumY;
+ 	if ((numeratorX <= 0) && (numeratorY <= 0))
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( sqrt (numeratorXY * numeratorXY /
+ 		(numeratorX * numeratorY)));
+ }
+ 
+ Datum float8_regr_r2(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorY, numeratorXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_r2", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4];
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorY = N * sumY2 - sumY * sumY;
+ 	numeratorXY = N * sumXY - sumX * sumY;
+ 	if ((numeratorX <= 0) && (numeratorY <= 0))
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( numeratorXY * numeratorXY /
+ 		(numeratorX * numeratorY));
+ }
+ 
+ Datum float8_regr_slope(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_slope", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4]; /* will be ignored */
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorXY = N * sumXY - sumX * sumY;
+ 	if (numeratorX <= 0)
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( numeratorXY / numeratorX );
+ }
+ 
+ Datum float8_regr_intercept(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	float8	   *transvalues;
+ 	float8		N, sumX, sumX2, sumY, sumY2, sumXY, numeratorX,
+ 		numeratorXXY;
+ 
+ 	transvalues = check_float8_array(transarray, "float8_regr_intercept", 6);
+ 	N = transvalues[0];
+ 	sumX = transvalues[1];
+ 	sumX2 = transvalues[2];
+ 	sumY = transvalues[3];
+ 	sumY2 = transvalues[4]; /* will be ignored */
+ 	sumXY = transvalues[5];
+ 
+ 	/* if N is 0 we should return NULL */
+ 	if (N < 1.0)
+ 		PG_RETURN_NULL();
+ 
+ 	numeratorX = N * sumX2 - sumX * sumX;
+ 	numeratorXXY = sumY * sumX2 - sumX * sumXY;
+ 	if (numeratorX <= 0)
+ 	{
+ 		PG_RETURN_NULL();
+ 	}
+ 	
+ 	PG_RETURN_FLOAT8( numeratorXXY / numeratorX );
+ }
+ 
  
  /*
   *		====================================
Index: src/backend/utils/adt/numeric.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/numeric.c,v
retrieving revision 1.94
diff -c -r1.94 numeric.c
*** src/backend/utils/adt/numeric.c	14 Jul 2006 05:28:28 -0000	1.94
--- src/backend/utils/adt/numeric.c	25 Jul 2006 09:13:24 -0000
***************
*** 2106,2111 ****
--- 2106,2358 ----
  	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
  }
  
+ Datum numeric_regr_avgx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N,
+ 				sumX;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 2)
+ 		elog(ERROR, "expected 2-element numeric array");
+ 	N = transdatums[0];
+ 	sumX = transdatums[1];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumX = DirectFunctionCall2(numeric_add, sumX,
+ 							   NumericGetDatum(newvalX));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 
+ 	outputarray = construct_array(transdatums, 2,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ Datum numeric_regr_avgy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N, sumY;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 2)
+ 		elog(ERROR, "expected 2-element numeric array");
+ 	N = transdatums[0];
+ 	sumY = transdatums[1];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumY;
+ 
+ 	outputarray = construct_array(transdatums, 2,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ Datum numeric_regr_sxx_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N,
+ 				sumX,
+ 				sumX2;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &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(newvalX));
+ 	sumX2 = DirectFunctionCall2(numeric_add, sumX2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalX)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 	transdatums[2] = sumX2;
+ 
+ 	outputarray = construct_array(transdatums, 3,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ Datum numeric_regr_syy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N,
+ 				sumY,
+ 				sumY2;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 3)
+ 		elog(ERROR, "expected 3-element numeric array");
+ 	N = transdatums[0];
+ 	sumY = transdatums[1];
+ 	sumY2 = transdatums[2];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY));
+ 	sumY2 = DirectFunctionCall2(numeric_add, sumY2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalY),
+ 													NumericGetDatum(newvalY)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumY;
+ 	transdatums[2] = sumY2;
+ 
+ 	outputarray = construct_array(transdatums, 3,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ Datum numeric_regr_sxy_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N, sumX, sumY, sumXY;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = transdatums[0];
+ 	sumX = transdatums[1];
+ 	sumY = transdatums[2];
+ 	sumXY = transdatums[3];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 	sumX = DirectFunctionCall2(numeric_add, sumX,
+ 							   NumericGetDatum(newvalX));
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY));
+ 	sumXY = DirectFunctionCall2(numeric_add, sumXY,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalY)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 	transdatums[2] = sumY;
+ 	transdatums[3] = sumXY;
+ 
+ 	outputarray = construct_array(transdatums, 4,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ Datum numeric_regr_all_accum(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Numeric		newvalX = PG_GETARG_NUMERIC(2);
+ 	Numeric		newvalY = PG_GETARG_NUMERIC(1);
+ 	ArrayType  *outputarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Datum		N, sumX, sumX2, sumY,  sumY2, sumXY;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = transdatums[0];
+ 	sumX = transdatums[1];
+ 	sumX2 = transdatums[2];
+ 	sumY = transdatums[3];
+ 	sumY2 = transdatums[4];
+ 	sumXY = transdatums[5];
+ 
+ 	N = DirectFunctionCall1(numeric_inc, N);
+ 
+ /* Probably can and should be optimized to not repeat 
+  * NumericGetDatum several times */
+ 	sumX = DirectFunctionCall2(numeric_add, sumX,
+ 							   NumericGetDatum(newvalX));
+ 	sumY = DirectFunctionCall2(numeric_add, sumY,
+ 							   NumericGetDatum(newvalY)); 
+ 	sumXY = DirectFunctionCall2(numeric_add, sumXY,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalY)));
+ 	sumX2 = DirectFunctionCall2(numeric_add, sumX2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalX),
+ 													NumericGetDatum(newvalX)));
+ 	sumY2 = DirectFunctionCall2(numeric_add, sumY2,
+ 								DirectFunctionCall2(numeric_mul,
+ 													NumericGetDatum(newvalY),
+ 													NumericGetDatum(newvalY)));
+ 
+ 	transdatums[0] = N;
+ 	transdatums[1] = sumX;
+ 	transdatums[2] = sumX2;
+ 	transdatums[3] = sumY;
+ 	transdatums[4] = sumY2;
+ 	transdatums[5] = sumXY;
+ 
+ 	outputarray = construct_array(transdatums, 6,
+ 							 NUMERICOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(outputarray);
+ }
+ 
+ 
+ 
+ 
  /*
   * Integer data types all use Numeric accumulators to share code and
   * avoid risk of overflow.	For int2 and int4 inputs, Numeric accumulation
***************
*** 2151,2156 ****
--- 2398,2416 ----
  	PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
  }
  
+ Datum numeric_regr_count_accum(PG_FUNCTION_ARGS)
+ {
+ 	int64 i = PG_GETARG_INT64(0);
+ 	if (PG_ARGISNULL(1)||PG_ARGISNULL(2))
+ 	{
+ 		PG_RETURN_INT64(i);
+ 	}
+ 	else
+ 	{
+ 		PG_RETURN_INT64(i+1);
+ 	}
+ }
+ 
  Datum
  numeric_avg(PG_FUNCTION_ARGS)
  {
***************
*** 2283,2288 ****
--- 2543,3392 ----
  	return res;
  }
  
+ Datum numeric_regr_avg(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType  *transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N,
+ 				sum;
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 2)
+ 		elog(ERROR, "expected 2-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sum = DatumGetNumeric(transdatums[1]);
+ 
+ 	/* 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(sum),
+ 										NumericGetDatum(N)));
+ }
+ 
+ 
+ Datum numeric_regr_sxx(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N,
+ 				sumX,
+ 				sumX2,
+ 				res;
+ 	NumericVar	vN,
+ 				vsumX,
+ 				vsumX2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &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));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	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
+ 	{
+ 		rscale = select_div_scale(&vsumX2, &vN);
+ 		div_var(&vsumX2, &vN, &vsumX, rscale, true);
+ 
+ 		res = make_result(&vsumX);
+ 	}
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumX2);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_regr_syy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N,
+ 				sumY,
+ 				sumY2,
+ 				res;
+ 	NumericVar	vN,
+ 				vsumY,
+ 				vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 3)
+ 		elog(ERROR, "expected 3-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumY = DatumGetNumeric(transdatums[1]);
+ 	sumY2 = DatumGetNumeric(transdatums[2]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumY2))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumY.dscale * 2;
+ 
+ 	mul_var(&vsumY, &vsumY, &vsumY, rscale);	/* vsumY = sumY * sumY */
+ 	mul_var(&vN, &vsumY2, &vsumY2, rscale);		/* vsumY2 = N * sumY2 */
+ 	sub_var(&vsumY2, &vsumY, &vsumY2);			/* N * sumY2 - sumY * sumY */
+ 
+ 	if (cmp_var(&vsumY2, &const_zero) <= 0)
+ 	{
+ 		/* Watch out for roundoff error producing a negative numerator */
+ 		res = make_result(&const_zero);
+ 	}
+ 	else
+ 	{
+ 		rscale = select_div_scale(&vsumY2, &vN);
+ 		div_var(&vsumY2, &vN, &vsumY, rscale, true);	/* variance */
+ 
+ 		res = make_result(&vsumY);
+ 	}
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumY);
+ 	free_var(&vsumY2);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_regr_sxy(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumY = DatumGetNumeric(transdatums[2]);
+ 	sumXY = DatumGetNumeric(transdatums[3]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vsumY, rscale);	/* vsumY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vsumY, &vsumXY);			/* N * sumXY - sumX * sumY */
+ 
+ 	rscale = select_div_scale(&vsumXY, &vN);
+ 	div_var(&vsumXY, &vN, &vsumY, rscale, true);	/* variance */
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_covar_samp(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vNminus1;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumY = DatumGetNumeric(transdatums[2]);
+ 	sumXY = DatumGetNumeric(transdatums[3]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 	init_var(&vNminus1);
+ 	sub_var(&vN, &const_one, &vNminus1);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vNminus1, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vNminus1);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vsumY, rscale);	/* vsumY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vsumY, &vsumXY);			/* N * sumXY - sumX * sumY */
+ 
+ 	mul_var(&vN, &vNminus1, &vNminus1, 0);				/* N * (N - 1) */
+ 	rscale = select_div_scale(&vsumXY, &vNminus1);
+ 	div_var(&vsumXY, &vNminus1, &vsumY, rscale, true);
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vNminus1);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_covar_pop(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 4)
+ 		elog(ERROR, "expected 4-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumY = DatumGetNumeric(transdatums[2]);
+ 	sumXY = DatumGetNumeric(transdatums[3]);
+ 
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY))
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vsumY, rscale);	/* vsumY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vsumY, &vsumXY);			/* N * sumXY - sumX * sumY */
+ 
+ 	mul_var(&vN, &vN, &vN, 0);				/* N * N */
+ 	rscale = select_div_scale(&vsumXY, &vN);
+ 	div_var(&vsumXY, &vN, &vsumY, rscale, true);
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_corr(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 	
+ 	mul_var(&vsumX, &vsumY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vtmpXY, &vsumXY);			/* vsumXY = N * sumXY - sumX * sumY */
+ 	
+ 	rscale = vsumXY.dscale * 2;
+ 	mul_var(&vsumXY, &vsumXY, &vsumXY, rscale);
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 
+ 	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */
+ 	sub_var(&vsumX2, &vsumX, &vsumX2);			/* vsumX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = 2 * vsumY.dscale;
+ 
+ 	mul_var(&vsumY, &vsumY, &vsumY, rscale);	/* vsumY = sumY * sumY */
+ 	mul_var(&vN, &vsumY2, &vsumY2, rscale);		/* vsumY2 = N * sumY2 */
+ 	sub_var(&vsumY2, &vsumY, &vsumY2);			/* vsumY2 = N * sumY2 - sumY * sumY */
+ 
+ 	if (cmp_var(&vsumY2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 	rscale = vsumY2.dscale + vsumX2.dscale;
+ 	mul_var(&vsumX2, &vsumY2, &vsumY2, rscale);	/* vsumY2 = sumX2 * sumY2 */
+ 
+ 	rscale = select_div_scale(&vsumXY, &vsumY2);
+ 	div_var(&vsumXY, &vsumY2, &vsumY, rscale, true);	/* variance */
+ 
+ 	sqrt_var(&vsumY, &vsumY, rscale);
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ Datum numeric_regr_r2(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vtmpXY, &vsumXY);			/* vtmpXY = N * sumXY - sumX * sumY */
+ 
+ 	rscale = vsumXY.dscale * 2;
+ 	mul_var(&vsumXY, &vsumXY, &vsumXY, rscale);
+ 
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 
+ 	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */
+ 	sub_var(&vsumX2, &vsumX, &vsumX2);			/* vsumX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = 2 * vsumY.dscale;
+ 
+ 	mul_var(&vsumY, &vsumY, &vsumY, rscale);	/* vsumY = sumY * sumY */
+ 	mul_var(&vN, &vsumY2, &vsumY2, rscale);		/* vsumY2 = N * sumY2 */
+ 	sub_var(&vsumY2, &vsumY, &vsumY2);			/* vsumY2 = N * sumY2 - sumY * sumY */
+ 
+ 	if (cmp_var(&vsumY2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = vsumY2.dscale + vsumX2.dscale;
+ 	mul_var(&vsumX2, &vsumY2, &vsumY2, rscale);	/* vsumY2 = sumX2 * sumY2 */
+ 
+ 	rscale = select_div_scale(&vsumXY, &vsumY2);
+ 	div_var(&vsumXY, &vsumY2, &vsumY, rscale, true);	/* variance */
+ 
+ 	res = make_result(&vsumY);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_regr_slope(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumY.dscale;
+ 
+ 	mul_var(&vsumX, &vsumY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumY */
+ 	mul_var(&vN, &vsumXY, &vsumXY, rscale);		/* vsumXY = N * sumXY */
+ 	sub_var(&vsumXY, &vtmpXY, &vsumXY);			/* vtmpXY = N * sumXY - sumX * sumY */
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 
+ 	mul_var(&vsumX, &vsumX, &vsumX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vsumX2, rscale);		/* vsumX2 = N * sumX2 */
+ 	sub_var(&vsumX2, &vsumX, &vsumX2);			/* vsumX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	rscale = select_div_scale(&vsumXY, &vsumX2);
+ 	div_var(&vsumXY, &vsumX2, &vsumX, rscale, true);	/* variance */
+ 
+ 	res = make_result(&vsumX);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
+ Datum numeric_regr_intercept(PG_FUNCTION_ARGS)
+ {
+ 	ArrayType *transarray;
+ 	Datum	   *transdatums;
+ 	int			ndatums;
+ 	Numeric		N, sumX, sumY, sumXY, sumX2, sumY2, res;
+ 	NumericVar	vN, vsumX, vsumY, vsumXY, vtmpXY, vsumX2, vsumY2, vtmpX, vtmpX2, vtmpY2;
+ 	NumericVar *comp;
+ 	int			rscale;
+ 
+ 	transarray = PG_GETARG_ARRAYTYPE_P(0);
+ 
+ 
+ 	/* We assume the input is array of numeric */
+ 	deconstruct_array(transarray,
+ 					  NUMERICOID, -1, false, 'i',
+ 					  &transdatums, NULL, &ndatums);
+ 	if (ndatums != 6)
+ 		elog(ERROR, "expected 6-element numeric array");
+ 	N = DatumGetNumeric(transdatums[0]);
+ 	sumX = DatumGetNumeric(transdatums[1]);
+ 	sumX2 = DatumGetNumeric(transdatums[2]);
+ 	sumY = DatumGetNumeric(transdatums[3]);
+ 	sumY2 = DatumGetNumeric(transdatums[4]);
+ 	sumXY = DatumGetNumeric(transdatums[5]);
+ 	/* I'm not really sure that the check for NAN does make sense
+ 	 * for sumY2 when sumY is already not NAN, but ... 
+ 	 */
+ 	if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) ||
+ 		NUMERIC_IS_NAN(sumY) || NUMERIC_IS_NAN(sumXY) ||
+ 		NUMERIC_IS_NAN(sumX2) || NUMERIC_IS_NAN(sumY2))
+ 	{
+ 		PG_RETURN_NUMERIC(make_result(&const_nan));
+ 	}
+ 
+ 	init_var(&vN);
+ 	set_var_from_num(N, &vN);
+ 
+ 	comp = &const_zero;
+ 
+ 	if (cmp_var(&vN, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 
+ 	init_var(&vsumX);
+ 	set_var_from_num(sumX, &vsumX);
+ 	init_var(&vsumY);
+ 	set_var_from_num(sumY, &vsumY);
+ 	init_var(&vsumX2);
+ 	set_var_from_num(sumX2, &vsumX2);
+ 	init_var(&vsumY2);
+ 	set_var_from_num(sumY2, &vsumY2);
+ 	init_var(&vsumXY);
+ 	set_var_from_num(sumXY, &vsumXY);
+ 	init_var(&vtmpXY);
+ 	init_var(&vtmpX2);
+ 	init_var(&vtmpY2);
+ 
+ 	/* compute rscale for mul_var calls */
+ 	rscale = vsumX.dscale + vsumXY.dscale;
+ 	mul_var(&vsumX, &vsumXY, &vtmpXY, rscale);	/* vtmpXY = sumX * sumXY */
+ 	rscale = vsumY.dscale + vsumX2.dscale;
+ 	mul_var(&vsumY, &vsumX2, &vtmpY2, rscale);		/* vtmpY2 = vsumY * sumX2 */
+ 	sub_var(&vtmpY2, &vtmpXY, &vtmpXY);			/* vtmpXY = vsumY * sumX2 - sumX * sumXY */
+ 
+ 	rscale = 2 * vsumX.dscale;
+ 	mul_var(&vsumX, &vsumX, &vtmpX, rscale);	/* vsumX = sumX * sumX */
+ 	mul_var(&vN, &vsumX2, &vtmpX2, rscale);		/* vtmpX2 = N * sumX2 */
+ 	sub_var(&vtmpX2, &vtmpX, &vtmpX2);			/* vtmpX2 = N * sumX2 - sumX * sumX */
+ 
+ 	if (cmp_var(&vsumX2, comp) <= 0)
+ 	{
+ 		free_var(&vN);
+ 		free_var(&vsumX);
+ 		free_var(&vsumY);
+ 		free_var(&vsumXY);
+ 		free_var(&vtmpX2);
+ 		free_var(&vtmpY2);
+ 		free_var(&vsumY2);
+ 		free_var(&vsumX2);
+ 		free_var(&vtmpXY);	
+ 		PG_RETURN_NULL();
+ 	}
+ 
+ 	rscale = select_div_scale(&vtmpXY, &vtmpX2);
+ 	div_var(&vtmpXY, &vtmpX2, &vsumX, rscale, true);
+ 
+ 	res = make_result(&vsumX);
+ 
+ 	free_var(&vN);
+ 	free_var(&vsumX);
+ 	free_var(&vsumY);
+ 	free_var(&vsumXY);
+ 	free_var(&vtmpX2);
+ 	free_var(&vtmpY2);
+ 	free_var(&vsumY2);
+ 	free_var(&vsumX2);
+ 	free_var(&vtmpXY);
+ 
+ 	PG_RETURN_NUMERIC(res);
+ }
+ 
+ 
  Datum
  numeric_var_samp(PG_FUNCTION_ARGS)
  {
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.228
diff -c -r1.228 ruleutils.c
*** src/backend/utils/adt/ruleutils.c	14 Jul 2006 14:52:24 -0000	1.228
--- src/backend/utils/adt/ruleutils.c	25 Jul 2006 09:13:26 -0000
***************
*** 3880,3894 ****
  get_agg_expr(Aggref *aggref, deparse_context *context)
  {
  	StringInfo	buf = context->buf;
! 	Oid			argtype = exprType((Node *) aggref->target);
  
  	appendStringInfo(buf, "%s(%s",
! 					 generate_function_name(aggref->aggfnoid, 1, &argtype),
  					 aggref->aggdistinct ? "DISTINCT " : "");
  	if (aggref->aggstar)
  		appendStringInfo(buf, "*");
  	else
! 		get_rule_expr((Node *) aggref->target, context, true);
  	appendStringInfoChar(buf, ')');
  }
  
--- 3880,3908 ----
  get_agg_expr(Aggref *aggref, deparse_context *context)
  {
  	StringInfo	buf = context->buf;
! 	Oid			argtypes[FUNC_MAX_ARGS];
! 	int			nargs;
! 	ListCell   *l;
! 
! 	nargs = 0;
! 	foreach(l, aggref->args)
! 	{
! 		if (nargs >= FUNC_MAX_ARGS)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
! 					 errmsg("too many arguments")));
! 		argtypes[nargs] = exprType((Node *) lfirst(l));
! 		nargs++;
! 	}
  
  	appendStringInfo(buf, "%s(%s",
! 					 generate_function_name(aggref->aggfnoid, nargs, argtypes),
  					 aggref->aggdistinct ? "DISTINCT " : "");
+ 	/* aggstar can be set only in one-argument aggregates */
  	if (aggref->aggstar)
  		appendStringInfo(buf, "*");
  	else
! 		get_rule_expr((Node *) aggref->args, context, true);
  	appendStringInfoChar(buf, ')');
  }
  
Index: src/include/catalog/pg_aggregate.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_aggregate.h,v
retrieving revision 1.55
diff -c -r1.55 pg_aggregate.h
*** src/include/catalog/pg_aggregate.h	21 Jul 2006 20:51:33 -0000	1.55
--- src/include/catalog/pg_aggregate.h	25 Jul 2006 09:14:29 -0000
***************
*** 194,199 ****
--- 194,240 ----
  DATA(insert ( 2158	float8_accum	float8_stddev_samp	0	1022	"{0,0,0}" ));
  DATA(insert ( 2159	numeric_accum	numeric_stddev_samp	0	1231	"{0,0,0}" ));
  
+ DATA(insert ( 2800	numeric_regr_count_accum	-	0	20	0 ));
+ DATA(insert ( 2801	float8_regr_count_accum	-	0	20	0 ));
+ DATA(insert ( 2802	float4_regr_sxx_accum	float8_regr_sxx	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2803	float4_regr_syy_accum	float8_regr_syy	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2804	float4_regr_sxy_accum	float8_regr_sxy	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2805	float4_regr_avgx_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ DATA(insert ( 2806	float4_regr_avgy_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ 
+ DATA(insert ( 2807	float8_regr_sxx_accum	float8_regr_sxx	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2808	float8_regr_syy_accum	float8_regr_syy	0	1022	"{0,0,0}" ));
+ DATA(insert ( 2809	float8_regr_sxy_accum	float8_regr_sxy	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2810	float8_regr_avgx_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ DATA(insert ( 2811	float8_regr_avgy_accum	float8_regr_avg	0	1022	"{0,0}" ));
+ 
+ DATA(insert ( 2812	numeric_regr_sxx_accum	numeric_regr_sxx	0	1231	"{0,0,0}" ));
+ DATA(insert ( 2813	numeric_regr_syy_accum	numeric_regr_syy	0	1231	"{0,0,0}" ));
+ DATA(insert ( 2814	numeric_regr_sxy_accum	numeric_regr_sxy	0	1231	"{0,0,0,0}" ));
+ DATA(insert ( 2815	numeric_regr_avgx_accum	numeric_regr_avg	0	1231	"{0,0}" ));
+ DATA(insert ( 2816	numeric_regr_avgy_accum	numeric_regr_avg	0	1231	"{0,0}" ));
+ 
+ DATA(insert ( 2817	float4_regr_sxy_accum	float8_covar_pop	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2818	float8_regr_sxy_accum	float8_covar_pop	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2819	numeric_regr_sxy_accum	numeric_covar_pop	0	1231	"{0,0,0,0}" ));
+ DATA(insert ( 2820	float4_regr_sxy_accum	float8_covar_samp	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2821	float8_regr_sxy_accum	float8_covar_samp	0	1022	"{0,0,0,0}" ));
+ DATA(insert ( 2822	numeric_regr_sxy_accum	numeric_covar_samp	0	1231	"{0,0,0,0}" ));
+ 
+ DATA(insert ( 2823	float4_regr_all_accum	float8_corr	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2824	float8_regr_all_accum	float8_corr	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2825	numeric_regr_all_accum	numeric_corr	0	1231	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2826	float4_regr_all_accum	float8_regr_r2	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2827	float8_regr_all_accum	float8_regr_r2	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2828	numeric_regr_all_accum	numeric_regr_r2	0	1231	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2829	float4_regr_all_accum	float8_regr_slope	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2830	float8_regr_all_accum	float8_regr_slope	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2831	numeric_regr_all_accum	numeric_regr_slope	0	1231	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2832	float4_regr_all_accum	float8_regr_intercept	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2833	float8_regr_all_accum	float8_regr_intercept	0	1022	"{0,0,0,0,0,0}" ));
+ DATA(insert ( 2834	numeric_regr_all_accum	numeric_regr_intercept	0	1231	"{0,0,0,0,0,0}" ));
+ 
+ 
  /* boolean-and and boolean-or */
  DATA(insert ( 2517	booland_statefunc	-			0	16		_null_ ));
  DATA(insert ( 2518	boolor_statefunc	-			0	16		_null_ ));
***************
*** 214,220 ****
   */
  extern void AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid aggBaseType,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
--- 255,262 ----
   */
  extern void AggregateCreate(const char *aggName,
  				Oid aggNamespace,
! 				Oid *aggBaseTypeArray,
! 				int numArgs,
  				List *aggtransfnName,
  				List *aggfinalfnName,
  				List *aggsortopName,
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.416
diff -c -r1.416 pg_proc.h
*** src/include/catalog/pg_proc.h	21 Jul 2006 20:51:33 -0000	1.416
--- src/include/catalog/pg_proc.h	25 Jul 2006 09:14:30 -0000
***************
*** 2728,2733 ****
--- 2728,2827 ----
  DESCR("AVG(int4) transition function");
  DATA(insert OID = 1964 (  int8_avg		   PGNSP PGUID 12 f f t f i 1 1700 "1016" _null_ _null_ _null_	int8_avg - _null_ ));
  DESCR("AVG(int) aggregate final function");
+ DATA(insert OID = 2850 (  numeric_regr_count_accum	   PGNSP PGUID 12 f f t f i 3 20 "20 1700 1700" _null_ _null_ _null_ numeric_regr_count_accum - _null_ ));
+ DESCR("REGR_COUNT(numeric) transition function");
+ DATA(insert OID = 2851 (  float8_regr_count_accum	   PGNSP PGUID 12 f f t f i 3 20 "20 701 701" _null_ _null_ _null_ float8_regr_count_accum - _null_ ));
+ DESCR("REGR_COUNT(double, double) transition function");
+ DATA(insert OID = 2852 (  float4_regr_sxx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_sxx_accum - _null_ ));
+ DESCR("REGR_SXX(float, float) aggregate transition function");
+ DATA(insert OID = 2853 (  float4_regr_syy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_syy_accum - _null_ ));
+ DESCR("REGR_SYY(float, float) aggregate transition function");
+ DATA(insert OID = 2854 (  float4_regr_sxy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_sxy_accum - _null_ ));
+ DESCR("REGR_SXY(float, float) aggregate transition function");
+ DATA(insert OID = 2855 (  float4_regr_avgx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_avgx_accum - _null_ ));
+ DESCR("REGR_AVGX(float, float) aggregate transition function");
+ DATA(insert OID = 2856 (  float4_regr_avgy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_avgy_accum - _null_ ));
+ DESCR("REGR_AVGY(float, float) aggregate transition function");
+ DATA(insert OID = 2857 (  float8_regr_sxx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_sxx_accum - _null_ ));
+ DESCR("REGR_SXX(double, double) aggregate transition function");
+ DATA(insert OID = 2858 (  float8_regr_syy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_syy_accum - _null_ ));
+ DESCR("REGR_SYY(double, double) aggregate transition function");
+ DATA(insert OID = 2859 (  float8_regr_sxy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_sxy_accum - _null_ ));
+ DESCR("REGR_SXY(double, double) aggregate transition function");
+ DATA(insert OID = 2860 (  float8_regr_avgx_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_avgx_accum - _null_ ));
+ DESCR("REGR_AVGX(float, float) aggregate transition function");
+ DATA(insert OID = 2861 (  float8_regr_avgy_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_avgy_accum - _null_ ));
+ DESCR("REGR_AVGY(float, float) aggregate transition function");
+ DATA(insert OID = 2862 (  numeric_regr_sxx_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_sxx_accum - _null_ ));
+ DESCR("REGR_SXX(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2863 (  numeric_regr_syy_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_syy_accum - _null_ ));
+ DESCR("REGR_SYY(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2864 (  numeric_regr_sxy_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_sxy_accum - _null_ ));
+ DESCR("REGR_SXY(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2865 (  numeric_regr_avgx_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_avgx_accum - _null_ ));
+ DESCR("REGR_AVGX(numeric, numeric) aggregate transition function");
+ DATA(insert OID = 2866 (  numeric_regr_avgy_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_avgy_accum - _null_ ));
+ DESCR("REGR_AVGY(numeric, numeric) aggregate transition function");
+ 
+ DATA(insert OID = 2867 (  float8_regr_sxx	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_sxx - _null_ ));
+ DESCR("REGR_SXX(double, double) aggregate final function");
+ DATA(insert OID = 2868 (  float8_regr_syy	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_syy - _null_ ));
+ DESCR("REGR_SYY(double, double) aggregate final function");
+ DATA(insert OID = 2869 (  float8_regr_sxy	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_sxy - _null_ ));
+ DESCR("REGR_SXY(double, double) aggregate final function");
+ DATA(insert OID = 2870 (  float8_regr_avg	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_avg - _null_ ));
+ DESCR("REGR_AVGX(double, double) AND REGR_AVGY(double,double) aggregate final function");
+ 
+ DATA(insert OID = 2871 (  numeric_regr_sxx	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_sxx - _null_ ));
+ DESCR("REGR_SXX(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2872 (  numeric_regr_syy	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_syy - _null_ ));
+ DESCR("REGR_SYY(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2873 (  numeric_regr_sxy	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_sxy - _null_ ));
+ DESCR("REGR_SXY(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2874 (  numeric_regr_avg	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_avg - _null_ ));
+ DESCR("REGR_AVGX(numeric, numeric) AND REGR_AVGY(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2875 (  float8_covar_samp	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_covar_samp - _null_ ));
+ DESCR("COVAR_SAMP(float8, float8) aggregate final function");
+ DATA(insert OID = 2876 (  numeric_covar_samp	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_covar_samp - _null_ ));
+ DESCR("COVAR_SAMP(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2877 (  float8_covar_pop	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_covar_pop - _null_ ));
+ DESCR("COVAR_POP(float8, float8) aggregate final function");
+ DATA(insert OID = 2878 (  numeric_covar_pop	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_covar_pop - _null_ ));
+ DESCR("COVAR_POP(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2879 (  float4_regr_all_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 700 700" _null_ _null_ _null_ float4_regr_all_accum - _null_ ));
+ DESCR("REGR_...(float4, float4) aggregate transition function");
+ DATA(insert OID = 2880 (  float8_regr_all_accum	   PGNSP PGUID 12 f f t f i 3 1022 "1022 701 701" _null_ _null_ _null_ float8_regr_all_accum - _null_ ));
+ DESCR("REGR_...(float8, float8) aggregate transition function");
+ DATA(insert OID = 2881 (  numeric_regr_all_accum	   PGNSP PGUID 12 f f t f i 3 1231 "1231 1700 1700" _null_ _null_ _null_ numeric_regr_all_accum - _null_ ));
+ DESCR("REGR_...(numeric, numeric) aggregate transition function");
+ 
+ DATA(insert OID = 2882 (  float4_corr	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_corr - _null_ ));
+ DESCR("CORR(float4, float4) aggregate final function");
+ DATA(insert OID = 2883 (  float4_regr_r2	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_r2 - _null_ ));
+ DESCR("REGR_R2(float4, float4) aggregate final function");
+ DATA(insert OID = 2884 (  float4_regr_slope	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_slope - _null_ ));
+ DESCR("REGR_SLOPE(float4, float4) aggregate final function");
+ DATA(insert OID = 2885 (  float4_regr_intercept	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_intercept - _null_ ));
+ DESCR("REGR_INTERCEPT(float4, float4) aggregate final function");
+ 
+ DATA(insert OID = 2886 (  float8_corr	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_corr - _null_ ));
+ DESCR("CORR(double, double) aggregate final function");
+ DATA(insert OID = 2887 (  float8_regr_r2	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_r2 - _null_ ));
+ DESCR("REGR_R2(double, double) aggregate final function");
+ DATA(insert OID = 2888 (  float8_regr_slope	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_slope - _null_ ));
+ DESCR("REGR_SLOPE(double, double) aggregate final function");
+ DATA(insert OID = 2889 (  float8_regr_intercept	   PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_ float8_regr_intercept - _null_ ));
+ DESCR("REGR_INTERCEPT(double, double) aggregate final function");
+ 
+ DATA(insert OID = 2890 (  numeric_corr	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_corr - _null_ ));
+ DESCR("CORR(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2891 (  numeric_regr_r2	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_r2 - _null_ ));
+ DESCR("REGR_R2(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2892 (  numeric_regr_slope	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_slope - _null_ ));
+ DESCR("REGR_SLOPE(numeric, numeric) aggregate final function");
+ DATA(insert OID = 2893 (  numeric_regr_intercept	   PGNSP PGUID 12 f f t f i 1 1700 "1231" _null_ _null_ _null_ numeric_regr_intercept - _null_ ));
+ DESCR("REGR_INTERCEPT(numeric, numeric) aggregate final function");
+ 
  
  /* To ASCII conversion */
  DATA(insert OID = 1845 ( to_ascii	PGNSP PGUID 12 f f t f i 1	25 "25" _null_ _null_ _null_	to_ascii_default - _null_ ));
***************
*** 3192,3197 ****
--- 3286,3330 ----
  DATA(insert OID = 2158 (  stddev			PGNSP PGUID 12 t f f f i 1 701 "701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
  DATA(insert OID = 2159 (  stddev			PGNSP PGUID 12 t f f f i 1 1700 "1700" _null_ _null_ _null_ aggregate_dummy - _null_ ));
  
+ DATA(insert OID = 2800 (  regr_count		PGNSP PGUID 12 t f f f i 2 20 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2801 (  regr_count		PGNSP PGUID 12 t f f f i 2 20 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2802 (  regr_sxx		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2803 (  regr_syy		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2804 (  regr_sxy		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2805 (  regr_avgx		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2806 (  regr_avgy		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2807 (  regr_sxx		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2808 (  regr_syy		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2809 (  regr_sxy		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2810 (  regr_avgx		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2811 (  regr_avgy		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2812 (  regr_sxx		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2813 (  regr_syy		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2814 (  regr_sxy		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2815 (  regr_avgx		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2816 (  regr_avgy		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ 
+ DATA(insert OID = 2817 (  covar_pop		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2818 (  covar_pop		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2819 (  covar_pop		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2820 (  covar_samp		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2821 (  covar_samp		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2822 (  covar_samp		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ 
+ DATA(insert OID = 2823 (  corr		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2824 (  corr		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2825 (  corr		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2826 (  regr_r2		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2827 (  regr_r2		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2828 (  regr_r2		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2829 (  regr_slope		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2830 (  regr_slope		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2831 (  regr_slope		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2832 (  regr_intercept		PGNSP PGUID 12 t f f f i 2 701 "700 700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2833 (  regr_intercept		PGNSP PGUID 12 t f f f i 2 701 "701 701" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ DATA(insert OID = 2834 (  regr_intercept		PGNSP PGUID 12 t f f f i 2 1700 "1700 1700" _null_ _null_ _null_  aggregate_dummy - _null_ ));
+ 
+ 
  DATA(insert OID = 2160 ( text_pattern_lt	 PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_lt - _null_ ));
  DATA(insert OID = 2161 ( text_pattern_le	 PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_le - _null_ ));
  DATA(insert OID = 2162 ( text_pattern_eq	 PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_eq - _null_ ));
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.153
diff -c -r1.153 execnodes.h
*** src/include/nodes/execnodes.h	13 Jul 2006 16:49:19 -0000	1.153
--- src/include/nodes/execnodes.h	25 Jul 2006 09:14:30 -0000
***************
*** 449,455 ****
  typedef struct AggrefExprState
  {
  	ExprState	xprstate;
! 	ExprState  *target;			/* state of my child node */
  	int			aggno;			/* ID number for agg within its plan node */
  } AggrefExprState;
  
--- 449,455 ----
  typedef struct AggrefExprState
  {
  	ExprState	xprstate;
! 	List	   *args;			/* states of argument expressions */
  	int			aggno;			/* ID number for agg within its plan node */
  } AggrefExprState;
  
Index: src/include/nodes/primnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/primnodes.h,v
retrieving revision 1.114
diff -c -r1.114 primnodes.h
*** src/include/nodes/primnodes.h	13 Jul 2006 16:49:19 -0000	1.114
--- src/include/nodes/primnodes.h	25 Jul 2006 09:14:31 -0000
***************
*** 184,190 ****
  	Expr		xpr;
  	Oid			aggfnoid;		/* pg_proc Oid of the aggregate */
  	Oid			aggtype;		/* type Oid of result of the aggregate */
! 	Expr	   *target;			/* expression we are aggregating on */
  	Index		agglevelsup;	/* > 0 if agg belongs to outer query */
  	bool		aggstar;		/* TRUE if argument was really '*' */
  	bool		aggdistinct;	/* TRUE if it's agg(DISTINCT ...) */
--- 184,190 ----
  	Expr		xpr;
  	Oid			aggfnoid;		/* pg_proc Oid of the aggregate */
  	Oid			aggtype;		/* type Oid of result of the aggregate */
! 	List	   *args;			/* arguments to the function */
  	Index		agglevelsup;	/* > 0 if agg belongs to outer query */
  	bool		aggstar;		/* TRUE if argument was really '*' */
  	bool		aggdistinct;	/* TRUE if it's agg(DISTINCT ...) */
Index: src/include/parser/parse_agg.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/parser/parse_agg.h,v
retrieving revision 1.33
diff -c -r1.33 parse_agg.h
*** src/include/parser/parse_agg.h	5 Mar 2006 15:58:57 -0000	1.33
--- src/include/parser/parse_agg.h	25 Jul 2006 09:14:31 -0000
***************
*** 19,25 ****
  
  extern void parseCheckAggregates(ParseState *pstate, Query *qry);
  
! extern void build_aggregate_fnexprs(Oid agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
--- 19,25 ----
  
  extern void parseCheckAggregates(ParseState *pstate, Query *qry);
  
! extern void build_aggregate_fnexprs(Oid *agg_input_type,
  						Oid agg_state_type,
  						Oid agg_result_type,
  						Oid transfn_oid,
Index: src/include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.280
diff -c -r1.280 builtins.h
*** src/include/utils/builtins.h	21 Jul 2006 20:51:33 -0000	1.280
--- src/include/utils/builtins.h	25 Jul 2006 09:14:31 -0000
***************
*** 368,373 ****
--- 368,389 ----
  extern Datum float84le(PG_FUNCTION_ARGS);
  extern Datum float84gt(PG_FUNCTION_ARGS);
  extern Datum float84ge(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_count_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxx_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_syy_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxy_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_avgx_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_avgy_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_sxx_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_syy_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_sxy_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_avgx_accum(PG_FUNCTION_ARGS);
+ extern Datum float4_regr_avgy_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxx(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_syy(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_sxy(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_avg(PG_FUNCTION_ARGS);
+ 
  
  /* dbsize.c */
  extern Datum pg_tablespace_size_oid(PG_FUNCTION_ARGS);
***************
*** 836,841 ****
--- 852,885 ----
  extern Datum int4_avg_accum(PG_FUNCTION_ARGS);
  extern Datum int8_avg(PG_FUNCTION_ARGS);
  extern Datum width_bucket_numeric(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_count_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxx_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_syy_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxy_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_avgx_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_avgy_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxx(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_syy(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_sxy(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_avg(PG_FUNCTION_ARGS);
+ extern Datum numeric_covar_pop(PG_FUNCTION_ARGS);
+ extern Datum numeric_covar_samp(PG_FUNCTION_ARGS);
+ extern Datum float8_covar_pop(PG_FUNCTION_ARGS);
+ extern Datum float8_covar_samp(PG_FUNCTION_ARGS);
+ 
+ extern Datum float4_regr_all_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_all_accum(PG_FUNCTION_ARGS);
+ extern Datum float8_corr(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_r2(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_slope(PG_FUNCTION_ARGS);
+ extern Datum float8_regr_intercept(PG_FUNCTION_ARGS);
+ 
+ extern Datum numeric_regr_all_accum(PG_FUNCTION_ARGS);
+ extern Datum numeric_corr(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_r2(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_slope(PG_FUNCTION_ARGS);
+ extern Datum numeric_regr_intercept(PG_FUNCTION_ARGS);
+ 
  
  /* ri_triggers.c */
  extern Datum RI_FKey_check_ins(PG_FUNCTION_ARGS);
Index: src/test/regress/expected/opr_sanity.out
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/expected/opr_sanity.out,v
retrieving revision 1.64
diff -c -r1.64 opr_sanity.out
*** src/test/regress/expected/opr_sanity.out	11 Jul 2006 19:49:14 -0000	1.64
--- src/test/regress/expected/opr_sanity.out	25 Jul 2006 09:14:51 -0000
***************
*** 72,77 ****
--- 72,78 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
+     p1.proisagg = false AND p2.proisagg = false AND
      (p1.prolang != p2.prolang OR
       p1.proisagg != p2.proisagg OR
       p1.prosecdef != p2.prosecdef OR
***************
*** 617,623 ****
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.pronargs != 1 OR p.proretset);
   aggfnoid | proname 
  ----------+---------
  (0 rows)
--- 618,624 ----
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.proretset);
   aggfnoid | proname 
  ----------+---------
  (0 rows)
***************
*** 650,656 ****
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs = 2 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
--- 651,657 ----
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs > 1 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
Index: src/test/regress/sql/opr_sanity.sql
===================================================================
RCS file: /projects/cvsroot/pgsql/src/test/regress/sql/opr_sanity.sql,v
retrieving revision 1.50
diff -c -r1.50 opr_sanity.sql
*** src/test/regress/sql/opr_sanity.sql	2 May 2006 11:28:56 -0000	1.50
--- src/test/regress/sql/opr_sanity.sql	25 Jul 2006 09:14:55 -0000
***************
*** 75,80 ****
--- 75,81 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
+     p1.proisagg = false AND p2.proisagg = false AND
      (p1.prolang != p2.prolang OR
       p1.proisagg != p2.proisagg OR
       p1.prosecdef != p2.prosecdef OR
***************
*** 515,521 ****
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.pronargs != 1 OR p.proretset);
  
  -- Make sure there are no proisagg pg_proc entries without matches.
  
--- 516,522 ----
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.proretset);
  
  -- Make sure there are no proisagg pg_proc entries without matches.
  
***************
*** 541,547 ****
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs = 2 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
--- 542,548 ----
      (ptr.proretset
       OR NOT physically_coercible(ptr.prorettype, a.aggtranstype)
       OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0])
!      OR NOT ((ptr.pronargs > 1 AND
                physically_coercible(p.proargtypes[0], ptr.proargtypes[1]))
               OR
               (ptr.pronargs = 1 AND
#5Gregory Stark
gsstark@mit.edu
In reply to: Tom Lane (#2)
Re: patch implementing the multi-argument aggregates (SOC project)

Tom Lane <tgl@sss.pgh.pa.us> writes:

This patch is nowhere near ready for submission :-(. Most of the
comments seem to be "I don't know what to do here" ...

Just to be clear, I think what Tom's saying it's not ready to be *applied*.
Sending patches to this list early and often during development is generally
encouraged.

--
Gregory Stark
EnterpriseDB http://www.enterprisedb.com

#6Tom Lane
tgl@sss.pgh.pa.us
In reply to: Gregory Stark (#5)
Re: patch implementing the multi-argument aggregates (SOC project)

Gregory Stark <gsstark@mit.edu> writes:

Tom Lane <tgl@sss.pgh.pa.us> writes:

This patch is nowhere near ready for submission :-(. Most of the
comments seem to be "I don't know what to do here" ...

Just to be clear, I think what Tom's saying it's not ready to be *applied*.
Sending patches to this list early and often during development is generally
encouraged.

Indeed, but if that was the point we should have been seeing drafts of
this patch long ago. I interpreted Sergey's submission as "getting this
in before feature freeze", and in that context the bar is higher. If a
patch isn't pretty nearly ready to be applied when the freeze deadline
arrives, we won't wait around for it.

regards, tom lane

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Sergey E. Koposov (#4)
Re: patch implementing the multi-argument aggregates (SOC project)

"Sergey E. Koposov" <math@sai.msu.ru> writes:

Some small clean-up of the patch...
+ implementing the Tom's idea of minimizing the copying of the data inside
advance_transition_function by using the temporary FunctionCallInfoData
(now the computed arguments of the aggregates are putted directly into
proper fcinfo.args fields, ready for the transition function call).

I've committed the core parts of this, but not yet the newly added
standard aggregates (it seemed like a good idea to break the thing
into smaller chunks for review). Will work on those next.

regards, tom lane