From 4b05912f0b6aa69507bc32ac6ddaf8aeecdeb396 Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Sun, 4 Jan 1998 04:31:43 +0000
Subject: [PATCH] Fix for count(*), aggs with views and multiple tables and
 sum(3).

---
 src/backend/executor/nodeAgg.c       | 55 +++++++++++-------
 src/backend/nodes/copyfuncs.c        |  3 +-
 src/backend/parser/gram.y            | 11 ++--
 src/backend/parser/parse_agg.c       | 84 ++++++++++++++++++++++++----
 src/backend/parser/parse_func.c      | 14 ++---
 src/backend/parser/parse_relation.c  | 30 +---------
 src/backend/parser/parse_target.c    |  7 ++-
 src/backend/rewrite/locks.c          | 28 ++++++++--
 src/backend/rewrite/rewriteHandler.c |  3 +-
 src/backend/rewrite/rewriteManip.c   | 45 ++++++++++++++-
 src/include/nodes/primnodes.h        | 15 ++---
 src/include/parser/parse_agg.h       |  5 +-
 src/include/parser/parse_expr.h      |  5 +-
 src/include/parser/parse_func.h      |  4 +-
 src/include/parser/parse_relation.h  |  3 +-
 15 files changed, 215 insertions(+), 97 deletions(-)

diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 59c18ab158c..2037994027a 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -278,7 +278,7 @@ ExecAgg(Agg *node)
 		for (i = 0; i < nagg; i++)
 		{
 			AttrNumber	attnum;
-			int2		attlen;
+			int2		attlen = 0;
 			Datum		newVal = (Datum) NULL;
 			AggFuncInfo *aggfns = &aggFuncInfo[i];
 			Datum		args[2];
@@ -298,18 +298,24 @@ ExecAgg(Agg *node)
 					newVal = ExecEvalExpr(aggregates[i]->target, econtext,
 										  &isNull, &isDone);
 					break;
+				case T_Const:
+					tagnode = NULL;
+					econtext->ecxt_scantuple = outerslot;
+					newVal = ExecEvalExpr(aggregates[i]->target, econtext,
+										  &isNull, &isDone);
+					break;
 				default:
 					elog(WARN, "ExecAgg: Bad Agg->Target for Agg %d", i);
 			}
 
