rewriteHandler.c 52.5 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * rewriteHandler.c
4
 *
B
Add:  
Bruce Momjian 已提交
5 6
 * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
 * Portions Copyright (c) 1994, Regents of the University of California
7 8 9
 *
 *
 * IDENTIFICATION
B
Bruce Momjian 已提交
10
 *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.76 2000/06/15 03:32:22 momjian Exp $
11 12 13 14 15
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

B
Bruce Momjian 已提交
16
#include "access/heapam.h"
17
#include "catalog/pg_operator.h"
18
#include "catalog/pg_type.h"
B
Bruce Momjian 已提交
19
#include "miscadmin.h"
20
#include "nodes/makefuncs.h"
B
Bruce Momjian 已提交
21 22
#include "optimizer/clauses.h"
#include "optimizer/prep.h"
23
#include "optimizer/var.h"
B
Bruce Momjian 已提交
24
#include "parser/analyze.h"
25 26
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
B
Bruce Momjian 已提交
27 28
#include "parser/parse_target.h"
#include "parser/parsetree.h"
B
Bruce Momjian 已提交
29
#include "parser/parse_type.h"
B
Bruce Momjian 已提交
30 31 32 33
#include "rewrite/locks.h"
#include "rewrite/rewriteManip.h"
#include "utils/acl.h"
#include "utils/lsyscache.h"
34 35


36 37 38 39 40 41 42 43 44 45 46 47 48
extern void CheckSelectForUpdate(Query *rule_action);	/* in analyze.c */


/* macros borrowed from expression_tree_mutator */

#define FLATCOPY(newnode, node, nodetype)  \
	( (newnode) = makeNode(nodetype), \
	  memcpy((newnode), (node), sizeof(nodetype)) )

#define MUTATE(newfield, oldfield, fieldtype, mutator, context)  \
		( (newfield) = (fieldtype) mutator((Node *) (oldfield), (context)) )


49 50 51 52 53 54 55
static RewriteInfo *gatherRewriteMeta(Query *parsetree,
				  Query *rule_action,
				  Node *rule_qual,
				  int rt_index,
				  CmdType event,
				  bool *instead_flag);
static bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up);
56
static bool attribute_used(Node *node, int rt_index, int attno,
57
			   int sublevels_up);
58
static bool modifyAggrefChangeVarnodes(Node *node, int rt_index, int new_index,
59
						   int sublevels_up, int new_sublevels_up);
60
static Node *modifyAggrefDropQual(Node *node, Node *targetNode);
61
static SubLink *modifyAggrefMakeSublink(Aggref *aggref, Query *parsetree);
62
static Node *modifyAggrefQual(Node *node, Query *parsetree);
63
static Query *fireRIRrules(Query *parsetree);
64 65
static Query *Except_Intersect_Rewrite(Query *parsetree);
static void check_targetlists_are_compatible(List *prev_target,
66
								 List *current_target);
67 68
static void create_intersect_list(Node *ptr, List **intersect_list);
static Node *intersect_tree_analyze(Node *tree, Node *first_select,
69
					   Node *parsetree);
70 71 72

/*
 * gatherRewriteMeta -
73 74 75
 *	  Gather meta information about parsetree, and rule. Fix rule body
 *	  and qualifier so that they can be mixed with the parsetree and
 *	  maintain semantic validity
76 77
 */
static RewriteInfo *
78 79 80
gatherRewriteMeta(Query *parsetree,
				  Query *rule_action,
				  Node *rule_qual,
81 82
				  int rt_index,
				  CmdType event,
83
				  bool *instead_flag)
84
{
85 86 87
	RewriteInfo *info;
	int			rt_length;
	int			result_reln;
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103

	info = (RewriteInfo *) palloc(sizeof(RewriteInfo));
	info->rt_index = rt_index;
	info->event = event;
	info->instead_flag = *instead_flag;
	info->rule_action = (Query *) copyObject(rule_action);
	info->rule_qual = (Node *) copyObject(rule_qual);
	if (info->rule_action == NULL)
		info->nothing = TRUE;
	else
	{
		info->nothing = FALSE;
		info->action = info->rule_action->commandType;
		info->current_varno = rt_index;
		info->rt = parsetree->rtable;
		rt_length = length(info->rt);
B
Bruce Momjian 已提交
104
		info->rt = nconc(info->rt, copyObject(info->rule_action->rtable));
105 106

		info->new_varno = PRS2_NEW_VARNO + rt_length;
B
Bruce Momjian 已提交
107 108 109
		OffsetVarNodes(info->rule_action->qual, rt_length, 0);
		OffsetVarNodes((Node *) info->rule_action->targetList, rt_length, 0);
		OffsetVarNodes(info->rule_qual, rt_length, 0);
110
		ChangeVarNodes((Node *) info->rule_action->qual,
111
					   PRS2_OLD_VARNO + rt_length, rt_index, 0);
112
		ChangeVarNodes((Node *) info->rule_action->targetList,
113
					   PRS2_OLD_VARNO + rt_length, rt_index, 0);
114
		ChangeVarNodes(info->rule_qual,
115
					   PRS2_OLD_VARNO + rt_length, rt_index, 0);
116 117 118 119 120 121 122 123

		/*
		 * bug here about replace CURRENT  -- sort of replace current is
		 * deprecated now so this code shouldn't really need to be so
		 * clutzy but.....
		 */
		if (info->action != CMD_SELECT)
		{						/* i.e update XXXXX */
124
			int			new_result_reln = 0;
125 126 127 128

			result_reln = info->rule_action->resultRelation;
			switch (result_reln)
			{
129
				case PRS2_OLD_VARNO:
130 131 132 133 134 135
					new_result_reln = rt_index;
					break;
				case PRS2_NEW_VARNO:	/* XXX */
				default:
					new_result_reln = result_reln + rt_length;
					break;
136 137 138 139 140
			}
			info->rule_action->resultRelation = new_result_reln;
		}
	}
	return info;
141 142 143 144
}


/*
145 146 147
 * rangeTableEntry_used -
 *	we need to process a RTE for RIR rules only if it is
 *	referenced somewhere in var nodes of the query.
148
 */
149

150 151
typedef struct
{
152 153 154 155
	int			rt_index;
	int			sublevels_up;
} rangeTableEntry_used_context;

156
static bool
157 158
rangeTableEntry_used_walker(Node *node,
							rangeTableEntry_used_context *context)
159
{
160
	if (node == NULL)
161 162
		return false;
	if (IsA(node, Var))
B
Bruce Momjian 已提交
163
	{
164
		Var		   *var = (Var *) node;
165

166 167 168 169
		if (var->varlevelsup == context->sublevels_up &&
			var->varno == context->rt_index)
			return true;
		return false;
170
	}
171 172
	if (IsA(node, SubLink))
	{
173

174
		/*
175 176
		 * Standard expression_tree_walker will not recurse into
		 * subselect, but here we must do so.
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
		 */
		SubLink    *sub = (SubLink *) node;

		if (rangeTableEntry_used_walker((Node *) (sub->lefthand), context))
			return true;
		if (rangeTableEntry_used((Node *) (sub->subselect),
								 context->rt_index,
								 context->sublevels_up + 1))
			return true;
		return false;
	}
	if (IsA(node, Query))
	{
		/* Reach here after recursing down into subselect above... */
		Query	   *qry = (Query *) node;

		if (rangeTableEntry_used_walker((Node *) (qry->targetList), context))
			return true;
		if (rangeTableEntry_used_walker((Node *) (qry->qual), context))
			return true;
		if (rangeTableEntry_used_walker((Node *) (qry->havingQual), context))
			return true;
		return false;
	}
	return expression_tree_walker(node, rangeTableEntry_used_walker,
								  (void *) context);
}

static bool
rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
{
	rangeTableEntry_used_context context;
209

210 211 212
	context.rt_index = rt_index;
	context.sublevels_up = sublevels_up;
	return rangeTableEntry_used_walker(node, &context);
213
}
214 215


216 217 218 219
/*
 * attribute_used -
 *	Check if a specific attribute number of a RTE is used
 *	somewhere in the query
220
 */
221

222 223
typedef struct
{
224 225 226 227 228
	int			rt_index;
	int			attno;
	int			sublevels_up;
} attribute_used_context;

229
static bool
230 231
attribute_used_walker(Node *node,
					  attribute_used_context *context)
232
{
233
	if (node == NULL)
234 235
		return false;
	if (IsA(node, Var))
B
Bruce Momjian 已提交
236
	{
237
		Var		   *var = (Var *) node;
238

239 240 241 242 243 244 245 246
		if (var->varlevelsup == context->sublevels_up &&
			var->varno == context->rt_index &&
			var->varattno == context->attno)
			return true;
		return false;
	}
	if (IsA(node, SubLink))
	{
247

248
		/*
249 250
		 * Standard expression_tree_walker will not recurse into
		 * subselect, but here we must do so.
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
		 */
		SubLink    *sub = (SubLink *) node;

		if (attribute_used_walker((Node *) (sub->lefthand), context))
			return true;
		if (attribute_used((Node *) (sub->subselect),
						   context->rt_index,
						   context->attno,
						   context->sublevels_up + 1))
			return true;
		return false;
	}
	if (IsA(node, Query))
	{
		/* Reach here after recursing down into subselect above... */
		Query	   *qry = (Query *) node;

		if (attribute_used_walker((Node *) (qry->targetList), context))
			return true;
		if (attribute_used_walker((Node *) (qry->qual), context))
			return true;
		if (attribute_used_walker((Node *) (qry->havingQual), context))
			return true;
		return false;
275
	}
276 277 278 279 280 281 282 283
	return expression_tree_walker(node, attribute_used_walker,
								  (void *) context);
}

