1 /*-------------------------------------------------------------------------
2  *
3  * rewriteManip.c
4  *
5  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
6  * Portions Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *	  src/backend/rewrite/rewriteManip.c
11  *
12  *-------------------------------------------------------------------------
13  */
14 #include "postgres.h"
15 
16 #include "catalog/pg_type.h"
17 #include "nodes/makefuncs.h"
18 #include "nodes/nodeFuncs.h"
19 #include "nodes/pathnodes.h"
20 #include "nodes/plannodes.h"
21 #include "parser/parse_coerce.h"
22 #include "parser/parse_relation.h"
23 #include "parser/parsetree.h"
24 #include "rewrite/rewriteManip.h"
25 
26 
27 typedef struct
28 {
29 	int			sublevels_up;
30 } contain_aggs_of_level_context;
31 
32 typedef struct
33 {
34 	int			agg_location;
35 	int			sublevels_up;
36 } locate_agg_of_level_context;
37 
38 typedef struct
39 {
40 	int			win_location;
41 } locate_windowfunc_context;
42 
43 static bool contain_aggs_of_level_walker(Node *node,
44 										 contain_aggs_of_level_context *context);
45 static bool locate_agg_of_level_walker(Node *node,
46 									   locate_agg_of_level_context *context);
47 static bool contain_windowfuncs_walker(Node *node, void *context);
48 static bool locate_windowfunc_walker(Node *node,
49 									 locate_windowfunc_context *context);
50 static bool checkExprHasSubLink_walker(Node *node, void *context);
51 static Relids offset_relid_set(Relids relids, int offset);
52 static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
53 
54 
55 /*
56  * contain_aggs_of_level -
57  *	Check if an expression contains an aggregate function call of a
58  *	specified query level.
59  *
60  * The objective of this routine is to detect whether there are aggregates
61  * belonging to the given query level.  Aggregates belonging to subqueries
62  * or outer queries do NOT cause a true result.  We must recurse into
63  * subqueries to detect outer-reference aggregates that logically belong to
64  * the specified query level.
65  */
66 bool
contain_aggs_of_level(Node * node,int levelsup)67 contain_aggs_of_level(Node *node, int levelsup)
68 {
69 	contain_aggs_of_level_context context;
70 
71 	context.sublevels_up = levelsup;
72 
73 	/*
74 	 * Must be prepared to start with a Query or a bare expression tree; if
75 	 * it's a Query, we don't want to increment sublevels_up.
76 	 */
77 	return query_or_expression_tree_walker(node,
78 										   contain_aggs_of_level_walker,
79 										   (void *) &context,
80 										   0);
81 }
82 
83 static bool
contain_aggs_of_level_walker(Node * node,contain_aggs_of_level_context * context)84 contain_aggs_of_level_walker(Node *node,
85 							 contain_aggs_of_level_context *context)
86 {
87 	if (node == NULL)
88 		return false;
89 	if (IsA(node, Aggref))
90 	{
91 		if (((Aggref *) node)->agglevelsup == context->sublevels_up)
92 			return true;		/* abort the tree traversal and return true */
93 		/* else fall through to examine argument */
94 	}
95 	if (IsA(node, GroupingFunc))
96 	{
97 		if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up)
98 			return true;
99 		/* else fall through to examine argument */
100 	}
101 	if (IsA(node, Query))
102 	{
103 		/* Recurse into subselects */
104 		bool		result;
105 
106 		context->sublevels_up++;
107 		result = query_tree_walker((Query *) node,
108 								   contain_aggs_of_level_walker,
109 								   (void *) context, 0);
110 		context->sublevels_up--;
111 		return result;
112 	}
113 	return expression_tree_walker(node, contain_aggs_of_level_walker,
114 								  (void *) context);
115 }
116 
117 /*
118  * locate_agg_of_level -
119  *	  Find the parse location of any aggregate of the specified query level.
120  *
121  * Returns -1 if no such agg is in the querytree, or if they all have
122  * unknown parse location.  (The former case is probably caller error,
123  * but we don't bother to distinguish it from the latter case.)
124  *
125  * Note: it might seem appropriate to merge this functionality into
126  * contain_aggs_of_level, but that would complicate that function's API.
127  * Currently, the only uses of this function are for error reporting,
128  * and so shaving cycles probably isn't very important.
129  */
130 int
locate_agg_of_level(Node * node,int levelsup)131 locate_agg_of_level(Node *node, int levelsup)
132 {
133 	locate_agg_of_level_context context;
134 
135 	context.agg_location = -1;	/* in case we find nothing */
136 	context.sublevels_up = levelsup;
137 
138 	/*
139 	 * Must be prepared to start with a Query or a bare expression tree; if
140 	 * it's a Query, we don't want to increment sublevels_up.
141 	 */
142 	(void) query_or_expression_tree_walker(node,
143 										   locate_agg_of_level_walker,
144 										   (void *) &context,
145 										   0);
146 
147 	return context.agg_location;
148 }
149 
150 static bool
locate_agg_of_level_walker(Node * node,locate_agg_of_level_context * context)151 locate_agg_of_level_walker(Node *node,
152 						   locate_agg_of_level_context *context)
153 {
154 	if (node == NULL)
155 		return false;
156 	if (IsA(node, Aggref))
157 	{
158 		if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
159 			((Aggref *) node)->location >= 0)
160 		{
161 			context->agg_location = ((Aggref *) node)->location;
162 			return true;		/* abort the tree traversal and return true */
163 		}
164 		/* else fall through to examine argument */
165 	}
166 	if (IsA(node, GroupingFunc))
167 	{
168 		if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up &&
169 			((GroupingFunc *) node)->location >= 0)
170 		{
171 			context->agg_location = ((GroupingFunc *) node)->location;
172 			return true;		/* abort the tree traversal and return true */
173 		}
174 	}
175 	if (IsA(node, Query))
176 	{
177 		/* Recurse into subselects */
178 		bool		result;
179 
180 		context->sublevels_up++;
181 		result = query_tree_walker((Query *) node,
182 								   locate_agg_of_level_walker,
183 								   (void *) context, 0);
184 		context->sublevels_up--;
185 		return result;
186 	}
187 	return expression_tree_walker(node, locate_agg_of_level_walker,
188 								  (void *) context);
189 }
190 
191 /*
192  * contain_windowfuncs -
193  *	Check if an expression contains a window function call of the
194  *	current query level.
195  */
196 bool
contain_windowfuncs(Node * node)197 contain_windowfuncs(Node *node)
198 {
199 	/*
200 	 * Must be prepared to start with a Query or a bare expression tree; if
201 	 * it's a Query, we don't want to increment sublevels_up.
202 	 */
203 	return query_or_expression_tree_walker(node,
204 										   contain_windowfuncs_walker,
205 										   NULL,
206 										   0);
207 }
208 
209 static bool
contain_windowfuncs_walker(Node * node,void * context)210 contain_windowfuncs_walker(Node *node, void *context)
211 {
212 	if (node == NULL)
213 		return false;
214 	if (IsA(node, WindowFunc))
215 		return true;			/* abort the tree traversal and return true */
216 	/* Mustn't recurse into subselects */
217 	return expression_tree_walker(node, contain_windowfuncs_walker,
218 								  (void *) context);
219 }
220 
221 /*
222  * locate_windowfunc -
223  *	  Find the parse location of any windowfunc of the current query level.
224  *
225  * Returns -1 if no such windowfunc is in the querytree, or if they all have
226  * unknown parse location.  (The former case is probably caller error,
227  * but we don't bother to distinguish it from the latter case.)
228  *
229  * Note: it might seem appropriate to merge this functionality into
230  * contain_windowfuncs, but that would complicate that function's API.
231  * Currently, the only uses of this function are for error reporting,
232  * and so shaving cycles probably isn't very important.
233  */
234 int
locate_windowfunc(Node * node)235 locate_windowfunc(Node *node)
236 {
237 	locate_windowfunc_context context;
238 
239 	context.win_location = -1;	/* in case we find nothing */
240 
241 	/*
242 	 * Must be prepared to start with a Query or a bare expression tree; if
243 	 * it's a Query, we don't want to increment sublevels_up.
244 	 */
245 	(void) query_or_expression_tree_walker(node,
246 										   locate_windowfunc_walker,
247 										   (void *) &context,
248 										   0);
249 
250 	return context.win_location;
251 }
252 
253 static bool
locate_windowfunc_walker(Node * node,locate_windowfunc_context * context)254 locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
255 {
256 	if (node == NULL)
257 		return false;
258 	if (IsA(node, WindowFunc))
259 	{
260 		if (((WindowFunc *) node)->location >= 0)
261 		{
262 			context->win_location = ((WindowFunc *) node)->location;
263 			return true;		/* abort the tree traversal and return true */
264 		}
265 		/* else fall through to examine argument */
266 	}
267 	/* Mustn't recurse into subselects */
268 	return expression_tree_walker(node, locate_windowfunc_walker,
269 								  (void *) context);
270 }
271 
272 /*
273  * checkExprHasSubLink -
274  *	Check if an expression contains a SubLink.
275  */
276 bool
checkExprHasSubLink(Node * node)277 checkExprHasSubLink(Node *node)
278 {
279 	/*
280 	 * If a Query is passed, examine it --- but we should not recurse into
281 	 * sub-Queries that are in its rangetable or CTE list.
282 	 */
283 	return query_or_expression_tree_walker(node,
284 										   checkExprHasSubLink_walker,
285 										   NULL,
286 										   QTW_IGNORE_RC_SUBQUERIES);
287 }
288 
289 static bool
checkExprHasSubLink_walker(Node * node,void * context)290 checkExprHasSubLink_walker(Node *node, void *context)
291 {
292 	if (node == NULL)
293 		return false;
294 	if (IsA(node, SubLink))
295 		return true;			/* abort the tree traversal and return true */
296 	return expression_tree_walker(node, checkExprHasSubLink_walker, context);
297 }
298 
299 /*
300  * Check for MULTIEXPR Param within expression tree
301  *
302  * We intentionally don't descend into SubLinks: only Params at the current
303  * query level are of interest.
304  */
305 static bool
contains_multiexpr_param(Node * node,void * context)306 contains_multiexpr_param(Node *node, void *context)
307 {
308 	if (node == NULL)
309 		return false;
310 	if (IsA(node, Param))
311 	{
312 		if (((Param *) node)->paramkind == PARAM_MULTIEXPR)
313 			return true;		/* abort the tree traversal and return true */
314 		return false;
315 	}
316 	return expression_tree_walker(node, contains_multiexpr_param, context);
317 }
318 
319 
320 /*
321  * OffsetVarNodes - adjust Vars when appending one query's RT to another
322  *
323  * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
324  * and increment their varno fields (rangetable indexes) by 'offset'.
325  * The varnosyn fields are adjusted similarly.  Also, adjust other nodes
326  * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
327  *
328  * NOTE: although this has the form of a walker, we cheat and modify the
329  * nodes in-place.  The given expression tree should have been copied
330  * earlier to ensure that no unwanted side-effects occur!
331  */
332 
333 typedef struct
334 {
335 	int			offset;
336 	int			sublevels_up;
337 } OffsetVarNodes_context;
338 
339 static bool
OffsetVarNodes_walker(Node * node,OffsetVarNodes_context * context)340 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
341 {
342 	if (node == NULL)
343 		return false;
344 	if (IsA(node, Var))
345 	{
346 		Var		   *var = (Var *) node;
347 
348 		if (var->varlevelsup == context->sublevels_up)
349 		{
350 			var->varno += context->offset;
351 			if (var->varnosyn > 0)
352 				var->varnosyn += context->offset;
353 		}
354 		return false;
355 	}
356 	if (IsA(node, CurrentOfExpr))
357 	{
358 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
359 
360 		if (context->sublevels_up == 0)
361 			cexpr->cvarno += context->offset;
362 		return false;
363 	}
364 	if (IsA(node, RangeTblRef))
365 	{
366 		RangeTblRef *rtr = (RangeTblRef *) node;
367 
368 		if (context->sublevels_up == 0)
369 			rtr->rtindex += context->offset;
370 		/* the subquery itself is visited separately */
371 		return false;
372 	}
373 	if (IsA(node, JoinExpr))
374 	{
375 		JoinExpr   *j = (JoinExpr *) node;
376 
377 		if (j->rtindex && context->sublevels_up == 0)
378 			j->rtindex += context->offset;
379 		/* fall through to examine children */
380 	}
381 	if (IsA(node, PlaceHolderVar))
382 	{
383 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
384 
385 		if (phv->phlevelsup == context->sublevels_up)
386 		{
387 			phv->phrels = offset_relid_set(phv->phrels,
388 										   context->offset);
389 		}
390 		/* fall through to examine children */
391 	}
392 	if (IsA(node, AppendRelInfo))
393 	{
394 		AppendRelInfo *appinfo = (AppendRelInfo *) node;
395 
396 		if (context->sublevels_up == 0)
397 		{
398 			appinfo->parent_relid += context->offset;
399 			appinfo->child_relid += context->offset;
400 		}
401 		/* fall through to examine children */
402 	}
403 	/* Shouldn't need to handle other planner auxiliary nodes here */
404 	Assert(!IsA(node, PlanRowMark));
405 	Assert(!IsA(node, SpecialJoinInfo));
406 	Assert(!IsA(node, PlaceHolderInfo));
407 	Assert(!IsA(node, MinMaxAggInfo));
408 
409 	if (IsA(node, Query))
410 	{
411 		/* Recurse into subselects */
412 		bool		result;
413 
414 		context->sublevels_up++;
415 		result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
416 								   (void *) context, 0);
417 		context->sublevels_up--;
418 		return result;
419 	}
420 	return expression_tree_walker(node, OffsetVarNodes_walker,
421 								  (void *) context);
422 }
423 
424 void
OffsetVarNodes(Node * node,int offset,int sublevels_up)425 OffsetVarNodes(Node *node, int offset, int sublevels_up)
426 {
427 	OffsetVarNodes_context context;
428 
429 	context.offset = offset;
430 	context.sublevels_up = sublevels_up;
431 
432 	/*
433 	 * Must be prepared to start with a Query or a bare expression tree; if
434 	 * it's a Query, go straight to query_tree_walker to make sure that
435 	 * sublevels_up doesn't get incremented prematurely.
436 	 */
437 	if (node && IsA(node, Query))
438 	{
439 		Query	   *qry = (Query *) node;
440 
441 		/*
442 		 * If we are starting at a Query, and sublevels_up is zero, then we
443 		 * must also fix rangetable indexes in the Query itself --- namely
444 		 * resultRelation, exclRelIndex and rowMarks entries.  sublevels_up
445 		 * cannot be zero when recursing into a subquery, so there's no need
446 		 * to have the same logic inside OffsetVarNodes_walker.
447 		 */
448 		if (sublevels_up == 0)
449 		{
450 			ListCell   *l;
451 
452 			if (qry->resultRelation)
453 				qry->resultRelation += offset;
454 
455 			if (qry->onConflict && qry->onConflict->exclRelIndex)
456 				qry->onConflict->exclRelIndex += offset;
457 
458 			foreach(l, qry->rowMarks)
459 			{
460 				RowMarkClause *rc = (RowMarkClause *) lfirst(l);
461 
462 				rc->rti += offset;
463 			}
464 		}
465 		query_tree_walker(qry, OffsetVarNodes_walker,
466 						  (void *) &context, 0);
467 	}
468 	else
469 		OffsetVarNodes_walker(node, &context);
470 }
471 
472 static Relids
offset_relid_set(Relids relids,int offset)473 offset_relid_set(Relids relids, int offset)
474 {
475 	Relids		result = NULL;
476 	int			rtindex;
477 
478 	rtindex = -1;
479 	while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
480 		result = bms_add_member(result, rtindex + offset);
481 	return result;
482 }
483 
484 /*
485  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
486  *
487  * Find all Var nodes in the given tree belonging to a specific relation
488  * (identified by sublevels_up and rt_index), and change their varno fields
489  * to 'new_index'.  The varnosyn fields are changed too.  Also, adjust other
490  * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
491  *
492  * NOTE: although this has the form of a walker, we cheat and modify the
493  * nodes in-place.  The given expression tree should have been copied
494  * earlier to ensure that no unwanted side-effects occur!
495  */
496 
497 typedef struct
498 {
499 	int			rt_index;
500 	int			new_index;
501 	int			sublevels_up;
502 } ChangeVarNodes_context;
503 
504 static bool
ChangeVarNodes_walker(Node * node,ChangeVarNodes_context * context)505 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
506 {
507 	if (node == NULL)
508 		return false;
509 	if (IsA(node, Var))
510 	{
511 		Var		   *var = (Var *) node;
512 
513 		if (var->varlevelsup == context->sublevels_up &&
514 			var->varno == context->rt_index)
515 		{
516 			var->varno = context->new_index;
517 			/* If the syntactic referent is same RTE, fix it too */
518 			if (var->varnosyn == context->rt_index)
519 				var->varnosyn = context->new_index;
520 		}
521 		return false;
522 	}
523 	if (IsA(node, CurrentOfExpr))
524 	{
525 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
526 
527 		if (context->sublevels_up == 0 &&
528 			cexpr->cvarno == context->rt_index)
529 			cexpr->cvarno = context->new_index;
530 		return false;
531 	}
532 	if (IsA(node, RangeTblRef))
533 	{
534 		RangeTblRef *rtr = (RangeTblRef *) node;
535 
536 		if (context->sublevels_up == 0 &&
537 			rtr->rtindex == context->rt_index)
538 			rtr->rtindex = context->new_index;
539 		/* the subquery itself is visited separately */
540 		return false;
541 	}
542 	if (IsA(node, JoinExpr))
543 	{
544 		JoinExpr   *j = (JoinExpr *) node;
545 
546 		if (context->sublevels_up == 0 &&
547 			j->rtindex == context->rt_index)
548 			j->rtindex = context->new_index;
549 		/* fall through to examine children */
550 	}
551 	if (IsA(node, PlaceHolderVar))
552 	{
553 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
554 
555 		if (phv->phlevelsup == context->sublevels_up)
556 		{
557 			phv->phrels = adjust_relid_set(phv->phrels,
558 										   context->rt_index,
559 										   context->new_index);
560 		}
561 		/* fall through to examine children */
562 	}
563 	if (IsA(node, PlanRowMark))
564 	{
565 		PlanRowMark *rowmark = (PlanRowMark *) node;
566 
567 		if (context->sublevels_up == 0)
568 		{
569 			if (rowmark->rti == context->rt_index)
570 				rowmark->rti = context->new_index;
571 			if (rowmark->prti == context->rt_index)
572 				rowmark->prti = context->new_index;
573 		}
574 		return false;
575 	}
576 	if (IsA(node, AppendRelInfo))
577 	{
578 		AppendRelInfo *appinfo = (AppendRelInfo *) node;
579 
580 		if (context->sublevels_up == 0)
581 		{
582 			if (appinfo->parent_relid == context->rt_index)
583 				appinfo->parent_relid = context->new_index;
584 			if (appinfo->child_relid == context->rt_index)
585 				appinfo->child_relid = context->new_index;
586 		}
587 		/* fall through to examine children */
588 	}
589 	/* Shouldn't need to handle other planner auxiliary nodes here */
590 	Assert(!IsA(node, SpecialJoinInfo));
591 	Assert(!IsA(node, PlaceHolderInfo));
592 	Assert(!IsA(node, MinMaxAggInfo));
593 
594 	if (IsA(node, Query))
595 	{
596 		/* Recurse into subselects */
597 		bool		result;
598 
599 		context->sublevels_up++;
600 		result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
601 								   (void *) context, 0);
602 		context->sublevels_up--;
603 		return result;
604 	}
605 	return expression_tree_walker(node, ChangeVarNodes_walker,
606 								  (void *) context);
607 }
608 
609 void
ChangeVarNodes(Node * node,int rt_index,int new_index,int sublevels_up)610 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
611 {
612 	ChangeVarNodes_context context;
613 
614 	context.rt_index = rt_index;
615 	context.new_index = new_index;
616 	context.sublevels_up = sublevels_up;
617 
618 	/*
619 	 * Must be prepared to start with a Query or a bare expression tree; if
620 	 * it's a Query, go straight to query_tree_walker to make sure that
621 	 * sublevels_up doesn't get incremented prematurely.
622 	 */
623 	if (node && IsA(node, Query))
624 	{
625 		Query	   *qry = (Query *) node;
626 
627 		/*
628 		 * If we are starting at a Query, and sublevels_up is zero, then we
629 		 * must also fix rangetable indexes in the Query itself --- namely
630 		 * resultRelation and rowMarks entries.  sublevels_up cannot be zero
631 		 * when recursing into a subquery, so there's no need to have the same
632 		 * logic inside ChangeVarNodes_walker.
633 		 */
634 		if (sublevels_up == 0)
635 		{
636 			ListCell   *l;
637 
638 			if (qry->resultRelation == rt_index)
639 				qry->resultRelation = new_index;
640 
641 			/* this is unlikely to ever be used, but ... */
642 			if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
643 				qry->onConflict->exclRelIndex = new_index;
644 
645 			foreach(l, qry->rowMarks)
646 			{
647 				RowMarkClause *rc = (RowMarkClause *) lfirst(l);
648 
649 				if (rc->rti == rt_index)
650 					rc->rti = new_index;
651 			}
652 		}
653 		query_tree_walker(qry, ChangeVarNodes_walker,
654 						  (void *) &context, 0);
655 	}
656 	else
657 		ChangeVarNodes_walker(node, &context);
658 }
659 
660 /*
661  * Substitute newrelid for oldrelid in a Relid set
662  */
663 static Relids
adjust_relid_set(Relids relids,int oldrelid,int newrelid)664 adjust_relid_set(Relids relids, int oldrelid, int newrelid)
665 {
666 	if (bms_is_member(oldrelid, relids))
667 	{
668 		/* Ensure we have a modifiable copy */
669 		relids = bms_copy(relids);
670 		/* Remove old, add new */
671 		relids = bms_del_member(relids, oldrelid);
672 		relids = bms_add_member(relids, newrelid);
673 	}
674 	return relids;
675 }
676 
677 /*
678  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
679  *
680  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
681  * and add delta_sublevels_up to their varlevelsup value.  This is needed when
682  * an expression that's correct for some nesting level is inserted into a
683  * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that
684  * all Vars are affected.  The point of min_sublevels_up is that we can
685  * increment it when we recurse into a sublink, so that local variables in
686  * that sublink are not affected, only outer references to vars that belong
687  * to the expression's original query level or parents thereof.
688  *
689  * Likewise for other nodes containing levelsup fields, such as Aggref.
690  *
691  * NOTE: although this has the form of a walker, we cheat and modify the
692  * Var nodes in-place.  The given expression tree should have been copied
693  * earlier to ensure that no unwanted side-effects occur!
694  */
695 
696 typedef struct
697 {
698 	int			delta_sublevels_up;
699 	int			min_sublevels_up;
700 } IncrementVarSublevelsUp_context;
701 
702 static bool
IncrementVarSublevelsUp_walker(Node * node,IncrementVarSublevelsUp_context * context)703 IncrementVarSublevelsUp_walker(Node *node,
704 							   IncrementVarSublevelsUp_context *context)
705 {
706 	if (node == NULL)
707 		return false;
708 	if (IsA(node, Var))
709 	{
710 		Var		   *var = (Var *) node;
711 
712 		if (var->varlevelsup >= context->min_sublevels_up)
713 			var->varlevelsup += context->delta_sublevels_up;
714 		return false;			/* done here */
715 	}
716 	if (IsA(node, CurrentOfExpr))
717 	{
718 		/* this should not happen */
719 		if (context->min_sublevels_up == 0)
720 			elog(ERROR, "cannot push down CurrentOfExpr");
721 		return false;
722 	}
723 	if (IsA(node, Aggref))
724 	{
725 		Aggref	   *agg = (Aggref *) node;
726 
727 		if (agg->agglevelsup >= context->min_sublevels_up)
728 			agg->agglevelsup += context->delta_sublevels_up;
729 		/* fall through to recurse into argument */
730 	}
731 	if (IsA(node, GroupingFunc))
732 	{
733 		GroupingFunc *grp = (GroupingFunc *) node;
734 
735 		if (grp->agglevelsup >= context->min_sublevels_up)
736 			grp->agglevelsup += context->delta_sublevels_up;
737 		/* fall through to recurse into argument */
738 	}
739 	if (IsA(node, PlaceHolderVar))
740 	{
741 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
742 
743 		if (phv->phlevelsup >= context->min_sublevels_up)
744 			phv->phlevelsup += context->delta_sublevels_up;
745 		/* fall through to recurse into argument */
746 	}
747 	if (IsA(node, RangeTblEntry))
748 	{
749 		RangeTblEntry *rte = (RangeTblEntry *) node;
750 
751 		if (rte->rtekind == RTE_CTE)
752 		{
753 			if (rte->ctelevelsup >= context->min_sublevels_up)
754 				rte->ctelevelsup += context->delta_sublevels_up;
755 		}
756 		return false;			/* allow range_table_walker to continue */
757 	}
758 	if (IsA(node, Query))
759 	{
760 		/* Recurse into subselects */
761 		bool		result;
762 
763 		context->min_sublevels_up++;
764 		result = query_tree_walker((Query *) node,
765 								   IncrementVarSublevelsUp_walker,
766 								   (void *) context,
767 								   QTW_EXAMINE_RTES_BEFORE);
768 		context->min_sublevels_up--;
769 		return result;
770 	}
771 	return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
772 								  (void *) context);
773 }
774 
775 void
IncrementVarSublevelsUp(Node * node,int delta_sublevels_up,int min_sublevels_up)776 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
777 						int min_sublevels_up)
778 {
779 	IncrementVarSublevelsUp_context context;
780 
781 	context.delta_sublevels_up = delta_sublevels_up;
782 	context.min_sublevels_up = min_sublevels_up;
783 
784 	/*
785 	 * Must be prepared to start with a Query or a bare expression tree; if
786 	 * it's a Query, we don't want to increment sublevels_up.
787 	 */
788 	query_or_expression_tree_walker(node,
789 									IncrementVarSublevelsUp_walker,
790 									(void *) &context,
791 									QTW_EXAMINE_RTES_BEFORE);
792 }
793 
794 /*
795  * IncrementVarSublevelsUp_rtable -
796  *	Same as IncrementVarSublevelsUp, but to be invoked on a range table.
797  */
798 void
IncrementVarSublevelsUp_rtable(List * rtable,int delta_sublevels_up,int min_sublevels_up)799 IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
800 							   int min_sublevels_up)
801 {
802 	IncrementVarSublevelsUp_context context;
803 
804 	context.delta_sublevels_up = delta_sublevels_up;
805 	context.min_sublevels_up = min_sublevels_up;
806 
807 	range_table_walker(rtable,
808 					   IncrementVarSublevelsUp_walker,
809 					   (void *) &context,
810 					   QTW_EXAMINE_RTES_BEFORE);
811 }
812 
813 
814 /*
815  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
816  *	in var nodes or join or setOp trees of a query or expression.
817  */
818 
819 typedef struct
820 {
821 	int			rt_index;
822 	int			sublevels_up;
823 } rangeTableEntry_used_context;
824 
825 static bool
rangeTableEntry_used_walker(Node * node,rangeTableEntry_used_context * context)826 rangeTableEntry_used_walker(Node *node,
827 							rangeTableEntry_used_context *context)
828 {
829 	if (node == NULL)
830 		return false;
831 	if (IsA(node, Var))
832 	{
833 		Var		   *var = (Var *) node;
834 
835 		if (var->varlevelsup == context->sublevels_up &&
836 			var->varno == context->rt_index)
837 			return true;
838 		return false;
839 	}
840 	if (IsA(node, CurrentOfExpr))
841 	{
842 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
843 
844 		if (context->sublevels_up == 0 &&
845 			cexpr->cvarno == context->rt_index)
846 			return true;
847 		return false;
848 	}
849 	if (IsA(node, RangeTblRef))
850 	{
851 		RangeTblRef *rtr = (RangeTblRef *) node;
852 
853 		if (rtr->rtindex == context->rt_index &&
854 			context->sublevels_up == 0)
855 			return true;
856 		/* the subquery itself is visited separately */
857 		return false;
858 	}
859 	if (IsA(node, JoinExpr))
860 	{
861 		JoinExpr   *j = (JoinExpr *) node;
862 
863 		if (j->rtindex == context->rt_index &&
864 			context->sublevels_up == 0)
865 			return true;
866 		/* fall through to examine children */
867 	}
868 	/* Shouldn't need to handle planner auxiliary nodes here */
869 	Assert(!IsA(node, PlaceHolderVar));
870 	Assert(!IsA(node, PlanRowMark));
871 	Assert(!IsA(node, SpecialJoinInfo));
872 	Assert(!IsA(node, AppendRelInfo));
873 	Assert(!IsA(node, PlaceHolderInfo));
874 	Assert(!IsA(node, MinMaxAggInfo));
875 
876 	if (IsA(node, Query))
877 	{
878 		/* Recurse into subselects */
879 		bool		result;
880 
881 		context->sublevels_up++;
882 		result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
883 								   (void *) context, 0);
884 		context->sublevels_up--;
885 		return result;
886 	}
887 	return expression_tree_walker(node, rangeTableEntry_used_walker,
888 								  (void *) context);
889 }
890 
891 bool
rangeTableEntry_used(Node * node,int rt_index,int sublevels_up)892 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
893 {
894 	rangeTableEntry_used_context context;
895 
896 	context.rt_index = rt_index;
897 	context.sublevels_up = sublevels_up;
898 
899 	/*
900 	 * Must be prepared to start with a Query or a bare expression tree; if
901 	 * it's a Query, we don't want to increment sublevels_up.
902 	 */
903 	return query_or_expression_tree_walker(node,
904 										   rangeTableEntry_used_walker,
905 										   (void *) &context,
906 										   0);
907 }
908 
909 
910 /*
911  * If the given Query is an INSERT ... SELECT construct, extract and
912  * return the sub-Query node that represents the SELECT part.  Otherwise
913  * return the given Query.
914  *
915  * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
916  * of the link to the SELECT subquery inside parsetree, or NULL if not an
917  * INSERT ... SELECT.
918  *
919  * This is a hack needed because transformations on INSERT ... SELECTs that
920  * appear in rule actions should be applied to the source SELECT, not to the
921  * INSERT part.  Perhaps this can be cleaned up with redesigned querytrees.
922  */
923 Query *
getInsertSelectQuery(Query * parsetree,Query *** subquery_ptr)924 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
925 {
926 	Query	   *selectquery;
927 	RangeTblEntry *selectrte;
928 	RangeTblRef *rtr;
929 
930 	if (subquery_ptr)
931 		*subquery_ptr = NULL;
932 
933 	if (parsetree == NULL)
934 		return parsetree;
935 	if (parsetree->commandType != CMD_INSERT)
936 		return parsetree;
937 
938 	/*
939 	 * Currently, this is ONLY applied to rule-action queries, and so we
940 	 * expect to find the OLD and NEW placeholder entries in the given query.
941 	 * If they're not there, it must be an INSERT/SELECT in which they've been
942 	 * pushed down to the SELECT.
943 	 */
944 	if (list_length(parsetree->rtable) >= 2 &&
945 		strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
946 			   "old") == 0 &&
947 		strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
948 			   "new") == 0)
949 		return parsetree;
950 	Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
951 	if (list_length(parsetree->jointree->fromlist) != 1)
952 		elog(ERROR, "expected to find SELECT subquery");
953 	rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
954 	Assert(IsA(rtr, RangeTblRef));
955 	selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
956 	selectquery = selectrte->subquery;
957 	if (!(selectquery && IsA(selectquery, Query) &&
958 		  selectquery->commandType == CMD_SELECT))
959 		elog(ERROR, "expected to find SELECT subquery");
960 	if (list_length(selectquery->rtable) >= 2 &&
961 		strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
962 			   "old") == 0 &&
963 		strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
964 			   "new") == 0)
965 	{
966 		if (subquery_ptr)
967 			*subquery_ptr = &(selectrte->subquery);
968 		return selectquery;
969 	}
970 	elog(ERROR, "could not find rule placeholders");
971 	return NULL;				/* not reached */
972 }
973 
974 
975 /*
976  * Add the given qualifier condition to the query's WHERE clause
977  */
978 void
AddQual(Query * parsetree,Node * qual)979 AddQual(Query *parsetree, Node *qual)
980 {
981 	Node	   *copy;
982 
983 	if (qual == NULL)
984 		return;
985 
986 	if (parsetree->commandType == CMD_UTILITY)
987 	{
988 		/*
989 		 * There's noplace to put the qual on a utility statement.
990 		 *
991 		 * If it's a NOTIFY, silently ignore the qual; this means that the
992 		 * NOTIFY will execute, whether or not there are any qualifying rows.
993 		 * While clearly wrong, this is much more useful than refusing to
994 		 * execute the rule at all, and extra NOTIFY events are harmless for
995 		 * typical uses of NOTIFY.
996 		 *
997 		 * If it isn't a NOTIFY, error out, since unconditional execution of
998 		 * other utility stmts is unlikely to be wanted.  (This case is not
999 		 * currently allowed anyway, but keep the test for safety.)
1000 		 */
1001 		if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
1002 			return;
1003 		else
1004 			ereport(ERROR,
1005 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1006 					 errmsg("conditional utility statements are not implemented")));
1007 	}
1008 
1009 	if (parsetree->setOperations != NULL)
1010 	{
1011 		/*
1012 		 * There's noplace to put the qual on a setop statement, either. (This
1013 		 * could be fixed, but right now the planner simply ignores any qual
1014 		 * condition on a setop query.)
1015 		 */
1016 		ereport(ERROR,
1017 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1018 				 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
1019 	}
1020 
1021 	/* INTERSECT wants the original, but we need to copy - Jan */
1022 	copy = copyObject(qual);
1023 
1024 	parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
1025 											   copy);
1026 
1027 	/*
1028 	 * We had better not have stuck an aggregate into the WHERE clause.
1029 	 */
1030 	Assert(!contain_aggs_of_level(copy, 0));
1031 
1032 	/*
1033 	 * Make sure query is marked correctly if added qual has sublinks. Need
1034 	 * not search qual when query is already marked.
1035 	 */
1036 	if (!parsetree->hasSubLinks)
1037 		parsetree->hasSubLinks = checkExprHasSubLink(copy);
1038 }
1039 
1040 
1041 /*
1042  * Invert the given clause and add it to the WHERE qualifications of the
1043  * given querytree.  Inversion means "x IS NOT TRUE", not just "NOT x",
1044  * else we will do the wrong thing when x evaluates to NULL.
1045  */
1046 void
AddInvertedQual(Query * parsetree,Node * qual)1047 AddInvertedQual(Query *parsetree, Node *qual)
1048 {
1049 	BooleanTest *invqual;
1050 
1051 	if (qual == NULL)
1052 		return;
1053 
1054 	/* Need not copy input qual, because AddQual will... */
1055 	invqual = makeNode(BooleanTest);
1056 	invqual->arg = (Expr *) qual;
1057 	invqual->booltesttype = IS_NOT_TRUE;
1058 	invqual->location = -1;
1059 
1060 	AddQual(parsetree, (Node *) invqual);
1061 }
1062 
1063 
1064 /*
1065  * replace_rte_variables() finds all Vars in an expression tree
1066  * that reference a particular RTE, and replaces them with substitute
1067  * expressions obtained from a caller-supplied callback function.
1068  *
1069  * When invoking replace_rte_variables on a portion of a Query, pass the
1070  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
1071  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
1072  * will then cause an error.
1073  *
1074  * Note: the business with inserted_sublink is needed to update hasSubLinks
1075  * in subqueries when the replacement adds a subquery inside a subquery.
1076  * Messy, isn't it?  We do not need to do similar pushups for hasAggs,
1077  * because it isn't possible for this transformation to insert a level-zero
1078  * aggregate reference into a subquery --- it could only insert outer aggs.
1079  * Likewise for hasWindowFuncs.
1080  *
1081  * Note: usually, we'd not expose the mutator function or context struct
1082  * for a function like this.  We do so because callbacks often find it
1083  * convenient to recurse directly to the mutator on sub-expressions of
1084  * what they will return.
1085  */
1086 Node *
replace_rte_variables(Node * node,int target_varno,int sublevels_up,replace_rte_variables_callback callback,void * callback_arg,bool * outer_hasSubLinks)1087 replace_rte_variables(Node *node, int target_varno, int sublevels_up,
1088 					  replace_rte_variables_callback callback,
1089 					  void *callback_arg,
1090 					  bool *outer_hasSubLinks)
1091 {
1092 	Node	   *result;
1093 	replace_rte_variables_context context;
1094 
1095 	context.callback = callback;
1096 	context.callback_arg = callback_arg;
1097 	context.target_varno = target_varno;
1098 	context.sublevels_up = sublevels_up;
1099 
1100 	/*
1101 	 * We try to initialize inserted_sublink to true if there is no need to
1102 	 * detect new sublinks because the query already has some.
1103 	 */
1104 	if (node && IsA(node, Query))
1105 		context.inserted_sublink = ((Query *) node)->hasSubLinks;
1106 	else if (outer_hasSubLinks)
1107 		context.inserted_sublink = *outer_hasSubLinks;
1108 	else
1109 		context.inserted_sublink = false;
1110 
1111 	/*
1112 	 * Must be prepared to start with a Query or a bare expression tree; if
1113 	 * it's a Query, we don't want to increment sublevels_up.
1114 	 */
1115 	result = query_or_expression_tree_mutator(node,
1116 											  replace_rte_variables_mutator,
1117 											  (void *) &context,
1118 											  0);
1119 
1120 	if (context.inserted_sublink)
1121 	{
1122 		if (result && IsA(result, Query))
1123 			((Query *) result)->hasSubLinks = true;
1124 		else if (outer_hasSubLinks)
1125 			*outer_hasSubLinks = true;
1126 		else
1127 			elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
1128 	}
1129 
1130 	return result;
1131 }
1132 
1133 Node *
replace_rte_variables_mutator(Node * node,replace_rte_variables_context * context)1134 replace_rte_variables_mutator(Node *node,
1135 							  replace_rte_variables_context *context)
1136 {
1137 	if (node == NULL)
1138 		return NULL;
1139 	if (IsA(node, Var))
1140 	{
1141 		Var		   *var = (Var *) node;
1142 
1143 		if (var->varno == context->target_varno &&
1144 			var->varlevelsup == context->sublevels_up)
1145 		{
1146 			/* Found a matching variable, make the substitution */
1147 			Node	   *newnode;
1148 
1149 			newnode = context->callback(var, context);
1150 			/* Detect if we are adding a sublink to query */
1151 			if (!context->inserted_sublink)
1152 				context->inserted_sublink = checkExprHasSubLink(newnode);
1153 			return newnode;
1154 		}
1155 		/* otherwise fall through to copy the var normally */
1156 	}
1157 	else if (IsA(node, CurrentOfExpr))
1158 	{
1159 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
1160 
1161 		if (cexpr->cvarno == context->target_varno &&
1162 			context->sublevels_up == 0)
1163 		{
1164 			/*
1165 			 * We get here if a WHERE CURRENT OF expression turns out to apply
1166 			 * to a view.  Someday we might be able to translate the
1167 			 * expression to apply to an underlying table of the view, but
1168 			 * right now it's not implemented.
1169 			 */
1170 			ereport(ERROR,
1171 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1172 					 errmsg("WHERE CURRENT OF on a view is not implemented")));
1173 		}
1174 		/* otherwise fall through to copy the expr normally */
1175 	}
1176 	else if (IsA(node, Query))
1177 	{
1178 		/* Recurse into RTE subquery or not-yet-planned sublink subquery */
1179 		Query	   *newnode;
1180 		bool		save_inserted_sublink;
1181 
1182 		context->sublevels_up++;
1183 		save_inserted_sublink = context->inserted_sublink;
1184 		context->inserted_sublink = ((Query *) node)->hasSubLinks;
1185 		newnode = query_tree_mutator((Query *) node,
1186 									 replace_rte_variables_mutator,
1187 									 (void *) context,
1188 									 0);
1189 		newnode->hasSubLinks |= context->inserted_sublink;
1190 		context->inserted_sublink = save_inserted_sublink;
1191 		context->sublevels_up--;
1192 		return (Node *) newnode;
1193 	}
1194 	return expression_tree_mutator(node, replace_rte_variables_mutator,
1195 								   (void *) context);
1196 }
1197 
1198 
1199 /*
1200  * map_variable_attnos() finds all user-column Vars in an expression tree
1201  * that reference a particular RTE, and adjusts their varattnos according
1202  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
1203  * Vars for system columns are not modified.
1204  *
1205  * A zero in the mapping array represents a dropped column, which should not
1206  * appear in the expression.
1207  *
1208  * If the expression tree contains a whole-row Var for the target RTE,
1209  * *found_whole_row is set to true.  In addition, if to_rowtype is
1210  * not InvalidOid, we replace the Var with a Var of that vartype, inserting
1211  * a ConvertRowtypeExpr to map back to the rowtype expected by the expression.
1212  * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
1213  * RTE we're changing references to.)  Callers that don't provide to_rowtype
1214  * should report an error if *found_whole_row is true; we don't do that here
1215  * because we don't know exactly what wording for the error message would
1216  * be most appropriate.  The caller will be aware of the context.
1217  *
1218  * This could be built using replace_rte_variables and a callback function,
1219  * but since we don't ever need to insert sublinks, replace_rte_variables is
1220  * overly complicated.
1221  */
1222 
1223 typedef struct
1224 {
1225 	int			target_varno;	/* RTE index to search for */
1226 	int			sublevels_up;	/* (current) nesting depth */
1227 	const AttrMap *attno_map;	/* map array for user attnos */
1228 	Oid			to_rowtype;		/* change whole-row Vars to this type */
1229 	bool	   *found_whole_row;	/* output flag */
1230 } map_variable_attnos_context;
1231 
1232 static Node *
map_variable_attnos_mutator(Node * node,map_variable_attnos_context * context)1233 map_variable_attnos_mutator(Node *node,
1234 							map_variable_attnos_context *context)
1235 {
1236 	if (node == NULL)
1237 		return NULL;
1238 	if (IsA(node, Var))
1239 	{
1240 		Var		   *var = (Var *) node;
1241 
1242 		if (var->varno == context->target_varno &&
1243 			var->varlevelsup == context->sublevels_up)
1244 		{
1245 			/* Found a matching variable, make the substitution */
1246 			Var		   *newvar = (Var *) palloc(sizeof(Var));
1247 			int			attno = var->varattno;
1248 
1249 			*newvar = *var;		/* initially copy all fields of the Var */
1250 
1251 			if (attno > 0)
1252 			{
1253 				/* user-defined column, replace attno */
1254 				if (attno > context->attno_map->maplen ||
1255 					context->attno_map->attnums[attno - 1] == 0)
1256 					elog(ERROR, "unexpected varattno %d in expression to be mapped",
1257 						 attno);
1258 				newvar->varattno = context->attno_map->attnums[attno - 1];
1259 				/* If the syntactic referent is same RTE, fix it too */
1260 				if (newvar->varnosyn == context->target_varno)
1261 					newvar->varattnosyn = newvar->varattno;
1262 			}
1263 			else if (attno == 0)
1264 			{
1265 				/* whole-row variable, warn caller */
1266 				*(context->found_whole_row) = true;
1267 
1268 				/* If the caller expects us to convert the Var, do so. */
1269 				if (OidIsValid(context->to_rowtype) &&
1270 					context->to_rowtype != var->vartype)
1271 				{
1272 					ConvertRowtypeExpr *r;
1273 
1274 					/* This certainly won't work for a RECORD variable. */
1275 					Assert(var->vartype != RECORDOID);
1276 
1277 					/* Var itself is changed to the requested type. */
1278 					newvar->vartype = context->to_rowtype;
1279 
1280 					/*
1281 					 * Add a conversion node on top to convert back to the
1282 					 * original type expected by the expression.
1283 					 */
1284 					r = makeNode(ConvertRowtypeExpr);
1285 					r->arg = (Expr *) newvar;
1286 					r->resulttype = var->vartype;
1287 					r->convertformat = COERCE_IMPLICIT_CAST;
1288 					r->location = -1;
1289 
1290 					return (Node *) r;
1291 				}
1292 			}
1293 			return (Node *) newvar;
1294 		}
1295 		/* otherwise fall through to copy the var normally */
1296 	}
1297 	else if (IsA(node, ConvertRowtypeExpr))
1298 	{
1299 		ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
1300 		Var		   *var = (Var *) r->arg;
1301 
1302 		/*
1303 		 * If this is coercing a whole-row Var that we need to convert, then
1304 		 * just convert the Var without adding an extra ConvertRowtypeExpr.
1305 		 * Effectively we're simplifying var::parenttype::grandparenttype into
1306 		 * just var::grandparenttype.  This avoids building stacks of CREs if
1307 		 * this function is applied repeatedly.
1308 		 */
1309 		if (IsA(var, Var) &&
1310 			var->varno == context->target_varno &&
1311 			var->varlevelsup == context->sublevels_up &&
1312 			var->varattno == 0 &&
1313 			OidIsValid(context->to_rowtype) &&
1314 			context->to_rowtype != var->vartype)
1315 		{
1316 			ConvertRowtypeExpr *newnode;
1317 			Var		   *newvar = (Var *) palloc(sizeof(Var));
1318 
1319 			/* whole-row variable, warn caller */
1320 			*(context->found_whole_row) = true;
1321 
1322 			*newvar = *var;		/* initially copy all fields of the Var */
1323 
1324 			/* This certainly won't work for a RECORD variable. */
1325 			Assert(var->vartype != RECORDOID);
1326 
1327 			/* Var itself is changed to the requested type. */
1328 			newvar->vartype = context->to_rowtype;
1329 
1330 			newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
1331 			*newnode = *r;		/* initially copy all fields of the CRE */
1332 			newnode->arg = (Expr *) newvar;
1333 
1334 			return (Node *) newnode;
1335 		}
1336 		/* otherwise fall through to process the expression normally */
1337 	}
1338 	else if (IsA(node, Query))
1339 	{
1340 		/* Recurse into RTE subquery or not-yet-planned sublink subquery */
1341 		Query	   *newnode;
1342 
1343 		context->sublevels_up++;
1344 		newnode = query_tree_mutator((Query *) node,
1345 									 map_variable_attnos_mutator,
1346 									 (void *) context,
1347 									 0);
1348 		context->sublevels_up--;
1349 		return (Node *) newnode;
1350 	}
1351 	return expression_tree_mutator(node, map_variable_attnos_mutator,
1352 								   (void *) context);
1353 }
1354 
1355 Node *
map_variable_attnos(Node * node,int target_varno,int sublevels_up,const AttrMap * attno_map,Oid to_rowtype,bool * found_whole_row)1356 map_variable_attnos(Node *node,
1357 					int target_varno, int sublevels_up,
1358 					const AttrMap *attno_map,
1359 					Oid to_rowtype, bool *found_whole_row)
1360 {
1361 	map_variable_attnos_context context;
1362 
1363 	context.target_varno = target_varno;
1364 	context.sublevels_up = sublevels_up;
1365 	context.attno_map = attno_map;
1366 	context.to_rowtype = to_rowtype;
1367 	context.found_whole_row = found_whole_row;
1368 
1369 	*found_whole_row = false;
1370 
1371 	/*
1372 	 * Must be prepared to start with a Query or a bare expression tree; if
1373 	 * it's a Query, we don't want to increment sublevels_up.
1374 	 */
1375 	return query_or_expression_tree_mutator(node,
1376 											map_variable_attnos_mutator,
1377 											(void *) &context,
1378 											0);
1379 }
1380 
1381 
1382 /*
1383  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
1384  *
1385  * Vars matching target_varno and sublevels_up are replaced by the
1386  * entry with matching resno from targetlist, if there is one.
1387  *
1388  * If there is no matching resno for such a Var, the action depends on the
1389  * nomatch_option:
1390  *	REPLACEVARS_REPORT_ERROR: throw an error
1391  *	REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
1392  *	REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
1393  *
1394  * The caller must also provide target_rte, the RTE describing the target
1395  * relation.  This is needed to handle whole-row Vars referencing the target.
1396  * We expand such Vars into RowExpr constructs.
1397  *
1398  * outer_hasSubLinks works the same as for replace_rte_variables().
1399  */
1400 
1401 typedef struct
1402 {
1403 	RangeTblEntry *target_rte;
1404 	List	   *targetlist;
1405 	ReplaceVarsNoMatchOption nomatch_option;
1406 	int			nomatch_varno;
1407 } ReplaceVarsFromTargetList_context;
1408 
1409 static Node *
ReplaceVarsFromTargetList_callback(Var * var,replace_rte_variables_context * context)1410 ReplaceVarsFromTargetList_callback(Var *var,
1411 								   replace_rte_variables_context *context)
1412 {
1413 	ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
1414 	TargetEntry *tle;
1415 
1416 	if (var->varattno == InvalidAttrNumber)
1417 	{
1418 		/* Must expand whole-tuple reference into RowExpr */
1419 		RowExpr    *rowexpr;
1420 		List	   *colnames;
1421 		List	   *fields;
1422 
1423 		/*
1424 		 * If generating an expansion for a var of a named rowtype (ie, this
1425 		 * is a plain relation RTE), then we must include dummy items for
1426 		 * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
1427 		 * omit dropped columns.  Either way, attach column names to the
1428 		 * RowExpr for use of ruleutils.c.
1429 		 */
1430 		expandRTE(rcon->target_rte,
1431 				  var->varno, var->varlevelsup, var->location,
1432 				  (var->vartype != RECORDOID),
1433 				  &colnames, &fields);
1434 		/* Adjust the generated per-field Vars... */
1435 		fields = (List *) replace_rte_variables_mutator((Node *) fields,
1436 														context);
1437 		rowexpr = makeNode(RowExpr);
1438 		rowexpr->args = fields;
1439 		rowexpr->row_typeid = var->vartype;
1440 		rowexpr->row_format = COERCE_IMPLICIT_CAST;
1441 		rowexpr->colnames = colnames;
1442 		rowexpr->location = var->location;
1443 
1444 		return (Node *) rowexpr;
1445 	}
1446 
1447 	/* Normal case referencing one targetlist element */
1448 	tle = get_tle_by_resno(rcon->targetlist, var->varattno);
1449 
1450 	if (tle == NULL || tle->resjunk)
1451 	{
1452 		/* Failed to find column in targetlist */
1453 		switch (rcon->nomatch_option)
1454 		{
1455 			case REPLACEVARS_REPORT_ERROR:
1456 				/* fall through, throw error below */
1457 				break;
1458 
1459 			case REPLACEVARS_CHANGE_VARNO:
1460 				var = (Var *) copyObject(var);
1461 				var->varno = rcon->nomatch_varno;
1462 				/* we leave the syntactic referent alone */
1463 				return (Node *) var;
1464 
1465 			case REPLACEVARS_SUBSTITUTE_NULL:
1466 
1467 				/*
1468 				 * If Var is of domain type, we should add a CoerceToDomain
1469 				 * node, in case there is a NOT NULL domain constraint.
1470 				 */
1471 				return coerce_to_domain((Node *) makeNullConst(var->vartype,
1472 															   var->vartypmod,
1473 															   var->varcollid),
1474 										InvalidOid, -1,
1475 										var->vartype,
1476 										COERCION_IMPLICIT,
1477 										COERCE_IMPLICIT_CAST,
1478 										-1,
1479 										false);
1480 		}
1481 		elog(ERROR, "could not find replacement targetlist entry for attno %d",
1482 			 var->varattno);
1483 		return NULL;			/* keep compiler quiet */
1484 	}
1485 	else
1486 	{
1487 		/* Make a copy of the tlist item to return */
1488 		Expr	   *newnode = copyObject(tle->expr);
1489 
1490 		/* Must adjust varlevelsup if tlist item is from higher query */
1491 		if (var->varlevelsup > 0)
1492 			IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
1493 
1494 		/*
1495 		 * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
1496 		 * and throw error if so.  This case could only happen when expanding
1497 		 * an ON UPDATE rule's NEW variable and the referenced tlist item in
1498 		 * the original UPDATE command is part of a multiple assignment. There
1499 		 * seems no practical way to handle such cases without multiple
1500 		 * evaluation of the multiple assignment's sub-select, which would
1501 		 * create semantic oddities that users of rules would probably prefer
1502 		 * not to cope with.  So treat it as an unimplemented feature.
1503 		 */
1504 		if (contains_multiexpr_param((Node *) newnode, NULL))
1505 			ereport(ERROR,
1506 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1507 					 errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
1508 
1509 		return (Node *) newnode;
1510 	}
1511 }
1512 
1513 Node *
ReplaceVarsFromTargetList(Node * node,int target_varno,int sublevels_up,RangeTblEntry * target_rte,List * targetlist,ReplaceVarsNoMatchOption nomatch_option,int nomatch_varno,bool * outer_hasSubLinks)1514 ReplaceVarsFromTargetList(Node *node,
1515 						  int target_varno, int sublevels_up,
1516 						  RangeTblEntry *target_rte,
1517 						  List *targetlist,
1518 						  ReplaceVarsNoMatchOption nomatch_option,
1519 						  int nomatch_varno,
1520 						  bool *outer_hasSubLinks)
1521 {
1522 	ReplaceVarsFromTargetList_context context;
1523 
1524 	context.target_rte = target_rte;
1525 	context.targetlist = targetlist;
1526 	context.nomatch_option = nomatch_option;
1527 	context.nomatch_varno = nomatch_varno;
1528 
1529 	return replace_rte_variables(node, target_varno, sublevels_up,
1530 								 ReplaceVarsFromTargetList_callback,
1531 								 (void *) &context,
1532 								 outer_hasSubLinks);
1533 }
1534