-			if (isNull)
+			if (isNull && !aggregates[i]->usenulls)
 				continue;		/* ignore this tuple for this agg */
 
 			if (aggfns->xfn1)
 			{
 				if (noInitValue[i])
 				{
-					int			byVal;
+					int			byVal = 0;
 
 					/*
 					 * value1 and value2 has not been initialized. This is
@@ -322,22 +328,34 @@ ExecAgg(Agg *node)
 					 * a copy of it since the tuple from which it came
 					 * will be freed on the next iteration of the scan
 					 */
-					if (tagnode != NULL)
-					{
-						FunctionCachePtr fcache_ptr;
-
-						if (nodeTag(tagnode) == T_Func)
-							fcache_ptr = ((Func *) tagnode)->func_fcache;
-						else
-							fcache_ptr = ((Oper *) tagnode)->op_fcache;
-						attlen = fcache_ptr->typlen;
-						byVal = fcache_ptr->typbyval;
-					}
-					else
+					switch (nodeTag(aggregates[i]->target))
 					{
-						attnum = ((Var *) aggregates[i]->target)->varattno;
-						attlen = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attlen;
-						byVal = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attbyval;
+						case T_Var:
+							attnum = ((Var *) aggregates[i]->target)->varattno;
+							attlen = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attlen;
+							byVal = outerslot->ttc_tupleDescriptor->attrs[attnum - 1]->attbyval;
+
+							break;
+						case T_Expr:
+						{
+							FunctionCachePtr fcache_ptr;
+		
+							if (nodeTag(tagnode) == T_Func)
+								fcache_ptr = ((Func *) tagnode)->func_fcache;
+							else
+								fcache_ptr = ((Oper *) tagnode)->op_fcache;
+							attlen = fcache_ptr->typlen;
+							byVal = fcache_ptr->typbyval;
+
+							break;
+						}
+						case T_Const:
+							attlen = ((Const *) aggregates[i]->target)->constlen;
+							byVal = ((Const *) aggregates[i]->target)->constbyval;
+
+							break;
+						default:
+							elog(WARN, "ExecAgg: Bad Agg->Target for Agg %d", i);
 					}
 					if (attlen == -1)
 					{
@@ -349,7 +367,6 @@ ExecAgg(Agg *node)
 						value1[i] = newVal;
 					else
 						memmove((char *) (value1[i]), (char *) newVal, attlen);
-					/* value1[i] = newVal; */
 					noInitValue[i] = 0;
 					nulls[i] = 0;
 				}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 96dc5097e10..edc055dfdb0 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.26 1997/12/24 06:05:52 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.27 1998/01/04 04:31:02 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -899,6 +899,7 @@ _copyAggreg(Aggreg *from)
 	newnode->aggname = pstrdup(from->aggname);
 	newnode->basetype = from->basetype;
 	newnode->aggtype = from->aggtype;
+	newnode->usenulls = from->usenulls;
 
 	Node_Copy(from, newnode, target);
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c64c8d41d25..963d5adf0dc 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.82 1998/01/01 05:44:53 thomas Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 1.83 1998/01/04 04:31:08 momjian Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -2381,8 +2381,6 @@ OptUseOp:  USING Op								{ $$ = $2; }
  *
  *	...however, recursive addattr and rename supported.  make special
  *	cases for these.
- *
- *	XXX i believe '*' should be the default behavior, but...
  */
 opt_inh_star:  '*'								{ $$ = TRUE; }
 		| /*EMPTY*/								{ $$ = FALSE; }
@@ -2978,11 +2976,12 @@ a_expr:  attr opt_indirection
 				}
 		| name '(' '*' ')'
 				{
+					/* cheap hack for aggregate (eg. count) */
 					FuncCall *n = makeNode(FuncCall);
-					Ident *star = makeNode(Ident);
+					A_Const *star = makeNode(A_Const);
 
-					/* cheap hack for aggregate (eg. count) */
-					star->name = "oid";
+					star->val.type = T_String;
+					star->val.val.str = "";
 					n->funcname = $1;
 					n->args = lcons(star, NIL);
 					$$ = (Node *)n;
diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c
index e776f695000..a244d0398ce 100644
--- a/src/backend/parser/parse_agg.c
+++ b/src/backend/parser/parse_agg.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.4 1997/12/22 05:42:19 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.5 1998/01/04 04:31:14 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,14 +18,17 @@
 #include "postgres.h"
 #include "access/heapam.h"
 #include "catalog/pg_aggregate.h"
+#include "catalog/pg_type.h"
 #include "nodes/nodeFuncs.h"
 #include "nodes/primnodes.h"
 #include "nodes/relation.h"
 #include "optimizer/clauses.h"
 #include "parser/parse_agg.h"
+#include "parser/parse_expr.h"
 #include "parser/parse_node.h"
 #include "parser/parse_target.h"
 #include "utils/syscache.h"
+#include "utils/lsyscache.h"
 
 static bool contain_agg_clause(Node *clause);
 static bool exprIsAggOrGroupCol(Node *expr, List *groupClause);
@@ -276,7 +279,8 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
 
 
 Aggreg	   *
-ParseAgg(char *aggname, Oid basetype, Node *target)
+ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
+			List *target, int precedence)
 {
 	Oid			fintype;
 	Oid			vartype;
@@ -284,7 +288,8 @@ ParseAgg(char *aggname, Oid basetype, Node *target)
 	Form_pg_aggregate aggform;
 	Aggreg	   *aggreg;
 	HeapTuple	theAggTuple;
-
+	bool		usenulls = false;
+	
 	theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname),
 									  ObjectIdGetDatum(basetype),
 									  0, 0);
@@ -293,21 +298,78 @@ ParseAgg(char *aggname, Oid basetype, Node *target)
 		elog(WARN, "aggregate %s does not exist", aggname);
 	}
 
