rewriteHandler.c 25.2 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * rewriteHandler.c
4
 *		Primary module of query rewriter.
5
 *
6
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
B
Add:  
Bruce Momjian 已提交
7
 * Portions Copyright (c) 1994, Regents of the University of California
8 9
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.96 2001/07/06 13:40:47 wieck 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"
30
#include "rewrite/rewriteHandler.h"
B
Bruce Momjian 已提交
31 32
#include "rewrite/rewriteManip.h"
#include "utils/lsyscache.h"
33 34


35 36 37 38 39
static Query *rewriteRuleAction(Query *parsetree,
								Query *rule_action,
								Node *rule_qual,
								int rt_index,
								CmdType event);
40
static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
41
static void markQueryForUpdate(Query *qry, bool skipOldNew);
42
static List *matchLocks(CmdType event, RuleLock *rulelocks,
B
Bruce Momjian 已提交
43
		   int varno, Query *parsetree);
44
static Query *fireRIRrules(Query *parsetree);
45

46 47

/*
48 49 50
 * rewriteRuleAction -
 *	  Rewrite the rule action with appropriate qualifiers (taken from
 *	  the triggering query).
51
 */
52 53
static Query *
rewriteRuleAction(Query *parsetree,
54 55
				  Query *rule_action,
				  Node *rule_qual,
56
				  int rt_index,
57
				  CmdType event)
