setrefs.c 21.6 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * setrefs.c--
4
 *	  Routines to change varno/attno entries to contain references
5 6 7 8 9
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.11 1998/01/05 03:32:05 momjian Exp $
11 12 13
 *
 *-------------------------------------------------------------------------
 */
M
Marc G. Fournier 已提交
14 15
#include <sys/types.h>

16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
#include "postgres.h"

#include "nodes/pg_list.h"
#include "nodes/plannodes.h"
#include "nodes/primnodes.h"
#include "nodes/relation.h"

#include "utils/elog.h"
#include "nodes/nodeFuncs.h"
#include "nodes/makefuncs.h"

#include "optimizer/internal.h"
#include "optimizer/clauses.h"
#include "optimizer/clauseinfo.h"
#include "optimizer/keys.h"
#include "optimizer/planmain.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
#include "optimizer/tlist.h"

36 37 38
static void set_join_tlist_references(Join *join);
static void set_tempscan_tlist_references(SeqScan *tempscan);
static void set_temp_tlist_references(Temp *temp);
39
static List *
40 41
replace_clause_joinvar_refs(Expr *clause,
							List *outer_tlist, List *inner_tlist);
42
static List *
43 44 45 46 47 48 49
replace_subclause_joinvar_refs(List *clauses,
							   List *outer_tlist, List *inner_tlist);
static Var *replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist);
static List *tlist_temp_references(Oid tempid, List *tlist);
static void replace_result_clause(List *clause, List *subplanTargetList);
static bool OperandIsInner(Node *opnd, int inner_relid);
static void replace_agg_clause(Node *expr, List *targetlist);
50
static Node *del_agg_clause(Node *clause);
51 52

/*****************************************************************************
53 54 55
 *
 *		SUBPLAN REFERENCES
 *
56 57
 *****************************************************************************/

58
/*
59
 * set-tlist-references--
60 61 62
 *	  Modifies the target list of nodes in a plan to reference target lists
 *	  at lower levels.
 *
63
 * 'plan' is the plan whose target list and children's target lists will
64 65
 *		be modified
 *
66
 * Returns nothing of interest, but modifies internal fields of nodes.
67
 *
68 69
 */
void
70
set_tlist_references(Plan *plan)
71
{
72 73 74 75 76 77 78
	if (plan == NULL)
		return;

	if (IsA_Join(plan))
	{
		set_join_tlist_references((Join *) plan);
	}
79
	else if (IsA(plan, SeqScan) &&plan->lefttree &&
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
			 IsA_Temp(plan->lefttree))
	{
		set_tempscan_tlist_references((SeqScan *) plan);
	}
	else if (IsA(plan, Sort))
	{
		set_temp_tlist_references((Temp *) plan);
	}
	else if (IsA(plan, Result))
	{
		set_result_tlist_references((Result *) plan);
	}
	else if (IsA(plan, Hash))
	{
		set_tlist_references(plan->lefttree);
	}
	else if (IsA(plan, Choose))
	{
98
		List	   *x;
99 100 101 102 103 104

		foreach(x, ((Choose *) plan)->chooseplanlist)
		{
			set_tlist_references((Plan *) lfirst(x));
		}
	}
105 106
}

107
/*
108
 * set-join-tlist-references--
109 110 111 112 113 114 115 116 117
 *	  Modifies the target list of a join node by setting the varnos and
 *	  varattnos to reference the target list of the outer and inner join
 *	  relations.
 *
 *	  Creates a target list for a join node to contain references by setting
 *	  varno values to OUTER or INNER and setting attno values to the
 *	  result domain number of either the corresponding outer or inner join
 *	  tuple.
 *
118
 * 'join' is a join plan node
119
 *
120
 * Returns nothing of interest, but modifies internal fields of nodes.
121
 *
122 123
 */
