rewriteHandler.c 24.7 KB
Newer Older
1 2 3 4 5 6 7 8
/*-------------------------------------------------------------------------
 *
 * rewriteHandler.c--
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
9
 *	  $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.21 1998/09/01 04:31:33 momjian Exp $
10 11 12
 *
 *-------------------------------------------------------------------------
 */
M
Marc G. Fournier 已提交
13
#include <string.h>
14 15 16 17 18
#include "postgres.h"
#include "miscadmin.h"
#include "utils/palloc.h"
#include "utils/elog.h"
#include "utils/rel.h"
19
#include "nodes/pg_list.h"
20 21
#include "nodes/primnodes.h"

22
#include "parser/parsetree.h"	/* for parsetree manipulation */
M
 
Marc G. Fournier 已提交
23
#include "parser/parse_relation.h"
24 25
#include "nodes/parsenodes.h"

26
#include "rewrite/rewriteSupport.h"
27 28 29 30 31 32 33
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/locks.h"

#include "commands/creatinh.h"
#include "access/heapam.h"

M
Marc G. Fournier 已提交
34 35
#include "utils/syscache.h"
#include "utils/acl.h"
36
#include "catalog/pg_shadow.h"
M
Marc G. Fournier 已提交
37

38
static void ApplyRetrieveRule(Query *parsetree, RewriteRule *rule,
M
Marc G. Fournier 已提交
39 40
				  int rt_index, int relation_level,
				  Relation relation, int *modified);
41
static List *fireRules(Query *parsetree, int rt_index, CmdType event,
42
		  bool *instead_flag, List *locks, List **qual_products);
43
static void QueryRewriteSubLink(Node *node);
44
static List *QueryRewriteOne(Query *parsetree);
45
static List *deepRewriteQuery(Query *parsetree);
M
 
Marc G. Fournier 已提交
46 47
static void RewritePreprocessQuery(Query *parsetree);
static Query *RewritePostprocessNonSelect(Query *parsetree);
48 49 50

/*
 * gatherRewriteMeta -
51 52 53
 *	  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
54 55
 */
static RewriteInfo *
56 57 58
gatherRewriteMeta(Query *parsetree,
				  Query *rule_action,
				  Node *rule_qual,
59 60
				  int rt_index,
				  CmdType event,
61
				  bool *instead_flag)
62
{
63 64 65
	RewriteInfo *info;
	int			rt_length;
	int			result_reln;
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

	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);
		info->rt = append(info->rt, info->rule_action->rtable);

		info->new_varno = PRS2_NEW_VARNO + rt_length;
		OffsetVarNodes(info->rule_action->qual, rt_length);
		OffsetVarNodes((Node *) info->rule_action->targetList, rt_length);
		OffsetVarNodes(info->rule_qual, rt_length);
		ChangeVarNodes((Node *) info->rule_action->qual,
89
					   PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
90
		ChangeVarNodes((Node *) info->rule_action->targetList,
91
					   PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
92
		ChangeVarNodes(info->rule_qual,
93
					   PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
94 95 96 97 98 99 100 101

		/*
		 * 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 */
102
			int			new_result_reln = 0;
103 104 105 106

			result_reln = info->rule_action->resultRelation;
			switch (result_reln)
			{
107 108 109 110 111 112 113
				case PRS2_CURRENT_VARNO:
					new_result_reln = rt_index;
					break;
				case PRS2_NEW_VARNO:	/* XXX */
				default:
					new_result_reln = result_reln + rt_length;
					break;
114 115 116 117 118
			}
			info->rule_action->resultRelation = new_result_reln;
		}
	}
	return info;
119 120
}

121
static List *
122
OptimizeRIRRules(List *locks)
123
{
124 125 126
	List	   *attr_level = NIL,
			   *i;
	List	   *relation_level = NIL;
127 128 129

	foreach(i, locks)
	{
130
		RewriteRule *rule_lock = lfirst(i);
131 132 133 134 135 136 137

		if (rule_lock->attrno == -1)
			relation_level = lappend(relation_level, rule_lock);
		else
			attr_level = lappend(attr_level, rule_lock);
	}
	return nconc(relation_level, attr_level);
138 139 140
}

/*
M
 
Marc G. Fournier 已提交
141 142
 * idea is to fire regular rules first, then qualified instead
 * rules and unqualified instead rules last. Any lemming is counted for.
143
 */