58
{
59 60 61
	int			current_varno,
				new_varno;
	int			rt_length;
62 63
	Query	   *sub_action;
	Query	  **sub_action_ptr;
64

65 66 67 68 69 70 71 72
	/*
	 * Make modifiable copies of rule action and qual (what we're passed
	 * are the stored versions in the relcache; don't touch 'em!).
	 */
	rule_action = (Query *) copyObject(rule_action);
	rule_qual = (Node *) copyObject(rule_qual);

	current_varno = rt_index;
73
	rt_length = length(parsetree->rtable);
74
	new_varno = PRS2_NEW_VARNO + rt_length;
75

76 77
	/*
	 * Adjust rule action and qual to offset its varnos, so that we can
78
	 * merge its rtable with the main parsetree's rtable.
79
	 *
B
Bruce Momjian 已提交
80 81 82
	 * If the rule action is an INSERT...SELECT, the OLD/NEW rtable entries
	 * will be in the SELECT part, and we have to modify that rather than
	 * the top-level INSERT (kluge!).
83
	 */
84
	sub_action = getInsertSelectQuery(rule_action, &sub_action_ptr);
85

86
	OffsetVarNodes((Node *) sub_action, rt_length, 0);
87
	OffsetVarNodes(rule_qual, rt_length, 0);
88 89 90
	/* but references to *OLD* should point at original rt_index */
	ChangeVarNodes((Node *) sub_action,
				   PRS2_OLD_VARNO + rt_length, rt_index, 0);
91
	ChangeVarNodes(rule_qual,
92 93 94
				   PRS2_OLD_VARNO + rt_length, rt_index, 0);

	/*
95 96 97 98 99 100
	 * Generate expanded rtable consisting of main parsetree's rtable
	 * plus rule action's rtable; this becomes the complete rtable for the
	 * rule action.  Some of the entries may be unused after we finish
	 * rewriting, but if we tried to clean those out we'd have a much harder
	 * job to adjust RT indexes in the query's Vars.  It's OK to have unused
	 * RT entries, since planner will ignore them.
101
	 *
102 103 104
	 * NOTE: because planner will destructively alter rtable, we must ensure
	 * that rule action's rtable is separate and shares no substructure with
	 * the main rtable.  Hence do a deep copy here.
105
	 */
106 107
	sub_action->rtable = nconc((List *) copyObject(parsetree->rtable),
							   sub_action->rtable);
108

109 110
	/*
	 * Each rule action's jointree should be the main parsetree's jointree
B
Bruce Momjian 已提交
111 112 113 114 115 116 117 118 119
	 * plus that rule's jointree, but usually *without* the original
	 * rtindex that we're replacing (if present, which it won't be for
	 * INSERT). Note that if the rule action refers to OLD, its jointree
	 * will add a reference to rt_index.  If the rule action doesn't refer
	 * to OLD, but either the rule_qual or the user query quals do, then
	 * we need to keep the original rtindex in the jointree to provide
	 * data for the quals.	We don't want the original rtindex to be
	 * joined twice, however, so avoid keeping it if the rule action
	 * mentions it.
120 121 122
	 *
	 * As above, the action's jointree must not share substructure with
	 * the main parsetree's.
123
	 */
124
	if (sub_action->jointree != NULL)
125
	{
B
Bruce Momjian 已提交
126 127
		bool		keeporig;
		List	   *newjointree;
128

B
Bruce Momjian 已提交
129 130
		keeporig = (!rangeTableEntry_used((Node *) sub_action->jointree,
										  rt_index, 0)) &&
131 132
			(rangeTableEntry_used(rule_qual, rt_index, 0) ||
			 rangeTableEntry_used(parsetree->jointree->quals, rt_index, 0));
133
		newjointree = adjustJoinTreeList(parsetree, !keeporig, rt_index);
134 135 136 137 138 139 140 141
		sub_action->jointree->fromlist =
			nconc(newjointree, sub_action->jointree->fromlist);
	}

	/*
	 * We copy the qualifications of the parsetree to the action and vice
	 * versa. So force hasSubLinks if one of them has it. If this is not
	 * right, the flag will get cleared later, but we mustn't risk having
142 143
	 * it not set when it needs to be.  (XXX this should probably be handled
	 * by AddQual and friends, not here...)
144 145 146 147 148 149 150
	 */
	if (parsetree->hasSubLinks)
		sub_action->hasSubLinks = TRUE;
	else if (sub_action->hasSubLinks)
		parsetree->hasSubLinks = TRUE;

	/*
B
Bruce Momjian 已提交
151 152 153
	 * Event Qualification forces copying of parsetree and splitting into
	 * two queries one w/rule_qual, one w/NOT rule_qual. Also add user
	 * query qual onto rule action
154
	 */
155
	AddQual(sub_action, rule_qual);
156 157 158 159

	AddQual(sub_action, parsetree->jointree->quals);

	/*
B
Bruce Momjian 已提交
160 161
	 * Rewrite new.attribute w/ right hand side of target-list entry for
	 * appropriate field name in insert/update.
162 163 164
	 *
	 * KLUGE ALERT: since ResolveNew returns a mutated copy, we can't just
	 * apply it to sub_action; we have to remember to update the sublink
165
	 * inside rule_action, too.
166
	 */
167
	if (event == CMD_INSERT || event == CMD_UPDATE)
168 169
	{
		sub_action = (Query *) ResolveNew((Node *) sub_action,
170
										  new_varno,
171 172
										  0,
										  parsetree->targetList,
173 174
										  event,
										  current_varno);
175 176 177
		if (sub_action_ptr)
			*sub_action_ptr = sub_action;
		else
178
			rule_action = sub_action;
179
	}
180

181
	return rule_action;
182 183
}

184
/*
185 186 187 188
 * Copy the query's jointree list, and optionally attempt to remove any
 * occurrence of the given rt_index as a top-level join item (we do not look
 * for it within join items; this is OK because we are only expecting to find
 * it as an UPDATE or DELETE target relation, which will be at the top level
189 190
 * of the join).  Returns modified jointree list --- this is a separate copy
 * sharing no nodes with the original.
191
 */
192
static List *
193
adjustJoinTreeList(Query *parsetree, bool removert, int rt_index)
194
{
195
	List	   *newjointree = copyObject(parsetree->jointree->fromlist);
196
	List	   *jjt;
197

198
	if (removert)
B
Bruce Momjian 已提交
199
	{
200
		foreach(jjt, newjointree)
201
		{
202 203
			RangeTblRef *rtr = lfirst(jjt);

B
Bruce Momjian 已提交
204
			if (IsA(rtr, RangeTblRef) &&rtr->rtindex == rt_index)
205 206 207 208
			{
				newjointree = lremove(rtr, newjointree);
				break;
			}
209
		}
210
	}
211
	return newjointree;
212
}
213