+	/*
+	 *	We do a major hack for count(*) here.
+	 *
+	 *	Count(*) poses several problems.  First, we need a field that is
+	 *	guaranteed to be in the range table, and unique.  Using a constant
+	 *	causes the optimizer to properly remove the aggragate from any
+	 *	elements of the query.
+	 *	Using just 'oid', which can not be null, in the parser fails on:
+	 *
+	 *		select count(*) from tab1, tab2	    -- oid is not unique
+	 *		select count(*) from viewtable		-- views don't have real oids
+	 *
+	 *	So, for an aggregate with parameter '*', we use the first valid
+	 *	range table entry, and pick the first column from the table.
+	 *	We set a flag to count nulls, because we could have nulls in
+	 *	that column.
+	*/
+		
+	if (nodeTag(lfirst(target)) == T_Const)
+	{
+		Const *con = (Const *)lfirst(target);
+		
+		if (con->consttype == UNKNOWNOID && VARSIZE(con->constvalue) == VARHDRSZ)
+		{
+			Attr *attr = makeNode(Attr);
+			List	   *rtable, *rlist;
+			RangeTblEntry *first_valid_rte;
+
+			Assert(lnext(target) == NULL);
+
+			if (pstate->p_is_rule)
+				rtable = lnext(lnext(pstate->p_rtable));
+			else
+				rtable = pstate->p_rtable;
+		
+			first_valid_rte = NULL;
+			foreach(rlist, rtable)
+			{
+				RangeTblEntry *rte = lfirst(rlist);
+		
+				/* only entries on outer(non-function?) scope */
+				if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
+					continue;
+
+				first_valid_rte =rte;
+				break;
+			}
+			if (first_valid_rte == NULL)
+				elog(WARN, "Can't find column to do aggregate(*) on.");
+				
+			attr->relname = first_valid_rte->refname;
+			attr->attrs = lcons(makeString(
+							get_attname(first_valid_rte->relid,1)),NIL);
+
+			lfirst(target) = transformExpr(pstate, (Node *) attr, precedence);
+			usenulls = true;
+		}
+	}
+	
 	aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
 	fintype = aggform->aggfinaltype;
 	xfn1 = aggform->aggtransfn1;
 
-	if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
-		elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
-
+	
 	/* only aggregates with transfn1 need a base type */
 	if (OidIsValid(xfn1))
 	{
 		basetype = aggform->aggbasetype;
-		if (nodeTag(target) == T_Var)
-			vartype = ((Var *) target)->vartype;
+		if (nodeTag(lfirst(target)) == T_Var)
+			vartype = ((Var *) lfirst(target))->vartype;
 		else
-			vartype = ((Expr *) target)->typeOid;
+			vartype = ((Expr *) lfirst(target))->typeOid;
 
 		if (basetype != vartype)
 		{
@@ -327,7 +389,9 @@ ParseAgg(char *aggname, Oid basetype, Node *target)
 	aggreg->basetype = aggform->aggbasetype;
 	aggreg->aggtype = fintype;
 
-	aggreg->target = target;
+	aggreg->target = lfirst(target);
+	if (usenulls)
+		aggreg->usenulls = true;
 
 	return aggreg;
 }
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 4d1017b54a0..43c78e299de 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.3 1997/11/26 03:42:42 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.4 1998/01/04 04:31:18 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -87,7 +87,8 @@ typedef struct _SuperQE
  */
 
 Node *
-ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
+ParseFunc(ParseState *pstate, char *funcname, List *fargs,
+		int *curr_resno, int precedence)
 {
 	Oid			rettype = (Oid) 0;
 	Oid			argrelid = (Oid) 0;
@@ -194,9 +195,7 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
 				 */
 				if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
 					&& strcmp(funcname, "*"))
-				{
 					elog(WARN, "Functions on sets are not yet supported");
-				}
 			}
 
 			if (retval)
@@ -223,7 +222,8 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
 									ObjectIdGetDatum(basetype),
 									0, 0))
 			{
-				Aggreg	   *aggreg = ParseAgg(funcname, basetype, lfirst(fargs));
+				Aggreg	   *aggreg = ParseAgg(pstate, funcname, basetype,
+										fargs, precedence);
 
 				AddAggToParseState(pstate, aggreg);
 				return (Node *) aggreg;
@@ -368,7 +368,7 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
 		else
 		{
 			funcnode->func_tlist = setup_tlist(funcname, argrelid);
-			rettype = attnameTypeId(argrelid, funcname);
+			rettype = get_atttype(argrelid, get_attnum(argrelid, funcname));
 		}
 	}
 
@@ -1031,7 +1031,7 @@ setup_tlist(char *attname, Oid relid)
 	if (attno < 0)
 		elog(WARN, "cannot reference attribute '%s' of tuple params/return values for functions", attname);
 