static void
124
set_join_tlist_references(Join *join)
125
{
126 127 128 129 130 131 132 133 134
	Plan	   *outer = ((Plan *) join)->lefttree;
	Plan	   *inner = ((Plan *) join)->righttree;
	List	   *new_join_targetlist = NIL;
	TargetEntry *temp = (TargetEntry *) NULL;
	List	   *entry = NIL;
	List	   *inner_tlist = NULL;
	List	   *outer_tlist = NULL;
	TargetEntry *xtl = (TargetEntry *) NULL;
	List	   *qptlist = ((Plan *) join)->targetlist;
135 136 137

	foreach(entry, qptlist)
	{
138
		List	   *joinvar;
139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

		xtl = (TargetEntry *) lfirst(entry);
		inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
		outer_tlist = ((outer == NULL) ? NIL : outer->targetlist);
		joinvar = replace_clause_joinvar_refs((Expr *) get_expr(xtl),
											  outer_tlist,
											  inner_tlist);

		temp = MakeTLE(xtl->resdom, (Node *) joinvar);
		new_join_targetlist = lappend(new_join_targetlist, temp);
	}

	((Plan *) join)->targetlist = new_join_targetlist;
	if (outer != NULL)
		set_tlist_references(outer);
	if (inner != NULL)
		set_tlist_references(inner);
156 157
}

158
/*
159
 * set-tempscan-tlist-references--
160 161 162
 *	  Modifies the target list of a node that scans a temp relation (i.e., a
 *	  sort or hash node) so that the varnos refer to the child temporary.
 *
163
 * 'tempscan' is a seqscan node
164
 *
165
 * Returns nothing of interest, but modifies internal fields of nodes.
166
 *
167 168
 */
static void
169
set_tempscan_tlist_references(SeqScan *tempscan)
170
{
171
	Temp	   *temp = (Temp *) ((Plan *) tempscan)->lefttree;
172

173 174 175 176
	((Plan *) tempscan)->targetlist =
		tlist_temp_references(temp->tempid,
							  ((Plan *) tempscan)->targetlist);
	set_temp_tlist_references(temp);
177 178
}

179
/*
180
 * set-temp-tlist-references--
181 182 183 184
 *	  The temp's vars are made consistent with (actually, identical to) the
 *	  modified version of the target list of the node from which temp node
 *	  receives its tuples.
 *
185
 * 'temp' is a temp (e.g., sort, hash) plan node
186
 *
187
 * Returns nothing of interest, but modifies internal fields of nodes.
188
 *
189 190
 */
static void
191
set_temp_tlist_references(Temp *temp)
192
{
193
	Plan	   *source = ((Plan *) temp)->lefttree;
194 195 196 197 198 199 200 201 202 203

	if (source != NULL)
	{
		set_tlist_references(source);
		((Plan *) temp)->targetlist =
			copy_vars(((Plan *) temp)->targetlist,
					  (source)->targetlist);
	}
	else
	{
204
		elog(ABORT, "calling set_temp_tlist_references with empty lefttree");
205
	}
206 207
}

208
/*
209
 * join-references--
210 211 212 213
 *	   Creates a new set of join clauses by replacing the varno/varattno
 *	   values of variables in the clauses to reference target list values
 *	   from the outer and inner join relation target lists.
 *
214 215 216
 * 'clauses' is the list of join clauses
 * 'outer-tlist' is the target list of the outer join relation
 * 'inner-tlist' is the target list of the inner join relation
217
 *
218
 * Returns the new join clauses.
219
 *
220
 */
221
List	   *
222 223 224
join_references(List *clauses,
				List *outer_tlist,
				List *inner_tlist)
225
{
226 227 228
	return (replace_subclause_joinvar_refs(clauses,
										   outer_tlist,
										   inner_tlist));
229 230
}

231
/*
232
 * index-outerjoin-references--
233 234 235 236 237 238 239 240
 *	  Given a list of join clauses, replace the operand corresponding to the
 *	  outer relation in the join with references to the corresponding target
 *	  list element in 'outer-tlist' (the outer is rather obscurely
 *	  identified as the side that doesn't contain a var whose varno equals
 *	  'inner-relid').
 *
 *	  As a side effect, the operator is replaced by the regproc id.
 *
241 242
 * 'inner-indxqual' is the list of join clauses (so-called because they
 * are used as qualifications for the inner (inbex) scan of a nestloop)
243
 *
244
 * Returns the new list of clauses.
245
 *
246
 */