214

215
/*
216 217
 * matchLocks -
 *	  match the list of locks and returns the matching rules
218
 */
219 220 221 222 223
static List *
matchLocks(CmdType event,
		   RuleLock *rulelocks,
		   int varno,
		   Query *parsetree)
224
{
225 226 227
	List	   *real_locks = NIL;
	int			nlocks;
	int			i;
228

229 230
	Assert(rulelocks != NULL);	/* we get called iff there is some lock */
	Assert(parsetree != NULL);
231

232
	if (parsetree->commandType != CMD_SELECT)
233
	{
234 235
		if (parsetree->resultRelation != varno)
			return NIL;
236
	}
237

238
	nlocks = rulelocks->numLocks;
239

240
	for (i = 0; i < nlocks; i++)
B
Bruce Momjian 已提交
241
	{
242
		RewriteRule *oneLock = rulelocks->rules[i];
243

244
		if (oneLock->event == event)
245
		{
246 247 248 249 250 251
			if (parsetree->commandType != CMD_SELECT ||
				(oneLock->attrno == -1 ?
				 rangeTableEntry_used((Node *) parsetree, varno, 0) :
				 attribute_used((Node *) parsetree,
								varno, oneLock->attrno, 0)))
				real_locks = lappend(real_locks, oneLock);
252
		}
253
	}
254 255

	return real_locks;
256 257
}

258

259 260 261 262 263 264 265 266 267 268 269
static Query *
ApplyRetrieveRule(Query *parsetree,
				  RewriteRule *rule,
				  int rt_index,
				  bool relation_level,
				  Relation relation,
				  bool relIsUsed)
{
	Query	   *rule_action;
	RangeTblEntry *rte,
			   *subrte;
270

271 272 273 274
	if (length(rule->actions) != 1)
		elog(ERROR, "ApplyRetrieveRule: expected just one rule action");
	if (rule->qual != NULL)
		elog(ERROR, "ApplyRetrieveRule: can't handle qualified ON SELECT rule");
B
Bruce Momjian 已提交
275
	if (!relation_level)
276
		elog(ERROR, "ApplyRetrieveRule: can't handle per-attribute ON SELECT rule");
277

278
	/*
279 280
	 * Make a modifiable copy of the view query, and recursively expand
	 * any view references inside it.
281
	 */
282
	rule_action = copyObject(lfirst(rule->actions));
283

284
	rule_action = fireRIRrules(rule_action);
285

286
	/*
B
Bruce Momjian 已提交
287 288
	 * VIEWs are really easy --- just plug the view query in as a
	 * subselect, replacing the relation's original RTE.
289
	 */
290
	rte = rt_fetch(rt_index, parsetree->rtable);
291

292 293 294 295
	rte->relname = NULL;
	rte->relid = InvalidOid;
	rte->subquery = rule_action;
	rte->inh = false;			/* must not be set for a subquery */
296

297
	/*
298 299
	 * We move the view's permission check data down to its rangetable.
	 * The checks will actually be done against the *OLD* entry therein.
300
	 */
301 302 303 304
	subrte = rt_fetch(PRS2_OLD_VARNO, rule_action->rtable);
	Assert(subrte->relid == relation->rd_id);
	subrte->checkForRead = rte->checkForRead;
	subrte->checkForWrite = rte->checkForWrite;
305
	subrte->checkAsUser = rte->checkAsUser;
306

307 308
	rte->checkForRead = false;	/* no permission check on subquery itself */
	rte->checkForWrite = false;
309
	rte->checkAsUser = InvalidOid;
310

311
	/*
312
	 * FOR UPDATE of view?
313
	 */
314
	if (intMember(rt_index, parsetree->rowMarks))
315
	{
B
Bruce Momjian 已提交
316

317
		/*
318 319 320
		 * Remove the view from the list of rels that will actually be
		 * marked FOR UPDATE by the executor.  It will still be access-
		 * checked for write access, though.
321
		 */
322
		parsetree->rowMarks = lremovei(rt_index, parsetree->rowMarks);
B
Bruce Momjian 已提交
323 324

		/*
325
		 * Set up the view's referenced tables as if FOR UPDATE.
326
		 */
327
		markQueryForUpdate(rule_action, true);
328 329
	}

330
	return parsetree;
331 332
}