144
static List *
145
orderRules(List *locks)
146
{
147 148 149 150
	List	   *regular = NIL;
	List	   *instead_rules = NIL;
	List	   *instead_qualified = NIL;
	List	   *i;
151 152 153

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

156 157
		if (rule_lock->isInstead)
		{
M
 
Marc G. Fournier 已提交
158 159 160 161
			if (rule_lock->qual == NULL)
				instead_rules = lappend(instead_rules, rule_lock);
			else
				instead_qualified = lappend(instead_qualified, rule_lock);
162 163
		}
		else
164 165
			regular = lappend(regular, rule_lock);
	}
M
 
Marc G. Fournier 已提交
166
	regular = nconc(regular, instead_qualified);
167
	return nconc(regular, instead_rules);
168 169 170
}

static int
171
AllRetrieve(List *actions)
172
{
173
	List	   *n;
174 175 176

	foreach(n, actions)
	{
177
		Query	   *pt = lfirst(n);
178 179 180 181 182 183 184 185 186 187

		/*
		 * in the old postgres code, we check whether command_type is a
		 * consp of '('*'.commandType). but we've never supported
		 * transitive closures. Hence removed	 - ay 10/94.
		 */
		if (pt->commandType != CMD_SELECT)
			return false;
	}
	return true;
188 189
}

190
static List *
191
FireRetrieveRulesAtQuery(Query *parsetree,
192 193
						 int rt_index,
						 Relation relation,
194
						 bool *instead_flag,
195
						 int rule_flag)
196
{
197 198 199 200
	List	   *i,
			   *locks;
	RuleLock   *rt_entry_locks = NULL;
	List	   *work = NIL;
201

202
	if ((rt_entry_locks = relation->rd_rules) == NULL)
203
		return NIL;
204

205
	locks = matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
206 207 208 209

	/* find all retrieve instead */
	foreach(i, locks)
	{
210
		RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
211 212 213 214 215 216 217 218 219 220

		if (!rule_lock->isInstead)
			continue;
		work = lappend(work, rule_lock);
	}
	if (work != NIL)
	{
		work = OptimizeRIRRules(locks);
		foreach(i, work)
		{
221 222 223
			RewriteRule *rule_lock = lfirst(i);
			int			relation_level;
			int			modified = FALSE;
224 225 226 227 228 229 230 231 232 233 234 235 236 237

			relation_level = (rule_lock->attrno == -1);
			if (rule_lock->actions == NIL)
			{
				*instead_flag = TRUE;
				return NIL;
			}
			if (!rule_flag &&
				length(rule_lock->actions) >= 2 &&
				AllRetrieve(rule_lock->actions))
			{
				*instead_flag = TRUE;
				return rule_lock->actions;
			}
M
Marc G. Fournier 已提交
238
			ApplyRetrieveRule(parsetree, rule_lock, rt_index, relation_level, relation,
239 240 241 242 243 244 245 246
							  &modified);
			if (modified)
			{
				*instead_flag = TRUE;
				FixResdomTypes(parsetree->targetList);
				return lcons(parsetree, NIL);
			}
		}
247
	}
248 249
	return NIL;
}
250 251 252 253 254


/* Idea is like this:
 *
 * retrieve-instead-retrieve rules have different semantics than update nodes
255
 * Separate RIR rules from others.	Pass others to FireRules.
256 257 258 259 260
 * Order RIR rules and process.
 *
 * side effect: parsetree's rtable field might be changed
 */
static void
261 262
ApplyRetrieveRule(Query *parsetree,
				  RewriteRule *rule,
263 264
				  int rt_index,
				  int relation_level,
M
Marc G. Fournier 已提交
265
				  Relation relation,
266
				  int *modified)
