setrefs.c 28.7 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.46 1999/05/12 15:01:39 wieck 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
#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"
29
#include "optimizer/restrictinfo.h"
30 31 32 33 34 35
#include "optimizer/keys.h"
#include "optimizer/planmain.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
#include "optimizer/tlist.h"

36
static void set_join_tlist_references(Join *join);
37 38
static void set_nonamescan_tlist_references(SeqScan *nonamescan);
static void set_noname_tlist_references(Noname *noname);
39 40 41 42 43 44
static Node *replace_clause_joinvar_refs(Node *clause,
										 List *outer_tlist,
										 List *inner_tlist);
static Var *replace_joinvar_refs(Var *var,
								 List *outer_tlist,
								 List *inner_tlist);
45
static List *tlist_noname_references(Oid nonameid, List *tlist);
46
static bool OperandIsInner(Node *opnd, int inner_relid);
47
static List *pull_agg_clause(Node *clause);
48
static Node *del_agg_clause(Node *clause);
49
static void set_result_tlist_references(Result *resultNode);
50 51

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

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

	if (IsA_Join(plan))
		set_join_tlist_references((Join *) plan);
76
	else if (IsA(plan, SeqScan) &&plan->lefttree &&
77 78
			 IsA_Noname(plan->lefttree))
		set_nonamescan_tlist_references((SeqScan *) plan);
79
	else if (IsA(plan, Sort))
80
		set_noname_tlist_references((Noname *) plan);
81 82 83 84
	else if (IsA(plan, Result))
		set_result_tlist_references((Result *) plan);
	else if (IsA(plan, Hash))
		set_tlist_references(plan->lefttree);
85 86
}

87
/*
88
 * set_join_tlist_references
89 90 91 92 93 94 95 96 97
 *	  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.
 *
98
 * 'join' is a join plan node
99
 *
100
 * Returns nothing of interest, but modifies internal fields of nodes.
101
 *
102 103
 */