333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
/*
 * Recursively mark all relations used by a view as FOR UPDATE.
 *
 * This may generate an invalid query, eg if some sub-query uses an
 * aggregate.  We leave it to the planner to detect that.
 *
 * NB: this must agree with the parser's transformForUpdate() routine.
 */
static void
markQueryForUpdate(Query *qry, bool skipOldNew)
{
	Index		rti = 0;
	List	   *l;

	foreach(l, qry->rtable)
	{
		RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);

		rti++;

		/* Ignore OLD and NEW entries if we are at top level of view */
		if (skipOldNew &&
			(rti == PRS2_OLD_VARNO || rti == PRS2_NEW_VARNO))
			continue;

		if (rte->subquery)
		{
			/* FOR UPDATE of subquery is propagated to subquery's rels */
			markQueryForUpdate(rte->subquery, false);
		}
		else
		{
			if (!intMember(rti, qry->rowMarks))
				qry->rowMarks = lappendi(qry->rowMarks, rti);
			rte->checkForWrite = true;
		}
	}
}

372

373
/*
374 375 376
 * fireRIRonSubLink -
 *	Apply fireRIRrules() to each SubLink (subselect in expression) found
 *	in the given tree.
377 378
 *
 * NOTE: although this has the form of a walker, we cheat and modify the
379
 * SubLink nodes in-place.	It is caller's responsibility to ensure that
380
 * no unwanted side-effects occur!
381 382 383 384
 *
 * This is unlike most of the other routines that recurse into subselects,
 * because we must take control at the SubLink node in order to replace
 * the SubLink's subselect link with the possibly-rewritten subquery.
385 386
 */
static bool
387
fireRIRonSubLink(Node *node, void *context)
388 389
{
	if (node == NULL)
390 391
		return false;
	if (IsA(node, SubLink))
B
Bruce Momjian 已提交
392
	{
393 394 395
		SubLink    *sub = (SubLink *) node;

		/* Do what we came for */
396 397
		sub->subselect = (Node *) fireRIRrules((Query *) (sub->subselect));
		/* Fall through to process lefthand args of SubLink */
398
	}
B
Bruce Momjian 已提交
399

400 401
	/*
	 * Do NOT recurse into Query nodes, because fireRIRrules already
402
	 * processed subselects of subselects for us.
403
	 */
404
	return expression_tree_walker(node, fireRIRonSubLink,
405
								  (void *) context);
406 407 408 409 410 411 412 413 414 415
}


/*
 * fireRIRrules -
 *	Apply all RIR rules on each rangetable entry in a query
 */