247
List	   *
248 249
index_outerjoin_references(List *inner_indxqual,
						   List *outer_tlist,
250
						   Index inner_relid)
251
{
252 253 254 255
	List	   *t_list = NIL;
	Expr	   *temp = NULL;
	List	   *t_clause = NIL;
	Expr	   *clause = NULL;
256

257 258 259 260 261 262 263 264 265
	foreach(t_clause, inner_indxqual)
	{
		clause = lfirst(t_clause);

		/*
		 * if inner scan on the right.
		 */
		if (OperandIsInner((Node *) get_rightop(clause), inner_relid))
		{
266
			Var		   *joinvar = (Var *)
267 268 269 270 271 272 273 274 275 276 277 278
			replace_clause_joinvar_refs((Expr *) get_leftop(clause),
										outer_tlist,
										NIL);

			temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
								 joinvar,
								 get_rightop(clause));
			t_list = lappend(t_list, temp);
		}
		else
		{
			/* inner scan on left */
279
			Var		   *joinvar = (Var *)
280 281 282 283 284 285 286 287 288 289 290 291
			replace_clause_joinvar_refs((Expr *) get_rightop(clause),
										outer_tlist,
										NIL);

			temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
								 get_leftop(clause),
								 joinvar);
			t_list = lappend(t_list, temp);
		}

	}
	return (t_list);
292 293
}

294
/*
295 296 297
 * replace-clause-joinvar-refs
 * replace-subclause-joinvar-refs
 * replace-joinvar-refs
298 299 300 301 302
 *
 *	  Replaces all variables within a join clause with a new var node
 *	  whose varno/varattno fields contain a reference to a target list
 *	  element from either the outer or inner join relation.
 *
303 304 305
 * 'clause' is the join clause
 * 'outer-tlist' is the target list of the outer join relation
 * 'inner-tlist' is the target list of the inner join relation
306
 *
307
 * Returns the new join clause.
308
 *
309
 */
310
static List *
311 312 313
replace_clause_joinvar_refs(Expr *clause,
							List *outer_tlist,
							List *inner_tlist)