static bool
attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
{
	attribute_used_context context;
284

285 286 287 288
	context.rt_index = rt_index;
	context.attno = attno;
	context.sublevels_up = sublevels_up;
	return attribute_used_walker(node, &context);
289
}
290

291

292
/*
B
Bruce Momjian 已提交
293
 * modifyAggrefChangeVarnodes -
294
 *	Change the var nodes in a sublink created for an aggregate column
295 296
 *	used in the qualification to point to the correct local RTE.
 *
297 298 299 300
 * XXX if we still need this after redoing querytree design, it should
 * be combined with ChangeVarNodes, which is the same thing except for
 * not having the option to adjust the vars' varlevelsup.
 *
301
 * NOTE: although this has the form of a walker, we cheat and modify the
302
 * Var nodes in-place.	The given expression tree should have been copied
303
 * earlier to ensure that no unwanted side-effects occur!
304 305
 */

306 307
typedef struct
{
308 309 310
	int			rt_index;
	int			new_index;
	int			sublevels_up;
311
	int			new_sublevels_up;
312
} modifyAggrefChangeVarnodes_context;
313

314 315
static bool
modifyAggrefChangeVarnodes_walker(Node *node,
316
							 modifyAggrefChangeVarnodes_context *context)
317 318 319 320
{
	if (node == NULL)
		return false;
	if (IsA(node, Var))
B
Bruce Momjian 已提交
321
	{
322
		Var		   *var = (Var *) node;
323

324 325 326 327 328
		if (var->varlevelsup == context->sublevels_up &&
			var->varno == context->rt_index)
		{
			var->varno = context->new_index;
			var->varnoold = context->new_index;
329
			var->varlevelsup = context->new_sublevels_up;
330 331 332 333 334
		}
		return false;
	}
	if (IsA(node, SubLink))
	{
335

336
		/*
337 338
		 * Standard expression_tree_walker will not recurse into
		 * subselect, but here we must do so.
339 340 341 342 343 344 345 346 347
		 */
		SubLink    *sub = (SubLink *) node;

		if (modifyAggrefChangeVarnodes_walker((Node *) (sub->lefthand),
											  context))
			return true;
		if (modifyAggrefChangeVarnodes((Node *) (sub->subselect),
									   context->rt_index,
									   context->new_index,
348 349
									   context->sublevels_up + 1,
									   context->new_sublevels_up + 1))
350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
			return true;
		return false;
	}
	if (IsA(node, Query))
	{
		/* Reach here after recursing down into subselect above... */
		Query	   *qry = (Query *) node;

		if (modifyAggrefChangeVarnodes_walker((Node *) (qry->targetList),
											  context))
			return true;
		if (modifyAggrefChangeVarnodes_walker((Node *) (qry->qual),
											  context))
			return true;
		if (modifyAggrefChangeVarnodes_walker((Node *) (qry->havingQual),
											  context))
			return true;
		return false;
	}
	return expression_tree_walker(node, modifyAggrefChangeVarnodes_walker,
								  (void *) context);
}
372

373 374
static bool
modifyAggrefChangeVarnodes(Node *node, int rt_index, int new_index,
375
						   int sublevels_up, int new_sublevels_up)
376 377
{
	modifyAggrefChangeVarnodes_context context;
378

379 380 381
	context.rt_index = rt_index;
	context.new_index = new_index;
	context.sublevels_up = sublevels_up;
382
	context.new_sublevels_up = new_sublevels_up;
383
	return modifyAggrefChangeVarnodes_walker(node, &context);
384 385 386 387
}


/*
B
Bruce Momjian 已提交
388
 * modifyAggrefDropQual -
389 390
 *	remove the pure aggref clause from a qualification
 *
391 392 393
 * targetNode is an Aggref node somewhere within the given expression tree.
 * Find the boolean operator that's presumably somewhere above it, and replace
 * that whole operator expression with a constant TRUE.  (This is NOT really
394
 * quite the right thing, but it handles simple cases.	This whole set of
395 396 397
 * Aggref-in-qual routines needs to be thrown away when we can do subselects
 * in FROM.)
 *
398 399 400 401 402 403
 * The return tree is a modified copy of the given tree; the given tree
 * is not altered.
 *
 * Note: we don't recurse into subselects looking for targetNode; that's
 * not necessary in the current usage, since in fact targetNode will be
 * within the same select level as the given toplevel node.
404
 */
405 406
static Node *
modifyAggrefDropQual(Node *node, Node *targetNode)
407 408
{
	if (node == NULL)
409 410
		return NULL;
	if (node == targetNode)
411 412 413 414 415
	{
		/* Oops, it's not inside an Expr we can rearrange... */
		elog(ERROR, "Cannot handle aggregate function inserted at this place in WHERE clause");
	}
	if (IsA(node, Expr))
B
Bruce Momjian 已提交
416
	{
417
		Expr	   *expr = (Expr *) node;
418
		List	   *i;
419

420 421 422 423 424 425 426 427 428 429 430 431 432
		foreach(i, expr->args)
		{
			if (((Node *) lfirst(i)) == targetNode)
			{
				/* Found the parent expression containing the Aggref */
				if (expr->typeOid != BOOLOID)
					elog(ERROR,
						 "aggregate function in qual must be argument of boolean operator");
				return (Node *) makeConst(BOOLOID, 1, (Datum) true,
										  false, true, false, false);
			}
		}
		/* else this isn't the expr we want, keep going */
433
	}
434 435
	return expression_tree_mutator(node, modifyAggrefDropQual,
								   (void *) targetNode);
436 437 438
}

/*
B
Bruce Momjian 已提交
439
 * modifyAggrefMakeSublink -
440 441 442 443
 *	Create a sublink node for a qualification expression that
 *	uses an aggregate column of a view
 */
static SubLink *
444
modifyAggrefMakeSublink(Aggref *aggref, Query *parsetree)
445
{
446
	List	   *aggVarNos;
447

448
	/* rte points to old structure: */
449
	RangeTblEntry *rte;
450

451 452 453
	/* these point to newly-created structures: */
	Query	   *subquery;
	SubLink    *sublink;
B
Bruce Momjian 已提交
454 455
	TargetEntry *tle;
	Resdom	   *resdom;
456

457 458 459 460
	aggVarNos = pull_varnos(aggref->target);
	if (length(aggVarNos) != 1)
		elog(ERROR, "rewrite: aggregates of views only allowed on single tables for now");
	rte = rt_fetch(lfirsti(aggVarNos), parsetree->rtable);
461

B
Bruce Momjian 已提交
462 463
	resdom = makeNode(Resdom);
	resdom->resno = 1;
464
	resdom->restype = aggref->aggtype;
465 466
	resdom->restypmod = -1;
	resdom->resname = pstrdup("<noname>");
B
Bruce Momjian 已提交
467
	resdom->reskey = 0;
468
	resdom->reskeyop = 0;
B
Bruce Momjian 已提交
469
	resdom->resjunk = false;
470

471
	tle = makeNode(TargetEntry);
B
Bruce Momjian 已提交
472
	tle->resdom = resdom;
473
	tle->expr = copyObject(aggref);		/* make a modifiable copy! */
474 475

	subquery = makeNode(Query);
476 477

	sublink = makeNode(SubLink);
B
Bruce Momjian 已提交
478
	sublink->subLinkType = EXPR_SUBLINK;
479
	sublink->useor = false;
480 481
	sublink->lefthand = NIL;
	sublink->oper = NIL;
B
Bruce Momjian 已提交
482 483 484 485 486 487 488 489 490
	sublink->subselect = (Node *) subquery;

	subquery->commandType = CMD_SELECT;
	subquery->utilityStmt = NULL;
	subquery->resultRelation = 0;
	subquery->into = NULL;
	subquery->isPortal = FALSE;
	subquery->isBinary = FALSE;
	subquery->isTemp = FALSE;
491
	subquery->unionall = FALSE;
492 493
	subquery->distinctClause = NIL;
	subquery->sortClause = NIL;
494
	subquery->rtable = lcons(copyObject(rte), NIL);
495 496
	subquery->targetList = lcons(tle, NIL);
	subquery->qual = modifyAggrefDropQual((Node *) parsetree->qual,
497
										  (Node *) aggref);
498

499
	/*
500 501 502
	 * If there are still aggs in the subselect's qual, give up. Recursing
	 * would be a bad idea --- we'd likely produce an infinite recursion.
	 * This whole technique is a crock, really...
503
	 */
504
	if (checkExprHasAggs(subquery->qual))
505
		elog(ERROR, "Cannot handle multiple aggregate functions in WHERE clause");
506 507 508
	subquery->groupClause = NIL;
	subquery->havingQual = NULL;
	subquery->hasAggs = TRUE;
509
	subquery->hasSubLinks = checkExprHasSubLink(subquery->qual);
510
	subquery->unionClause = NULL;
511

512
	/* Increment all varlevelsup fields in the new subquery */
513
	IncrementVarSublevelsUp((Node *) subquery, 1, 0);
514

515 516
	/*
	 * Replace references to the target table with correct local varno, 1.
517 518
	 * Note that because of previous line, these references have
	 * varlevelsup = 1, which must be changed to 0.
519
	 */
520 521 522
	modifyAggrefChangeVarnodes((Node *) subquery,
							   lfirsti(aggVarNos), 1,
							   1, 0);
523

524 525
	return sublink;
}
526 527