static Query *
fireRIRrules(Query *parsetree)
{
B
Bruce Momjian 已提交
416
	int			rt_index;
417

418 419 420
	/*
	 * don't try to convert this into a foreach loop, because rtable list
	 * can get changed each time through...
421
	 */
422
	rt_index = 0;
B
Bruce Momjian 已提交
423 424
	while (rt_index < length(parsetree->rtable))
	{
425 426 427 428 429 430 431 432 433 434
		RangeTblEntry *rte;
		Relation	rel;
		List	   *locks;
		RuleLock   *rules;
		RewriteRule *rule;
		LOCKMODE	lockmode;
		bool		relIsUsed;
		int			i;
		List	   *l;

435 436
		++rt_index;

437
		rte = rt_fetch(rt_index, parsetree->rtable);
438

439 440 441 442 443 444 445 446 447 448 449
		/*
		 * A subquery RTE can't have associated rules, so there's nothing
		 * to do to this level of the query, but we must recurse into the
		 * subquery to expand any rule references in it.
		 */
		if (rte->subquery)
		{
			rte->subquery = fireRIRrules(rte->subquery);
			continue;
		}

450
		/*
451 452 453
		 * 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
454 455
		 * part of the join set (a source table), or is referenced by any
		 * Var nodes, or is the result table.
456
		 */
457 458 459
		relIsUsed = rangeTableEntry_used((Node *) parsetree, rt_index, 0);

		if (!relIsUsed && rt_index != parsetree->resultRelation)
460
			continue;
B
Bruce Momjian 已提交
461

462
		/*
B
Bruce Momjian 已提交
463 464 465 466 467 468
		 * This may well be the first access to the relation during the
		 * current statement (it will be, if this Query was extracted from
		 * a rule or somehow got here other than via the parser).
		 * Therefore, grab the appropriate lock type for the relation, and
		 * do not release it until end of transaction.	This protects the
		 * rewriter and planner against schema changes mid-query.
469
		 *
B
Bruce Momjian 已提交
470 471 472 473
		 * If the relation is the query's result relation, then
		 * RewriteQuery() already got the right lock on it, so we need no
		 * additional lock. Otherwise, check to see if the relation is
		 * accessed FOR UPDATE or not.
474 475 476 477 478 479 480 481 482 483
		 */
		if (rt_index == parsetree->resultRelation)
			lockmode = NoLock;
		else if (intMember(rt_index, parsetree->rowMarks))
			lockmode = RowShareLock;
		else
			lockmode = AccessShareLock;

		rel = heap_openr(rte->relname, lockmode);

484 485 486 487 488 489 490 491 492 493 494 495 496
		/*
		 * Check to see if relation's OID matches the RTE.  If not, the RTE
		 * actually refers to an older relation that had the same name.
		 * Eventually we might want to reparse the referencing rule, but
		 * for now all we can do is punt.
		 */
		if (RelationGetRelid(rel) != rte->relid)
			elog(ERROR, "Relation \"%s\" with OID %u no longer exists",
				 rte->relname, rte->relid);

		/*
		 * Collect the RIR rules that we must apply
		 */
497 498
		rules = rel->rd_rules;
		if (rules == NULL)
B
Bruce Momjian 已提交
499
		{
500
			heap_close(rel, NoLock);
501 502
			continue;
		}
503
		locks = NIL;
B
Bruce Momjian 已提交
504 505
		for (i = 0; i < rules->numLocks; i++)
		{
506 507 508
			rule = rules->rules[i];
			if (rule->event != CMD_SELECT)
				continue;
B
Bruce Momjian 已提交
509

510 511 512
			if (rule->attrno > 0)
			{
				/* per-attr rule; do we need it? */
513
				if (!attribute_used((Node *) parsetree, rt_index,
514
									rule->attrno, 0))
515 516
					continue;
			}
517 518 519 520 521 522 523

			locks = lappend(locks, rule);
		}

		/*
		 * Now apply them
		 */
B
Bruce Momjian 已提交
524 525
		foreach(l, locks)
		{
526 527
			rule = lfirst(l);

528
			parsetree = ApplyRetrieveRule(parsetree,
529
										  rule,
530
										  rt_index,
531
										  rule->attrno == -1,
532
										  rel,
533
										  relIsUsed);
534 535
		}

536
		heap_close(rel, NoLock);
537 538
	}

539 540 541 542
	/*
	 * Recurse into sublink subqueries, too.
	 */
	if (parsetree->hasSubLinks)
543
		query_tree_walker(parsetree, fireRIRonSubLink, NULL,
B
Bruce Momjian 已提交
544
						false /* already handled the ones in rtable */ );
545

546
	/*
B
Bruce Momjian 已提交
547 548 549 550 551
	 * If the query was marked having aggregates, check if this is still
	 * true after rewriting.  Ditto for sublinks.  Note there should be no
	 * aggs in the qual at this point.	(Does this code still do anything
	 * useful?	The view-becomes-subselect-in-FROM approach doesn't look
	 * like it could remove aggs or sublinks...)
552 553 554 555 556 557 558 559
	 */
	if (parsetree->hasAggs)
	{
		parsetree->hasAggs = checkExprHasAggs((Node *) parsetree);
		if (parsetree->hasAggs)
			if (checkExprHasAggs((Node *) parsetree->jointree))
				elog(ERROR, "fireRIRrules: failed to remove aggs from qual");
	}
560
	if (parsetree->hasSubLinks)
561
		parsetree->hasSubLinks = checkExprHasSubLink((Node *) parsetree);
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
	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);