314
{
315
	List	   *temp = NULL;
316

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
	if (IsA(clause, Var))
	{
		temp = (List *) replace_joinvar_refs((Var *) clause,
											 outer_tlist, inner_tlist);
		if (temp)
			return (temp);
		else if (clause != NULL)
			return ((List *) clause);
		else
			return (NIL);
	}
	else if (single_node((Node *) clause))
	{
		return ((List *) clause);
	}
332 333 334 335 336 337 338 339 340
	else if (and_clause((Node *) clause))
	{
		List	   *andclause =
		replace_subclause_joinvar_refs(((Expr *) clause)->args,
									   outer_tlist,
									   inner_tlist);

		return ((List *) make_andclause(andclause));
	}
341 342
	else if (or_clause((Node *) clause))
	{
343
		List	   *orclause =
344 345 346
		replace_subclause_joinvar_refs(((Expr *) clause)->args,
									   outer_tlist,
									   inner_tlist);
347

348 349 350 351
		return ((List *) make_orclause(orclause));
	}
	else if (IsA(clause, ArrayRef))
	{
352
		ArrayRef   *aref = (ArrayRef *) clause;
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377

		temp = replace_subclause_joinvar_refs(aref->refupperindexpr,
											  outer_tlist,
											  inner_tlist);
		aref->refupperindexpr = (List *) temp;
		temp = replace_subclause_joinvar_refs(aref->reflowerindexpr,
											  outer_tlist,
											  inner_tlist);
		aref->reflowerindexpr = (List *) temp;
		temp = replace_clause_joinvar_refs((Expr *) aref->refexpr,
										   outer_tlist,
										   inner_tlist);
		aref->refexpr = (Node *) temp;

		/*
		 * no need to set refassgnexpr.  we only set that in the target
		 * list on replaces, and this is an array reference in the
		 * qualification.  if we got this far, it's 0x0 in the ArrayRef
		 * structure 'clause'.
		 */

		return ((List *) clause);
	}
	else if (is_funcclause((Node *) clause))
	{
378
		List	   *funcclause =
379 380 381 382 383 384 385 386 387
		replace_subclause_joinvar_refs(((Expr *) clause)->args,
									   outer_tlist,
									   inner_tlist);

		return ((List *) make_funcclause((Func *) ((Expr *) clause)->oper,
										 funcclause));
	}
	else if (not_clause((Node *) clause))
	{
388
		List	   *notclause =
389 390 391
		replace_clause_joinvar_refs(get_notclausearg(clause),
									outer_tlist,
									inner_tlist);
392

393 394 395 396
		return ((List *) make_notclause((Expr *) notclause));
	}
	else if (is_opclause((Node *) clause))
	{
397
		Var		   *leftvar =
398 399 400
		(Var *) replace_clause_joinvar_refs((Expr *) get_leftop(clause),
											outer_tlist,
											inner_tlist);
401
		Var		   *rightvar =
402 403 404 405 406 407 408 409 410 411
		(Var *) replace_clause_joinvar_refs((Expr *) get_rightop(clause),
											outer_tlist,
											inner_tlist);

		return ((List *) make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
									   leftvar,
									   rightvar));
	}
	/* shouldn't reach here */
	return NULL;
412 413
}

414
static List *
415 416 417
replace_subclause_joinvar_refs(List *clauses,
							   List *outer_tlist,
							   List *inner_tlist)
418
{
419 420 421
	List	   *t_list = NIL;
	List	   *temp = NIL;
	List	   *clause = NIL;
422 423 424 425 426 427 428 429 430

	foreach(clause, clauses)
	{
		temp = replace_clause_joinvar_refs(lfirst(clause),
										   outer_tlist,
										   inner_tlist);
		t_list = lappend(t_list, temp);
	}
	return (t_list);
431 432
}

433
static Var *
434
replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist)
435
{
436
	Resdom	   *outer_resdom = (Resdom *) NULL;
437 438 439 440 441 442 443 444 445 446 447 448 449

	outer_resdom = tlist_member(var, outer_tlist);

	if (outer_resdom != NULL && IsA(outer_resdom, Resdom))
	{
		return (makeVar(OUTER,
						outer_resdom->resno,
						var->vartype,
						var->varnoold,
						var->varoattno));
	}
	else
	{
450
		Resdom	   *inner_resdom;
451 452 453 454 455 456 457 458 459 460 461 462

		inner_resdom = tlist_member(var, inner_tlist);
		if (inner_resdom != NULL && IsA(inner_resdom, Resdom))
		{
			return (makeVar(INNER,
							inner_resdom->resno,
							var->vartype,
							var->varnoold,
							var->varoattno));
		}
	}
	return (Var *) NULL;
463 464
}

465
/*
466
 * tlist-temp-references--
467 468 469 470 471 472
 *	  Creates a new target list for a node that scans a temp relation,
 *	  setting the varnos to the id of the temp relation and setting varids
 *	  if necessary (varids are only needed if this is a targetlist internal
 *	  to the tree, in which case the targetlist entry always contains a var
 *	  node, so we can just copy it from the temp).
 *
473 474
 * 'tempid' is the id of the temp relation
 * 'tlist' is the target list to be modified
475
 *
476
 * Returns new target list
477
 *
478
 */
479
static List *
480
tlist_temp_references(Oid tempid,
481
					  List *tlist)