528 529 530 531 532 533 534 535 536 537 538 539 540 541
/*
 * modifyAggrefQual -
 *	Search for qualification expressions that contain aggregate
 *	functions and substitute them by sublinks. These expressions
 *	originally come from qualifications that use aggregate columns
 *	of a view.
 *
 *	The return value is a modified copy of the given expression tree.
 */
static Node *
modifyAggrefQual(Node *node, Query *parsetree)
{
	if (node == NULL)
		return NULL;
542 543
	if (IsA(node, Aggref))
	{
544 545 546 547
		SubLink    *sub = modifyAggrefMakeSublink((Aggref *) node, parsetree);

		parsetree->hasSubLinks = true;
		return (Node *) sub;
548
	}
549

550 551 552
	/*
	 * Otherwise, fall through and copy the expr normally.
	 *
553 554
	 * We do NOT recurse into subselects in this routine.  It's sufficient to
	 * get rid of aggregates that are in the qual expression proper.
555 556 557
	 */
	return expression_tree_mutator(node, modifyAggrefQual,
								   (void *) parsetree);
558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
}


static Node *
FindMatchingTLEntry(List *tlist, char *e_attname)
{
	List	   *i;

	foreach(i, tlist)
	{
		TargetEntry *tle = lfirst(i);
		char	   *resname;

		resname = tle->resdom->resname;
		if (!strcmp(e_attname, resname))
			return (tle->expr);
	}
	return NULL;
}


static Node *
make_null(Oid type)
{
	Const	   *c = makeNode(Const);

	c->consttype = type;
	c->constlen = get_typlen(type);
	c->constvalue = PointerGetDatum(NULL);
	c->constisnull = true;
	c->constbyval = get_typbyval(type);
	return (Node *) c;
}


593 594 595 596
/*
 * apply_RIR_view
 *	Replace Vars matching a given RT index with copies of TL expressions.
 */
597

598 599 600 601 602 603 604
typedef struct
{
	int			rt_index;
	int			sublevels_up;
	RangeTblEntry *rte;
	List	   *tlist;
	int		   *modified;
605
} apply_RIR_view_context;
606

607 608 609 610 611 612 613 614 615
static Node *
apply_RIR_view_mutator(Node *node,
					   apply_RIR_view_context *context)
{
	if (node == NULL)
		return NULL;
	if (IsA(node, Var))
	{
		Var		   *var = (Var *) node;
616

617 618 619 620
		if (var->varlevelsup == context->sublevels_up &&
			var->varno == context->rt_index)
		{
			Node	   *expr;
621

622 623 624 625
			if (var->varattno < 0)
				elog(ERROR, "system column %s not available - %s is a view",
					 get_attname(context->rte->relid, var->varattno),
					 context->rte->relname);
626

627 628 629 630
			expr = FindMatchingTLEntry(context->tlist,
									   get_attname(context->rte->relid,
												   var->varattno));
			if (expr == NULL)
631
			{
632 633
				/* XXX shouldn't this be an error condition? */
				return make_null(var->vartype);
634 635
			}

636
			/* Make a copy of the tlist item to return */
637
			expr = copyObject(expr);
638
			/* Adjust varlevelsup if tlist item is from higher query level */
639
			if (var->varlevelsup > 0)
640 641
				IncrementVarSublevelsUp(expr, var->varlevelsup, 0);

642 643 644 645 646
			*(context->modified) = true;
			return (Node *) expr;
		}
		/* otherwise fall through to copy the var normally */
	}
647

648 649 650 651 652 653
	/*
	 * Since expression_tree_mutator won't touch subselects, we have to
	 * handle them specially.
	 */
	if (IsA(node, SubLink))
	{
654 655
		SubLink    *sublink = (SubLink *) node;
		SubLink    *newnode;
656 657 658 659 660 661 662 663 664 665 666 667

		FLATCOPY(newnode, sublink, SubLink);
		MUTATE(newnode->lefthand, sublink->lefthand, List *,
			   apply_RIR_view_mutator, context);
		context->sublevels_up++;
		MUTATE(newnode->subselect, sublink->subselect, Node *,
			   apply_RIR_view_mutator, context);
		context->sublevels_up--;
		return (Node *) newnode;
	}
	if (IsA(node, Query))
	{
668 669
		Query	   *query = (Query *) node;
		Query	   *newnode;
670 671 672 673 674 675 676 677 678 679 680 681 682

		FLATCOPY(newnode, query, Query);
		MUTATE(newnode->targetList, query->targetList, List *,
			   apply_RIR_view_mutator, context);
		MUTATE(newnode->qual, query->qual, Node *,
			   apply_RIR_view_mutator, context);
		MUTATE(newnode->havingQual, query->havingQual, Node *,
			   apply_RIR_view_mutator, context);
		return (Node *) newnode;
	}
	return expression_tree_mutator(node, apply_RIR_view_mutator,
								   (void *) context);
}
683

684 685 686 687
static Node *
apply_RIR_view(Node *node, int rt_index, RangeTblEntry *rte, List *tlist,
			   int *modified, int sublevels_up)
{
688
	apply_RIR_view_context context;
689

690 691 692 693 694
	context.rt_index = rt_index;
	context.sublevels_up = sublevels_up;
	context.rte = rte;
	context.tlist = tlist;
	context.modified = modified;
695

696
	return apply_RIR_view_mutator(node, &context);
697 698 699
}


700
static Query *
701 702 703 704 705
ApplyRetrieveRule(Query *parsetree,
				  RewriteRule *rule,
				  int rt_index,
				  int relation_level,
				  Relation relation,
706
				  bool relWasInJoinSet)
707 708 709 710
{
	Query	   *rule_action = NULL;
	Node	   *rule_qual;
	List	   *rtable,
711
			   *addedrtable,
712
			   *l;
713 714
	int			nothing,
				rt_length;
715
	int			modified = false;
716
	int			badsql = false;
717 718 719 720 721 722 723 724

	rule_qual = rule->qual;
	if (rule->actions)
	{
		if (length(rule->actions) > 1)	/* ??? because we don't handle
										 * rules with more than one
										 * action? -ay */

725
			return parsetree;
726 727 728 729 730 731 732
		rule_action = copyObject(lfirst(rule->actions));
		nothing = FALSE;
	}
	else
		nothing = TRUE;

	rtable = copyObject(parsetree->rtable);
733
	rt_length = length(rtable); /* original length, not counting rule */
734

735 736
	addedrtable = copyObject(rule_action->rtable);

737 738
	/*
	 * If the original rel wasn't in the join set, none of its spawn is.
739 740
	 * If it was, then leave the spawn's flags as they are.
	 */
741
	if (!relWasInJoinSet)
742 743 744 745
	{
		foreach(l, addedrtable)
		{
			RangeTblEntry *rte = lfirst(l);
746

747 748
			rte->inJoinSet = false;
		}
749 750
	}

751
	rtable = nconc(rtable, addedrtable);
752 753
	parsetree->rtable = rtable;

754
	/* FOR UPDATE of view... */
B
Bruce Momjian 已提交
755
	foreach(l, parsetree->rowMark)
756
	{
B
Bruce Momjian 已提交
757
		if (((RowMark *) lfirst(l))->rti == rt_index)
758 759
			break;
	}
B
Bruce Momjian 已提交
760
	if (l != NULL)				/* oh, hell -:) */
761
	{
B
Bruce Momjian 已提交
762
		RowMark    *newrm;
763 764 765
		Index		rti = 1;
		List	   *l2;

766
		CheckSelectForUpdate(rule_action);
B
Bruce Momjian 已提交
767 768 769 770 771 772

		/*
		 * We believe that rt_index is VIEW - nothing should be marked for
		 * VIEW, but ACL check must be done. As for real tables of VIEW -
		 * their rows must be marked, but we have to skip ACL check for
		 * them.
773
		 */
B
Bruce Momjian 已提交
774
		((RowMark *) lfirst(l))->info &= ~ROW_MARK_FOR_UPDATE;
775

B
Bruce Momjian 已提交
776
		foreach(l2, rule_action->rtable)
777
		{
B
Bruce Momjian 已提交
778

779
			/*
B
Bruce Momjian 已提交
780 781
			 * RTable of VIEW has two entries of VIEW itself - we use
			 * relid to skip them.
782
			 */
B
Bruce Momjian 已提交
783
			if (relation->rd_id != ((RangeTblEntry *) lfirst(l2))->relid)
784 785 786 787 788 789 790 791 792 793 794
			{
				newrm = makeNode(RowMark);
				newrm->rti = rti + rt_length;
				newrm->info = ROW_MARK_FOR_UPDATE;
				lnext(l) = lcons(newrm, lnext(l));
				l = lnext(l);
			}
			rti++;
		}
	}

795
	rule_action->rtable = rtable;
B
Bruce Momjian 已提交
796
	OffsetVarNodes((Node *) rule_qual, rt_length, 0);
B
Bruce Momjian 已提交
797
	OffsetVarNodes((Node *) rule_action, rt_length, 0);
798

B
Bruce Momjian 已提交
799
	ChangeVarNodes((Node *) rule_qual,
800
				   PRS2_OLD_VARNO + rt_length, rt_index, 0);
B
Bruce Momjian 已提交
801
	ChangeVarNodes((Node *) rule_action,
802
				   PRS2_OLD_VARNO + rt_length, rt_index, 0);
803 804 805

	if (relation_level)
	{
806
		RangeTblEntry *rte = rt_fetch(rt_index, rtable);
807 808 809 810

		parsetree = (Query *) apply_RIR_view((Node *) parsetree,
											 rt_index, rte,
											 rule_action->targetList,
811
											 &modified, 0);
812 813 814
		rule_action = (Query *) apply_RIR_view((Node *) rule_action,
											   rt_index, rte,
											   rule_action->targetList,
815 816 817 818 819
											   &modified, 0);
		/* always apply quals of relation-level rules, whether we found a
		 * var to substitute or not.
		 */
		modified = true;
820 821 822
	}
	else
	{
B
Bruce Momjian 已提交
823
		HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList,
824 825
							   rt_index, rule->attrno, &modified, &badsql);
		/* quals will be inserted only if we found uses of the attribute */
B
Bruce Momjian 已提交
826
	}