589
		}
590 591
		else
			regular = lappend(regular, rule_lock);
592
	}
593
	return nconc(nconc(regular, instead_qualified), instead_rules);
594 595
}

596

597 598 599 600 601
/*
 * Modify the given query by adding 'AND NOT rule_qual' to its qualification.
 * This is used to generate suitable "else clauses" for conditional INSTEAD
 * rules.
 *
B
Bruce Momjian 已提交
602
 * The rule_qual may contain references to OLD or NEW.	OLD references are
603 604 605 606 607
 * replaced by references to the specified rt_index (the relation that the
 * rule applies to).  NEW references are only possible for INSERT and UPDATE
 * queries on the relation itself, and so they should be replaced by copies
 * of the related entries in the query's own targetlist.
 */
608
static Query *
609 610
CopyAndAddQual(Query *parsetree,
			   Node *rule_qual,
611 612
			   int rt_index,
			   CmdType event)
613
{
614
	Query	   *new_tree = (Query *) copyObject(parsetree);
615 616 617 618 619 620 621 622 623 624 625 626 627
	Node	   *new_qual = (Node *) copyObject(rule_qual);

	/* Fix references to OLD */
	ChangeVarNodes(new_qual, PRS2_OLD_VARNO, rt_index, 0);
	/* Fix references to NEW */
	if (event == CMD_INSERT || event == CMD_UPDATE)
		new_qual = ResolveNew(new_qual,
							  PRS2_NEW_VARNO,
							  0,
							  parsetree->targetList,
							  event,
							  rt_index);
	/* And attach the fixed qual */
628 629 630
	AddNotQual(new_tree, new_qual);

	return new_tree;
631 632 633
}


634

635
/*
636
 *	fireRules -
M
 
Marc G. Fournier 已提交
637 638 639 640 641
 *	   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.
642
 *
M
 
Marc G. Fournier 已提交
643
 *	   remember: reality is for dead birds -- glass
644 645
 *
 */
646
static List *
647
fireRules(Query *parsetree,
648 649
		  int rt_index,
		  CmdType event,
650 651 652
		  bool *instead_flag,
		  List *locks,
		  List **qual_products)
653
{
654 655
	List	   *results = NIL;
	List	   *i;
656 657 658

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

M
 
Marc G. Fournier 已提交
661
	locks = orderRules(locks);	/* real instead rules last */
662

663 664
	foreach(i, locks)
	{
665
		RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
666
		Node	   *event_qual;
667 668
		List	   *actions;
		List	   *r;
669 670 671 672 673

		/* multiple rule action time */
		*instead_flag = rule_lock->isInstead;
		event_qual = rule_lock->qual;
		actions = rule_lock->actions;
674

675 676 677
		if (event_qual != NULL && *instead_flag)
		{
			Query	   *qual_product;
M
 
Marc G. Fournier 已提交
678

679 680 681 682 683 684 685 686 687
			/*
			 * If there are instead rules with qualifications, the
			 * original query is still performed. But all the negated rule
			 * qualifications of the instead rules are added so it does
			 * its actions only 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.
M
 
Marc G. Fournier 已提交
688
			 */
689
			if (*qual_products == NIL)
M
 
Marc G. Fournier 已提交
690
				qual_product = parsetree;
691
			else
692
				qual_product = (Query *) lfirst(*qual_products);
M
 
Marc G. Fournier 已提交
693

694 695 696 697 698
			qual_product = CopyAndAddQual(qual_product,
										  event_qual,
										  rt_index,
										  event);

699
			*qual_products = makeList1(qual_product);
M
 
Marc G. Fournier 已提交
700 701
		}

702 703
		foreach(r, actions)
		{
704
			Query	   *rule_action = lfirst(r);
705

M
 
Marc G. Fournier 已提交
706 707 708
			if (rule_action->commandType == CMD_NOTHING)
				continue;

709 710
			rule_action = rewriteRuleAction(parsetree, rule_action,
											event_qual, rt_index, event);
711

712
			results = lappend(results, rule_action);
713
		}
M
 
Marc G. Fournier 已提交
714

715 716 717
		/*
		 * If this was an unqualified instead rule, throw away an
		 * eventually saved 'default' parsetree
M
 
Marc G. Fournier 已提交
718
		 */
719
		if (event_qual == NULL && *instead_flag)
M
 
Marc G. Fournier 已提交
720
			*qual_products = NIL;
721 722
	}
	return results;
723 724
}