-	typeid = attnameTypeId(relid, attname);
+	typeid = get_atttype(relid, attno);
 	resnode = makeResdom(1,
 						 typeid,
 						 typeLen(typeidType(typeid)),
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index 2b880213d7d..e2c53ed1523 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.3 1997/11/26 03:42:48 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.4 1998/01/04 04:31:19 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -346,34 +346,6 @@ attnumAttNelems(Relation rd, int attid)
 	return (rd->rd_att->attrs[attid - 1]->attnelems);
 }
 
-Oid
-attnameTypeId(Oid relid, char *attrname)
-{
-	int			attid;
-	Oid			vartype;
-	Relation	rd;
-
-	rd = heap_open(relid);
-	if (!RelationIsValid(rd))
-	{
-		rd = heap_openr(typeidTypeName(relid));
-		if (!RelationIsValid(rd))
-			elog(WARN, "cannot compute type of att %s for relid %d",
-				 attrname, relid);
-	}
-
-	attid = attnameAttNum(rd, attrname); /* could elog(WARN) and never return */
-
-	vartype = attnumTypeId(rd, attid);
-
-	/*
-	 * close relation we're done with it now
-	 */
-	heap_close(rd);
-
-	return (vartype);
-}
-
 /* given attribute id, return type of that attribute */
 /* XXX Special case for pseudo-attributes is a hack */
 Oid
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 04739fe5503..a7049b0b3f7 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -7,7 +7,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.3 1997/11/26 03:42:49 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.4 1998/01/04 04:31:22 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -255,7 +255,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
 					 * Target item is fully specified: ie.
 					 * relation.attribute
 					 */
