1 /*-------------------------------------------------------------------------
2  *
3  * rewriteManip.c
4  *
5  * Portions Copyright (c) 1996-2017, 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/plannodes.h"
20 #include "optimizer/clauses.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 varnoold 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 			var->varnoold += context->offset;
352 		}
353 		return false;
354 	}
355 	if (IsA(node, CurrentOfExpr))
356 	{
357 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
358 
359 		if (context->sublevels_up == 0)
360 			cexpr->cvarno += context->offset;
361 		return false;
362 	}
363 	if (IsA(node, RangeTblRef))
364 	{
365 		RangeTblRef *rtr = (RangeTblRef *) node;
366 
367 		if (context->sublevels_up == 0)
368 			rtr->rtindex += context->offset;
369 		/* the subquery itself is visited separately */
370 		return false;
371 	}
372 	if (IsA(node, JoinExpr))
373 	{
374 		JoinExpr   *j = (JoinExpr *) node;
375 
376 		if (j->rtindex && context->sublevels_up == 0)
377 			j->rtindex += context->offset;
378 		/* fall through to examine children */
379 	}
380 	if (IsA(node, PlaceHolderVar))
381 	{
382 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
383 
384 		if (phv->phlevelsup == context->sublevels_up)
385 		{
386 			phv->phrels = offset_relid_set(phv->phrels,
387 										   context->offset);
388 		}
389 		/* fall through to examine children */
390 	}
391 	if (IsA(node, AppendRelInfo))
392 	{
393 		AppendRelInfo *appinfo = (AppendRelInfo *) node;
394 
395 		if (context->sublevels_up == 0)
396 		{
397 			appinfo->parent_relid += context->offset;
398 			appinfo->child_relid += context->offset;
399 		}
400 		/* fall through to examine children */
401 	}
402 	/* Shouldn't need to handle other planner auxiliary nodes here */
403 	Assert(!IsA(node, PlanRowMark));
404 	Assert(!IsA(node, SpecialJoinInfo));
405 	Assert(!IsA(node, PlaceHolderInfo));
406 	Assert(!IsA(node, MinMaxAggInfo));
407 
408 	if (IsA(node, Query))
409 	{
410 		/* Recurse into subselects */
411 		bool		result;
412 
413 		context->sublevels_up++;
414 		result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
415 								   (void *) context, 0);
416 		context->sublevels_up--;
417 		return result;
418 	}
419 	return expression_tree_walker(node, OffsetVarNodes_walker,
420 								  (void *) context);
421 }
422 
423 void
OffsetVarNodes(Node * node,int offset,int sublevels_up)424 OffsetVarNodes(Node *node, int offset, int sublevels_up)
425 {
426 	OffsetVarNodes_context context;
427 
428 	context.offset = offset;
429 	context.sublevels_up = sublevels_up;
430 
431 	/*
432 	 * Must be prepared to start with a Query or a bare expression tree; if
433 	 * it's a Query, go straight to query_tree_walker to make sure that
434 	 * sublevels_up doesn't get incremented prematurely.
435 	 */
436 	if (node && IsA(node, Query))
437 	{
438 		Query	   *qry = (Query *) node;
439 
440 		/*
441 		 * If we are starting at a Query, and sublevels_up is zero, then we
442 		 * must also fix rangetable indexes in the Query itself --- namely
443 		 * resultRelation, exclRelIndex and rowMarks entries.  sublevels_up
444 		 * cannot be zero when recursing into a subquery, so there's no need
445 		 * to have the same logic inside OffsetVarNodes_walker.
446 		 */
447 		if (sublevels_up == 0)
448 		{
449 			ListCell   *l;
450 
451 			if (qry->resultRelation)
452 				qry->resultRelation += offset;
453 
454 			if (qry->onConflict && qry->onConflict->exclRelIndex)
455 				qry->onConflict->exclRelIndex += offset;
456 
457 			foreach(l, qry->rowMarks)
458 			{
459 				RowMarkClause *rc = (RowMarkClause *) lfirst(l);
460 
461 				rc->rti += offset;
462 			}
463 		}
464 		query_tree_walker(qry, OffsetVarNodes_walker,
465 						  (void *) &context, 0);
466 	}
467 	else
468 		OffsetVarNodes_walker(node, &context);
469 }
470 
471 static Relids
offset_relid_set(Relids relids,int offset)472 offset_relid_set(Relids relids, int offset)
473 {
474 	Relids		result = NULL;
475 	int			rtindex;
476 
477 	rtindex = -1;
478 	while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
479 		result = bms_add_member(result, rtindex + offset);
480 	return result;
481 }
482 
483 /*
484  * ChangeVarNodes - adjust Var nodes for a specific change of RT index
485  *
486  * Find all Var nodes in the given tree belonging to a specific relation
487  * (identified by sublevels_up and rt_index), and change their varno fields
488  * to 'new_index'.  The varnoold fields are changed too.  Also, adjust other
489  * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
490  *
491  * NOTE: although this has the form of a walker, we cheat and modify the
492  * nodes in-place.  The given expression tree should have been copied
493  * earlier to ensure that no unwanted side-effects occur!
494  */
495 
496 typedef struct
497 {
498 	int			rt_index;
499 	int			new_index;
500 	int			sublevels_up;
501 } ChangeVarNodes_context;
502 
503 static bool
ChangeVarNodes_walker(Node * node,ChangeVarNodes_context * context)504 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
505 {
506 	if (node == NULL)
507 		return false;
508 	if (IsA(node, Var))
509 	{
510 		Var		   *var = (Var *) node;
511 
512 		if (var->varlevelsup == context->sublevels_up &&
513 			var->varno == context->rt_index)
514 		{
515 			var->varno = context->new_index;
516 			var->varnoold = context->new_index;
517 		}
518 		return false;
519 	}
520 	if (IsA(node, CurrentOfExpr))
521 	{
522 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
523 
524 		if (context->sublevels_up == 0 &&
525 			cexpr->cvarno == context->rt_index)
526 			cexpr->cvarno = context->new_index;
527 		return false;
528 	}
529 	if (IsA(node, RangeTblRef))
530 	{
531 		RangeTblRef *rtr = (RangeTblRef *) node;
532 
533 		if (context->sublevels_up == 0 &&
534 			rtr->rtindex == context->rt_index)
535 			rtr->rtindex = context->new_index;
536 		/* the subquery itself is visited separately */
537 		return false;
538 	}
539 	if (IsA(node, JoinExpr))
540 	{
541 		JoinExpr   *j = (JoinExpr *) node;
542 
543 		if (context->sublevels_up == 0 &&
544 			j->rtindex == context->rt_index)
545 			j->rtindex = context->new_index;
546 		/* fall through to examine children */
547 	}
548 	if (IsA(node, PlaceHolderVar))
549 	{
550 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
551 
552 		if (phv->phlevelsup == context->sublevels_up)
553 		{
554 			phv->phrels = adjust_relid_set(phv->phrels,
555 										   context->rt_index,
556 										   context->new_index);
557 		}
558 		/* fall through to examine children */
559 	}
560 	if (IsA(node, PlanRowMark))
561 	{
562 		PlanRowMark *rowmark = (PlanRowMark *) node;
563 
564 		if (context->sublevels_up == 0)
565 		{
566 			if (rowmark->rti == context->rt_index)
567 				rowmark->rti = context->new_index;
568 			if (rowmark->prti == context->rt_index)
569 				rowmark->prti = context->new_index;
570 		}
571 		return false;
572 	}
573 	if (IsA(node, AppendRelInfo))
574 	{
575 		AppendRelInfo *appinfo = (AppendRelInfo *) node;
576 
577 		if (context->sublevels_up == 0)
578 		{
579 			if (appinfo->parent_relid == context->rt_index)
580 				appinfo->parent_relid = context->new_index;
581 			if (appinfo->child_relid == context->rt_index)
582 				appinfo->child_relid = context->new_index;
583 		}
584 		/* fall through to examine children */
585 	}
586 	/* Shouldn't need to handle other planner auxiliary nodes here */
587 	Assert(!IsA(node, SpecialJoinInfo));
588 	Assert(!IsA(node, PlaceHolderInfo));
589 	Assert(!IsA(node, MinMaxAggInfo));
590 
591 	if (IsA(node, Query))
592 	{
593 		/* Recurse into subselects */
594 		bool		result;
595 
596 		context->sublevels_up++;
597 		result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
598 								   (void *) context, 0);
599 		context->sublevels_up--;
600 		return result;
601 	}
602 	return expression_tree_walker(node, ChangeVarNodes_walker,
603 								  (void *) context);
604 }
605 
606 void
ChangeVarNodes(Node * node,int rt_index,int new_index,int sublevels_up)607 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
608 {
609 	ChangeVarNodes_context context;
610 
611 	context.rt_index = rt_index;
612 	context.new_index = new_index;
613 	context.sublevels_up = sublevels_up;
614 
615 	/*
616 	 * Must be prepared to start with a Query or a bare expression tree; if
617 	 * it's a Query, go straight to query_tree_walker to make sure that
618 	 * sublevels_up doesn't get incremented prematurely.
619 	 */
620 	if (node && IsA(node, Query))
621 	{
622 		Query	   *qry = (Query *) node;
623 
624 		/*
625 		 * If we are starting at a Query, and sublevels_up is zero, then we
626 		 * must also fix rangetable indexes in the Query itself --- namely
627 		 * resultRelation and rowMarks entries.  sublevels_up cannot be zero
628 		 * when recursing into a subquery, so there's no need to have the same
629 		 * logic inside ChangeVarNodes_walker.
630 		 */
631 		if (sublevels_up == 0)
632 		{
633 			ListCell   *l;
634 
635 			if (qry->resultRelation == rt_index)
636 				qry->resultRelation = new_index;
637 
638 			/* this is unlikely to ever be used, but ... */
639 			if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
640 				qry->onConflict->exclRelIndex = new_index;
641 
642 			foreach(l, qry->rowMarks)
643 			{
644 				RowMarkClause *rc = (RowMarkClause *) lfirst(l);
645 
646 				if (rc->rti == rt_index)
647 					rc->rti = new_index;
648 			}
649 		}
650 		query_tree_walker(qry, ChangeVarNodes_walker,
651 						  (void *) &context, 0);
652 	}
653 	else
654 		ChangeVarNodes_walker(node, &context);
655 }
656 
657 /*
658  * Substitute newrelid for oldrelid in a Relid set
659  */
660 static Relids
adjust_relid_set(Relids relids,int oldrelid,int newrelid)661 adjust_relid_set(Relids relids, int oldrelid, int newrelid)
662 {
663 	if (bms_is_member(oldrelid, relids))
664 	{
665 		/* Ensure we have a modifiable copy */
666 		relids = bms_copy(relids);
667 		/* Remove old, add new */
668 		relids = bms_del_member(relids, oldrelid);
669 		relids = bms_add_member(relids, newrelid);
670 	}
671 	return relids;
672 }
673 
674 /*
675  * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
676  *
677  * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
678  * and add delta_sublevels_up to their varlevelsup value.  This is needed when
679  * an expression that's correct for some nesting level is inserted into a
680  * subquery.  Ordinarily the initial call has min_sublevels_up == 0 so that
681  * all Vars are affected.  The point of min_sublevels_up is that we can
682  * increment it when we recurse into a sublink, so that local variables in
683  * that sublink are not affected, only outer references to vars that belong
684  * to the expression's original query level or parents thereof.
685  *
686  * Likewise for other nodes containing levelsup fields, such as Aggref.
687  *
688  * NOTE: although this has the form of a walker, we cheat and modify the
689  * Var nodes in-place.  The given expression tree should have been copied
690  * earlier to ensure that no unwanted side-effects occur!
691  */
692 
693 typedef struct
694 {
695 	int			delta_sublevels_up;
696 	int			min_sublevels_up;
697 } IncrementVarSublevelsUp_context;
698 
699 static bool
IncrementVarSublevelsUp_walker(Node * node,IncrementVarSublevelsUp_context * context)700 IncrementVarSublevelsUp_walker(Node *node,
701 							   IncrementVarSublevelsUp_context *context)
702 {
703 	if (node == NULL)
704 		return false;
705 	if (IsA(node, Var))
706 	{
707 		Var		   *var = (Var *) node;
708 
709 		if (var->varlevelsup >= context->min_sublevels_up)
710 			var->varlevelsup += context->delta_sublevels_up;
711 		return false;			/* done here */
712 	}
713 	if (IsA(node, CurrentOfExpr))
714 	{
715 		/* this should not happen */
716 		if (context->min_sublevels_up == 0)
717 			elog(ERROR, "cannot push down CurrentOfExpr");
718 		return false;
719 	}
720 	if (IsA(node, Aggref))
721 	{
722 		Aggref	   *agg = (Aggref *) node;
723 
724 		if (agg->agglevelsup >= context->min_sublevels_up)
725 			agg->agglevelsup += context->delta_sublevels_up;
726 		/* fall through to recurse into argument */
727 	}
728 	if (IsA(node, GroupingFunc))
729 	{
730 		GroupingFunc *grp = (GroupingFunc *) node;
731 
732 		if (grp->agglevelsup >= context->min_sublevels_up)
733 			grp->agglevelsup += context->delta_sublevels_up;
734 		/* fall through to recurse into argument */
735 	}
736 	if (IsA(node, PlaceHolderVar))
737 	{
738 		PlaceHolderVar *phv = (PlaceHolderVar *) node;
739 
740 		if (phv->phlevelsup >= context->min_sublevels_up)
741 			phv->phlevelsup += context->delta_sublevels_up;
742 		/* fall through to recurse into argument */
743 	}
744 	if (IsA(node, RangeTblEntry))
745 	{
746 		RangeTblEntry *rte = (RangeTblEntry *) node;
747 
748 		if (rte->rtekind == RTE_CTE)
749 		{
750 			if (rte->ctelevelsup >= context->min_sublevels_up)
751 				rte->ctelevelsup += context->delta_sublevels_up;
752 		}
753 		return false;			/* allow range_table_walker to continue */
754 	}
755 	if (IsA(node, Query))
756 	{
757 		/* Recurse into subselects */
758 		bool		result;
759 
760 		context->min_sublevels_up++;
761 		result = query_tree_walker((Query *) node,
762 								   IncrementVarSublevelsUp_walker,
763 								   (void *) context,
764 								   QTW_EXAMINE_RTES);
765 		context->min_sublevels_up--;
766 		return result;
767 	}
768 	return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
769 								  (void *) context);
770 }
771 
772 void
IncrementVarSublevelsUp(Node * node,int delta_sublevels_up,int min_sublevels_up)773 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
774 						int min_sublevels_up)
775 {
776 	IncrementVarSublevelsUp_context context;
777 
778 	context.delta_sublevels_up = delta_sublevels_up;
779 	context.min_sublevels_up = min_sublevels_up;
780 
781 	/*
782 	 * Must be prepared to start with a Query or a bare expression tree; if
783 	 * it's a Query, we don't want to increment sublevels_up.
784 	 */
785 	query_or_expression_tree_walker(node,
786 									IncrementVarSublevelsUp_walker,
787 									(void *) &context,
788 									QTW_EXAMINE_RTES);
789 }
790 
791 /*
792  * IncrementVarSublevelsUp_rtable -
793  *	Same as IncrementVarSublevelsUp, but to be invoked on a range table.
794  */
795 void
IncrementVarSublevelsUp_rtable(List * rtable,int delta_sublevels_up,int min_sublevels_up)796 IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
797 							   int min_sublevels_up)
798 {
799 	IncrementVarSublevelsUp_context context;
800 
801 	context.delta_sublevels_up = delta_sublevels_up;
802 	context.min_sublevels_up = min_sublevels_up;
803 
804 	range_table_walker(rtable,
805 					   IncrementVarSublevelsUp_walker,
806 					   (void *) &context,
807 					   QTW_EXAMINE_RTES);
808 }
809 
810 
811 /*
812  * rangeTableEntry_used - detect whether an RTE is referenced somewhere
813  *	in var nodes or join or setOp trees of a query or expression.
814  */
815 
816 typedef struct
817 {
818 	int			rt_index;
819 	int			sublevels_up;
820 } rangeTableEntry_used_context;
821 
822 static bool
rangeTableEntry_used_walker(Node * node,rangeTableEntry_used_context * context)823 rangeTableEntry_used_walker(Node *node,
824 							rangeTableEntry_used_context *context)
825 {
826 	if (node == NULL)
827 		return false;
828 	if (IsA(node, Var))
829 	{
830 		Var		   *var = (Var *) node;
831 
832 		if (var->varlevelsup == context->sublevels_up &&
833 			var->varno == context->rt_index)
834 			return true;
835 		return false;
836 	}
837 	if (IsA(node, CurrentOfExpr))
838 	{
839 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
840 
841 		if (context->sublevels_up == 0 &&
842 			cexpr->cvarno == context->rt_index)
843 			return true;
844 		return false;
845 	}
846 	if (IsA(node, RangeTblRef))
847 	{
848 		RangeTblRef *rtr = (RangeTblRef *) node;
849 
850 		if (rtr->rtindex == context->rt_index &&
851 			context->sublevels_up == 0)
852 			return true;
853 		/* the subquery itself is visited separately */
854 		return false;
855 	}
856 	if (IsA(node, JoinExpr))
857 	{
858 		JoinExpr   *j = (JoinExpr *) node;
859 
860 		if (j->rtindex == context->rt_index &&
861 			context->sublevels_up == 0)
862 			return true;
863 		/* fall through to examine children */
864 	}
865 	/* Shouldn't need to handle planner auxiliary nodes here */
866 	Assert(!IsA(node, PlaceHolderVar));
867 	Assert(!IsA(node, PlanRowMark));
868 	Assert(!IsA(node, SpecialJoinInfo));
869 	Assert(!IsA(node, AppendRelInfo));
870 	Assert(!IsA(node, PlaceHolderInfo));
871 	Assert(!IsA(node, MinMaxAggInfo));
872 
873 	if (IsA(node, Query))
874 	{
875 		/* Recurse into subselects */
876 		bool		result;
877 
878 		context->sublevels_up++;
879 		result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
880 								   (void *) context, 0);
881 		context->sublevels_up--;
882 		return result;
883 	}
884 	return expression_tree_walker(node, rangeTableEntry_used_walker,
885 								  (void *) context);
886 }
887 
888 bool
rangeTableEntry_used(Node * node,int rt_index,int sublevels_up)889 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
890 {
891 	rangeTableEntry_used_context context;
892 
893 	context.rt_index = rt_index;
894 	context.sublevels_up = sublevels_up;
895 
896 	/*
897 	 * Must be prepared to start with a Query or a bare expression tree; if
898 	 * it's a Query, we don't want to increment sublevels_up.
899 	 */
900 	return query_or_expression_tree_walker(node,
901 										   rangeTableEntry_used_walker,
902 										   (void *) &context,
903 										   0);
904 }
905 
906 
907 /*
908  * If the given Query is an INSERT ... SELECT construct, extract and
909  * return the sub-Query node that represents the SELECT part.  Otherwise
910  * return the given Query.
911  *
912  * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
913  * of the link to the SELECT subquery inside parsetree, or NULL if not an
914  * INSERT ... SELECT.
915  *
916  * This is a hack needed because transformations on INSERT ... SELECTs that
917  * appear in rule actions should be applied to the source SELECT, not to the
918  * INSERT part.  Perhaps this can be cleaned up with redesigned querytrees.
919  */
920 Query *
getInsertSelectQuery(Query * parsetree,Query *** subquery_ptr)921 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
922 {
923 	Query	   *selectquery;
924 	RangeTblEntry *selectrte;
925 	RangeTblRef *rtr;
926 
927 	if (subquery_ptr)
928 		*subquery_ptr = NULL;
929 
930 	if (parsetree == NULL)
931 		return parsetree;
932 	if (parsetree->commandType != CMD_INSERT)
933 		return parsetree;
934 
935 	/*
936 	 * Currently, this is ONLY applied to rule-action queries, and so we
937 	 * expect to find the OLD and NEW placeholder entries in the given query.
938 	 * If they're not there, it must be an INSERT/SELECT in which they've been
939 	 * pushed down to the SELECT.
940 	 */
941 	if (list_length(parsetree->rtable) >= 2 &&
942 		strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
943 			   "old") == 0 &&
944 		strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
945 			   "new") == 0)
946 		return parsetree;
947 	Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
948 	if (list_length(parsetree->jointree->fromlist) != 1)
949 		elog(ERROR, "expected to find SELECT subquery");
950 	rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
951 	Assert(IsA(rtr, RangeTblRef));
952 	selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
953 	selectquery = selectrte->subquery;
954 	if (!(selectquery && IsA(selectquery, Query) &&
955 		  selectquery->commandType == CMD_SELECT))
956 		elog(ERROR, "expected to find SELECT subquery");
957 	if (list_length(selectquery->rtable) >= 2 &&
958 		strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
959 			   "old") == 0 &&
960 		strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
961 			   "new") == 0)
962 	{
963 		if (subquery_ptr)
964 			*subquery_ptr = &(selectrte->subquery);
965 		return selectquery;
966 	}
967 	elog(ERROR, "could not find rule placeholders");
968 	return NULL;				/* not reached */
969 }
970 
971 
972 /*
973  * Add the given qualifier condition to the query's WHERE clause
974  */
975 void
AddQual(Query * parsetree,Node * qual)976 AddQual(Query *parsetree, Node *qual)
977 {
978 	Node	   *copy;
979 
980 	if (qual == NULL)
981 		return;
982 
983 	if (parsetree->commandType == CMD_UTILITY)
984 	{
985 		/*
986 		 * There's noplace to put the qual on a utility statement.
987 		 *
988 		 * If it's a NOTIFY, silently ignore the qual; this means that the
989 		 * NOTIFY will execute, whether or not there are any qualifying rows.
990 		 * While clearly wrong, this is much more useful than refusing to
991 		 * execute the rule at all, and extra NOTIFY events are harmless for
992 		 * typical uses of NOTIFY.
993 		 *
994 		 * If it isn't a NOTIFY, error out, since unconditional execution of
995 		 * other utility stmts is unlikely to be wanted.  (This case is not
996 		 * currently allowed anyway, but keep the test for safety.)
997 		 */
998 		if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
999 			return;
1000 		else
1001 			ereport(ERROR,
1002 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1003 					 errmsg("conditional utility statements are not implemented")));
1004 	}
1005 
1006 	if (parsetree->setOperations != NULL)
1007 	{
1008 		/*
1009 		 * There's noplace to put the qual on a setop statement, either. (This
1010 		 * could be fixed, but right now the planner simply ignores any qual
1011 		 * condition on a setop query.)
1012 		 */
1013 		ereport(ERROR,
1014 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1015 				 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
1016 	}
1017 
1018 	/* INTERSECT want's the original, but we need to copy - Jan */
1019 	copy = copyObject(qual);
1020 
1021 	parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
1022 											   copy);
1023 
1024 	/*
1025 	 * We had better not have stuck an aggregate into the WHERE clause.
1026 	 */
1027 	Assert(!contain_aggs_of_level(copy, 0));
1028 
1029 	/*
1030 	 * Make sure query is marked correctly if added qual has sublinks. Need
1031 	 * not search qual when query is already marked.
1032 	 */
1033 	if (!parsetree->hasSubLinks)
1034 		parsetree->hasSubLinks = checkExprHasSubLink(copy);
1035 }
1036 
1037 
1038 /*
1039  * Invert the given clause and add it to the WHERE qualifications of the
1040  * given querytree.  Inversion means "x IS NOT TRUE", not just "NOT x",
1041  * else we will do the wrong thing when x evaluates to NULL.
1042  */
1043 void
AddInvertedQual(Query * parsetree,Node * qual)1044 AddInvertedQual(Query *parsetree, Node *qual)
1045 {
1046 	BooleanTest *invqual;
1047 
1048 	if (qual == NULL)
1049 		return;
1050 
1051 	/* Need not copy input qual, because AddQual will... */
1052 	invqual = makeNode(BooleanTest);
1053 	invqual->arg = (Expr *) qual;
1054 	invqual->booltesttype = IS_NOT_TRUE;
1055 	invqual->location = -1;
1056 
1057 	AddQual(parsetree, (Node *) invqual);
1058 }
1059 
1060 
1061 /*
1062  * replace_rte_variables() finds all Vars in an expression tree
1063  * that reference a particular RTE, and replaces them with substitute
1064  * expressions obtained from a caller-supplied callback function.
1065  *
1066  * When invoking replace_rte_variables on a portion of a Query, pass the
1067  * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
1068  * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
1069  * will then cause an error.
1070  *
1071  * Note: the business with inserted_sublink is needed to update hasSubLinks
1072  * in subqueries when the replacement adds a subquery inside a subquery.
1073  * Messy, isn't it?  We do not need to do similar pushups for hasAggs,
1074  * because it isn't possible for this transformation to insert a level-zero
1075  * aggregate reference into a subquery --- it could only insert outer aggs.
1076  * Likewise for hasWindowFuncs.
1077  *
1078  * Note: usually, we'd not expose the mutator function or context struct
1079  * for a function like this.  We do so because callbacks often find it
1080  * convenient to recurse directly to the mutator on sub-expressions of
1081  * what they will return.
1082  */
1083 Node *
replace_rte_variables(Node * node,int target_varno,int sublevels_up,replace_rte_variables_callback callback,void * callback_arg,bool * outer_hasSubLinks)1084 replace_rte_variables(Node *node, int target_varno, int sublevels_up,
1085 					  replace_rte_variables_callback callback,
1086 					  void *callback_arg,
1087 					  bool *outer_hasSubLinks)
1088 {
1089 	Node	   *result;
1090 	replace_rte_variables_context context;
1091 
1092 	context.callback = callback;
1093 	context.callback_arg = callback_arg;
1094 	context.target_varno = target_varno;
1095 	context.sublevels_up = sublevels_up;
1096 
1097 	/*
1098 	 * We try to initialize inserted_sublink to true if there is no need to
1099 	 * detect new sublinks because the query already has some.
1100 	 */
1101 	if (node && IsA(node, Query))
1102 		context.inserted_sublink = ((Query *) node)->hasSubLinks;
1103 	else if (outer_hasSubLinks)
1104 		context.inserted_sublink = *outer_hasSubLinks;
1105 	else
1106 		context.inserted_sublink = false;
1107 
1108 	/*
1109 	 * Must be prepared to start with a Query or a bare expression tree; if
1110 	 * it's a Query, we don't want to increment sublevels_up.
1111 	 */
1112 	result = query_or_expression_tree_mutator(node,
1113 											  replace_rte_variables_mutator,
1114 											  (void *) &context,
1115 											  0);
1116 
1117 	if (context.inserted_sublink)
1118 	{
1119 		if (result && IsA(result, Query))
1120 			((Query *) result)->hasSubLinks = true;
1121 		else if (outer_hasSubLinks)
1122 			*outer_hasSubLinks = true;
1123 		else
1124 			elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
1125 	}
1126 
1127 	return result;
1128 }
1129 
1130 Node *
replace_rte_variables_mutator(Node * node,replace_rte_variables_context * context)1131 replace_rte_variables_mutator(Node *node,
1132 							  replace_rte_variables_context *context)
1133 {
1134 	if (node == NULL)
1135 		return NULL;
1136 	if (IsA(node, Var))
1137 	{
1138 		Var		   *var = (Var *) node;
1139 
1140 		if (var->varno == context->target_varno &&
1141 			var->varlevelsup == context->sublevels_up)
1142 		{
1143 			/* Found a matching variable, make the substitution */
1144 			Node	   *newnode;
1145 
1146 			newnode = (*context->callback) (var, context);
1147 			/* Detect if we are adding a sublink to query */
1148 			if (!context->inserted_sublink)
1149 				context->inserted_sublink = checkExprHasSubLink(newnode);
1150 			return newnode;
1151 		}
1152 		/* otherwise fall through to copy the var normally */
1153 	}
1154 	else if (IsA(node, CurrentOfExpr))
1155 	{
1156 		CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
1157 
1158 		if (cexpr->cvarno == context->target_varno &&
1159 			context->sublevels_up == 0)
1160 		{
1161 			/*
1162 			 * We get here if a WHERE CURRENT OF expression turns out to apply
1163 			 * to a view.  Someday we might be able to translate the
1164 			 * expression to apply to an underlying table of the view, but
1165 			 * right now it's not implemented.
1166 			 */
1167 			ereport(ERROR,
1168 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1169 					 errmsg("WHERE CURRENT OF on a view is not implemented")));
1170 		}
1171 		/* otherwise fall through to copy the expr normally */
1172 	}
1173 	else if (IsA(node, Query))
1174 	{
1175 		/* Recurse into RTE subquery or not-yet-planned sublink subquery */
1176 		Query	   *newnode;
1177 		bool		save_inserted_sublink;
1178 
1179 		context->sublevels_up++;
1180 		save_inserted_sublink = context->inserted_sublink;
1181 		context->inserted_sublink = ((Query *) node)->hasSubLinks;
1182 		newnode = query_tree_mutator((Query *) node,
1183 									 replace_rte_variables_mutator,
1184 									 (void *) context,
1185 									 0);
1186 		newnode->hasSubLinks |= context->inserted_sublink;
1187 		context->inserted_sublink = save_inserted_sublink;
1188 		context->sublevels_up--;
1189 		return (Node *) newnode;
1190 	}
1191 	return expression_tree_mutator(node, replace_rte_variables_mutator,
1192 								   (void *) context);
1193 }
1194 
1195 
1196 /*
1197  * map_variable_attnos() finds all user-column Vars in an expression tree
1198  * that reference a particular RTE, and adjusts their varattnos according
1199  * to the given mapping array (varattno n is replaced by attno_map[n-1]).
1200  * Vars for system columns are not modified.
1201  *
1202  * A zero in the mapping array represents a dropped column, which should not
1203  * appear in the expression.
1204  *
1205  * If the expression tree contains a whole-row Var for the target RTE,
1206  * *found_whole_row is returned as TRUE.  In addition, if to_rowtype is
1207  * not InvalidOid, we modify the Var's vartype and insert a ConvertRowTypeExpr
1208  * to map back to the orignal rowtype.  Callers that don't provide to_rowtype
1209  * should report an error if *found_row_type is true; we don't do that here
1210  * because we don't know exactly what wording for the error message would
1211  * be most appropriate.  The caller will be aware of the context.
1212  *
1213  * This could be built using replace_rte_variables and a callback function,
1214  * but since we don't ever need to insert sublinks, replace_rte_variables is
1215  * overly complicated.
1216  */
1217 
1218 typedef struct
1219 {
1220 	int			target_varno;	/* RTE index to search for */
1221 	int			sublevels_up;	/* (current) nesting depth */
1222 	const AttrNumber *attno_map;	/* map array for user attnos */
1223 	int			map_length;		/* number of entries in attno_map[] */
1224 	/* Target type when converting whole-row vars */
1225 	Oid			to_rowtype;
1226 	bool	   *found_whole_row;	/* output flag */
1227 } map_variable_attnos_context;
1228 
1229 static Node *
map_variable_attnos_mutator(Node * node,map_variable_attnos_context * context)1230 map_variable_attnos_mutator(Node *node,
1231 							map_variable_attnos_context *context)
1232 {
1233 	if (node == NULL)
1234 		return NULL;
1235 	if (IsA(node, Var))
1236 	{
1237 		Var		   *var = (Var *) node;
1238 
1239 		if (var->varno == context->target_varno &&
1240 			var->varlevelsup == context->sublevels_up)
1241 		{
1242 			/* Found a matching variable, make the substitution */
1243 			Var		   *newvar = (Var *) palloc(sizeof(Var));
1244 			int			attno = var->varattno;
1245 
1246 			*newvar = *var;
1247 			if (attno > 0)
1248 			{
1249 				/* user-defined column, replace attno */
1250 				if (attno > context->map_length ||
1251 					context->attno_map[attno - 1] == 0)
1252 					elog(ERROR, "unexpected varattno %d in expression to be mapped",
1253 						 attno);
1254 				newvar->varattno = newvar->varoattno = context->attno_map[attno - 1];
1255 			}
1256 			else if (attno == 0)
1257 			{
1258 				/* whole-row variable, warn caller */
1259 				*(context->found_whole_row) = true;
1260 
1261 				/* If the callers expects us to convert the same, do so. */
1262 				if (OidIsValid(context->to_rowtype))
1263 				{
1264 					/* No support for RECORDOID. */
1265 					Assert(var->vartype != RECORDOID);
1266 
1267 					/* Don't convert unless necessary. */
1268 					if (context->to_rowtype != var->vartype)
1269 					{
1270 						ConvertRowtypeExpr *r;
1271 
1272 						/* Var itself is converted to the requested type. */
1273 						newvar->vartype = context->to_rowtype;
1274 
1275 						/*
1276 						 * And a conversion node on top to convert back to the
1277 						 * original type.
1278 						 */
1279 						r = makeNode(ConvertRowtypeExpr);
1280 						r->arg = (Expr *) newvar;
1281 						r->resulttype = var->vartype;
1282 						r->convertformat = COERCE_IMPLICIT_CAST;
1283 						r->location = -1;
1284 
1285 						return (Node *) r;
1286 					}
1287 				}
1288 			}
1289 			return (Node *) newvar;
1290 		}
1291 		/* otherwise fall through to copy the var normally */
1292 	}
1293 	else if (IsA(node, Query))
1294 	{
1295 		/* Recurse into RTE subquery or not-yet-planned sublink subquery */
1296 		Query	   *newnode;
1297 
1298 		context->sublevels_up++;
1299 		newnode = query_tree_mutator((Query *) node,
1300 									 map_variable_attnos_mutator,
1301 									 (void *) context,
1302 									 0);
1303 		context->sublevels_up--;
1304 		return (Node *) newnode;
1305 	}
1306 	return expression_tree_mutator(node, map_variable_attnos_mutator,
1307 								   (void *) context);
1308 }
1309 
1310 Node *
map_variable_attnos(Node * node,int target_varno,int sublevels_up,const AttrNumber * attno_map,int map_length,Oid to_rowtype,bool * found_whole_row)1311 map_variable_attnos(Node *node,
1312 					int target_varno, int sublevels_up,
1313 					const AttrNumber *attno_map, int map_length,
1314 					Oid to_rowtype, bool *found_whole_row)
1315 {
1316 	map_variable_attnos_context context;
1317 
1318 	context.target_varno = target_varno;
1319 	context.sublevels_up = sublevels_up;
1320 	context.attno_map = attno_map;
1321 	context.map_length = map_length;
1322 	context.to_rowtype = to_rowtype;
1323 	context.found_whole_row = found_whole_row;
1324 
1325 	*found_whole_row = false;
1326 
1327 	/*
1328 	 * Must be prepared to start with a Query or a bare expression tree; if
1329 	 * it's a Query, we don't want to increment sublevels_up.
1330 	 */
1331 	return query_or_expression_tree_mutator(node,
1332 											map_variable_attnos_mutator,
1333 											(void *) &context,
1334 											0);
1335 }
1336 
1337 
1338 /*
1339  * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
1340  *
1341  * Vars matching target_varno and sublevels_up are replaced by the
1342  * entry with matching resno from targetlist, if there is one.
1343  *
1344  * If there is no matching resno for such a Var, the action depends on the
1345  * nomatch_option:
1346  *	REPLACEVARS_REPORT_ERROR: throw an error
1347  *	REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
1348  *	REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
1349  *
1350  * The caller must also provide target_rte, the RTE describing the target
1351  * relation.  This is needed to handle whole-row Vars referencing the target.
1352  * We expand such Vars into RowExpr constructs.
1353  *
1354  * outer_hasSubLinks works the same as for replace_rte_variables().
1355  */
1356 
1357 typedef struct
1358 {
1359 	RangeTblEntry *target_rte;
1360 	List	   *targetlist;
1361 	ReplaceVarsNoMatchOption nomatch_option;
1362 	int			nomatch_varno;
1363 } ReplaceVarsFromTargetList_context;
1364 
1365 static Node *
ReplaceVarsFromTargetList_callback(Var * var,replace_rte_variables_context * context)1366 ReplaceVarsFromTargetList_callback(Var *var,
1367 								   replace_rte_variables_context *context)
1368 {
1369 	ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
1370 	TargetEntry *tle;
1371 
1372 	if (var->varattno == InvalidAttrNumber)
1373 	{
1374 		/* Must expand whole-tuple reference into RowExpr */
1375 		RowExpr    *rowexpr;
1376 		List	   *colnames;
1377 		List	   *fields;
1378 
1379 		/*
1380 		 * If generating an expansion for a var of a named rowtype (ie, this
1381 		 * is a plain relation RTE), then we must include dummy items for
1382 		 * dropped columns.  If the var is RECORD (ie, this is a JOIN), then
1383 		 * omit dropped columns.  Either way, attach column names to the
1384 		 * RowExpr for use of ruleutils.c.
1385 		 */
1386 		expandRTE(rcon->target_rte,
1387 				  var->varno, var->varlevelsup, var->location,
1388 				  (var->vartype != RECORDOID),
1389 				  &colnames, &fields);
1390 		/* Adjust the generated per-field Vars... */
1391 		fields = (List *) replace_rte_variables_mutator((Node *) fields,
1392 														context);
1393 		rowexpr = makeNode(RowExpr);
1394 		rowexpr->args = fields;
1395 		rowexpr->row_typeid = var->vartype;
1396 		rowexpr->row_format = COERCE_IMPLICIT_CAST;
1397 		rowexpr->colnames = colnames;
1398 		rowexpr->location = var->location;
1399 
1400 		return (Node *) rowexpr;
1401 	}
1402 
1403 	/* Normal case referencing one targetlist element */
1404 	tle = get_tle_by_resno(rcon->targetlist, var->varattno);
1405 
1406 	if (tle == NULL || tle->resjunk)
1407 	{
1408 		/* Failed to find column in targetlist */
1409 		switch (rcon->nomatch_option)
1410 		{
1411 			case REPLACEVARS_REPORT_ERROR:
1412 				/* fall through, throw error below */
1413 				break;
1414 
1415 			case REPLACEVARS_CHANGE_VARNO:
1416 				var = (Var *) copyObject(var);
1417 				var->varno = rcon->nomatch_varno;
1418 				var->varnoold = rcon->nomatch_varno;
1419 				return (Node *) var;
1420 
1421 			case REPLACEVARS_SUBSTITUTE_NULL:
1422 
1423 				/*
1424 				 * If Var is of domain type, we should add a CoerceToDomain
1425 				 * node, in case there is a NOT NULL domain constraint.
1426 				 */
1427 				return coerce_to_domain((Node *) makeNullConst(var->vartype,
1428 															   var->vartypmod,
1429 															   var->varcollid),
1430 										InvalidOid, -1,
1431 										var->vartype,
1432 										COERCE_IMPLICIT_CAST,
1433 										-1,
1434 										false,
1435 										false);
1436 		}
1437 		elog(ERROR, "could not find replacement targetlist entry for attno %d",
1438 			 var->varattno);
1439 		return NULL;			/* keep compiler quiet */
1440 	}
1441 	else
1442 	{
1443 		/* Make a copy of the tlist item to return */
1444 		Expr	   *newnode = copyObject(tle->expr);
1445 
1446 		/* Must adjust varlevelsup if tlist item is from higher query */
1447 		if (var->varlevelsup > 0)
1448 			IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
1449 
1450 		/*
1451 		 * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
1452 		 * and throw error if so.  This case could only happen when expanding
1453 		 * an ON UPDATE rule's NEW variable and the referenced tlist item in
1454 		 * the original UPDATE command is part of a multiple assignment. There
1455 		 * seems no practical way to handle such cases without multiple
1456 		 * evaluation of the multiple assignment's sub-select, which would
1457 		 * create semantic oddities that users of rules would probably prefer
1458 		 * not to cope with.  So treat it as an unimplemented feature.
1459 		 */
1460 		if (contains_multiexpr_param((Node *) newnode, NULL))
1461 			ereport(ERROR,
1462 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1463 					 errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
1464 
1465 		return (Node *) newnode;
1466 	}
1467 }
1468 
1469 Node *
ReplaceVarsFromTargetList(Node * node,int target_varno,int sublevels_up,RangeTblEntry * target_rte,List * targetlist,ReplaceVarsNoMatchOption nomatch_option,int nomatch_varno,bool * outer_hasSubLinks)1470 ReplaceVarsFromTargetList(Node *node,
1471 						  int target_varno, int sublevels_up,
1472 						  RangeTblEntry *target_rte,
1473 						  List *targetlist,
1474 						  ReplaceVarsNoMatchOption nomatch_option,
1475 						  int nomatch_varno,
1476 						  bool *outer_hasSubLinks)
1477 {
1478 	ReplaceVarsFromTargetList_context context;
1479 
1480 	context.target_rte = target_rte;
1481 	context.targetlist = targetlist;
1482 	context.nomatch_option = nomatch_option;
1483 	context.nomatch_varno = nomatch_varno;
1484 
1485 	return replace_rte_variables(node, target_varno, sublevels_up,
1486 								 ReplaceVarsFromTargetList_callback,
1487 								 (void *) &context,
1488 								 outer_hasSubLinks);
1489 }
1490