482
{
483 484 485 486
	List	   *t_list = NIL;
	TargetEntry *temp = (TargetEntry *) NULL;
	TargetEntry *xtl = NULL;
	List	   *entry;
487 488 489

	foreach(entry, tlist)
	{
490
		AttrNumber	oattno;
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507

		xtl = lfirst(entry);
		if (IsA(get_expr(xtl), Var))
			oattno = ((Var *) xtl->expr)->varoattno;
		else
			oattno = 0;

		temp = MakeTLE(xtl->resdom,
					   (Node *) makeVar(tempid,
										xtl->resdom->resno,
										xtl->resdom->restype,
										tempid,
										oattno));

		t_list = lappend(t_list, temp);
	}
	return (t_list);
508 509 510 511 512 513 514 515 516 517
}

/*---------------------------------------------------------
 *
 * set_result_tlist_references
 *
 * Change the target list of a Result node, so that it correctly
 * addresses the tuples returned by its left tree subplan.
 *
 * NOTE:
518 519 520 521
 *	1) we ignore the right tree! (in the current implementation
 *	   it is always nil
 *	2) this routine will probably *NOT* work with nested dot
 *	   fields....
522 523
 */
void
524
set_result_tlist_references(Result *resultNode)
525
{
526 527 528 529 530 531
	Plan	   *subplan;
	List	   *resultTargetList;
	List	   *subplanTargetList;
	List	   *t;
	TargetEntry *entry;
	Expr	   *expr;
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560

	resultTargetList = ((Plan *) resultNode)->targetlist;

	/*
	 * NOTE: we only consider the left tree subplan. This is usually a seq
	 * scan.
	 */
	subplan = ((Plan *) resultNode)->lefttree;
	if (subplan != NULL)
	{
		subplanTargetList = subplan->targetlist;
	}
	else
	{
		subplanTargetList = NIL;
	}

	/*
	 * now for traverse all the entris of the target list. These should be
	 * of the form (Resdom_Node Expression). For every expression clause,
	 * call "replace_result_clause()" to appropriatelly change all the Var
	 * nodes.
	 */
	foreach(t, resultTargetList)
	{
		entry = (TargetEntry *) lfirst(t);
		expr = (Expr *) get_expr(entry);
		replace_result_clause((List *) expr, subplanTargetList);
	}
561 562 563 564 565 566 567 568 569
}

/*---------------------------------------------------------
 *
 * replace_result_clause
 *
 * This routine is called from set_result_tlist_references().
 * and modifies the expressions of the target list of a Result
 * node so that all Var nodes reference the target list of its subplan.
570
 *
571 572
 */
static void
573 574
replace_result_clause(List *clause,
					  List *subplanTargetList)	/* target list of the
575
												 * subplan */
576
{
577 578 579
	List	   *t;
	List	   *subClause;
	TargetEntry *subplanVar;
580

581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
	if (IsA(clause, Var))
	{

		/*
		 * Ha! A Var node!
		 */
		subplanVar = match_varid((Var *) clause, subplanTargetList);

		/*
		 * Change the varno & varattno fields of the var node.
		 *
		 */
		((Var *) clause)->varno = (Index) OUTER;
		((Var *) clause)->varattno = subplanVar->resdom->resno;
	}
	else if (is_funcclause((Node *) clause))
	{

		/*
		 * This is a function. Recursively call this routine for its
		 * arguments...
		 */
		subClause = ((Expr *) clause)->args;
		foreach(t, subClause)
		{
			replace_result_clause(lfirst(t), subplanTargetList);
		}
	}
	else if (IsA(clause, ArrayRef))
	{
611
		ArrayRef   *aref = (ArrayRef *) clause;
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

		/*
		 * This is an arrayref. Recursively call this routine for its
		 * expression and its index expression...
		 */
		subClause = aref->refupperindexpr;
		foreach(t, subClause)
		{
			replace_result_clause(lfirst(t), subplanTargetList);
		}
		subClause = aref->reflowerindexpr;
		foreach(t, subClause)
		{
			replace_result_clause(lfirst(t), subplanTargetList);
		}
		replace_result_clause((List *) aref->refexpr,
							  subplanTargetList);
		replace_result_clause((List *) aref->refassgnexpr,
							  subplanTargetList);
	}
	else if (is_opclause((Node *) clause))
	{

		/*
		 * This is an operator. Recursively call this routine for both its
		 * left and right operands
		 */
		subClause = (List *) get_leftop((Expr *) clause);
		replace_result_clause(subClause, subplanTargetList);
		subClause = (List *) get_rightop((Expr *) clause);
		replace_result_clause(subClause, subplanTargetList);
	}
644
	else if (IsA(clause, Param) ||IsA(clause, Const))
645 646 647 648 649 650 651 652 653
	{
		/* do nothing! */
	}
	else
	{

		/*
		 * Ooops! we can not handle that!
		 */
654
		elog(ABORT, "replace_result_clause: Can not handle this tlist!\n");
655
	}
656 657 658
}