static void
104
set_join_tlist_references(Join *join)
105
{
106 107
	Plan	   *outer = ((Plan *) join)->lefttree;
	Plan	   *inner = ((Plan *) join)->righttree;
108 109
	List	   *outer_tlist = ((outer == NULL) ? NIL : outer->targetlist);
	List	   *inner_tlist = ((inner == NULL) ? NIL : inner->targetlist);
110 111
	List	   *new_join_targetlist = NIL;
	List	   *qptlist = ((Plan *) join)->targetlist;
112
	List	   *entry;
113 114 115

	foreach(entry, qptlist)
	{
116 117 118 119 120 121
		TargetEntry *xtl = (TargetEntry *) lfirst(entry);
		Node *joinvar = replace_clause_joinvar_refs(xtl->expr,
													outer_tlist,
													inner_tlist);
		new_join_targetlist = lappend(new_join_targetlist,
									  makeTargetEntry(xtl->resdom, joinvar));
122 123 124 125 126 127 128
	}

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

131
/*
132
 * set_nonamescan_tlist_references
133 134
 *	  Modifies the target list of a node that scans a noname relation (i.e., a
 *	  sort or hash node) so that the varnos refer to the child noname.
135
 *
136
 * 'nonamescan' is a seqscan node
137
 *
138
 * Returns nothing of interest, but modifies internal fields of nodes.
139
 *
140 141
 */
static void
142
set_nonamescan_tlist_references(SeqScan *nonamescan)
143
{
144
	Noname	   *noname = (Noname *) ((Plan *) nonamescan)->lefttree;
145

146 147 148
	((Plan *) nonamescan)->targetlist = tlist_noname_references(noname->nonameid,
							  ((Plan *) nonamescan)->targetlist);
	set_noname_tlist_references(noname);
149 150
}

151
/*
152
 * set_noname_tlist_references
153 154
 *	  The noname's vars are made consistent with (actually, identical to) the
 *	  modified version of the target list of the node from which noname node
155 156
 *	  receives its tuples.
 *
157
 * 'noname' is a noname (e.g., sort, hash) plan node
158
 *
159
 * Returns nothing of interest, but modifies internal fields of nodes.
160
 *
161 162
 */
static void
163
set_noname_tlist_references(Noname *noname)
164
{
165
	Plan	   *source = ((Plan *) noname)->lefttree;
166 167 168 169

	if (source != NULL)
	{
		set_tlist_references(source);
170
		((Plan *) noname)->targetlist = copy_vars(((Plan *) noname)->targetlist,
171 172 173
					  (source)->targetlist);
	}
	else
174
		elog(ERROR, "calling set_noname_tlist_references with empty lefttree");
175 176
}

177
/*
178
 * join_references
179
 *	   Creates a new set of join clauses by changing the varno/varattno
180 181
 *	   values of variables in the clauses to reference target list values
 *	   from the outer and inner join relation target lists.
182
 *	   This is just an external interface for replace_clause_joinvar_refs.
183
 *
184
 * 'clauses' is the list of join clauses
185 186
 * 'outer_tlist' is the target list of the outer join relation
 * 'inner_tlist' is the target list of the inner join relation
187
 *
188 189
 * Returns the new join clauses.  The original clause structure is
 * not modified.
190
 *
191
 */
192
List *
193 194 195
join_references(List *clauses,
				List *outer_tlist,
				List *inner_tlist)
196
{
197 198 199
	return (List *) replace_clause_joinvar_refs((Node *) clauses,
												outer_tlist,
												inner_tlist);
200 201
}

202
/*
203
 * index_outerjoin_references
204 205
 *	  Given a list of join clauses, replace the operand corresponding to the
 *	  outer relation in the join with references to the corresponding target
206
 *	  list element in 'outer_tlist' (the outer is rather obscurely
207
 *	  identified as the side that doesn't contain a var whose varno equals
208
 *	  'inner_relid').
209 210 211
 *
 *	  As a side effect, the operator is replaced by the regproc id.
 *
212
 * 'inner_indxqual' is the list of join clauses (so-called because they
213
 * are used as qualifications for the inner (inbex) scan of a nestloop)
214
 *
215
 * Returns the new list of clauses.
216
 *
217
 */
218
List *
219 220
index_outerjoin_references(List *inner_indxqual,
						   List *outer_tlist,
221
						   Index inner_relid)
222
{
223 224 225 226
	List	   *t_list = NIL;
	Expr	   *temp = NULL;
	List	   *t_clause = NIL;
	Expr	   *clause = NULL;
227

228 229 230 231 232 233 234 235 236
	foreach(t_clause, inner_indxqual)
	{
		clause = lfirst(t_clause);

		/*
		 * if inner scan on the right.
		 */
		if (OperandIsInner((Node *) get_rightop(clause), inner_relid))
		{
237
			Var		   *joinvar = (Var *)
238 239 240
				replace_clause_joinvar_refs((Node *) get_leftop(clause),
											outer_tlist,
											NIL);
241 242 243 244 245 246 247 248 249

			temp = make_opclause(replace_opid((Oper *) ((Expr *) clause)->oper),
								 joinvar,
								 get_rightop(clause));
			t_list = lappend(t_list, temp);
		}
		else
		{
			/* inner scan on left */
250
			Var		   *joinvar = (Var *)
251 252 253
				replace_clause_joinvar_refs((Node *) get_rightop(clause),
											outer_tlist,
											NIL);
254 255 256 257 258 259 260 261

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

	}
262
	return t_list;
263 264
}

265
/*
266 267
 * replace_clause_joinvar_refs
 * replace_joinvar_refs
268 269 270 271 272
 *
 *	  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.
 *
273
 * 'clause' is the join clause
274 275
 * 'outer_tlist' is the target list of the outer join relation
 * 'inner_tlist' is the target list of the inner join relation
276
 *
277
 * Returns the new join clause.
278 279
 * NB: it is critical that the original clause structure not be modified!
 * The changes must be applied to a copy.
280
 *
281 282
 * XXX the current implementation does not copy unchanged primitive
 * nodes; they remain shared with the original.  Is this safe?
283
 */
284 285
static Node *
replace_clause_joinvar_refs(Node *clause,
286 287
							List *outer_tlist,
							List *inner_tlist)
288
{
289 290
	if (clause == NULL)
		return NULL;
291 292
	if (IsA(clause, Var))
	{
293 294
		Var	   *temp = replace_joinvar_refs((Var *) clause,
											outer_tlist, inner_tlist);
295
		if (temp != NULL)
296
			return (Node *) temp;
297
		else
298
			return clause;
299
	}
300 301 302
	else if (single_node(clause))
		return clause;
	else if (and_clause(clause))
303
	{
304 305 306 307
		return (Node *) make_andclause((List *)
			replace_clause_joinvar_refs((Node *) ((Expr *) clause)->args,
										outer_tlist,
										inner_tlist));
308
	}
309
	else if (or_clause(clause))
310
	{
311 312 313 314
		return (Node *) make_orclause((List *)
			replace_clause_joinvar_refs((Node *) ((Expr *) clause)->args,
										outer_tlist,
										inner_tlist));
315 316 317
	}
	else if (IsA(clause, ArrayRef))
	{
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
		ArrayRef   *oldnode = (ArrayRef *) clause;
		ArrayRef   *newnode = makeNode(ArrayRef);

		newnode->refattrlength = oldnode->refattrlength;
		newnode->refelemlength = oldnode->refelemlength;
		newnode->refelemtype = oldnode->refelemtype;
		newnode->refelembyval = oldnode->refelembyval;
		newnode->refupperindexpr = (List *)
			replace_clause_joinvar_refs((Node *) oldnode->refupperindexpr,
										outer_tlist,
										inner_tlist);
		newnode->reflowerindexpr = (List *)
			replace_clause_joinvar_refs((Node *) oldnode->reflowerindexpr,
										outer_tlist,
										inner_tlist);
		newnode->refexpr =
			replace_clause_joinvar_refs(oldnode->refexpr,
										outer_tlist,
										inner_tlist);
		newnode->refassgnexpr =
			replace_clause_joinvar_refs(oldnode->refassgnexpr,
										outer_tlist,
										inner_tlist);
341

342
		return (Node *) newnode;
343
	}
344
	else if (is_funcclause(clause))
345
	{
346 347 348 349 350 351
		return (Node *) make_funcclause(
			(Func *) ((Expr *) clause)->oper,
			(List *) replace_clause_joinvar_refs(
				(Node *) ((Expr *) clause)->args,
				outer_tlist,
				inner_tlist));
352
	}
353
	else if (not_clause(clause))
354
	{
355 356 357 358 359
		return (Node *) make_notclause((Expr *)
				replace_clause_joinvar_refs(
					(Node *) get_notclausearg((Expr *) clause),
					outer_tlist,
					inner_tlist));
360
	}
361
	else if (is_opclause(clause))
362
	{
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
		return (Node *) make_opclause(
			replace_opid((Oper *) ((Expr *) clause)->oper),
			(Var *) replace_clause_joinvar_refs(
				(Node *) get_leftop((Expr *) clause),
				outer_tlist,
				inner_tlist),
			(Var *) replace_clause_joinvar_refs(
				(Node *) get_rightop((Expr *) clause),
				outer_tlist,
				inner_tlist));
	}
	else if (IsA(clause, List))
	{
		List	   *t_list = NIL;
		List	   *subclause;
378

379 380 381 382 383 384 385 386
		foreach(subclause, (List *) clause)
		{
			t_list = lappend(t_list,
							 replace_clause_joinvar_refs(lfirst(subclause),
														 outer_tlist,
														 inner_tlist));
		}
		return (Node *) t_list;
387
	}
388 389
	else if (is_subplan(clause))
	{
390 391 392 393 394 395 396 397 398 399 400 401
		/* This is a tad wasteful of space, but it works... */
		Expr *newclause = (Expr *) copyObject(clause);
		newclause->args = (List *)
			replace_clause_joinvar_refs((Node *) newclause->args,
										outer_tlist,
										inner_tlist);
		((SubPlan *) newclause->oper)->sublink->oper = (List *)
			replace_clause_joinvar_refs(
				(Node *) ((SubPlan *) newclause->oper)->sublink->oper,
				outer_tlist,
				inner_tlist);
		return (Node *) newclause;
402
	}
403 404
	else if (IsA(clause, CaseExpr))
	{
405 406 407 408 409 410 411 412 413 414 415 416 417
		CaseExpr   *oldnode = (CaseExpr *) clause;
		CaseExpr   *newnode = makeNode(CaseExpr);

		newnode->casetype = oldnode->casetype;
		newnode->arg = oldnode->arg; /* XXX should always be null anyway ... */
		newnode->args = (List *)
			replace_clause_joinvar_refs((Node *) oldnode->args,
										outer_tlist,
										inner_tlist);
		newnode->defresult =
			replace_clause_joinvar_refs(oldnode->defresult,
										outer_tlist,
										inner_tlist);
418

419
		return (Node *) newnode;
420 421 422
	}
	else if (IsA(clause, CaseWhen))
	{
423 424
		CaseWhen   *oldnode = (CaseWhen *) clause;
		CaseWhen   *newnode = makeNode(CaseWhen);
425

426 427 428 429 430 431 432 433
		newnode->expr =
			replace_clause_joinvar_refs(oldnode->expr,
										outer_tlist,
										inner_tlist);
		newnode->result =
			replace_clause_joinvar_refs(oldnode->result,
										outer_tlist,
										inner_tlist);
434

435 436 437
		return (Node *) newnode;
	}
	else
438
	{
439 440 441
		elog(ERROR, "replace_clause_joinvar_refs: unsupported clause %d",
			 nodeTag(clause));
		return NULL;
442
	}
443 444
}

445
static Var *
446
replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist)
447
{
448
	Resdom	   *outer_resdom;
449 450 451 452 453 454 455 456

	outer_resdom = tlist_member(var, outer_tlist);

	if (outer_resdom != NULL && IsA(outer_resdom, Resdom))
	{
		return (makeVar(OUTER,
						outer_resdom->resno,
						var->vartype,
457
						var->vartypmod,
458
						0,
459 460 461 462 463
						var->varnoold,
						var->varoattno));
	}
	else
	{
464
		Resdom	   *inner_resdom;
465 466 467 468 469 470 471

		inner_resdom = tlist_member(var, inner_tlist);
		if (inner_resdom != NULL && IsA(inner_resdom, Resdom))
		{
			return (makeVar(INNER,
							inner_resdom->resno,
							var->vartype,
472
							var->vartypmod,
473
							0,
474 475 476 477 478
							var->varnoold,
							var->varoattno));
		}
	}
	return (Var *) NULL;
479 480
}

481
/*
482
 * tlist_noname_references
483 484
 *	  Creates a new target list for a node that scans a noname relation,
 *	  setting the varnos to the id of the noname relation and setting varids
485 486
 *	  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
487
 *	  node, so we can just copy it from the noname).
488
 *
489
 * 'nonameid' is the id of the noname relation
490
 * 'tlist' is the target list to be modified
491
 *
492
 * Returns new target list
493
 *
494
 */
495
static List *
496
tlist_noname_references(Oid nonameid,
497
					  List *tlist)
498
{
499
	List	   *t_list = NIL;
500
	TargetEntry *noname = (TargetEntry *) NULL;
501 502
	TargetEntry *xtl = NULL;
	List	   *entry;
503 504 505

	foreach(entry, tlist)
	{
506
		AttrNumber	oattno;
507 508 509 510 511 512 513

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

514 515
		noname = makeTargetEntry(xtl->resdom,
							   (Node *) makeVar(nonameid,
516 517 518 519
												xtl->resdom->resno,
												xtl->resdom->restype,
												xtl->resdom->restypmod,
												0,
520
												nonameid,
521
												oattno));
522

523
		t_list = lappend(t_list, noname);
524
	}
525
	return t_list;
526 527 528 529 530 531 532 533 534 535
}

/*---------------------------------------------------------
 *
 * 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:
536 537 538 539
 *	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....
540
 */
541
static void
542
set_result_tlist_references(Result *resultNode)
543
{
544 545 546
	Plan	   *subplan;
	List	   *resultTargetList;
	List	   *subplanTargetList;
547 548 549 550 551 552 553 554 555 556 557 558 559

	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;

560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
	replace_tlist_with_subplan_refs(resultTargetList,
									(Index) OUTER,
									subplanTargetList);
}

/*---------------------------------------------------------
 *
 * replace_tlist_with_subplan_refs
 *
 * Applies replace_vars_with_subplan_refs() to each entry of a targetlist.
 */
void
replace_tlist_with_subplan_refs(List *tlist,
								Index subvarno,
								List *subplanTargetList)
{
	List   *t;

	foreach(t, tlist)
579
	{
580 581 582
		TargetEntry *entry = (TargetEntry *) lfirst(t);
		replace_vars_with_subplan_refs((Node *) get_expr(entry),
									   subvarno, subplanTargetList);
583
	}
584 585 586 587
}

/*---------------------------------------------------------
 *
588 589 590 591 592
 * replace_vars_with_subplan_refs
 *
 * This routine modifies (destructively!) an expression tree so that all
 * Var nodes reference target nodes of a subplan.  It is used to fix up
 * target expressions of upper-level plan nodes.
593
 *
594 595 596
 * 'clause': the tree to be fixed
 * 'subvarno': varno to be assigned to all Vars
 * 'subplanTargetList': target list for subplan
597
 *
598 599
 * Afterwards, all Var nodes have varno = subvarno, varattno = resno
 * of corresponding subplan target.
600
 */
601 602 603 604
void
replace_vars_with_subplan_refs(Node *clause,
							   Index subvarno,
							   List *subplanTargetList)
605
{
606
	List	   *t;
607

608 609
	if (clause == NULL)
		return;
610 611 612 613
	if (IsA(clause, Var))
	{
		/*
		 * Ha! A Var node!
614 615 616 617 618 619
		 *
		 * It could be that this varnode has been created by make_groupplan
		 * and is already set up to reference the subplan target list.
		 * We recognize that case by varno = 1, varnoold = -1,
		 * varattno = varoattno, and varlevelsup = 0.  (Probably ought to
		 * have an explicit flag, but this should do for now.)
620
		 */
621 622 623 624 625 626 627 628
		Var			*var = (Var *) clause;
		TargetEntry *subplanVar;

		if (var->varno == (Index) 1 && 
			var->varnoold == ((Index) -1) &&
			var->varattno == var->varoattno &&
			var->varlevelsup == 0)
			return;				/* OK to leave it alone */
629

630 631
		/* Otherwise it had better be in the subplan list. */
		subplanVar = match_varid(var, subplanTargetList);
632
		if (! subplanVar)
633
			elog(ERROR, "replace_vars_with_subplan_refs: variable not in target list");
634

635 636 637
		/*
		 * Change the varno & varattno fields of the var node.
		 */
638 639
		var->varno = subvarno;
		var->varattno = subplanVar->resdom->resno;
640
	}
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
	else if (single_node(clause))
	{
		/* do nothing! */
	}
	else if (IsA(clause, Iter))
		replace_vars_with_subplan_refs(((Iter *) clause)->iterexpr,
									   subvarno, subplanTargetList);
	else if (is_subplan(clause))
	{
		foreach(t, ((Expr *) clause)->args)
			replace_vars_with_subplan_refs(lfirst(t),
										   subvarno, subplanTargetList);
		foreach(t, ((SubPlan *) ((Expr *) clause)->oper)->sublink->oper)
			replace_vars_with_subplan_refs(lfirst(((Expr *) lfirst(t))->args),
										   subvarno, subplanTargetList);
	}
	else if (IsA(clause, Expr))
658
	{
659
		/*
660 661 662
		 * Recursively scan the arguments of an expression.
		 * NOTE: this must come after is_subplan() case since
		 * subplan is a kind of Expr node.
663
		 */
664 665 666
		foreach(t, ((Expr *) clause)->args)
			replace_vars_with_subplan_refs(lfirst(t),
										   subvarno, subplanTargetList);
667
	}
668 669 670
	else if (IsA(clause, Aggref))
		replace_vars_with_subplan_refs(((Aggref *) clause)->target,
									   subvarno, subplanTargetList);
671 672
	else if (IsA(clause, ArrayRef))
	{
673
		ArrayRef   *aref = (ArrayRef *) clause;
674
		foreach(t, aref->refupperindexpr)
675 676
			replace_vars_with_subplan_refs(lfirst(t),
										   subvarno, subplanTargetList);
677
		foreach(t, aref->reflowerindexpr)
678 679 680 681 682 683
			replace_vars_with_subplan_refs(lfirst(t),
										   subvarno, subplanTargetList);
		replace_vars_with_subplan_refs(aref->refexpr,
									   subvarno, subplanTargetList);
		replace_vars_with_subplan_refs(aref->refassgnexpr,
									   subvarno, subplanTargetList);
684
	}
685
	else if (case_clause(clause))
686
	{
687 688 689 690 691 692 693 694 695 696
		foreach(t, ((CaseExpr *) clause)->args)
		{
			CaseWhen   *when = (CaseWhen *) lfirst(t);
			replace_vars_with_subplan_refs(when->expr,
										   subvarno, subplanTargetList);
			replace_vars_with_subplan_refs(when->result,
										   subvarno, subplanTargetList);
		}
		replace_vars_with_subplan_refs(((CaseExpr *) clause)->defresult,
									   subvarno, subplanTargetList);
697 698 699
	}
	else
	{
700 701
		elog(ERROR, "replace_vars_with_subplan_refs: Cannot handle node type %d",
			 nodeTag(clause));
702
	}
703 704
}

705
static bool
706
OperandIsInner(Node *opnd, int inner_relid)
707
{
708 709 710 711 712 713 714 715 716 717 718

	/*
	 * 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))
		return true;
	if (is_funcclause(opnd))
719
	{
720
		List	   *firstArg = lfirst(((Expr *) opnd)->args);
721

722 723 724
		if (IsA(firstArg, Var) &&
			(inner_relid == ((Var *) firstArg)->varno))
			return true;
725
	}
726
	return false;
727 728 729 730 731 732 733 734
}

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

/*---------------------------------------------------------
 *
735 736 737
 * set_agg_tlist_references -
 *	  This routine has several responsibilities:
 *	* Update the target list of an Agg node so that it points to
738
 *	  the tuples returned by its left tree subplan.
739 740 741
 *	* If there is a qual list (from a HAVING clause), similarly update
 *	  vars in it to point to the subplan target list.
 *	* Generate the aggNode->aggs list of Aggref nodes contained in the Agg.
742
 *
743 744
 * The return value is TRUE if all qual clauses include Aggrefs, or FALSE
 * if any do not (caller may choose to raise an error condition).
745
 */
746 747
bool
set_agg_tlist_references(Agg *aggNode)
748
{
749 750
	List	   *subplanTargetList;
	List	   *tl;
751 752
	List	   *ql;
	bool		all_quals_ok;
753

754
	subplanTargetList = aggNode->plan.lefttree->targetlist;
755
	aggNode->aggs = NIL;
756

757
	foreach(tl, aggNode->plan.targetlist)
758
	{
759
		TargetEntry *tle = lfirst(tl);
760

761 762 763 764
		replace_vars_with_subplan_refs(tle->expr,
									   (Index) 0,
									   subplanTargetList);
		aggNode->aggs = nconc(pull_agg_clause(tle->expr), aggNode->aggs);
765
	}
766 767 768 769 770

	all_quals_ok = true;
	foreach(ql, aggNode->plan.qual)
	{
		Node *qual = lfirst(ql);
771 772 773 774 775 776
		List *qualaggs;

		replace_vars_with_subplan_refs(qual,
									   (Index) 0,
									   subplanTargetList);
		qualaggs = pull_agg_clause(qual);
777 778 779 780 781 782 783
		if (qualaggs == NIL)
			all_quals_ok = false; /* this qual clause has no agg functions! */
		else
			aggNode->aggs = nconc(qualaggs, aggNode->aggs);
	}

	return all_quals_ok;
784 785
}

786 787 788
/*
 * Make a list of all Aggref nodes contained in the given expression.
 */
789
static List *
790
pull_agg_clause(Node *clause)
791
{
792
	List	   *agg_list = NIL;
793
	List	   *t;
794

795 796
	if (clause == NULL)
		return NIL;
797
	else if (single_node(clause))
798
		return NIL;
799 800
	else if (IsA(clause, Iter))
		return pull_agg_clause(((Iter *) clause)->iterexpr);
801
	else if (is_subplan(clause))
802
	{
803
		SubLink *sublink = ((SubPlan *) ((Expr *) clause)->oper)->sublink;
804

805
		/*
806 807 808 809
		 * Only the lefthand side of the sublink should be checked for
		 * aggregates to be attached to the aggs list
		 */
		foreach(t, sublink->lefthand)
810
			agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
811 812
		/* The first argument of ...->oper has also to be checked */
		foreach(t, sublink->oper)
813
			agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
814 815 816 817 818 819 820
	}
	else if (IsA(clause, Expr))
	{
		/*
		 * Recursively scan the arguments of an expression.
		 * NOTE: this must come after is_subplan() case since
		 * subplan is a kind of Expr node.
821 822
		 */
		foreach(t, ((Expr *) clause)->args)
823
			agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
824
	}
B
Bruce Momjian 已提交
825
	else if (IsA(clause, Aggref))
826
	{
827
		return lcons(clause,
828
					 pull_agg_clause(((Aggref *) clause)->target));
829
	}
830 831
	else if (IsA(clause, ArrayRef))
	{
832
		ArrayRef   *aref = (ArrayRef *) clause;
833
		foreach(t, aref->refupperindexpr)
834
			agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
835
		foreach(t, aref->reflowerindexpr)
836 837 838
			agg_list = nconc(pull_agg_clause(lfirst(t)), agg_list);
		agg_list = nconc(pull_agg_clause(aref->refexpr), agg_list);
		agg_list = nconc(pull_agg_clause(aref->refassgnexpr), agg_list);
839
	}
840
	else if (case_clause(clause))
841
	{
842 843 844 845 846 847 848 849
		foreach(t, ((CaseExpr *) clause)->args)
		{
			CaseWhen   *when = (CaseWhen *) lfirst(t);
			agg_list = nconc(agg_list, pull_agg_clause(when->expr));
			agg_list = nconc(agg_list, pull_agg_clause(when->result));
		}
		agg_list = nconc(pull_agg_clause(((CaseExpr *) clause)->defresult),
						 agg_list);
850 851 852
	}
	else
	{
853
		elog(ERROR, "pull_agg_clause: Cannot handle node type %d",
854
			 nodeTag(clause));
855
	}
856 857

	return agg_list;
858
}
859

860

861 862 863 864 865
/*
 * del_agg_tlist_references
 *	  Remove the Agg nodes from the target list
 *	  We do this so inheritance only does aggregates in the upper node
 */
866 867
void
del_agg_tlist_references(List *tlist)
868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
{
	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;

884 885 886
	if (clause == NULL)
		return clause;

887 888 889 890
	if (IsA(clause, Var))
		return clause;
	else if (is_funcclause(clause))
	{
891

892 893 894 895 896 897 898
		/*
		 * This is a function. Recursively call this routine for its
		 * arguments...
		 */
		foreach(t, ((Expr *) clause)->args)
			lfirst(t) = del_agg_clause(lfirst(t));
	}
B
Bruce Momjian 已提交
899
	else if (IsA(clause, Aggref))
900 901 902
	{

		/* here is the real action, to remove the Agg node */
B
Bruce Momjian 已提交
903
		return del_agg_clause(((Aggref *) clause)->target);
904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943

	}
	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!
		 */
944
		elog(ERROR, "del_agg_clause: Can not handle this tlist!\n");
945 946 947
	}
	return NULL;
}
948

949 950 951 952 953 954 955 956 957 958 959 960 961
/*
 * check_having_for_ungrouped_vars takes the havingQual and the list of
 * GROUP BY clauses and checks for subplans in the havingQual that are being
 * passed ungrouped variables as parameters.  In other contexts, ungrouped
 * vars in the havingQual will be detected by the parser (see parse_agg.c,
 * exprIsAggOrGroupCol()).  But that routine currently does not check subplans,
 * because the necessary info is not computed until the planner runs.
 * This ought to be cleaned up someday.
 *
 * NOTE: the havingClause has been cnf-ified, so AND subclauses have been
 * turned into a plain List.  Thus, this routine has to cope with List nodes
 * where the routine above does not...
 */
B
Bruce Momjian 已提交
962

963
void
964 965
check_having_for_ungrouped_vars(Node *clause, List *groupClause,
						List *targetList)
966 967
{
	List	   *t;
968

969 970 971
	if (clause == NULL)
		return;

972 973
	if (IsA(clause, Var))
	{
974 975
		/* Ignore vars elsewhere in the having clause, since the
		 * parser already checked 'em.
B
Bruce Momjian 已提交
976
		 */
977
	}
978 979 980 981 982 983 984
	else if (single_node(clause))
	{
		/* ignore */
	}
	else if (IsA(clause, Iter))
	{
		check_having_for_ungrouped_vars(((Iter *) clause)->iterexpr,
985
										groupClause, targetList);
986
	}
987
	else if (is_subplan(clause))
988 989
	{
		/*
990 991
		 * The args list of the subplan node represents attributes from outside
		 * passed into the sublink.
992 993 994
		 */
		foreach(t, ((Expr *) clause)->args)
		{
995 996 997 998
			bool contained_in_group_clause = false;
			List	   *gl;

			foreach(gl, groupClause)
B
Bruce Momjian 已提交
999
			{
1000
				if (var_equal(lfirst(t),
1001 1002
							  get_groupclause_expr((GroupClause *) 
							  					lfirst(gl), targetList)))
1003 1004 1005 1006
				{
					contained_in_group_clause = true;
					break;
				}
B
Bruce Momjian 已提交
1007
			}
1008 1009 1010

			if (!contained_in_group_clause)
				elog(ERROR, "Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT");
1011
		}
1012 1013 1014 1015 1016 1017 1018 1019 1020
	}
	else if (IsA(clause, Expr))
	{
		/*
		 * Recursively scan the arguments of an expression.
		 * NOTE: this must come after is_subplan() case since
		 * subplan is a kind of Expr node.
		 */
		foreach(t, ((Expr *) clause)->args)
1021 1022
			check_having_for_ungrouped_vars(lfirst(t), groupClause,
														targetList);
1023 1024 1025 1026 1027 1028 1029
	}
	else if (IsA(clause, List))
	{
		/*
		 * Recursively scan AND subclauses (see NOTE above).
		 */
		foreach(t, ((List *) clause))
1030 1031
			check_having_for_ungrouped_vars(lfirst(t), groupClause,
														targetList);
1032
	}
B
Bruce Momjian 已提交
1033
	else if (IsA(clause, Aggref))
1034
	{
1035
		check_having_for_ungrouped_vars(((Aggref *) clause)->target,
1036
										groupClause, targetList);
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
	}
	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)
1047 1048
			check_having_for_ungrouped_vars(lfirst(t), groupClause,
														targetList);
1049
		foreach(t, aref->reflowerindexpr)
1050 1051 1052 1053 1054 1055
			check_having_for_ungrouped_vars(lfirst(t), groupClause,
														targetList);
		check_having_for_ungrouped_vars(aref->refexpr, groupClause,
														targetList);
		check_having_for_ungrouped_vars(aref->refassgnexpr, groupClause,
														targetList);
1056
	}
1057
	else if (case_clause(clause))
1058
	{
1059 1060 1061
		foreach(t, ((CaseExpr *) clause)->args)
		{
			CaseWhen   *when = (CaseWhen *) lfirst(t);
1062 1063 1064 1065
			check_having_for_ungrouped_vars(when->expr, groupClause,
														targetList);
			check_having_for_ungrouped_vars(when->result, groupClause,
														targetList);
1066 1067
		}
		check_having_for_ungrouped_vars(((CaseExpr *) clause)->defresult,
1068
										groupClause, targetList);
B
Bruce Momjian 已提交
1069
	}
1070
	else
B
Bruce Momjian 已提交
1071
	{
1072
		elog(ERROR, "check_having_for_ungrouped_vars: Cannot handle node type %d",
B
Bruce Momjian 已提交
1073 1074
			 nodeTag(clause));
	}
1075
}