827
	if (modified && !badsql)
B
Bruce Momjian 已提交
828 829 830 831 832 833 834
	{
		AddQual(parsetree, rule_action->qual);
		AddGroupClause(parsetree, rule_action->groupClause,
					   rule_action->targetList);
		AddHavingQual(parsetree, rule_action->havingQual);
		parsetree->hasAggs = (rule_action->hasAggs || parsetree->hasAggs);
		parsetree->hasSubLinks = (rule_action->hasSubLinks || parsetree->hasSubLinks);
835
	}
836 837

	return parsetree;
838 839 840
}


841 842 843 844 845
/*
 * fireRIRonSubselect -
 *	Apply fireRIRrules() to each subselect found in the given tree.
 *
 * NOTE: although this has the form of a walker, we cheat and modify the
846
 * SubLink nodes in-place.	It is caller's responsibility to ensure that
847 848 849 850
 * no unwanted side-effects occur!
 */
static bool
fireRIRonSubselect(Node *node, void *context)
851 852
{
	if (node == NULL)
853 854
		return false;
	if (IsA(node, SubLink))
B
Bruce Momjian 已提交
855
	{
856 857 858 859 860 861 862 863 864
		SubLink    *sub = (SubLink *) node;
		Query	   *qry;

		/* Process lefthand args */
		if (fireRIRonSubselect((Node *) (sub->lefthand), context))
			return true;
		/* Do what we came for */
		qry = fireRIRrules((Query *) (sub->subselect));
		sub->subselect = (Node *) qry;
865
		/* Need not recurse into subselect, because fireRIRrules did it */
866 867 868 869
		return false;
	}
	if (IsA(node, Query))
	{
870
		/* Reach here when called from fireRIRrules */
871 872 873 874 875 876 877 878 879
		Query	   *qry = (Query *) node;

		if (fireRIRonSubselect((Node *) (qry->targetList), context))
			return true;
		if (fireRIRonSubselect((Node *) (qry->qual), context))
			return true;
		if (fireRIRonSubselect((Node *) (qry->havingQual), context))
			return true;
		return false;
880
	}
881 882
	return expression_tree_walker(node, fireRIRonSubselect,
								  (void *) context);
883 884 885 886 887 888 889 890 891 892
}


/*
 * fireRIRrules -
 *	Apply all RIR rules on each rangetable entry in a query
 */
static Query *
fireRIRrules(Query *parsetree)
{
B
Bruce Momjian 已提交
893 894
	int			rt_index;
	RangeTblEntry *rte;
895
	Relation	rel;
B
Bruce Momjian 已提交
896 897 898 899
	List	   *locks;
	RuleLock   *rules;
	RewriteRule *rule;
	RewriteRule RIRonly;
900
	bool		relWasInJoinSet;
B
Bruce Momjian 已提交
901 902
	int			i;
	List	   *l;
903

904 905 906
	/*
	 * don't try to convert this into a foreach loop, because rtable list
	 * can get changed each time through...
907
	 */
908
	rt_index = 0;
B
Bruce Momjian 已提交
909 910
	while (rt_index < length(parsetree->rtable))
	{
911 912
		++rt_index;

913
		rte = rt_fetch(rt_index, parsetree->rtable);
914

915
		/*
916 917 918 919 920
		 * If the table is not referenced in the query, then we ignore it.
		 * This prevents infinite expansion loop due to new rtable entries
		 * inserted by expansion of a rule. A table is referenced if it is
		 * part of the join set (a source table), or is the result table,
		 * or is referenced by any Var nodes.
921
		 */
922
		if (!rte->inJoinSet && rt_index != parsetree->resultRelation &&
923
			!rangeTableEntry_used((Node *) parsetree, rt_index, 0))
924
			continue;
B
Bruce Momjian 已提交
925

926
		rel = heap_openr(rte->relname, AccessShareLock);
927 928
		rules = rel->rd_rules;
		if (rules == NULL)
B
Bruce Momjian 已提交
929
		{
930
			heap_close(rel, AccessShareLock);
931 932 933
			continue;
		}

934 935
		relWasInJoinSet = rte->inJoinSet;		/* save before possibly
												 * clearing */
936 937 938 939

		/*
		 * Collect the RIR rules that we must apply
		 */
940
		locks = NIL;
B
Bruce Momjian 已提交
941 942
		for (i = 0; i < rules->numLocks; i++)
		{
943 944 945
			rule = rules->rules[i];
			if (rule->event != CMD_SELECT)
				continue;
B
Bruce Momjian 已提交
946

947 948 949
			if (rule->attrno > 0)
			{
				/* per-attr rule; do we need it? */
950 951 952
				if (!attribute_used((Node *) parsetree,
									rt_index,
									rule->attrno, 0))
953 954 955 956
					continue;
			}
			else
			{
957 958 959 960 961

				/*
				 * Rel-wide ON SELECT DO INSTEAD means this is a view.
				 * Remove the view from the planner's join target set, or
				 * we'll get no rows out because view itself is empty!
962 963 964 965
				 */
				if (rule->isInstead)
					rte->inJoinSet = false;
			}
966 967 968 969 970 971 972 973 974 975 976 977

			locks = lappend(locks, rule);
		}

		/*
		 * Check permissions
		 */
		checkLockPerms(locks, parsetree, rt_index);

		/*
		 * Now apply them
		 */
B
Bruce Momjian 已提交
978 979
		foreach(l, locks)
		{
980 981
			rule = lfirst(l);

B
Bruce Momjian 已提交
982 983 984 985
			RIRonly.event = rule->event;
			RIRonly.attrno = rule->attrno;
			RIRonly.qual = rule->qual;
			RIRonly.actions = rule->actions;
986

987 988 989 990 991
			parsetree = ApplyRetrieveRule(parsetree,
										  &RIRonly,
										  rt_index,
										  RIRonly.attrno == -1,
										  rel,
992
										  relWasInJoinSet);
993 994
		}

995
		heap_close(rel, AccessShareLock);
996 997
	}

998 999
	if (parsetree->hasAggs)
		parsetree->qual = modifyAggrefQual(parsetree->qual, parsetree);
1000

1001 1002 1003
	if (parsetree->hasSubLinks)
		fireRIRonSubselect((Node *) parsetree, NULL);

1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
	return parsetree;
}


/*
 * idea is to fire regular rules first, then qualified instead
 * rules and unqualified instead rules last. Any lemming is counted for.
 */
static List *
orderRules(List *locks)
{
	List	   *regular = NIL;
	List	   *instead_rules = NIL;
	List	   *instead_qualified = NIL;
	List	   *i;

	foreach(i, locks)
	{
		RewriteRule *rule_lock = (RewriteRule *) lfirst(i);

		if (rule_lock->isInstead)
		{
			if (rule_lock->qual == NULL)
				instead_rules = lappend(instead_rules, rule_lock);
			else
				instead_qualified = lappend(instead_qualified, rule_lock);
1030
		}
1031 1032
		else
			regular = lappend(regular, rule_lock);
1033
	}
1034 1035
	regular = nconc(regular, instead_qualified);
	return nconc(regular, instead_rules);
1036 1037
}

1038 1039


1040
static Query *
1041 1042 1043
CopyAndAddQual(Query *parsetree,
			   List *actions,
			   Node *rule_qual,
1044 1045
			   int rt_index,
			   CmdType event)
1046
{
1047 1048 1049
	Query	   *new_tree = (Query *) copyObject(parsetree);
	Node	   *new_qual = NULL;
	Query	   *rule_action = NULL;
1050 1051 1052 1053 1054 1055 1056

	if (actions)
		rule_action = lfirst(actions);
	if (rule_qual != NULL)
		new_qual = (Node *) copyObject(rule_qual);
	if (rule_action != NULL)
	{
1057 1058
		List	   *rtable;
		int			rt_length;
1059 1060 1061

		rtable = new_tree->rtable;
		rt_length = length(rtable);
B
Bruce Momjian 已提交
1062
		rtable = nconc(rtable, copyObject(rule_action->rtable));
1063
		new_tree->rtable = rtable;
B
Bruce Momjian 已提交
1064
		OffsetVarNodes(new_qual, rt_length, 0);
1065
		ChangeVarNodes(new_qual, PRS2_OLD_VARNO + rt_length, rt_index, 0);
1066 1067 1068 1069 1070
	}
	/* XXX -- where current doesn't work for instead nothing.... yet */
	AddNotQual(new_tree, new_qual);

	return new_tree;
1071 1072 1073
}