M
 
Marc G. Fournier 已提交
725 726


727
static List *
728
RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
729
{
730
	CmdType		event;
B
Bruce Momjian 已提交
731
	List	   *product_queries = NIL;
732
	int			result_relation;
B
Bruce Momjian 已提交
733
	RangeTblEntry *rt_entry;
734 735
	Relation	rt_entry_relation;
	RuleLock   *rt_entry_locks;
736

737 738 739 740
	Assert(parsetree != NULL);

	event = parsetree->commandType;

741
	/*
B
Bruce Momjian 已提交
742 743
	 * SELECT rules are handled later when we have all the queries that
	 * should get executed
744 745 746 747 748 749 750
	 */
	if (event == CMD_SELECT)
		return NIL;

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

754
	/*
B
Bruce Momjian 已提交
755
	 * the statement is an update, insert or delete - fire rules on it.
756
	 */
757
	result_relation = parsetree->resultRelation;
758
	Assert(result_relation != 0);
759
	rt_entry = rt_fetch(result_relation, parsetree->rtable);
760 761

	/*
B
Bruce Momjian 已提交
762 763 764 765 766 767
	 * This may well be the first access to the result relation during the
	 * current statement (it will be, if this Query was extracted from a
	 * rule or somehow got here other than via the parser). Therefore,
	 * grab the appropriate lock type for a result relation, and do not
	 * release it until end of transaction.  This protects the rewriter
	 * and planner against schema changes mid-query.
768 769 770
	 */
	rt_entry_relation = heap_openr(rt_entry->relname, RowExclusiveLock);

771 772 773 774 775 776 777 778 779 780 781 782 783
	/*
	 * Check to see if relation's OID matches the RTE.  If not, the RTE
	 * actually refers to an older relation that had the same name.
	 * Eventually we might want to reparse the referencing rule, but
	 * for now all we can do is punt.
	 */
	if (RelationGetRelid(rt_entry_relation) != rt_entry->relid)
		elog(ERROR, "Relation \"%s\" with OID %u no longer exists",
			 rt_entry->relname, rt_entry->relid);

	/*
	 * Collect and apply the appropriate rules.
	 */
784
	rt_entry_locks = rt_entry_relation->rd_rules;
M
 
Marc G. Fournier 已提交
785

786
	if (rt_entry_locks != NULL)
787
	{
788 789
		List	   *locks = matchLocks(event, rt_entry_locks,
									   result_relation, parsetree);
790

791
		product_queries = fireRules(parsetree,
B
Bruce Momjian 已提交
792 793 794 795 796
									result_relation,
									event,
									instead_flag,
									locks,
									qual_products);
797
	}
798

B
Bruce Momjian 已提交
799
	heap_close(rt_entry_relation, NoLock);		/* keep lock! */
800

801
	return product_queries;
802 803
}

804

805 806
/*
 * to avoid infinite recursion, we restrict the number of times a query
807
 * can be rewritten. Detecting cycles is left for the reader as an exercise.
808 809
 */