-					result = handleNestedDots(pstate, att, &pstate->p_last_resno);
+					result = handleNestedDots(pstate, att, &pstate->p_last_resno,EXPR_COLUMN_FIRST);
 					handleTargetColname(pstate, &res->name, att->relname, attrname);
 					if (att->indirection != NIL)
 					{
@@ -467,7 +467,8 @@ make_targetlist_expr(ParseState *pstate,
 			att->relname = pstrdup(RelationGetRelationName(rd)->data);
 			att->attrs = lcons(makeString(colname), NIL);
 			target_expr = (Expr *) handleNestedDots(pstate, att,
-												  &pstate->p_last_resno);
+												  &pstate->p_last_resno,
+												  EXPR_COLUMN_FIRST);
 			while (ar != NIL)
 			{
 				A_Indices  *ind = lfirst(ar);
diff --git a/src/backend/rewrite/locks.c b/src/backend/rewrite/locks.c
index d446da653cc..70dc37080e2 100644
--- a/src/backend/rewrite/locks.c
+++ b/src/backend/rewrite/locks.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.5 1997/09/08 21:46:33 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/Attic/locks.c,v 1.6 1998/01/04 04:31:27 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -58,6 +58,14 @@ nodeThisLockWasTriggered(Node *node, int varno, AttrNumber attnum)
 					nodeThisLockWasTriggered(tle->expr, varno, attnum);
 			}
 			break;
+		case T_Aggreg:
+			{
+				Aggreg *agg = (Aggreg *) node;
+
+				return
+					nodeThisLockWasTriggered(agg->target, varno, attnum);
+			}
+			break;
 		case T_List:
 			{
 				List	   *l;
@@ -87,10 +95,20 @@ thisLockWasTriggered(int varno,
 					 AttrNumber attnum,
 					 Query *parsetree)
 {
-	return
-	(nodeThisLockWasTriggered(parsetree->qual, varno, attnum) ||
-	 nodeThisLockWasTriggered((Node *) parsetree->targetList,
-							  varno, attnum));
+	int i;
+	
+	if (nodeThisLockWasTriggered(parsetree->qual, varno, attnum))
+		return true;
+
+	if (nodeThisLockWasTriggered((Node *) parsetree->targetList, varno, attnum))
+		return true;
+
+	for(i=0; i < parsetree->qry_numAgg; i++)
+		if (nodeThisLockWasTriggered(parsetree->qry_aggs[i]->target,
+					varno, attnum))
+			return true;
+	return false;
+		
 }
 
 /*
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index d6dc95e387d..1f6bd86343c 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.6 1997/09/08 21:46:38 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.7 1998/01/04 04:31:28 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -225,6 +225,7 @@ FireRetrieveRulesAtQuery(Query *parsetree,
 			{
 				*instead_flag = TRUE;
 				FixResdomTypes(parsetree->targetList);
+
 				return lcons(parsetree, NIL);
 			}
 		}
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index f7e3896040c..122067a2424 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -6,7 +6,7 @@
  *
  *
  * IDENTIFICATION
- *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.8 1997/09/18 20:21:11 momjian Exp $
+ *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteManip.c,v 1.9 1998/01/04 04:31:29 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,6 +46,13 @@ OffsetVarNodes(Node *node, int offset)
 				OffsetVarNodes(tle->expr, offset);
 			}
 			break;
+		case T_Aggreg:
+			{
+				Aggreg *agg = (Aggreg *) node;
+
+				OffsetVarNodes(agg->target, offset);
+			}
+			break;
 		case T_Expr:
 			{
 				Expr	   *expr = (Expr *) node;
@@ -91,6 +98,13 @@ ChangeVarNodes(Node *node, int old_varno, int new_varno)
 				ChangeVarNodes(tle->expr, old_varno, new_varno);
 			}
 			break;
+		case T_Aggreg:
+			{
+				Aggreg *agg = (Aggreg *) node;
+
+				ChangeVarNodes(agg->target, old_varno, new_varno);
+			}
+			break;
 		case T_Expr:
 			{
 				Expr	   *expr = (Expr *) node;
@@ -235,6 +249,9 @@ ResolveNew(RewriteInfo *info, List *targetlist, Node **nodePtr)
 		case T_TargetEntry:
 			ResolveNew(info, targetlist, &((TargetEntry *) node)->expr);
 			break;
+		case T_Aggreg:
+			ResolveNew(info, targetlist, &((Aggreg *) node)->target);
+			break;
 		case T_Expr:
 			ResolveNew(info, targetlist, (Node **) (&(((Expr *) node)->args)));
 			break;
@@ -325,6 +342,14 @@ nodeHandleRIRAttributeRule(Node **nodePtr,
 								   rt_index, attr_num, modified, badsql);
 			}
 			break;
+		case T_Aggreg:
+			{
+				Aggreg *agg = (Aggreg *) node;
+
+				nodeHandleRIRAttributeRule(&agg->target, rtable, targetlist,
+								   rt_index, attr_num, modified, badsql);
+			}
+			break;
 		case T_Expr:
 			{
 				Expr	   *expr = (Expr *) node;
@@ -395,11 +420,16 @@ HandleRIRAttributeRule(Query *parsetree,
 					   int *modified,
 					   int *badsql)
 {
+	int i;
+	
 	nodeHandleRIRAttributeRule((Node **) (&(parsetree->targetList)), rtable,
 							   targetlist, rt_index, attr_num,
 							   modified, badsql);
 	nodeHandleRIRAttributeRule(&parsetree->qual, rtable, targetlist,
 							   rt_index, attr_num, modified, badsql);
+	for(i=0; i < parsetree->qry_numAgg; i++)
+		nodeHandleRIRAttributeRule(&parsetree->qry_aggs[i]->target, rtable,
+					targetlist, rt_index, attr_num, modified, badsql);
 }
 
 
@@ -437,6 +467,14 @@ nodeHandleViewRule(Node **nodePtr,
 								   rt_index, modified);
 			}
 			break;
+		case T_Aggreg:
+			{
+				Aggreg *agg = (Aggreg *) node;
+
+				nodeHandleViewRule(&(agg->target), rtable, targetlist,
+								   rt_index, modified);
+			}
+			break;
 		case T_Expr:
 			{
 				Expr	   *expr = (Expr *) node;
@@ -483,8 +521,13 @@ HandleViewRule(Query *parsetree,
 			   int rt_index,
 			   int *modified)
 {
+	int i;
+	
 	nodeHandleViewRule(&parsetree->qual, rtable, targetlist, rt_index,
 					   modified);
 	nodeHandleViewRule((Node **) (&(parsetree->targetList)), rtable, targetlist,
 					   rt_index, modified);
+	for(i=0; i < parsetree->qry_numAgg; i++)
+		nodeHandleViewRule(&parsetree->qry_aggs[i]->target, rtable, targetlist, rt_index,
+					   modified);
 }
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index f0706d1392e..1e896e5e136 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: primnodes.h,v 1.11 1997/09/08 21:52:58 momjian Exp $
+ * $Id: primnodes.h,v 1.12 1998/01/04 04:31:37 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -255,18 +255,19 @@ typedef struct Func
  *		aggname			- name of the aggregate
  *		basetype		- base type Oid of the aggregate
  *		aggtype			- type Oid of final result of the aggregate
- *		query			- XXX comment me
- *		target			- XXX comment me
+ *		target			- attribute or expression we are aggregating on
+ *		aggno			- index to ecxt_values
  * ----------------
  */
 typedef struct Aggreg
 {
 	NodeTag		type;
 	char	   *aggname;
-	Oid			basetype;		/* base type of the aggregate */
-	Oid			aggtype;		/* type of final result */
-	Node	   *target;			/* attribute to aggreg on */
-	int			aggno;			/* index to ecxt_values */
+	Oid			basetype;
+	Oid			aggtype;
+	Node	   *target;	
+	int			aggno;
+	bool		usenulls;
 } Aggreg;
 
 /* ----------------
diff --git a/src/include/parser/parse_agg.h b/src/include/parser/parse_agg.h
index 9761aa94e17..8d1e0fb31fd 100644
--- a/src/include/parser/parse_agg.h
+++ b/src/include/parser/parse_agg.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_agg.h,v 1.3 1997/11/26 03:43:08 momjian Exp $
+ * $Id: parse_agg.h,v 1.4 1998/01/04 04:31:39 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,8 @@
 extern void AddAggToParseState(ParseState *pstate, Aggreg *aggreg);
 extern void finalizeAggregates(ParseState *pstate, Query *qry);
 extern void parseCheckAggregates(ParseState *pstate, Query *qry);
-extern Aggreg *ParseAgg(char *aggname, Oid basetype, Node *target);
+extern Aggreg *ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
+			List *target, int precedence);
 extern void agg_error(char *caller, char *aggname, Oid basetypeID);
 
 #endif							/* PARSE_AGG_H */
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
index f26bf34acb9..ba8eed9c814 100644
--- a/src/include/parser/parse_expr.h
+++ b/src/include/parser/parse_expr.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_expr.h,v 1.3 1997/11/26 03:43:11 momjian Exp $
+ * $Id: parse_expr.h,v 1.4 1998/01/04 04:31:41 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,7 +21,8 @@
 extern Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
 extern Node *transformIdent(ParseState *pstate, Node *expr, int precedence);
 extern Oid exprType(Node *expr);
-extern Node *handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno);
+extern Node *handleNestedDots(ParseState *pstate, Attr *attr,
+		int *curr_resno, int precedence);
 extern Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen);
 
 #endif							/* PARSE_EXPR_H */