1074

1075
/*
1076
 *	fireRules -
M
 
Marc G. Fournier 已提交
1077 1078 1079 1080 1081
 *	   Iterate through rule locks applying rules.
 *	   All rules create their own parsetrees. Instead rules
 *	   with rule qualification save the original parsetree
 *	   and add their negated qualification to it. Real instead
 *	   rules finally throw away the original parsetree.
1082
 *
M
 
Marc G. Fournier 已提交
1083
 *	   remember: reality is for dead birds -- glass
1084 1085
 *
 */
1086
static List *
1087
fireRules(Query *parsetree,
1088 1089
		  int rt_index,
		  CmdType event,
1090 1091 1092
		  bool *instead_flag,
		  List *locks,
		  List **qual_products)
1093
{
1094 1095 1096
	RewriteInfo *info;
	List	   *results = NIL;
	List	   *i;
1097 1098 1099

	/* choose rule to fire from list of rules */
	if (locks == NIL)
1100
		return NIL;
1101

M
 
Marc G. Fournier 已提交
1102
	locks = orderRules(locks);	/* real instead rules last */
1103 1104
	foreach(i, locks)
	{
1105 1106 1107 1108 1109
		RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
		Node	   *qual,
				   *event_qual;
		List	   *actions;
		List	   *r;
1110

1111
		/*
1112 1113 1114 1115 1116 1117
		 * Instead rules change the resultRelation of the query. So the
		 * permission checks on the initial resultRelation would never be
		 * done (this is normally done in the executor deep down). So we
		 * must do it here. The result relations resulting from earlier
		 * rewrites are already checked against the rules eventrelation
		 * owner (during matchLocks) and have the skipAcl flag set.
1118
		 */
1119 1120 1121 1122
		if (rule_lock->isInstead &&
			parsetree->commandType != CMD_SELECT)
		{
			RangeTblEntry *rte;
1123 1124 1125
			int32		acl_rc;
			int32		reqperm;

1126 1127
			switch (parsetree->commandType)
			{
1128 1129 1130 1131 1132 1133 1134
				case CMD_INSERT:
					reqperm = ACL_AP;
					break;
				default:
					reqperm = ACL_WR;
					break;
			}
1135

1136
			rte = rt_fetch(parsetree->resultRelation, parsetree->rtable);
1137 1138
			if (!rte->skipAcl)
			{
1139
				acl_rc = pg_aclcheck(rte->relname,
1140 1141 1142
									 GetPgUserName(), reqperm);
				if (acl_rc != ACLCHECK_OK)
				{
1143
					elog(ERROR, "%s: %s",
1144 1145
						 rte->relname,
						 aclcheck_error_strings[acl_rc]);
1146 1147 1148 1149
				}
			}
		}

1150 1151 1152 1153
		/* multiple rule action time */
		*instead_flag = rule_lock->isInstead;
		event_qual = rule_lock->qual;
		actions = rule_lock->actions;
1154 1155 1156 1157
		if (event_qual != NULL && *instead_flag)
		{
			Query	   *qual_product;
			RewriteInfo qual_info;
M
 
Marc G. Fournier 已提交
1158 1159 1160 1161 1162

			/* ----------
			 * If there are instead rules with qualifications,
			 * the original query is still performed. But all
			 * the negated rule qualifications of the instead
B
Bruce Momjian 已提交
1163
			 * rules are added so it does its actions only
M
 
Marc G. Fournier 已提交
1164 1165 1166 1167 1168 1169 1170
			 * in cases where the rule quals of all instead
			 * rules are false. Think of it as the default
			 * action in a case. We save this in *qual_products
			 * so deepRewriteQuery() can add it to the query
			 * list after we mangled it up enough.
			 * ----------
			 */
1171
			if (*qual_products == NIL)
M
 
Marc G. Fournier 已提交
1172
				qual_product = parsetree;
1173 1174
			else
				qual_product = (Query *) nth(0, *qual_products);
M
 
Marc G. Fournier 已提交
1175

1176
			MemSet(&qual_info, 0, sizeof(qual_info));
1177
			qual_info.event = qual_product->commandType;
1178
			qual_info.current_varno = rt_index;
1179
			qual_info.new_varno = length(qual_product->rtable) + 2;
1180

1181 1182 1183 1184 1185 1186 1187
			qual_product = CopyAndAddQual(qual_product,
										  actions,
										  event_qual,
										  rt_index,
										  event);

			qual_info.rule_action = qual_product;
M
 
Marc G. Fournier 已提交
1188 1189 1190 1191 1192 1193 1194

			if (event == CMD_INSERT || event == CMD_UPDATE)
				FixNew(&qual_info, qual_product);

			*qual_products = lappend(NIL, qual_product);
		}

1195 1196
		foreach(r, actions)
		{
1197 1198
			Query	   *rule_action = lfirst(r);
			Node	   *rule_qual = copyObject(event_qual);
1199

M
 
Marc G. Fournier 已提交
1200 1201 1202
			if (rule_action->commandType == CMD_NOTHING)
				continue;

B
Bruce Momjian 已提交
1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222
			/*--------------------------------------------------
			 * We copy the qualifications of the parsetree
			 * to the action and vice versa. So force
			 * hasSubLinks if one of them has it.
			 *
			 * As of 6.4 only parsetree qualifications can
			 * have sublinks. If this changes, we must make
			 * this a node lookup at the end of rewriting.
			 *
			 * Jan
			 *--------------------------------------------------
			 */
			if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
			{
				rule_action = copyObject(rule_action);
				rule_action->hasSubLinks = TRUE;
			}
			if (!parsetree->hasSubLinks && rule_action->hasSubLinks)
				parsetree->hasSubLinks = TRUE;

1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
			/*--------------------------------------------------
			 * Step 1:
			 *	  Rewrite current.attribute or current to tuple variable
			 *	  this appears to be done in parser?
			 *--------------------------------------------------
			 */
			info = gatherRewriteMeta(parsetree, rule_action, rule_qual,
									 rt_index, event, instead_flag);

			/* handle escapable cases, or those handled by other code */
			if (info->nothing)
			{
				if (*instead_flag)
					return NIL;
				else
					continue;
			}

			if (info->action == info->event &&
				info->event == CMD_SELECT)
				continue;

			/*
M
 
Marc G. Fournier 已提交
1246
			 * Event Qualification forces copying of parsetree and
1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270
			 * splitting into two queries one w/rule_qual, one w/NOT
			 * rule_qual. Also add user query qual onto rule action
			 */
			qual = parsetree->qual;
			AddQual(info->rule_action, qual);

			if (info->rule_qual != NULL)
				AddQual(info->rule_action, info->rule_qual);

			/*--------------------------------------------------
			 * Step 2:
			 *	  Rewrite new.attribute w/ right hand side of target-list
			 *	  entry for appropriate field name in insert/update
			 *--------------------------------------------------
			 */
			if ((info->event == CMD_INSERT) || (info->event == CMD_UPDATE))
				FixNew(info, parsetree);

			/*--------------------------------------------------
			 * Step 3:
			 *	  rewriting due to retrieve rules
			 *--------------------------------------------------
			 */
			info->rule_action->rtable = info->rt;
B
Bruce Momjian 已提交
1271

1272
			/*
B
Bruce Momjian 已提交
1273 1274 1275
			 * ProcessRetrieveQuery(info->rule_action, info->rt,
			 * &orig_instead_flag, TRUE);
			 */
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286

			/*--------------------------------------------------
			 * Step 4
			 *	  Simplify? hey, no algorithm for simplification... let
			 *	  the planner do it.
			 *--------------------------------------------------
			 */
			results = lappend(results, info->rule_action);

			pfree(info);
		}
M
 
Marc G. Fournier 已提交
1287 1288 1289 1290 1291 1292

		/* ----------
		 * If this was an unqualified instead rule,
		 * throw away an eventually saved 'default' parsetree
		 * ----------
		 */
1293
		if (event_qual == NULL && *instead_flag)
M
 
Marc G. Fournier 已提交
1294
			*qual_products = NIL;
1295 1296
	}
	return results;
1297 1298
}

M
 
Marc G. Fournier 已提交
1299 1300