267
{
268 269 270 271 272 273 274
	Query	   *rule_action = NULL;
	Node	   *rule_qual;
	List	   *rtable,
			   *rt;
	int			nothing,
				rt_length;
	int			badsql = FALSE;
275 276 277 278 279

	rule_qual = rule->qual;
	if (rule->actions)
	{
		if (length(rule->actions) > 1)	/* ??? because we don't handle
280 281 282 283 284 285 286 287 288
										 * rules with more than one
										 * action? -ay */

			/*
			 * WARNING!!! If we sometimes handle rules with more than one
			 * action, the view acl checks might get broken.
			 * viewAclOverride should only become true (below) if this is
			 * a relation_level, instead, select query - Jan
			 */
289 290 291 292 293 294 295 296 297 298
			return;
		rule_action = copyObject(lfirst(rule->actions));
		nothing = FALSE;
	}
	else
		nothing = TRUE;

	rtable = copyObject(parsetree->rtable);
	foreach(rt, rtable)
	{
299
		RangeTblEntry *rte = lfirst(rt);
300 301 302 303 304 305 306 307

		/*
		 * this is to prevent add_missing_vars_to_base_rels() from adding
		 * a bogus entry to the new target list.
		 */
		rte->inFromCl = false;
	}
	rt_length = length(rtable);
M
Marc G. Fournier 已提交
308

309
	rtable = nconc(rtable, copyObject(rule_action->rtable));
310 311 312 313 314 315
	parsetree->rtable = rtable;

	rule_action->rtable = rtable;
	OffsetVarNodes(rule_action->qual, rt_length);
	OffsetVarNodes((Node *) rule_action->targetList, rt_length);
	OffsetVarNodes(rule_qual, rt_length);
316

317 318 319
	OffsetVarNodes((Node *) rule_action->groupClause, rt_length);
	OffsetVarNodes((Node *) rule_action->havingQual, rt_length);

320
	ChangeVarNodes(rule_action->qual,
321
				   PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
322
	ChangeVarNodes((Node *) rule_action->targetList,
323 324
				   PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
	ChangeVarNodes(rule_qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
325 326 327 328 329 330

	ChangeVarNodes((Node *) rule_action->groupClause,
				   PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
	ChangeVarNodes((Node *) rule_action->havingQual,
				   PRS2_CURRENT_VARNO + rt_length, rt_index, 0);

331 332
	if (relation_level)
	{
333 334
		HandleViewRule(parsetree, rtable, rule_action->targetList, rt_index,
					   modified);
335 336 337
	}
	else
	{
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
		HandleRIRAttributeRule(parsetree, rtable, rule_action->targetList,
							   rt_index, rule->attrno, modified, &badsql);
	}
	if (*modified && !badsql)
	{
		AddQual(parsetree, rule_action->qual);

		/*
		 * This will only work if the query made to the view defined by
		 * the following groupClause groups by the same attributes or does
		 * not use group at all!
		 */
		if (parsetree->groupClause == NULL)
			parsetree->groupClause = rule_action->groupClause;
		AddHavingQual(parsetree, rule_action->havingQual);
		parsetree->hasAggs = (rule_action->hasAggs || parsetree->hasAggs);
		parsetree->hasSubLinks = (rule_action->hasSubLinks || parsetree->hasSubLinks);
355
	}
356 357
}

358
static List *
359 360 361
ProcessRetrieveQuery(Query *parsetree,
					 List *rtable,
					 bool *instead_flag,
362
					 bool rule)
363
{
364 365 366
	List	   *rt;
	List	   *product_queries = NIL;
	int			rt_index = 0;
367

368

369 370
	foreach(rt, rtable)
	{
371 372 373
		RangeTblEntry *rt_entry = lfirst(rt);
		Relation	rt_entry_relation = NULL;
		List	   *result = NIL;
374 375 376 377

		rt_index++;
		rt_entry_relation = heap_openr(rt_entry->relname);

378 379


380 381 382 383 384 385 386 387 388 389
		if (rt_entry_relation->rd_rules != NULL)
		{
			result =
				FireRetrieveRulesAtQuery(parsetree,
										 rt_index,
										 rt_entry_relation,
										 instead_flag,
										 rule);
		}
		heap_close(rt_entry_relation);
390
		if (*instead_flag)
391
			return result;
392
	}
393 394
	if (rule)
		return NIL;
395

396 397
	rt_index = 0;

398 399
	foreach(rt, rtable)
	{
400 401 402 403 404 405
		RangeTblEntry *rt_entry = lfirst(rt);
		Relation	rt_entry_relation = NULL;
		RuleLock   *rt_entry_locks = NULL;
		List	   *result = NIL;
		List	   *locks = NIL;
		List	   *dummy_products;
406 407 408 409 410 411

		rt_index++;
		rt_entry_relation = heap_openr(rt_entry->relname);
		rt_entry_locks = rt_entry_relation->rd_rules;
		heap_close(rt_entry_relation);

412

413 414 415 416 417 418 419 420 421 422 423 424 425 426
		if (rt_entry_locks)
		{
			locks =
				matchLocks(CMD_SELECT, rt_entry_locks, rt_index, parsetree);
		}
		if (locks != NIL)
		{
			result = fireRules(parsetree, rt_index, CMD_SELECT,
							   instead_flag, locks, &dummy_products);
			if (*instead_flag)
				return lappend(NIL, result);
			if (result != NIL)
				product_queries = nconc(product_queries, result);
		}
427
	}
428
	return product_queries;
429 430
}

431
static Query *
432 433 434
CopyAndAddQual(Query *parsetree,
			   List *actions,
			   Node *rule_qual,
435 436
			   int rt_index,
			   CmdType event)
437
{
438 439 440
	Query	   *new_tree = (Query *) copyObject(parsetree);
	Node	   *new_qual = NULL;
	Query	   *rule_action = NULL;
441 442 443 444 445 446 447

	if (actions)
		rule_action = lfirst(actions);
	if (rule_qual != NULL)
		new_qual = (Node *) copyObject(rule_qual);
	if (rule_action != NULL)
	{
448 449
		List	   *rtable;
		int			rt_length;
450 451 452 453 454 455

		rtable = new_tree->rtable;
		rt_length = length(rtable);
		rtable = append(rtable, listCopy(rule_action->rtable));
		new_tree->rtable = rtable;
		OffsetVarNodes(new_qual, rt_length);
456
		ChangeVarNodes(new_qual, PRS2_CURRENT_VARNO + rt_length, rt_index, 0);
457 458 459 460 461
	}
	/* XXX -- where current doesn't work for instead nothing.... yet */
	AddNotQual(new_tree, new_qual);

	return new_tree;
462 463 464 465
}


/*
466
 *	fireRules -
M
 
Marc G. Fournier 已提交
467 468 469 470 471
 *	   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.
472
 *
M
 
Marc G. Fournier 已提交
473
 *	   remember: reality is for dead birds -- glass
474 475
 *
 */
476
static List *
477
fireRules(Query *parsetree,
478 479
		  int rt_index,
		  CmdType event,
480 481 482
		  bool *instead_flag,
		  List *locks,
		  List **qual_products)
483
{
484 485 486
	RewriteInfo *info;
	List	   *results = NIL;
	List	   *i;
487 488 489 490 491 492 493

	/* choose rule to fire from list of rules */
	if (locks == NIL)
	{
		ProcessRetrieveQuery(parsetree,
							 parsetree->rtable,
							 instead_flag, TRUE);
494
		if (*instead_flag)
495
			return lappend(NIL, parsetree);
496
		else
497
			return NIL;
498
	}
499

M
 
Marc G. Fournier 已提交
500
	locks = orderRules(locks);	/* real instead rules last */
501 502
	foreach(i, locks)
	{
503 504 505 506 507 508
		RewriteRule *rule_lock = (RewriteRule *) lfirst(i);
		Node	   *qual,
				   *event_qual;
		List	   *actions;
		List	   *r;
		bool		orig_instead_flag = *instead_flag;
509

510
		/*
511 512 513 514 515 516
		 * 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.
517
		 */
518 519 520 521
		if (rule_lock->isInstead &&
			parsetree->commandType != CMD_SELECT)
		{
			RangeTblEntry *rte;
522 523 524
			int32		acl_rc;
			int32		reqperm;

525 526
			switch (parsetree->commandType)
			{
527 528 529 530 531 532 533
				case CMD_INSERT:
					reqperm = ACL_AP;
					break;
				default:
					reqperm = ACL_WR;
					break;
			}
534 535 536 537 538

			rte = (RangeTblEntry *) nth(parsetree->resultRelation - 1,
										parsetree->rtable);
			if (!rte->skipAcl)
			{
539
				acl_rc = pg_aclcheck(rte->relname,
540 541 542
									 GetPgUserName(), reqperm);
				if (acl_rc != ACLCHECK_OK)
				{
543
					elog(ERROR, "%s: %s",
544 545
						 rte->relname,
						 aclcheck_error_strings[acl_rc]);
546 547 548 549
				}
			}
		}

550 551 552 553
		/* multiple rule action time */
		*instead_flag = rule_lock->isInstead;
		event_qual = rule_lock->qual;
		actions = rule_lock->actions;
554 555 556 557
		if (event_qual != NULL && *instead_flag)
		{
			Query	   *qual_product;
			RewriteInfo qual_info;
M
 
Marc G. Fournier 已提交
558 559 560 561 562 563 564 565 566 567 568 569 570

			/* ----------
			 * 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 it's 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.
			 * ----------
			 */
571
			if (*qual_products == NIL)
M
 
Marc G. Fournier 已提交
572
				qual_product = parsetree;
573 574
			else
				qual_product = (Query *) nth(0, *qual_products);
M
 
Marc G. Fournier 已提交
575

576 577 578 579 580 581 582 583 584
			qual_info.event = qual_product->commandType;
			qual_info.new_varno = length(qual_product->rtable) + 2;
			qual_product = CopyAndAddQual(qual_product,
										  actions,
										  event_qual,
										  rt_index,
										  event);

			qual_info.rule_action = qual_product;
M
 
Marc G. Fournier 已提交
585 586 587 588 589 590 591

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

			*qual_products = lappend(NIL, qual_product);
		}

592 593
		foreach(r, actions)
		{
594 595
			Query	   *rule_action = lfirst(r);
			Node	   *rule_qual = copyObject(event_qual);
596

M
 
Marc G. Fournier 已提交
597 598 599
			if (rule_action->commandType == CMD_NOTHING)
				continue;

600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
			/*--------------------------------------------------
			 * 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 已提交
623
			 * Event Qualification forces copying of parsetree and
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
			 * 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;
			ProcessRetrieveQuery(info->rule_action, info->rt,
								 &orig_instead_flag, TRUE);

			/*--------------------------------------------------
			 * 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 已提交
661 662 663 664 665 666

		/* ----------
		 * If this was an unqualified instead rule,
		 * throw away an eventually saved 'default' parsetree
		 * ----------
		 */
667
		if (event_qual == NULL && *instead_flag)
M
 
Marc G. Fournier 已提交
668
			*qual_products = NIL;
669 670
	}
	return results;
671 672
}

M
 
Marc G. Fournier 已提交
673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
/* ----------
 * RewritePreprocessQuery -
 *	adjust details in the parsetree, the rule system
 *	depends on
 * ----------
 */
static void
RewritePreprocessQuery(Query *parsetree)
{
	/* ----------
	 * if the query has a resultRelation, reassign the
	 * result domain numbers to the attribute numbers in the
	 * target relation. FixNew() depends on it when replacing
	 * *new* references in a rule action by the expressions
	 * from the rewritten query.
	 * ----------
	 */
690 691 692
	if (parsetree->resultRelation > 0)
	{
		RangeTblEntry *rte;
M
 
Marc G. Fournier 已提交
693
		Relation	rd;
694 695 696 697 698 699
		List	   *tl;
		TargetEntry *tle;
		int			resdomno;

		rte = (RangeTblEntry *) nth(parsetree->resultRelation - 1,
									parsetree->rtable);
M
 
Marc G. Fournier 已提交
700 701
		rd = heap_openr(rte->relname);

702 703 704
		foreach(tl, parsetree->targetList)
		{
			tle = (TargetEntry *) lfirst(tl);
M
 
Marc G. Fournier 已提交
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
			resdomno = attnameAttNum(rd, tle->resdom->resname);
			tle->resdom->resno = resdomno;
		}

		heap_close(rd);
	}
}


/* ----------
 * RewritePostprocessNonSelect -
 *	apply instead select rules on a query fired in by
 *	the rewrite system
 * ----------
 */
static Query *
RewritePostprocessNonSelect(Query *parsetree)
{
723 724 725 726
	List	   *rt;
	int			rt_index = 0;
	Query	   *newtree = copyObject(parsetree);

M
 
Marc G. Fournier 已提交
727 728
	foreach(rt, parsetree->rtable)
	{
729
		RangeTblEntry *rt_entry = lfirst(rt);
M
 
Marc G. Fournier 已提交
730
		Relation	rt_entry_relation = NULL;
731 732 733 734 735
		RuleLock   *rt_entry_locks = NULL;
		List	   *locks = NIL;
		List	   *instead_locks = NIL;
		List	   *lock;
		RewriteRule *rule;
M
 
Marc G. Fournier 已提交
736 737 738 739 740 741 742

		rt_index++;
		rt_entry_relation = heap_openr(rt_entry->relname);
		rt_entry_locks = rt_entry_relation->rd_rules;

		if (rt_entry_locks)
		{
743 744
			int			origcmdtype = newtree->commandType;

M
 
Marc G. Fournier 已提交
745 746 747 748 749 750 751
			newtree->commandType = CMD_SELECT;
			locks =
				matchLocks(CMD_SELECT, rt_entry_locks, rt_index, newtree);
			newtree->commandType = origcmdtype;
		}
		if (locks != NIL)
		{
752 753 754 755
			foreach(lock, locks)
			{
				rule = (RewriteRule *) lfirst(lock);
				if (rule->isInstead)
M
 
Marc G. Fournier 已提交
756 757 758 759 760
					instead_locks = nconc(instead_locks, lock);
			}
		}
		if (instead_locks != NIL)
		{
761 762 763 764
			foreach(lock, instead_locks)
			{
				int			relation_level;
				int			modified = 0;
M
 
Marc G. Fournier 已提交
765

766
				rule = (RewriteRule *) lfirst(lock);
M
 
Marc G. Fournier 已提交
767 768 769
				relation_level = (rule->attrno == -1);

				ApplyRetrieveRule(newtree,
770 771 772 773 774
								  rule,
								  rt_index,
								  relation_level,
								  rt_entry_relation,
								  &modified);
M
 
Marc G. Fournier 已提交
775 776 777 778 779 780 781 782 783
			}
		}

		heap_close(rt_entry_relation);
	}

	return newtree;
}

784
static List *
785
RewriteQuery(Query *parsetree, bool *instead_flag, List **qual_products)
786
{
787 788 789
	CmdType		event;
	List	   *product_queries = NIL;
	int			result_relation = 0;
790

791 792 793 794 795 796
	Assert(parsetree != NULL);

	event = parsetree->commandType;

	if (event == CMD_UTILITY)
		return NIL;
797 798

	/*
799
	 * only for a delete may the targetlist be NULL
800
	 */
801 802 803 804 805 806 807 808 809 810 811
	if (event != CMD_DELETE)
		Assert(parsetree->targetList != NULL);

	result_relation = parsetree->resultRelation;

	if (event != CMD_SELECT)
	{

		/*
		 * the statement is an update, insert or delete
		 */
812 813 814
		RangeTblEntry *rt_entry;
		Relation	rt_entry_relation = NULL;
		RuleLock   *rt_entry_locks = NULL;
815 816 817 818 819 820 821 822

		rt_entry = rt_fetch(result_relation, parsetree->rtable);
		rt_entry_relation = heap_openr(rt_entry->relname);
		rt_entry_locks = rt_entry_relation->rd_rules;
		heap_close(rt_entry_relation);

		if (rt_entry_locks != NULL)
		{
823
			List	   *locks =
824
			matchLocks(event, rt_entry_locks, result_relation, parsetree);
825

826 827 828 829 830 831 832 833
			product_queries =
				fireRules(parsetree,
						  result_relation,
						  event,
						  instead_flag,
						  locks,
						  qual_products);
		}
M
 
Marc G. Fournier 已提交
834 835 836 837 838 839 840 841

		/* ----------
		 * deepRewriteQuery does not handle the situation
		 * where a query fired by a rule uses relations that
		 * have instead select rules defined (views and the like).
		 * So we care for them here.
		 * ----------
		 */
842 843 844 845 846 847 848 849 850
		if (product_queries != NIL)
		{
			List	   *pq;
			Query	   *tmp;
			List	   *new_products = NIL;

			foreach(pq, product_queries)
			{
				tmp = (Query *) lfirst(pq);
M
 
Marc G. Fournier 已提交
851 852
				tmp = RewritePostprocessNonSelect(tmp);
				new_products = lappend(new_products, tmp);
853
			}
M
 
Marc G. Fournier 已提交
854 855 856
			product_queries = new_products;
		}

857 858 859 860 861 862 863 864
		return product_queries;
	}
	else
	{

		/*
		 * the statement is a select
		 */
865
		Query	   *other;
866

B
Bruce Momjian 已提交
867
		/*
868 869
		 * ApplyRetrieveRule changes the range table XXX Unions are copied
		 * again.
B
Bruce Momjian 已提交
870 871 872
		 */
		other = copyObject(parsetree);

873 874 875
		return
			ProcessRetrieveQuery(other, parsetree->rtable,
								 instead_flag, FALSE);
876 877 878 879 880 881 882 883
	}
}

/*
 * 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
884
#define REWRITE_INVOKE_MAX		10
885 886
#endif

887
static int	numQueryRewriteInvoked = 0;
888 889 890

/*
 * QueryRewrite -
891 892 893
 *	  rewrite one query via QueryRewrite system, possibly returning 0, or many
 *	  queries
 */
894
List *
895
QueryRewrite(Query *parsetree)
896
{
M
 
Marc G. Fournier 已提交
897 898
	RewritePreprocessQuery(parsetree);

899
	QueryRewriteSubLink(parsetree->qual);
900 901
	QueryRewriteSubLink(parsetree->havingQual);

902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927
	return QueryRewriteOne(parsetree);
}

/*
 *	QueryRewriteSubLink
 *
 *	This rewrites the SubLink subqueries first, doing the lowest ones first.
 *	We already have code in the main rewrite loops to process correlated
 *	variables from upper queries that exist in subqueries.
 */
static void
QueryRewriteSubLink(Node *node)
{
	if (node == NULL)
		return;

	switch (nodeTag(node))
	{
		case T_TargetEntry:
			break;
		case T_Aggreg:
			break;
		case T_Expr:
			{
				Expr	   *expr = (Expr *) node;

928
				QueryRewriteSubLink((Node *) expr->args);
929 930 931 932 933 934 935 936 937 938 939 940 941 942
			}
			break;
		case T_Var:
			break;
		case T_List:
			{
				List	   *l;

				foreach(l, (List *) node)
					QueryRewriteSubLink(lfirst(l));
			}
			break;
		case T_SubLink:
			{
943 944 945
				SubLink    *sublink = (SubLink *) node;
				Query	   *query = (Query *) sublink->subselect;
				List	   *ret;
946 947

				/*
948 949
				 * Nest down first.  We do this so if a rewrite adds a
				 * SubLink we don't process it as part of this loop.
950
				 */
951
				QueryRewriteSubLink((Node *) query->qual);
952

953
				QueryRewriteSubLink((Node *) query->havingQual);
954 955 956 957 958 959 960

				ret = QueryRewriteOne(query);
				if (!ret)
					sublink->subselect = NULL;
				else if (lnext(ret) == NIL)
					sublink->subselect = lfirst(ret);
				else
961
					elog(ERROR, "Don't know how to process subquery that rewrites to multiple queries.");
962 963 964 965 966 967 968 969 970 971 972 973 974
			}
			break;
		default:
			/* ignore the others */
			break;
	}
	return;
}

/*
 * QueryOneRewrite -
 *	  rewrite one query
 */
975
static List *
976
QueryRewriteOne(Query *parsetree)
977
{
978
	numQueryRewriteInvoked = 0;
979

980 981 982 983
	/*
	 * take a deep breath and apply all the rewrite rules - ay
	 */
	return deepRewriteQuery(parsetree);
984 985 986 987
}

/*
 * deepRewriteQuery -
988
 *	  rewrites the query and apply the rules again on the queries rewritten
989
 */
990
static List *
991
deepRewriteQuery(Query *parsetree)
992
{
993 994 995 996 997
	List	   *n;
	List	   *rewritten = NIL;
	List	   *result = NIL;
	bool		instead;
	List	   *qual_products = NIL;
998

999 1000


1001 1002
	if (++numQueryRewriteInvoked > REWRITE_INVOKE_MAX)
	{
1003
		elog(ERROR, "query rewritten %d times, may contain cycles",
1004 1005 1006 1007 1008
			 numQueryRewriteInvoked - 1);
	}

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

1010 1011
	foreach(n, result)
	{
1012 1013
		Query	   *pt = lfirst(n);
		List	   *newstuff = NIL;
1014 1015 1016 1017 1018

		newstuff = deepRewriteQuery(pt);
		if (newstuff != NIL)
			rewritten = nconc(rewritten, newstuff);
	}
M
 
Marc G. Fournier 已提交
1019 1020 1021 1022 1023 1024

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

M
 
Marc G. Fournier 已提交
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
	/* ----------
	 * 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);

1041 1042
	return rewritten;
}