static
659 660
bool
OperandIsInner(Node *opnd, int inner_relid)
661
{
662 663 664 665 666 667 668 669 670

	/*
	 * Can be the inner scan if its a varnode or a function and the
	 * inner_relid is equal to the varnode's var number or in the case of
	 * a function the first argument's var number (all args in a
	 * functional index are from the same relation).
	 */
	if (IsA(opnd, Var) &&
		(inner_relid == ((Var *) opnd)->varno))
671
	{
672
		return true;
673
	}
674
	if (is_funcclause(opnd))
675
	{
676
		List	   *firstArg = lfirst(((Expr *) opnd)->args);
677

678 679
		if (IsA(firstArg, Var) &&
			(inner_relid == ((Var *) firstArg)->varno))
680
		{
681
			return true;
682 683
		}
	}
684
	return false;
685 686 687 688 689 690 691 692 693
}

/*****************************************************************************
 *
 *****************************************************************************/

/*---------------------------------------------------------
 *
 * set_agg_tlist_references -
694 695
 *	  changes the target list of an Agg node so that it points to
 *	  the tuples returned by its left tree subplan.
696 697 698
 *
 */
void
B
Bruce Momjian 已提交
699
set_agg_tlist_references(Agg *aggNode)
700
{
701 702 703
	List	   *aggTargetList;
	List	   *subplanTargetList;
	List	   *tl;
704

705 706
	aggTargetList = aggNode->plan.targetlist;
	subplanTargetList = aggNode->plan.lefttree->targetlist;
707

708 709
	foreach(tl, aggTargetList)
	{
710
		TargetEntry *tle = lfirst(tl);
711

712 713
		replace_agg_clause(tle->expr, subplanTargetList);
	}
714 715 716
}

void
B
Bruce Momjian 已提交
717
set_agg_agglist_references(Agg *aggNode)
718
{
719 720 721
	List	   *subplanTargetList;
	Aggreg	  **aggs;
	int			i;
722

723 724
	aggs = aggNode->aggs;
	subplanTargetList = aggNode->plan.lefttree->targetlist;
725

726 727 728 729
	for (i = 0; i < aggNode->numAgg; i++)
	{
		replace_agg_clause(aggs[i]->target, subplanTargetList);
	}
730 731 732
}