1301
static List *
1302
RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
1303
{
1304
	CmdType		event;
B
Bruce Momjian 已提交
1305 1306 1307
	List	   *product_queries = NIL;
	int			result_relation = 0;
	RangeTblEntry *rt_entry;
1308
	Relation	rt_entry_relation = NULL;
B
Bruce Momjian 已提交
1309
	RuleLock   *rt_entry_locks = NULL;
1310

1311 1312 1313 1314
	Assert(parsetree != NULL);

	event = parsetree->commandType;

1315
	/*
B
Bruce Momjian 已提交
1316 1317
	 * SELECT rules are handled later when we have all the queries that
	 * should get executed
1318 1319 1320 1321 1322 1323 1324
	 */
	if (event == CMD_SELECT)
		return NIL;

	/*
	 * Utilities aren't rewritten at all - why is this here?
	 */
1325 1326
	if (event == CMD_UTILITY)
		return NIL;
1327

1328
	/*
B
Bruce Momjian 已提交
1329
	 * the statement is an update, insert or delete - fire rules on it.
1330
	 */
1331
	result_relation = parsetree->resultRelation;
1332
	rt_entry = rt_fetch(result_relation, parsetree->rtable);
1333
	rt_entry_relation = heap_openr(rt_entry->relname, AccessShareLock);
1334
	rt_entry_locks = rt_entry_relation->rd_rules;
1335
	heap_close(rt_entry_relation, AccessShareLock);
M
 
Marc G. Fournier 已提交
1336

1337
	if (rt_entry_locks != NULL)
1338
	{
1339
		List	   *locks = matchLocks(event, rt_entry_locks, result_relation, parsetree);
1340

1341
		product_queries = fireRules(parsetree,
B
Bruce Momjian 已提交
1342 1343 1344 1345 1346
									result_relation,
									event,
									instead_flag,
									locks,
									qual_products);
1347
	}
1348

1349
	return product_queries;
1350 1351
}

1352

1353 1354 1355 1356 1357
/*
 * to avoid infinite recursion, we restrict the number of times a query
 * can be rewritten. Detecting cycles is left for the reader as an excercise.
 */
#ifndef REWRITE_INVOKE_MAX
1358
#define REWRITE_INVOKE_MAX		10
1359 1360
#endif

1361
static int	numQueryRewriteInvoked = 0;
1362 1363 1364

/*
 * deepRewriteQuery -
1365
 *	  rewrites the query and apply the rules again on the queries rewritten
1366
 */
1367
static List *
1368
deepRewriteQuery(Query *parsetree)
1369
{
1370 1371 1372 1373 1374
	List	   *n;
	List	   *rewritten = NIL;
	List	   *result = NIL;
	bool		instead;
	List	   *qual_products = NIL;
1375

1376 1377


1378 1379
	if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
	{
1380
		elog(ERROR, "query rewritten %d times, may contain cycles",
1381 1382 1383 1384 1385
			 numQueryRewriteInvoked - 1);
	}

	instead = FALSE;
	result = RewriteQuery(parsetree, &instead, &qual_products);
1386

1387 1388
	foreach(n, result)
	{
1389 1390
		Query	   *pt = lfirst(n);
		List	   *newstuff = NIL;
1391 1392 1393 1394 1395

		newstuff = deepRewriteQuery(pt);
		if (newstuff != NIL)
			rewritten = nconc(rewritten, newstuff);
	}
M
 
Marc G. Fournier 已提交
1396 1397 1398 1399 1400 1401

	/* ----------
	 * qual_products are the original query with the negated
	 * rule qualification of an instead rule
	 * ----------
	 */
1402 1403 1404
	if (qual_products != NIL)
		rewritten = nconc(rewritten, qual_products);

M
 
Marc G. Fournier 已提交
1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
	/* ----------
	 * The original query is appended last if not instead
	 * because update and delete rule actions might not do
	 * anything if they are invoked after the update or
	 * delete is performed. The command counter increment
	 * between the query execution makes the deleted (and
	 * maybe the updated) tuples disappear so the scans
	 * for them in the rule actions cannot find them.
	 * ----------
	 */
	if (!instead)
		rewritten = lappend(rewritten, parsetree);

1418 1419
	return rewritten;
}
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438


/*
 * QueryOneRewrite -
 *	  rewrite one query
 */
static List *
QueryRewriteOne(Query *parsetree)
{
	numQueryRewriteInvoked = 0;

	/*
	 * take a deep breath and apply all the rewrite rules - ay
	 */
	return deepRewriteQuery(parsetree);
}


/*
1439
 * BasicQueryRewrite -
1440 1441 1442
 *	  rewrite one query via query rewrite system, possibly returning 0
 *	  or many queries
 */
1443 1444
static List *
BasicQueryRewrite(Query *parsetree)
1445
{
B
Bruce Momjian 已提交
1446 1447 1448 1449
	List	   *querylist;
	List	   *results = NIL;
	List	   *l;
	Query	   *query;
1450 1451 1452 1453 1454 1455 1456 1457 1458

	/*
	 * Step 1
	 *
	 * Apply all non-SELECT rules possibly getting 0 or many queries
	 */
	querylist = QueryRewriteOne(parsetree);

	/*
1459
	 * Step 2
1460 1461 1462
	 *
	 * Apply all the RIR rules on each query
	 */
B
Bruce Momjian 已提交
1463 1464 1465 1466
	foreach(l, querylist)
	{
		query = fireRIRrules((Query *) lfirst(l));

1467
		/*
B
Bruce Momjian 已提交
1468
		 * If the query was marked having aggregates, check if this is
1469
		 * still true after rewriting.	Ditto for sublinks.  Note there
1470
		 * should be no aggs in the qual at this point.
1471 1472
		 */
		if (query->hasAggs)
1473 1474
		{
			query->hasAggs =
1475 1476 1477
				checkExprHasAggs((Node *) (query->targetList)) ||
				checkExprHasAggs((Node *) (query->havingQual));
			if (checkExprHasAggs((Node *) (query->qual)))
1478 1479
				elog(ERROR, "BasicQueryRewrite: failed to remove aggs from qual");
		}
1480
		if (query->hasSubLinks)
1481
			query->hasSubLinks =
1482 1483 1484
				checkExprHasSubLink((Node *) (query->targetList)) ||
				checkExprHasSubLink((Node *) (query->qual)) ||
				checkExprHasSubLink((Node *) (query->havingQual));
1485
		results = lappend(results, query);
1486
	}
1487

1488 1489
	return results;
}
1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500

/*
 * QueryRewrite -
 *	  Primary entry point to the query rewriter.
 *	  Rewrite one query via query rewrite system, possibly returning 0
 *	  or many queries.
 *
 * NOTE: The code in QueryRewrite was formerly in pg_parse_and_plan(), and was
 * moved here so that it would be invoked during EXPLAIN.  The division of
 * labor between this routine and BasicQueryRewrite is not obviously correct
 * ... at least not to me ... tgl 5/99.
B
Hi!  
Bruce Momjian 已提交
1501
 */
1502 1503 1504 1505 1506 1507
List *
QueryRewrite(Query *parsetree)
{
	List	   *rewritten,
			   *rewritten_item;

B
Bruce Momjian 已提交
1508 1509 1510 1511
	/*
	 * Rewrite Union, Intersect and Except Queries to normal Union Queries
	 * using IN and NOT IN subselects
	 */
1512 1513 1514 1515 1516 1517 1518 1519 1520
	if (parsetree->intersectClause)
		parsetree = Except_Intersect_Rewrite(parsetree);

	/* Rewrite basic queries (retrieve, append, delete, replace) */
	rewritten = BasicQueryRewrite(parsetree);

	/*
	 * Rewrite the UNIONS.
	 */
B
Bruce Momjian 已提交
1521
	foreach(rewritten_item, rewritten)
1522 1523 1524 1525 1526
	{
		Query	   *qry = (Query *) lfirst(rewritten_item);
		List	   *union_result = NIL;
		List	   *union_item;

B
Bruce Momjian 已提交
1527
		foreach(union_item, qry->unionClause)
1528 1529
		{
			union_result = nconc(union_result,
B
Bruce Momjian 已提交
1530
						BasicQueryRewrite((Query *) lfirst(union_item)));
1531 1532 1533 1534 1535 1536 1537 1538 1539 1540
		}
		qry->unionClause = union_result;
	}

	return rewritten;
}

/* This function takes two targetlists as arguments and checks if the
 * targetlists are compatible (i.e. both select for the same number of
 * attributes and the types are compatible */