diff --git a/src/include/parser/parse_func.h b/src/include/parser/parse_func.h
index 9ff6ee91b80..12d6ba16b88 100644
--- a/src/include/parser/parse_func.h
+++ b/src/include/parser/parse_func.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_func.h,v 1.3 1997/11/26 03:43:12 momjian Exp $
+ * $Id: parse_func.h,v 1.4 1998/01/04 04:31:42 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,7 +43,7 @@ typedef struct _CandidateList
 }		   *CandidateList;
 
 extern Node *ParseFunc(ParseState *pstate, char *funcname, List *fargs,
-	int *curr_resno);
+	int *curr_resno, int precedence);
 
 extern void func_error(char *caller, char *funcname, int nargs, Oid *argtypes);
 
diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h
index 7c78757ac32..e379b92932f 100644
--- a/src/include/parser/parse_relation.h
+++ b/src/include/parser/parse_relation.h
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_relation.h,v 1.3 1997/11/26 03:43:16 momjian Exp $
+ * $Id: parse_relation.h,v 1.4 1998/01/04 04:31:43 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,7 +34,6 @@ extern int attnameAttNum(Relation rd, char *a);
 extern bool attnameIsSet(Relation rd, char *name);
 extern char *attnumAttName(Relation rd, int attrno);
 extern int attnumAttNelems(Relation rd, int attid);
-extern Oid attnameTypeId(Oid relid, char *attrname);
 extern Oid attnumTypeId(Relation rd, int attid);
 extern void handleTargetColname(ParseState *pstate, char **resname,
 					char *refname, char *colname);
-- 
GitLab