static void
733
replace_agg_clause(Node *clause, List *subplanTargetList)
734
{
735 736
	List	   *t;
	TargetEntry *subplanVar;
737

738 739
	if (IsA(clause, Var))
	{
740

741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
		/*
		 * Ha! A Var node!
		 */
		subplanVar = match_varid((Var *) clause, subplanTargetList);

		/*
		 * Change the varno & varattno fields of the var node.
		 *
		 */
		((Var *) clause)->varattno = subplanVar->resdom->resno;
	}
	else if (is_funcclause(clause))
	{

		/*
		 * This is a function. Recursively call this routine for its
		 * arguments...
		 */
		foreach(t, ((Expr *) clause)->args)
		{
			replace_agg_clause(lfirst(t), subplanTargetList);
		}
763
	}
764 765 766
	else if (IsA(clause, Aggreg))
	{
		replace_agg_clause(((Aggreg *) clause)->target, subplanTargetList);
767
	}
768 769
	else if (IsA(clause, ArrayRef))
	{
770
		ArrayRef   *aref = (ArrayRef *) clause;
771

772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
		/*
		 * This is an arrayref. Recursively call this routine for its
		 * expression and its index expression...
		 */
		foreach(t, aref->refupperindexpr)
		{
			replace_agg_clause(lfirst(t), subplanTargetList);
		}
		foreach(t, aref->reflowerindexpr)
		{
			replace_agg_clause(lfirst(t), subplanTargetList);
		}
		replace_agg_clause(aref->refexpr, subplanTargetList);
		replace_agg_clause(aref->refassgnexpr, subplanTargetList);
	}
	else if (is_opclause(clause))
	{

		/*
		 * This is an operator. Recursively call this routine for both its
		 * left and right operands
		 */
794 795
		Node	   *left = (Node *) get_leftop((Expr *) clause);
		Node	   *right = (Node *) get_rightop((Expr *) clause);
796 797 798 799 800 801

		if (left != (Node *) NULL)
			replace_agg_clause(left, subplanTargetList);
		if (right != (Node *) NULL)
			replace_agg_clause(right, subplanTargetList);
	}
802
	else if (IsA(clause, Param) ||IsA(clause, Const))
803 804 805 806 807
	{
		/* do nothing! */
	}
	else
	{
808

809 810 811
		/*
		 * Ooops! we can not handle that!
		 */
812
		elog(ABORT, "replace_agg_clause: Can not handle this tlist!\n");
813
	}
814

815
}
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904

/*
 * del_agg_tlist_references
 *	  Remove the Agg nodes from the target list
 *	  We do this so inheritance only does aggregates in the upper node
 */
void del_agg_tlist_references(List *tlist)
{
	List	   *tl;

	foreach(tl, tlist)
	{
		TargetEntry *tle = lfirst(tl);

		tle->expr = del_agg_clause(tle->expr);
	}
}

static Node *
del_agg_clause(Node *clause)
{
	List	   *t;

	if (IsA(clause, Var))
	{
		return clause;
	}
	else if (is_funcclause(clause))
	{
		/*
		 * This is a function. Recursively call this routine for its
		 * arguments...
		 */
		foreach(t, ((Expr *) clause)->args)
		{
			lfirst(t) = del_agg_clause(lfirst(t));
		}
	}
	else if (IsA(clause, Aggreg))
	{

		/* here is the real action, to remove the Agg node */
		return del_agg_clause(((Aggreg *) clause)->target);

	}
	else if (IsA(clause, ArrayRef))
	{
		ArrayRef   *aref = (ArrayRef *) clause;

		/*
		 * This is an arrayref. Recursively call this routine for its
		 * expression and its index expression...
		 */
		foreach(t, aref->refupperindexpr)
		{
			lfirst(t) = del_agg_clause(lfirst(t));
		}
		foreach(t, aref->reflowerindexpr)
		{
			lfirst(t) = del_agg_clause(lfirst(t));
		}
		aref->refexpr = del_agg_clause(aref->refexpr);
		aref->refassgnexpr = del_agg_clause(aref->refassgnexpr);
	}
	else if (is_opclause(clause))
	{

		/*
		 * This is an operator. Recursively call this routine for both its
		 * left and right operands
		 */
		Node	   *left = (Node *) get_leftop((Expr *) clause);
		Node	   *right = (Node *) get_rightop((Expr *) clause);

		if (left != (Node *) NULL)
			left = del_agg_clause(left);
		if (right != (Node *) NULL)
			right = del_agg_clause(right);
	}
	else if (IsA(clause, Param) ||IsA(clause, Const))
	{
		return clause;
	}
	else
	{

		/*
		 * Ooops! we can not handle that!
		 */
905
		elog(ABORT, "del_agg_clause: Can not handle this tlist!\n");
906 907 908
	}
	return NULL;
}