1541
static void
B
Bruce Momjian 已提交
1542
check_targetlists_are_compatible(List *prev_target, List *current_target)
B
Hi!  
Bruce Momjian 已提交
1543
{
1544
	List	   *tl;
B
Bruce Momjian 已提交
1545 1546
	int			prev_len = 0,
				next_len = 0;
1547

B
Bruce Momjian 已提交
1548 1549
	foreach(tl, prev_target)
		if (!((TargetEntry *) lfirst(tl))->resdom->resjunk)
1550
			prev_len++;
1551

1552 1553 1554
	foreach(tl, current_target)
		if (!((TargetEntry *) lfirst(tl))->resdom->resjunk)
			next_len++;
B
Bruce Momjian 已提交
1555 1556 1557 1558

	if (prev_len != next_len)
		elog(ERROR, "Each UNION | EXCEPT | INTERSECT query must have the same number of columns.");

1559
	foreach(tl, current_target)
B
Hi!  
Bruce Momjian 已提交
1560
	{
1561 1562 1563 1564 1565 1566 1567
		TargetEntry	   *next_tle = (TargetEntry *) lfirst(tl);
		TargetEntry	   *prev_tle;
		Oid				itype;
		Oid				otype;

		if (next_tle->resdom->resjunk)
			continue;
B
Bruce Momjian 已提交
1568

1569 1570 1571 1572 1573 1574 1575 1576 1577
		/* This loop must find an entry, since we counted them above. */
		do
		{
			prev_tle = (TargetEntry *) lfirst(prev_target);
			prev_target = lnext(prev_target);
		} while (prev_tle->resdom->resjunk);

		itype = next_tle->resdom->restype;
		otype = prev_tle->resdom->restype;
B
Bruce Momjian 已提交
1578 1579 1580 1581 1582 1583

		/* one or both is a NULL column? then don't convert... */
		if (otype == InvalidOid)
		{
			/* propagate a known type forward, if available */
			if (itype != InvalidOid)
1584
				prev_tle->resdom->restype = itype;
M
 
Marc G. Fournier 已提交
1585
#ifdef NOT_USED
B
Bruce Momjian 已提交
1586 1587
			else
			{
1588 1589
				prev_tle->resdom->restype = UNKNOWNOID;
				next_tle->resdom->restype = UNKNOWNOID;
B
Bruce Momjian 已提交
1590
			}
B
Hi!  
Bruce Momjian 已提交
1591
#endif
B
Bruce Momjian 已提交
1592 1593 1594 1595 1596 1597 1598 1599 1600
		}
		else if (itype == InvalidOid)
		{
		}
		/* they don't match in type? then convert... */
		else if (itype != otype)
		{
			Node	   *expr;

1601
			expr = next_tle->expr;
1602
			expr = CoerceTargetExpr(NULL, expr, itype, otype, -1);
B
Bruce Momjian 已提交
1603 1604 1605 1606 1607 1608 1609
			if (expr == NULL)
			{
				elog(ERROR, "Unable to transform %s to %s"
					 "\n\tEach UNION | EXCEPT | INTERSECT clause must have compatible target types",
					 typeidTypeName(itype),
					 typeidTypeName(otype));
			}
1610 1611
			next_tle->expr = expr;
			next_tle->resdom->restype = otype;
B
Bruce Momjian 已提交
1612 1613 1614 1615 1616
		}

		/* both are UNKNOWN? then evaluate as text... */
		else if (itype == UNKNOWNOID)
		{
1617 1618
			next_tle->resdom->restype = TEXTOID;
			prev_tle->resdom->restype = TEXTOID;
B
Bruce Momjian 已提交
1619
		}
B
Hi!  
Bruce Momjian 已提交
1620 1621 1622 1623
	}
}

/* Rewrites UNION INTERSECT and EXCEPT queries to semantiacally equivalent
B
Bruce Momjian 已提交
1624 1625
 * queries that use IN and NOT IN subselects.
 *
B
Hi!  
Bruce Momjian 已提交
1626 1627 1628
 * The operator tree is attached to 'intersectClause' (see rule
 * 'SelectStmt' in gram.y) of the 'parsetree' given as an
 * argument. First we remember some clauses (the sortClause, the
1629
 * distinctClause etc.)  Then we translate the operator tree to DNF
B
Hi!  
Bruce Momjian 已提交
1630 1631 1632 1633 1634 1635 1636 1637
 * (disjunctive normal form) by 'cnfify'. (Note that 'cnfify' produces
 * CNF but as we exchanged ANDs with ORs in function A_Expr_to_Expr()
 * earlier we get DNF after exchanging ANDs and ORs again in the
 * result.) Now we create a new query by evaluating the new operator
 * tree which is in DNF now. For every AND we create an entry in the
 * union list and for every OR we create an IN subselect. (NOT IN
 * subselects are created for OR NOT nodes). The first entry of the
 * union list is handed back but before that the remembered clauses
B
Bruce Momjian 已提交
1638
 * (sortClause etc) are attached to the new top Node (Note that the
B
Hi!  
Bruce Momjian 已提交
1639
 * new top Node can differ from the parsetree given as argument because of
1640 1641
 * the translation to DNF. That's why we have to remember the sortClause
 * and so on!) */
1642
static Query *
B
Bruce Momjian 已提交
1643
Except_Intersect_Rewrite(Query *parsetree)
B
Hi!  
Bruce Momjian 已提交
1644
{
B
Bruce Momjian 已提交
1645 1646 1647 1648 1649 1650 1651 1652 1653

	SubLink    *n;
	Query	   *result,
			   *intersect_node;
	List	   *elist,
			   *intersect_list = NIL,
			   *intersect,
			   *intersectClause;
	List	   *union_list = NIL,
1654 1655
			   *sortClause,
			   *distinctClause;
B
Bruce Momjian 已提交
1656 1657 1658 1659 1660 1661 1662
	List	   *left_expr,
			   *resnames = NIL;
	char	   *op,
			   *into;
	bool		isBinary,
				isPortal,
				isTemp;
1663 1664
	Node	   *limitOffset,
			   *limitCount;
B
Bruce Momjian 已提交
1665
	CmdType		commandType = CMD_SELECT;
1666
	RangeTblEntry *rtable_insert = NULL;
B
Bruce Momjian 已提交
1667 1668 1669 1670 1671 1672 1673 1674
	List	   *prev_target = NIL;

	/*
	 * Remember the Resnames of the given parsetree's targetlist (these
	 * are the resnames of the first Select Statement of the query
	 * formulated by the user and he wants the columns named by these
	 * strings. The transformation to DNF can cause another Select
	 * Statment to be the top one which uses other names for its columns.
1675
	 * Therefore we remember the original names and attach them to the
B
Bruce Momjian 已提交
1676 1677 1678 1679 1680 1681
	 * targetlist of the new topmost Node at the end of this function
	 */
	foreach(elist, parsetree->targetList)
	{
		TargetEntry *tent = (TargetEntry *) lfirst(elist);

1682 1683
		if (! tent->resdom->resjunk)
			resnames = lappend(resnames, tent->resdom->resname);
B
Bruce Momjian 已提交
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693
	}

	/*
	 * If the Statement is an INSERT INTO ... (SELECT...) statement using
	 * UNIONs, INTERSECTs or EXCEPTs and the transformation to DNF makes
	 * another Node to the top node we have to transform the new top node
	 * to an INSERT node and the original INSERT node to a SELECT node
	 */
	if (parsetree->commandType == CMD_INSERT)
	{
1694

B
Bruce Momjian 已提交
1695 1696 1697 1698
		/*
		 * The result relation ( = the one to insert into) has to be
		 * attached to the rtable list of the new top node
		 */
1699 1700 1701 1702 1703
		rtable_insert = rt_fetch(parsetree->resultRelation, parsetree->rtable);

		parsetree->commandType = CMD_SELECT;
		commandType = CMD_INSERT;
		parsetree->resultRelation = 0;
B
Hi!  
Bruce Momjian 已提交
1704
	}
B
Bruce Momjian 已提交
1705 1706 1707 1708 1709 1710

	/*
	 * Save some items, to be able to attach them to the resulting top
	 * node at the end of the function
	 */
	sortClause = parsetree->sortClause;
1711
	distinctClause = parsetree->distinctClause;
B
Bruce Momjian 已提交
1712 1713 1714 1715
	into = parsetree->into;
	isBinary = parsetree->isBinary;
	isPortal = parsetree->isPortal;
	isTemp = parsetree->isTemp;
1716 1717
	limitOffset = parsetree->limitOffset;
	limitCount = parsetree->limitCount;
B
Bruce Momjian 已提交
1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772

	/*
	 * The operator tree attached to parsetree->intersectClause is still
	 * 'raw' ( = the leaf nodes are still SelectStmt nodes instead of
	 * Query nodes) So step through the tree and transform the nodes using
	 * parse_analyze().
	 *
	 * The parsetree (given as an argument to Except_Intersect_Rewrite()) has
	 * already been transformed and transforming it again would cause
	 * troubles.  So we give the 'raw' version (of the cooked parsetree)
	 * to the function to prevent an additional transformation. Instead we
	 * hand back the 'cooked' version also given as an argument to
	 * intersect_tree_analyze()
	 */
	intersectClause =
		(List *) intersect_tree_analyze((Node *) parsetree->intersectClause,
								 (Node *) lfirst(parsetree->unionClause),
										(Node *) parsetree);

	/* intersectClause is no longer needed so set it to NIL */
	parsetree->intersectClause = NIL;

	/*
	 * unionClause will be needed later on but the list it delivered is no
	 * longer needed, so set it to NIL
	 */
	parsetree->unionClause = NIL;

	/*
	 * Transform the operator tree to DNF (remember ANDs and ORs have been
	 * exchanged, that's why we get DNF by using cnfify)
	 *
	 * After the call, explicit ANDs are removed and all AND operands are
	 * simply items in the intersectClause list
	 */
	intersectClause = cnfify((Expr *) intersectClause, true);

	/*
	 * For every entry of the intersectClause list we generate one entry
	 * in the union_list
	 */
	foreach(intersect, intersectClause)
	{

		/*
		 * for every OR we create an IN subselect and for every OR NOT we
		 * create a NOT IN subselect, so first extract all the Select
		 * Query nodes from the tree (that contains only OR or OR NOTs any
		 * more because we did a transformation to DNF
		 *
		 * There must be at least one node that is not negated (i.e. just OR
		 * and not OR NOT) and this node will be the first in the list
		 * returned
		 */
		intersect_list = NIL;
1773
		create_intersect_list((Node *) lfirst(intersect), &intersect_list);
B
Bruce Momjian 已提交
1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843

		/*
		 * This one will become the Select Query node, all other nodes are
		 * transformed into subselects under this node!
		 */
		intersect_node = (Query *) lfirst(intersect_list);
		intersect_list = lnext(intersect_list);

		/*
		 * Check if all Select Statements use the same number of
		 * attributes and if all corresponding attributes are of the same
		 * type
		 */
		if (prev_target)
			check_targetlists_are_compatible(prev_target, intersect_node->targetList);
		prev_target = intersect_node->targetList;

		/*
		 * Transform all nodes remaining into subselects and add them to
		 * the qualifications of the Select Query node
		 */
		while (intersect_list != NIL)
		{

			n = makeNode(SubLink);

			/* Here we got an OR so transform it to an IN subselect */
			if (IsA(lfirst(intersect_list), Query))
			{

				/*
				 * Check if all Select Statements use the same number of
				 * attributes and if all corresponding attributes are of
				 * the same type
				 */
				check_targetlists_are_compatible(prev_target,
						 ((Query *) lfirst(intersect_list))->targetList);

				n->subselect = lfirst(intersect_list);
				op = "=";
				n->subLinkType = ANY_SUBLINK;
				n->useor = false;
			}

			/*
			 * Here we got an OR NOT node so transform it to a NOT IN
			 * subselect
			 */
			else
			{

				/*
				 * Check if all Select Statements use the same number of
				 * attributes and if all corresponding attributes are of
				 * the same type
				 */
				check_targetlists_are_compatible(prev_target,
												 ((Query *) lfirst(((Expr *) lfirst(intersect_list))->args))->targetList);

				n->subselect = (Node *) lfirst(((Expr *) lfirst(intersect_list))->args);
				op = "<>";
				n->subLinkType = ALL_SUBLINK;
				n->useor = true;
			}

			/*
			 * Prepare the lefthand side of the Sublinks: All the entries
			 * of the targetlist must be (IN) or must not be (NOT IN) the
			 * subselect
			 */
1844
			n->lefthand = NIL;
B
Bruce Momjian 已提交
1845 1846
			foreach(elist, intersect_node->targetList)
			{
1847
				TargetEntry *tent = (TargetEntry *) lfirst(elist);
B
Bruce Momjian 已提交
1848

1849 1850
				if (! tent->resdom->resjunk)
					n->lefthand = lappend(n->lefthand, tent->expr);
B
Bruce Momjian 已提交
1851 1852 1853
			}

			/*
1854
			 * Also prepare the list of Opers that must be used for the
1855 1856
			 * comparisons (they depend on the specific datatypes
			 * involved!)
B
Bruce Momjian 已提交
1857 1858
			 */
			left_expr = n->lefthand;
1859
			n->oper = NIL;
B
Bruce Momjian 已提交
1860

1861
			foreach(elist, ((Query *) (n->subselect))->targetList)
B
Bruce Momjian 已提交
1862
			{
1863 1864
				TargetEntry *tent = (TargetEntry *) lfirst(elist);
				Node	   *lexpr;
1865 1866 1867 1868
				Operator	optup;
				Form_pg_operator opform;
				Oper	   *newop;

1869 1870 1871 1872 1873
				if (tent->resdom->resjunk)
					continue;

				lexpr = lfirst(left_expr);

1874 1875 1876 1877 1878 1879 1880 1881 1882
				optup = oper(op,
							 exprType(lexpr),
							 exprType(tent->expr),
							 FALSE);
				opform = (Form_pg_operator) GETSTRUCT(optup);

				if (opform->oprresult != BOOLOID)
					elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);

1883 1884
				newop = makeOper(oprid(optup),	/* opno */
								 InvalidOid,	/* opid */
1885 1886 1887
								 opform->oprresult,
								 0,
								 NULL);
B
Bruce Momjian 已提交
1888

1889
				n->oper = lappend(n->oper, newop);
B
Bruce Momjian 已提交
1890

1891
				left_expr = lnext(left_expr);
B
Bruce Momjian 已提交
1892 1893
			}

1894 1895
			Assert(left_expr == NIL); /* should have used 'em all */

B
Bruce Momjian 已提交
1896 1897 1898 1899
			/*
			 * If the Select Query node has aggregates in use add all the
			 * subselects to the HAVING qual else to the WHERE qual
			 */
1900
			if (intersect_node->hasAggs)
B
Bruce Momjian 已提交
1901
				AddHavingQual(intersect_node, (Node *) n);
1902 1903
			else
				AddQual(intersect_node, (Node *) n);
B
Bruce Momjian 已提交
1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918

			/* Now we got sublinks */
			intersect_node->hasSubLinks = true;
			intersect_list = lnext(intersect_list);
		}
		intersect_node->intersectClause = NIL;
		union_list = lappend(union_list, intersect_node);
	}

	/* The first entry to union_list is our new top node */
	result = (Query *) lfirst(union_list);
	/* attach the rest to unionClause */
	result->unionClause = lnext(union_list);
	/* Attach all the items remembered in the beginning of the function */
	result->sortClause = sortClause;