#ifndef REWRITE_INVOKE_MAX
810
#define REWRITE_INVOKE_MAX		10
811 812
#endif

813
static int	numQueryRewriteInvoked = 0;
814 815 816

/*
 * deepRewriteQuery -
817
 *	  rewrites the query and apply the rules again on the queries rewritten
818
 */
819
static List *
820
deepRewriteQuery(Query *parsetree)
821
{
822 823
	List	   *n;
	List	   *rewritten = NIL;
824
	List	   *result;
825 826
	bool		instead;
	List	   *qual_products = NIL;
827 828 829

	if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
	{
830
		elog(ERROR, "query rewritten %d times, may contain cycles",
831 832 833 834 835
			 numQueryRewriteInvoked - 1);
	}

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

837 838
	foreach(n, result)
	{
839
		Query	   *pt = lfirst(n);
840
		List	   *newstuff;
841 842 843 844 845

		newstuff = deepRewriteQuery(pt);
		if (newstuff != NIL)
			rewritten = nconc(rewritten, newstuff);
	}
M
 
Marc G. Fournier 已提交
846

847 848 849
	/*
	 * qual_products are the original query with the negated rule
	 * qualification of an instead rule
M
 
Marc G. Fournier 已提交
850
	 */
851 852 853
	if (qual_products != NIL)
		rewritten = nconc(rewritten, qual_products);

854 855 856 857 858 859 860
	/*
	 * The original query is appended last (if no "instead" rule) 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.
M
 
Marc G. Fournier 已提交
861 862
	 */
	if (!instead)
863 864 865 866
		if (parsetree->commandType == CMD_INSERT)
			rewritten = lcons(parsetree, rewritten);
		else
			rewritten = lappend(rewritten, parsetree);
M
 
Marc G. Fournier 已提交
867

868 869
	return rewritten;
}
870 871 872


/*
873
 * QueryRewriteOne -
874 875 876 877 878 879 880 881 882 883 884 885 886 887 888
 *	  rewrite one query
 */
static List *
QueryRewriteOne(Query *parsetree)
{
	numQueryRewriteInvoked = 0;

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


/*
889 890 891 892 893 894 895
 * 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.
896
 */
897 898
List *
QueryRewrite(Query *parsetree)
899
{
B
Bruce Momjian 已提交
900 901 902
	List	   *querylist;
	List	   *results = NIL;
	List	   *l;
903 904 905 906 907 908 909 910 911

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

	/*
912
	 * Step 2
913 914 915
	 *
	 * Apply all the RIR rules on each query
	 */
B
Bruce Momjian 已提交
916 917
	foreach(l, querylist)
	{
B
Bruce Momjian 已提交
918
		Query	   *query = (Query *) lfirst(l);
B
Bruce Momjian 已提交
919

920
		query = fireRIRrules(query);
921

B
Bruce Momjian 已提交
922
		/*
923
		 * If the query target was rewritten as a view, complain.
B
Bruce Momjian 已提交
924
		 */
925
		if (query->resultRelation)
B
Bruce Momjian 已提交
926
		{
927 928
			RangeTblEntry *rte = rt_fetch(query->resultRelation,
										  query->rtable);
B
Bruce Momjian 已提交
929

930
			if (rte->subquery)
B
Bruce Momjian 已提交
931
			{
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947
				switch (query->commandType)
				{
					case CMD_INSERT:
						elog(ERROR, "Cannot insert into a view without an appropriate rule");
						break;
					case CMD_UPDATE:
						elog(ERROR, "Cannot update a view without an appropriate rule");
						break;
					case CMD_DELETE:
						elog(ERROR, "Cannot delete from a view without an appropriate rule");
						break;
					default:
						elog(ERROR, "QueryRewrite: unexpected commandType %d",
							 (int) query->commandType);
						break;
				}
B
Bruce Momjian 已提交
948 949 950
			}
		}

951
		results = lappend(results, query);
B
Bruce Momjian 已提交
952
	}
953

954
	return results;
B
Hi!  
Bruce Momjian 已提交
955
}