1919
	result->distinctClause = distinctClause;
B
Bruce Momjian 已提交
1920 1921 1922 1923
	result->into = into;
	result->isPortal = isPortal;
	result->isBinary = isBinary;
	result->isTemp = isTemp;
1924 1925
	result->limitOffset = limitOffset;
	result->limitCount = limitCount;
B
Bruce Momjian 已提交
1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945

	/*
	 * The relation to insert into is attached to the range table of the
	 * new top node
	 */
	if (commandType == CMD_INSERT)
	{
		result->rtable = lappend(result->rtable, rtable_insert);
		result->resultRelation = length(result->rtable);
		result->commandType = commandType;
	}

	/*
	 * The resnames of the originally first SelectStatement are attached
	 * to the new first SelectStatement
	 */
	foreach(elist, result->targetList)
	{
		TargetEntry *tent = (TargetEntry *) lfirst(elist);

1946 1947 1948
		if (tent->resdom->resjunk)
			continue;

B
Bruce Momjian 已提交
1949 1950 1951
		tent->resdom->resname = lfirst(resnames);
		resnames = lnext(resnames);
	}
1952

B
Bruce Momjian 已提交
1953
	return result;
B
Hi!  
Bruce Momjian 已提交
1954 1955 1956 1957 1958 1959 1960
}

/* Create a list of nodes that are either Query nodes of NOT Expr
 * nodes followed by a Query node. The tree given in ptr contains at
 * least one non negated Query node. This node is attached to the
 * beginning of the list */

1961 1962
static void
create_intersect_list(Node *ptr, List **intersect_list)
B
Hi!  
Bruce Momjian 已提交
1963
{
B
Bruce Momjian 已提交
1964 1965 1966
	List	   *arg;

	if (IsA(ptr, Query))
B
Hi!  
Bruce Momjian 已提交
1967
	{
B
Bruce Momjian 已提交
1968 1969 1970
		/* The non negated node is attached at the beginning (lcons) */
		*intersect_list = lcons(ptr, *intersect_list);
		return;
B
Hi!  
Bruce Momjian 已提交
1971
	}
B
Bruce Momjian 已提交
1972 1973

	if (IsA(ptr, Expr))
B
Hi!  
Bruce Momjian 已提交
1974
	{
B
Bruce Momjian 已提交
1975 1976 1977 1978 1979 1980 1981 1982 1983
		if (((Expr *) ptr)->opType == NOT_EXPR)
		{
			/* negated nodes are appended to the end (lappend) */
			*intersect_list = lappend(*intersect_list, ptr);
			return;
		}
		else
		{
			foreach(arg, ((Expr *) ptr)->args)
1984
				create_intersect_list(lfirst(arg), intersect_list);
B
Bruce Momjian 已提交
1985 1986 1987
			return;
		}
		return;
B
Hi!  
Bruce Momjian 已提交
1988 1989 1990 1991 1992
	}
}

/* The nodes given in 'tree' are still 'raw' so 'cook' them using parse_analyze().
 * The node given in first_select has already been cooked, so don't transform
B
Bruce Momjian 已提交
1993
 * it again but return a pointer to the previously cooked version given in 'parsetree'
B
Hi!  
Bruce Momjian 已提交
1994
 * instead. */
1995
static Node *
B
Bruce Momjian 已提交
1996
intersect_tree_analyze(Node *tree, Node *first_select, Node *parsetree)
B
Hi!  
Bruce Momjian 已提交
1997
{
B
Bruce Momjian 已提交
1998 1999
	Node	   *result = (Node *) NIL;
	List	   *arg;
2000 2001

	if (IsA(tree, SelectStmt))
B
Bruce Momjian 已提交
2002 2003 2004 2005 2006 2007
	{

		/*
		 * If we get to the tree given in first_select return parsetree
		 * instead of performing parse_analyze()
		 */
2008 2009 2010
		if (tree == first_select)
			result = parsetree;
		else
B
Bruce Momjian 已提交
2011 2012 2013 2014
		{
			/* transform the 'raw' nodes to 'cooked' Query nodes */
			List	   *qtree = parse_analyze(lcons(tree, NIL), NULL);

2015 2016
			result = (Node *) lfirst(qtree);
		}
B
Bruce Momjian 已提交
2017
	}
2018

B
Bruce Momjian 已提交
2019
	if (IsA(tree, Expr))
B
Hi!  
Bruce Momjian 已提交
2020
	{
B
Bruce Momjian 已提交
2021 2022 2023 2024
		/* Call recursively for every argument of the node */
		foreach(arg, ((Expr *) tree)->args)
			lfirst(arg) = intersect_tree_analyze(lfirst(arg), first_select, parsetree);
		result = tree;
B
Hi!  
Bruce Momjian 已提交
2025
	}
B
Bruce Momjian 已提交
2026
	return result;
B
Hi!  
Bruce Momjian 已提交
2027
}