Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * rewriteManip.c
4 : *
5 : * Portions Copyright (c) 1996-2023, 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 : typedef struct
44 : {
45 : const Bitmapset *target_relids;
46 : const Bitmapset *added_relids;
47 : int sublevels_up;
48 : } add_nulling_relids_context;
49 :
50 : typedef struct
51 : {
52 : const Bitmapset *removable_relids;
53 : const Bitmapset *except_relids;
54 : int sublevels_up;
55 : } remove_nulling_relids_context;
56 :
57 : static bool contain_aggs_of_level_walker(Node *node,
58 : contain_aggs_of_level_context *context);
59 : static bool locate_agg_of_level_walker(Node *node,
60 : locate_agg_of_level_context *context);
61 : static bool contain_windowfuncs_walker(Node *node, void *context);
62 : static bool locate_windowfunc_walker(Node *node,
63 : locate_windowfunc_context *context);
64 : static bool checkExprHasSubLink_walker(Node *node, void *context);
65 : static Relids offset_relid_set(Relids relids, int offset);
66 : static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
67 : static Node *add_nulling_relids_mutator(Node *node,
68 : add_nulling_relids_context *context);
69 : static Node *remove_nulling_relids_mutator(Node *node,
70 : remove_nulling_relids_context *context);
71 :
72 :
73 : /*
74 : * contain_aggs_of_level -
75 : * Check if an expression contains an aggregate function call of a
76 : * specified query level.
77 : *
78 : * The objective of this routine is to detect whether there are aggregates
79 : * belonging to the given query level. Aggregates belonging to subqueries
80 : * or outer queries do NOT cause a true result. We must recurse into
81 : * subqueries to detect outer-reference aggregates that logically belong to
82 : * the specified query level.
83 : */
84 : bool
5343 tgl 85 GIC 1192 : contain_aggs_of_level(Node *node, int levelsup)
86 : {
87 : contain_aggs_of_level_context context;
88 :
89 1192 : context.sublevels_up = levelsup;
90 :
91 : /*
92 : * Must be prepared to start with a Query or a bare expression tree; if
93 : * it's a Query, we don't want to increment sublevels_up.
94 : */
7387 95 1192 : return query_or_expression_tree_walker(node,
96 : contain_aggs_of_level_walker,
97 : (void *) &context,
98 : 0);
99 : }
100 :
101 : static bool
5343 102 5678 : contain_aggs_of_level_walker(Node *node,
5343 tgl 103 ECB : contain_aggs_of_level_context *context)
104 : {
8424 tgl 105 GIC 5678 : if (node == NULL)
106 652 : return false;
8424 tgl 107 CBC 5026 : if (IsA(node, Aggref))
108 : {
7247 tgl 109 UIC 0 : if (((Aggref *) node)->agglevelsup == context->sublevels_up)
6385 bruce 110 0 : return true; /* abort the tree traversal and return true */
111 : /* else fall through to examine argument */
112 : }
2885 andres 113 CBC 5026 : if (IsA(node, GroupingFunc))
114 : {
2885 andres 115 UIC 0 : if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up)
116 0 : return true;
117 : /* else fall through to examine argument */
118 : }
7247 tgl 119 GIC 5026 : if (IsA(node, Query))
7247 tgl 120 ECB : {
121 : /* Recurse into subselects */
122 : bool result;
123 :
7247 tgl 124 CBC 50 : context->sublevels_up++;
125 50 : result = query_tree_walker((Query *) node,
126 : contain_aggs_of_level_walker,
7247 tgl 127 EUB : (void *) context, 0);
7247 tgl 128 GBC 50 : context->sublevels_up--;
7247 tgl 129 GIC 50 : return result;
130 : }
5343 tgl 131 CBC 4976 : return expression_tree_walker(node, contain_aggs_of_level_walker,
132 : (void *) context);
8424 tgl 133 EUB : }
134 :
135 : /*
136 : * locate_agg_of_level -
5333 tgl 137 ECB : * Find the parse location of any aggregate of the specified query level.
138 : *
139 : * Returns -1 if no such agg is in the querytree, or if they all have
140 : * unknown parse location. (The former case is probably caller error,
141 : * but we don't bother to distinguish it from the latter case.)
142 : *
143 : * Note: it might seem appropriate to merge this functionality into
144 : * contain_aggs_of_level, but that would complicate that function's API.
145 : * Currently, the only uses of this function are for error reporting,
146 : * and so shaving cycles probably isn't very important.
147 : */
148 : int
5333 tgl 149 CBC 30 : locate_agg_of_level(Node *node, int levelsup)
150 : {
151 : locate_agg_of_level_context context;
152 :
5050 bruce 153 GIC 30 : context.agg_location = -1; /* in case we find nothing */
5333 tgl 154 30 : context.sublevels_up = levelsup;
155 :
156 : /*
157 : * Must be prepared to start with a Query or a bare expression tree; if
158 : * it's a Query, we don't want to increment sublevels_up.
159 : */
160 30 : (void) query_or_expression_tree_walker(node,
161 : locate_agg_of_level_walker,
162 : (void *) &context,
163 : 0);
164 :
165 30 : return context.agg_location;
166 : }
5333 tgl 167 ECB :
168 : static bool
5333 tgl 169 GIC 120 : locate_agg_of_level_walker(Node *node,
170 : locate_agg_of_level_context *context)
5333 tgl 171 ECB : {
5333 tgl 172 CBC 120 : if (node == NULL)
5333 tgl 173 GIC 6 : return false;
174 114 : if (IsA(node, Aggref))
175 : {
176 27 : if (((Aggref *) node)->agglevelsup == context->sublevels_up &&
177 24 : ((Aggref *) node)->location >= 0)
5333 tgl 178 ECB : {
5333 tgl 179 GIC 24 : context->agg_location = ((Aggref *) node)->location;
180 24 : return true; /* abort the tree traversal and return true */
181 : }
182 : /* else fall through to examine argument */
5333 tgl 183 ECB : }
2885 andres 184 GIC 90 : if (IsA(node, GroupingFunc))
185 : {
2885 andres 186 UIC 0 : if (((GroupingFunc *) node)->agglevelsup == context->sublevels_up &&
2885 andres 187 LBC 0 : ((GroupingFunc *) node)->location >= 0)
188 : {
2885 andres 189 UIC 0 : context->agg_location = ((GroupingFunc *) node)->location;
2885 andres 190 LBC 0 : return true; /* abort the tree traversal and return true */
2885 andres 191 ECB : }
192 : }
5333 tgl 193 GIC 90 : if (IsA(node, Query))
5333 tgl 194 ECB : {
195 : /* Recurse into subselects */
196 : bool result;
197 :
5333 tgl 198 CBC 6 : context->sublevels_up++;
5333 tgl 199 GIC 6 : result = query_tree_walker((Query *) node,
200 : locate_agg_of_level_walker,
201 : (void *) context, 0);
5333 tgl 202 CBC 6 : context->sublevels_up--;
5333 tgl 203 GIC 6 : return result;
5333 tgl 204 EUB : }
5333 tgl 205 GBC 84 : return expression_tree_walker(node, locate_agg_of_level_walker,
206 : (void *) context);
5333 tgl 207 EUB : }
208 :
209 : /*
210 : * contain_windowfuncs -
5215 tgl 211 ECB : * Check if an expression contains a window function call of the
212 : * current query level.
213 : */
214 : bool
3894 tgl 215 GIC 837 : contain_windowfuncs(Node *node)
5215 tgl 216 ECB : {
217 : /*
218 : * Must be prepared to start with a Query or a bare expression tree; if
219 : * it's a Query, we don't want to increment sublevels_up.
220 : */
5215 tgl 221 CBC 837 : return query_or_expression_tree_walker(node,
222 : contain_windowfuncs_walker,
5215 tgl 223 ECB : NULL,
224 : 0);
225 : }
226 :
227 : static bool
5215 tgl 228 GIC 1188 : contain_windowfuncs_walker(Node *node, void *context)
229 : {
230 1188 : if (node == NULL)
231 84 : return false;
232 1104 : if (IsA(node, WindowFunc))
5050 bruce 233 CBC 6 : return true; /* abort the tree traversal and return true */
234 : /* Mustn't recurse into subselects */
5215 tgl 235 GIC 1098 : return expression_tree_walker(node, contain_windowfuncs_walker,
236 : (void *) context);
237 : }
238 :
5215 tgl 239 ECB : /*
240 : * locate_windowfunc -
241 : * Find the parse location of any windowfunc of the current query level.
242 : *
243 : * Returns -1 if no such windowfunc is in the querytree, or if they all have
244 : * unknown parse location. (The former case is probably caller error,
245 : * but we don't bother to distinguish it from the latter case.)
246 : *
247 : * Note: it might seem appropriate to merge this functionality into
248 : * contain_windowfuncs, but that would complicate that function's API.
249 : * Currently, the only uses of this function are for error reporting,
250 : * and so shaving cycles probably isn't very important.
251 : */
252 : int
5215 tgl 253 CBC 3 : locate_windowfunc(Node *node)
254 : {
255 : locate_windowfunc_context context;
256 :
5050 bruce 257 GIC 3 : context.win_location = -1; /* in case we find nothing */
258 :
259 : /*
260 : * Must be prepared to start with a Query or a bare expression tree; if
261 : * it's a Query, we don't want to increment sublevels_up.
262 : */
5215 tgl 263 3 : (void) query_or_expression_tree_walker(node,
264 : locate_windowfunc_walker,
265 : (void *) &context,
266 : 0);
267 :
268 3 : return context.win_location;
269 : }
270 :
5215 tgl 271 ECB : static bool
5215 tgl 272 GIC 3 : locate_windowfunc_walker(Node *node, locate_windowfunc_context *context)
273 : {
274 3 : if (node == NULL)
5215 tgl 275 LBC 0 : return false;
5215 tgl 276 GIC 3 : if (IsA(node, WindowFunc))
277 : {
278 3 : if (((WindowFunc *) node)->location >= 0)
279 : {
280 3 : context->win_location = ((WindowFunc *) node)->location;
5215 tgl 281 CBC 3 : return true; /* abort the tree traversal and return true */
282 : }
283 : /* else fall through to examine argument */
284 : }
285 : /* Mustn't recurse into subselects */
5215 tgl 286 LBC 0 : return expression_tree_walker(node, locate_windowfunc_walker,
287 : (void *) context);
288 : }
289 :
8424 tgl 290 ECB : /*
291 : * checkExprHasSubLink -
6604 292 : * Check if an expression contains a SubLink.
8424 tgl 293 EUB : */
8424 tgl 294 ECB : bool
8424 tgl 295 GIC 51578 : checkExprHasSubLink(Node *node)
8424 tgl 296 ECB : {
297 : /*
5300 298 : * If a Query is passed, examine it --- but we should not recurse into
299 : * sub-Queries that are in its rangetable or CTE list.
300 : */
7387 tgl 301 GIC 51578 : return query_or_expression_tree_walker(node,
302 : checkExprHasSubLink_walker,
303 : NULL,
5300 tgl 304 EUB : QTW_IGNORE_RC_SUBQUERIES);
305 : }
306 :
307 : static bool
8424 tgl 308 GIC 86564 : checkExprHasSubLink_walker(Node *node, void *context)
309 : {
310 86564 : if (node == NULL)
311 1743 : return false;
312 84821 : if (IsA(node, SubLink))
6385 bruce 313 CBC 3161 : return true; /* abort the tree traversal and return true */
8424 tgl 314 GIC 81660 : return expression_tree_walker(node, checkExprHasSubLink_walker, context);
315 : }
316 :
317 : /*
318 : * Check for MULTIEXPR Param within expression tree
3217 tgl 319 ECB : *
320 : * We intentionally don't descend into SubLinks: only Params at the current
321 : * query level are of interest.
322 : */
323 : static bool
3217 tgl 324 GIC 4102 : contains_multiexpr_param(Node *node, void *context)
325 : {
3217 tgl 326 CBC 4102 : if (node == NULL)
3217 tgl 327 GIC 9 : return false;
3217 tgl 328 CBC 4093 : if (IsA(node, Param))
3217 tgl 329 ECB : {
3217 tgl 330 LBC 0 : if (((Param *) node)->paramkind == PARAM_MULTIEXPR)
331 0 : return true; /* abort the tree traversal and return true */
332 0 : return false;
333 : }
3217 tgl 334 GIC 4093 : return expression_tree_walker(node, contains_multiexpr_param, context);
335 : }
336 :
337 : /*
338 : * CombineRangeTables
339 : * Adds the RTEs of 'src_rtable' into 'dst_rtable'
340 : *
341 : * This also adds the RTEPermissionInfos of 'src_perminfos' (belonging to the
342 : * RTEs in 'src_rtable') into *dst_perminfos and also updates perminfoindex of
343 : * the RTEs in 'src_rtable' to now point to the perminfos' indexes in
344 : * *dst_perminfos.
345 : *
346 : * Note that this changes both 'dst_rtable' and 'dst_perminfo' destructively,
347 : * so the caller should have better passed safe-to-modify copies.
348 : */
349 : void
124 alvherre 350 GNC 18811 : CombineRangeTables(List **dst_rtable, List **dst_perminfos,
351 : List *src_rtable, List *src_perminfos)
352 : {
353 : ListCell *l;
354 18811 : int offset = list_length(*dst_perminfos);
355 :
356 18811 : if (offset > 0)
357 : {
358 46089 : foreach(l, src_rtable)
359 : {
360 30915 : RangeTblEntry *rte = lfirst_node(RangeTblEntry, l);
361 :
362 30915 : if (rte->perminfoindex > 0)
363 18337 : rte->perminfoindex += offset;
364 : }
365 : }
366 :
367 18811 : *dst_perminfos = list_concat(*dst_perminfos, src_perminfos);
368 18811 : *dst_rtable = list_concat(*dst_rtable, src_rtable);
369 18811 : }
370 :
371 : /*
372 : * OffsetVarNodes - adjust Vars when appending one query's RT to another
373 : *
374 : * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
8591 tgl 375 ECB : * and increment their varno fields (rangetable indexes) by 'offset'.
376 : * The varnosyn fields are adjusted similarly. Also, adjust other nodes
7384 377 : * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
8591 378 : *
379 : * NOTE: although this has the form of a walker, we cheat and modify the
380 : * nodes in-place. The given expression tree should have been copied
8591 tgl 381 EUB : * earlier to ensure that no unwanted side-effects occur!
382 : */
8882 lockhart 383 :
384 : typedef struct
8397 bruce 385 ECB : {
386 : int offset;
387 : int sublevels_up;
388 : } OffsetVarNodes_context;
389 :
390 : static bool
8591 tgl 391 GIC 994434 : OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
392 : {
393 994434 : if (node == NULL)
394 301540 : return false;
395 692894 : if (IsA(node, Var))
396 : {
397 356047 : Var *var = (Var *) node;
398 :
399 356047 : if (var->varlevelsup == context->sublevels_up)
400 : {
8591 tgl 401 CBC 342896 : var->varno += context->offset;
69 tgl 402 GNC 342896 : var->varnullingrels = offset_relid_set(var->varnullingrels,
403 : context->offset);
1186 tgl 404 GIC 342896 : if (var->varnosyn > 0)
405 342896 : var->varnosyn += context->offset;
406 : }
8591 tgl 407 CBC 356047 : return false;
408 : }
5781 409 336847 : if (IsA(node, CurrentOfExpr))
410 : {
5781 tgl 411 LBC 0 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
412 :
413 0 : if (context->sublevels_up == 0)
5781 tgl 414 UIC 0 : cexpr->cvarno += context->offset;
5781 tgl 415 LBC 0 : return false;
5781 tgl 416 ECB : }
8244 tgl 417 GIC 336847 : if (IsA(node, RangeTblRef))
418 : {
8053 bruce 419 29780 : RangeTblRef *rtr = (RangeTblRef *) node;
8397 bruce 420 ECB :
8244 tgl 421 CBC 29780 : if (context->sublevels_up == 0)
422 25462 : rtr->rtindex += context->offset;
423 : /* the subquery itself is visited separately */
8591 tgl 424 GIC 29780 : return false;
425 : }
7698 426 307067 : if (IsA(node, JoinExpr))
427 : {
7522 bruce 428 6867 : JoinExpr *j = (JoinExpr *) node;
429 :
5156 tgl 430 6867 : if (j->rtindex && context->sublevels_up == 0)
7698 431 6109 : j->rtindex += context->offset;
432 : /* fall through to examine children */
433 : }
5283 434 307067 : if (IsA(node, PlaceHolderVar))
435 : {
436 202 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
437 :
438 202 : if (phv->phlevelsup == context->sublevels_up)
439 : {
440 166 : phv->phrels = offset_relid_set(phv->phrels,
441 : context->offset);
69 tgl 442 GNC 166 : phv->phnullingrels = offset_relid_set(phv->phnullingrels,
443 : context->offset);
444 : }
445 : /* fall through to examine children */
5283 tgl 446 ECB : }
6277 tgl 447 GIC 307067 : if (IsA(node, AppendRelInfo))
6277 tgl 448 ECB : {
6277 tgl 449 CBC 196 : AppendRelInfo *appinfo = (AppendRelInfo *) node;
6277 tgl 450 ECB :
6277 tgl 451 GIC 196 : if (context->sublevels_up == 0)
6277 tgl 452 ECB : {
6277 tgl 453 GIC 196 : appinfo->parent_relid += context->offset;
6277 tgl 454 CBC 196 : appinfo->child_relid += context->offset;
455 : }
6277 tgl 456 ECB : /* fall through to examine children */
457 : }
458 : /* Shouldn't need to handle other planner auxiliary nodes here */
4236 tgl 459 CBC 307067 : Assert(!IsA(node, PlanRowMark));
5282 460 307067 : Assert(!IsA(node, SpecialJoinInfo));
5282 tgl 461 GIC 307067 : Assert(!IsA(node, PlaceHolderInfo));
4539 tgl 462 CBC 307067 : Assert(!IsA(node, MinMaxAggInfo));
463 :
8591 464 307067 : if (IsA(node, Query))
465 : {
8244 tgl 466 EUB : /* Recurse into subselects */
467 : bool result;
8591 468 :
8244 tgl 469 GBC 4134 : context->sublevels_up++;
470 4134 : result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
471 : (void *) context, 0);
8244 tgl 472 CBC 4134 : context->sublevels_up--;
8244 tgl 473 GIC 4134 : return result;
8591 tgl 474 ECB : }
8591 tgl 475 GIC 302933 : return expression_tree_walker(node, OffsetVarNodes_walker,
8591 tgl 476 ECB : (void *) context);
9770 scrappy 477 : }
478 :
479 : void
8591 tgl 480 GIC 36378 : OffsetVarNodes(Node *node, int offset, int sublevels_up)
9770 scrappy 481 ECB : {
482 : OffsetVarNodes_context context;
8936 bruce 483 :
8591 tgl 484 GIC 36378 : context.offset = offset;
8591 tgl 485 CBC 36378 : context.sublevels_up = sublevels_up;
8244 tgl 486 ECB :
487 : /*
488 : * Must be prepared to start with a Query or a bare expression tree; if
6385 bruce 489 : * it's a Query, go straight to query_tree_walker to make sure that
490 : * sublevels_up doesn't get incremented prematurely.
8244 tgl 491 : */
8244 tgl 492 GIC 36378 : if (node && IsA(node, Query))
8159 tgl 493 CBC 18189 : {
8053 bruce 494 GIC 18189 : Query *qry = (Query *) node;
8159 tgl 495 ECB :
496 : /*
6385 bruce 497 : * If we are starting at a Query, and sublevels_up is zero, then we
498 : * must also fix rangetable indexes in the Query itself --- namely
499 : * resultRelation, exclRelIndex and rowMarks entries. sublevels_up
500 : * cannot be zero when recursing into a subquery, so there's no need
501 : * to have the same logic inside OffsetVarNodes_walker.
8159 tgl 502 : */
8159 tgl 503 GIC 18189 : if (sublevels_up == 0)
8159 tgl 504 ECB : {
505 : ListCell *l;
6892 neilc 506 :
8159 tgl 507 GIC 18189 : if (qry->resultRelation)
8159 tgl 508 CBC 612 : qry->resultRelation += offset;
2888 andres 509 ECB :
2888 andres 510 GIC 18189 : if (qry->onConflict && qry->onConflict->exclRelIndex)
511 18 : qry->onConflict->exclRelIndex += offset;
512 :
8159 tgl 513 18263 : foreach(l, qry->rowMarks)
6188 tgl 514 ECB : {
6188 tgl 515 CBC 74 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
6188 tgl 516 ECB :
6188 tgl 517 CBC 74 : rc->rti += offset;
518 : }
8159 tgl 519 ECB : }
8159 tgl 520 GIC 18189 : query_tree_walker(qry, OffsetVarNodes_walker,
521 : (void *) &context, 0);
522 : }
523 : else
8244 tgl 524 CBC 18189 : OffsetVarNodes_walker(node, &context);
8591 525 36378 : }
526 :
7365 tgl 527 ECB : static Relids
7365 tgl 528 CBC 343228 : offset_relid_set(Relids relids, int offset)
529 : {
530 343228 : Relids result = NULL;
531 : int rtindex;
532 :
3054 tgl 533 GIC 343228 : rtindex = -1;
534 387454 : while ((rtindex = bms_next_member(relids, rtindex)) >= 0)
7365 tgl 535 CBC 44226 : result = bms_add_member(result, rtindex + offset);
7365 tgl 536 GIC 343228 : return result;
537 : }
538 :
8591 tgl 539 ECB : /*
540 : * ChangeVarNodes - adjust Var nodes for a specific change of RT index
541 : *
542 : * Find all Var nodes in the given tree belonging to a specific relation
543 : * (identified by sublevels_up and rt_index), and change their varno fields
544 : * to 'new_index'. The varnosyn fields are changed too. Also, adjust other
545 : * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
546 : *
547 : * NOTE: although this has the form of a walker, we cheat and modify the
3260 bruce 548 : * nodes in-place. The given expression tree should have been copied
8591 tgl 549 : * earlier to ensure that no unwanted side-effects occur!
550 : */
551 :
552 : typedef struct
553 : {
554 : int rt_index;
555 : int new_index;
556 : int sublevels_up;
557 : } ChangeVarNodes_context;
8936 bruce 558 :
559 : static bool
8591 tgl 560 GIC 100723 : ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
561 : {
8591 tgl 562 CBC 100723 : if (node == NULL)
563 34161 : return false;
8591 tgl 564 GIC 66562 : if (IsA(node, Var))
8591 tgl 565 ECB : {
8591 tgl 566 CBC 18503 : Var *var = (Var *) node;
567 :
69 tgl 568 GNC 18503 : if (var->varlevelsup == context->sublevels_up)
8591 tgl 569 ECB : {
69 tgl 570 GNC 17606 : if (var->varno == context->rt_index)
571 13464 : var->varno = context->new_index;
572 17606 : var->varnullingrels = adjust_relid_set(var->varnullingrels,
573 : context->rt_index,
574 : context->new_index);
1186 tgl 575 GIC 17606 : if (var->varnosyn == context->rt_index)
576 13464 : var->varnosyn = context->new_index;
8591 tgl 577 ECB : }
8591 tgl 578 GIC 18503 : return false;
579 : }
5781 580 48059 : if (IsA(node, CurrentOfExpr))
5781 tgl 581 ECB : {
5781 tgl 582 LBC 0 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
583 :
5781 tgl 584 UIC 0 : if (context->sublevels_up == 0 &&
5781 tgl 585 LBC 0 : cexpr->cvarno == context->rt_index)
5781 tgl 586 UIC 0 : cexpr->cvarno = context->new_index;
5781 tgl 587 LBC 0 : return false;
588 : }
8244 tgl 589 GIC 48059 : if (IsA(node, RangeTblRef))
8591 tgl 590 ECB : {
8053 bruce 591 CBC 1661 : RangeTblRef *rtr = (RangeTblRef *) node;
8397 bruce 592 ECB :
8244 tgl 593 CBC 1661 : if (context->sublevels_up == 0 &&
8244 tgl 594 GIC 1103 : rtr->rtindex == context->rt_index)
595 820 : rtr->rtindex = context->new_index;
596 : /* the subquery itself is visited separately */
8591 597 1661 : return false;
598 : }
7698 599 46398 : if (IsA(node, JoinExpr))
600 : {
7522 bruce 601 UIC 0 : JoinExpr *j = (JoinExpr *) node;
602 :
7698 tgl 603 0 : if (context->sublevels_up == 0 &&
604 0 : j->rtindex == context->rt_index)
605 0 : j->rtindex = context->new_index;
606 : /* fall through to examine children */
607 : }
5283 tgl 608 GIC 46398 : if (IsA(node, PlaceHolderVar))
609 : {
5283 tgl 610 UIC 0 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
611 :
612 0 : if (phv->phlevelsup == context->sublevels_up)
613 : {
614 0 : phv->phrels = adjust_relid_set(phv->phrels,
615 : context->rt_index,
616 : context->new_index);
69 tgl 617 UNC 0 : phv->phnullingrels = adjust_relid_set(phv->phnullingrels,
618 : context->rt_index,
619 : context->new_index);
5283 tgl 620 ECB : }
621 : /* fall through to examine children */
622 : }
4236 tgl 623 CBC 46398 : if (IsA(node, PlanRowMark))
4236 tgl 624 ECB : {
4236 tgl 625 UIC 0 : PlanRowMark *rowmark = (PlanRowMark *) node;
4236 tgl 626 ECB :
4236 tgl 627 UIC 0 : if (context->sublevels_up == 0)
4236 tgl 628 ECB : {
4236 tgl 629 UIC 0 : if (rowmark->rti == context->rt_index)
4236 tgl 630 LBC 0 : rowmark->rti = context->new_index;
631 0 : if (rowmark->prti == context->rt_index)
632 0 : rowmark->prti = context->new_index;
633 : }
4236 tgl 634 UIC 0 : return false;
4236 tgl 635 ECB : }
6277 tgl 636 CBC 46398 : if (IsA(node, AppendRelInfo))
637 : {
6277 tgl 638 LBC 0 : AppendRelInfo *appinfo = (AppendRelInfo *) node;
639 :
640 0 : if (context->sublevels_up == 0)
641 : {
6277 tgl 642 UBC 0 : if (appinfo->parent_relid == context->rt_index)
6277 tgl 643 UIC 0 : appinfo->parent_relid = context->new_index;
6277 tgl 644 UBC 0 : if (appinfo->child_relid == context->rt_index)
645 0 : appinfo->child_relid = context->new_index;
6277 tgl 646 EUB : }
647 : /* fall through to examine children */
648 : }
5282 tgl 649 ECB : /* Shouldn't need to handle other planner auxiliary nodes here */
5282 tgl 650 GIC 46398 : Assert(!IsA(node, SpecialJoinInfo));
5282 tgl 651 CBC 46398 : Assert(!IsA(node, PlaceHolderInfo));
4539 tgl 652 GIC 46398 : Assert(!IsA(node, MinMaxAggInfo));
5283 tgl 653 ECB :
8591 tgl 654 CBC 46398 : if (IsA(node, Query))
8591 tgl 655 ECB : {
656 : /* Recurse into subselects */
8244 657 : bool result;
658 :
8244 tgl 659 CBC 558 : context->sublevels_up++;
8244 tgl 660 GIC 558 : result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
7515 tgl 661 EUB : (void *) context, 0);
8244 tgl 662 GIC 558 : context->sublevels_up--;
8244 tgl 663 GBC 558 : return result;
8591 tgl 664 EUB : }
8591 tgl 665 GBC 45840 : return expression_tree_walker(node, ChangeVarNodes_walker,
666 : (void *) context);
667 : }
9770 scrappy 668 ECB :
669 : void
8591 tgl 670 GBC 9836 : ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
671 : {
8591 tgl 672 EUB : ChangeVarNodes_context context;
673 :
8591 tgl 674 GBC 9836 : context.rt_index = rt_index;
8591 tgl 675 GIC 9836 : context.new_index = new_index;
676 9836 : context.sublevels_up = sublevels_up;
8244 tgl 677 EUB :
678 : /*
679 : * Must be prepared to start with a Query or a bare expression tree; if
680 : * it's a Query, go straight to query_tree_walker to make sure that
681 : * sublevels_up doesn't get incremented prematurely.
682 : */
8244 tgl 683 CBC 9836 : if (node && IsA(node, Query))
8159 tgl 684 GIC 1804 : {
8053 bruce 685 GBC 1804 : Query *qry = (Query *) node;
686 :
8159 tgl 687 EUB : /*
688 : * If we are starting at a Query, and sublevels_up is zero, then we
6385 bruce 689 : * must also fix rangetable indexes in the Query itself --- namely
690 : * resultRelation and rowMarks entries. sublevels_up cannot be zero
691 : * when recursing into a subquery, so there's no need to have the same
692 : * logic inside ChangeVarNodes_walker.
693 : */
8159 tgl 694 GBC 1804 : if (sublevels_up == 0)
695 : {
6892 neilc 696 ECB : ListCell *l;
697 :
8159 tgl 698 GBC 1804 : if (qry->resultRelation == rt_index)
8159 tgl 699 GIC 1138 : qry->resultRelation = new_index;
2888 andres 700 EUB :
701 : /* this is unlikely to ever be used, but ... */
2888 andres 702 GBC 1804 : if (qry->onConflict && qry->onConflict->exclRelIndex == rt_index)
2888 andres 703 UBC 0 : qry->onConflict->exclRelIndex = new_index;
2888 andres 704 EUB :
8159 tgl 705 GBC 1810 : foreach(l, qry->rowMarks)
706 : {
6188 tgl 707 GIC 6 : RowMarkClause *rc = (RowMarkClause *) lfirst(l);
708 :
709 6 : if (rc->rti == rt_index)
6188 tgl 710 LBC 0 : rc->rti = new_index;
8159 tgl 711 ECB : }
712 : }
8159 tgl 713 GIC 1804 : query_tree_walker(qry, ChangeVarNodes_walker,
7515 tgl 714 ECB : (void *) &context, 0);
715 : }
716 : else
8244 tgl 717 GIC 8032 : ChangeVarNodes_walker(node, &context);
8591 718 9836 : }
8936 bruce 719 ECB :
7365 tgl 720 : /*
721 : * Substitute newrelid for oldrelid in a Relid set
722 : */
723 : static Relids
7365 tgl 724 GIC 17606 : adjust_relid_set(Relids relids, int oldrelid, int newrelid)
7365 tgl 725 ECB : {
7365 tgl 726 GIC 17606 : if (bms_is_member(oldrelid, relids))
727 : {
728 : /* Ensure we have a modifiable copy */
7365 tgl 729 UIC 0 : relids = bms_copy(relids);
7365 tgl 730 ECB : /* Remove old, add new */
7365 tgl 731 UIC 0 : relids = bms_del_member(relids, oldrelid);
732 0 : relids = bms_add_member(relids, newrelid);
733 : }
7365 tgl 734 CBC 17606 : return relids;
7365 tgl 735 ECB : }
736 :
737 : /*
738 : * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
739 : *
740 : * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
741 : * and add delta_sublevels_up to their varlevelsup value. This is needed when
742 : * an expression that's correct for some nesting level is inserted into a
8424 743 : * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
744 : * all Vars are affected. The point of min_sublevels_up is that we can
745 : * increment it when we recurse into a sublink, so that local variables in
746 : * that sublink are not affected, only outer references to vars that belong
747 : * to the expression's original query level or parents thereof.
748 : *
749 : * Likewise for other nodes containing levelsup fields, such as Aggref.
750 : *
751 : * NOTE: although this has the form of a walker, we cheat and modify the
752 : * Var nodes in-place. The given expression tree should have been copied
753 : * earlier to ensure that no unwanted side-effects occur!
754 : */
755 :
756 : typedef struct
757 : {
758 : int delta_sublevels_up;
759 : int min_sublevels_up;
760 : } IncrementVarSublevelsUp_context;
761 :
762 : static bool
8424 tgl 763 GBC 1138928 : IncrementVarSublevelsUp_walker(Node *node,
764 : IncrementVarSublevelsUp_context *context)
8424 tgl 765 ECB : {
8424 tgl 766 GIC 1138928 : if (node == NULL)
8424 tgl 767 CBC 333670 : return false;
8424 tgl 768 GIC 805258 : if (IsA(node, Var))
8424 tgl 769 ECB : {
8424 tgl 770 GBC 390681 : Var *var = (Var *) node;
771 :
8424 tgl 772 GIC 390681 : if (var->varlevelsup >= context->min_sublevels_up)
8424 tgl 773 CBC 4408 : var->varlevelsup += context->delta_sublevels_up;
7247 tgl 774 GIC 390681 : return false; /* done here */
775 : }
5781 776 414577 : if (IsA(node, CurrentOfExpr))
5781 tgl 777 ECB : {
778 : /* this should not happen */
5781 tgl 779 UIC 0 : if (context->min_sublevels_up == 0)
780 0 : elog(ERROR, "cannot push down CurrentOfExpr");
781 0 : return false;
782 : }
7247 tgl 783 GIC 414577 : if (IsA(node, Aggref))
7247 tgl 784 ECB : {
7247 tgl 785 GIC 1123 : Aggref *agg = (Aggref *) node;
7247 tgl 786 ECB :
7247 tgl 787 GIC 1123 : if (agg->agglevelsup >= context->min_sublevels_up)
788 35 : agg->agglevelsup += context->delta_sublevels_up;
7247 tgl 789 EUB : /* fall through to recurse into argument */
790 : }
2885 andres 791 GBC 414577 : if (IsA(node, GroupingFunc))
2885 andres 792 EUB : {
2878 bruce 793 GIC 32 : GroupingFunc *grp = (GroupingFunc *) node;
2885 andres 794 ECB :
2885 andres 795 GIC 32 : if (grp->agglevelsup >= context->min_sublevels_up)
796 32 : grp->agglevelsup += context->delta_sublevels_up;
797 : /* fall through to recurse into argument */
798 : }
5283 tgl 799 414577 : if (IsA(node, PlaceHolderVar))
800 : {
801 374 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
802 :
803 374 : if (phv->phlevelsup >= context->min_sublevels_up)
804 208 : phv->phlevelsup += context->delta_sublevels_up;
805 : /* fall through to recurse into argument */
806 : }
5300 807 414577 : if (IsA(node, RangeTblEntry))
808 : {
809 42586 : RangeTblEntry *rte = (RangeTblEntry *) node;
810 :
811 42586 : if (rte->rtekind == RTE_CTE)
812 : {
813 1108 : if (rte->ctelevelsup >= context->min_sublevels_up)
814 1093 : rte->ctelevelsup += context->delta_sublevels_up;
815 : }
816 42586 : return false; /* allow range_table_walker to continue */
817 : }
8244 818 371991 : if (IsA(node, Query))
819 : {
820 : /* Recurse into subselects */
821 : bool result;
822 :
8244 tgl 823 CBC 6228 : context->min_sublevels_up++;
8244 tgl 824 GIC 6228 : result = query_tree_walker((Query *) node,
825 : IncrementVarSublevelsUp_walker,
5300 tgl 826 ECB : (void *) context,
1535 827 : QTW_EXAMINE_RTES_BEFORE);
8244 tgl 828 CBC 6228 : context->min_sublevels_up--;
8244 tgl 829 GIC 6228 : return result;
8244 tgl 830 ECB : }
8244 tgl 831 GIC 365763 : return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
8244 tgl 832 ECB : (void *) context);
833 : }
834 :
835 : void
8244 tgl 836 CBC 38205 : IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
837 : int min_sublevels_up)
838 : {
8244 tgl 839 EUB : IncrementVarSublevelsUp_context context;
840 :
8244 tgl 841 GBC 38205 : context.delta_sublevels_up = delta_sublevels_up;
8244 tgl 842 GIC 38205 : context.min_sublevels_up = min_sublevels_up;
8244 tgl 843 ECB :
844 : /*
6385 bruce 845 : * Must be prepared to start with a Query or a bare expression tree; if
846 : * it's a Query, we don't want to increment sublevels_up.
8244 tgl 847 : */
7387 tgl 848 CBC 38205 : query_or_expression_tree_walker(node,
849 : IncrementVarSublevelsUp_walker,
850 : (void *) &context,
1535 tgl 851 ECB : QTW_EXAMINE_RTES_BEFORE);
8244 tgl 852 GIC 38205 : }
8244 tgl 853 ECB :
854 : /*
5351 heikki.linnakangas 855 : * IncrementVarSublevelsUp_rtable -
856 : * Same as IncrementVarSublevelsUp, but to be invoked on a range table.
857 : */
858 : void
5351 heikki.linnakangas 859 CBC 625 : IncrementVarSublevelsUp_rtable(List *rtable, int delta_sublevels_up,
860 : int min_sublevels_up)
5351 heikki.linnakangas 861 ECB : {
862 : IncrementVarSublevelsUp_context context;
863 :
5351 heikki.linnakangas 864 CBC 625 : context.delta_sublevels_up = delta_sublevels_up;
5351 heikki.linnakangas 865 GIC 625 : context.min_sublevels_up = min_sublevels_up;
866 :
5351 heikki.linnakangas 867 CBC 625 : range_table_walker(rtable,
868 : IncrementVarSublevelsUp_walker,
5351 heikki.linnakangas 869 ECB : (void *) &context,
870 : QTW_EXAMINE_RTES_BEFORE);
5351 heikki.linnakangas 871 CBC 625 : }
872 :
8244 tgl 873 ECB :
874 : /*
875 : * rangeTableEntry_used - detect whether an RTE is referenced somewhere
8221 876 : * in var nodes or join or setOp trees of a query or expression.
877 : */
8244 878 :
879 : typedef struct
880 : {
881 : int rt_index;
882 : int sublevels_up;
883 : } rangeTableEntry_used_context;
884 :
885 : static bool
8244 tgl 886 GIC 1455721 : rangeTableEntry_used_walker(Node *node,
887 : rangeTableEntry_used_context *context)
8244 tgl 888 ECB : {
8244 tgl 889 CBC 1455721 : if (node == NULL)
8244 tgl 890 GIC 242072 : return false;
8244 tgl 891 CBC 1213649 : if (IsA(node, Var))
892 : {
8244 tgl 893 GIC 344292 : Var *var = (Var *) node;
894 :
895 344292 : if (var->varlevelsup == context->sublevels_up &&
69 tgl 896 GNC 537529 : (var->varno == context->rt_index ||
897 206570 : bms_is_member(context->rt_index, var->varnullingrels)))
8424 tgl 898 GIC 124389 : return true;
899 219903 : return false;
900 : }
5781 901 869357 : if (IsA(node, CurrentOfExpr))
5781 tgl 902 ECB : {
5781 tgl 903 CBC 6 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
904 :
5781 tgl 905 GIC 6 : if (context->sublevels_up == 0 &&
906 6 : cexpr->cvarno == context->rt_index)
5781 tgl 907 UIC 0 : return true;
5781 tgl 908 GIC 6 : return false;
5781 tgl 909 ECB : }
8244 tgl 910 GIC 869351 : if (IsA(node, RangeTblRef))
911 : {
912 47999 : RangeTblRef *rtr = (RangeTblRef *) node;
8424 tgl 913 ECB :
8244 tgl 914 GIC 47999 : if (rtr->rtindex == context->rt_index &&
915 25649 : context->sublevels_up == 0)
8424 916 25032 : return true;
917 : /* the subquery itself is visited separately */
8244 918 22967 : return false;
919 : }
7698 tgl 920 CBC 821352 : if (IsA(node, JoinExpr))
921 : {
7522 bruce 922 GIC 15618 : JoinExpr *j = (JoinExpr *) node;
923 :
7698 tgl 924 15618 : if (j->rtindex == context->rt_index &&
7698 tgl 925 CBC 33 : context->sublevels_up == 0)
7698 tgl 926 LBC 0 : return true;
927 : /* fall through to examine children */
7698 tgl 928 ECB : }
929 : /* Shouldn't need to handle planner auxiliary nodes here */
5283 tgl 930 GIC 821352 : Assert(!IsA(node, PlaceHolderVar));
4236 931 821352 : Assert(!IsA(node, PlanRowMark));
5351 tgl 932 CBC 821352 : Assert(!IsA(node, SpecialJoinInfo));
6277 tgl 933 GIC 821352 : Assert(!IsA(node, AppendRelInfo));
5283 934 821352 : Assert(!IsA(node, PlaceHolderInfo));
4539 935 821352 : Assert(!IsA(node, MinMaxAggInfo));
936 :
8244 937 821352 : if (IsA(node, Query))
938 : {
939 : /* Recurse into subselects */
940 : bool result;
941 :
942 5195 : context->sublevels_up++;
943 5195 : result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
944 : (void *) context, 0);
945 5195 : context->sublevels_up--;
946 5195 : return result;
8244 tgl 947 ECB : }
8244 tgl 948 GIC 816157 : return expression_tree_walker(node, rangeTableEntry_used_walker,
949 : (void *) context);
8244 tgl 950 ECB : }
951 :
952 : bool
8244 tgl 953 GIC 157558 : rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
8244 tgl 954 ECB : {
955 : rangeTableEntry_used_context context;
956 :
8244 tgl 957 CBC 157558 : context.rt_index = rt_index;
958 157558 : context.sublevels_up = sublevels_up;
8244 tgl 959 ECB :
960 : /*
961 : * Must be prepared to start with a Query or a bare expression tree; if
6385 bruce 962 : * it's a Query, we don't want to increment sublevels_up.
963 : */
7387 tgl 964 CBC 157558 : return query_or_expression_tree_walker(node,
965 : rangeTableEntry_used_walker,
7387 tgl 966 ECB : (void *) &context,
967 : 0);
8244 tgl 968 EUB : }
8244 tgl 969 ECB :
970 :
8160 971 : /*
972 : * If the given Query is an INSERT ... SELECT construct, extract and
973 : * return the sub-Query node that represents the SELECT part. Otherwise
974 : * return the given Query.
975 : *
976 : * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
977 : * of the link to the SELECT subquery inside parsetree, or NULL if not an
978 : * INSERT ... SELECT.
979 : *
980 : * This is a hack needed because transformations on INSERT ... SELECTs that
981 : * appear in rule actions should be applied to the source SELECT, not to the
982 : * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
983 : */
984 : Query *
8160 tgl 985 CBC 2194 : getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
8160 tgl 986 ECB : {
8160 tgl 987 EUB : Query *selectquery;
988 : RangeTblEntry *selectrte;
989 : RangeTblRef *rtr;
990 :
8160 tgl 991 CBC 2194 : if (subquery_ptr)
992 666 : *subquery_ptr = NULL;
8160 tgl 993 ECB :
8160 tgl 994 CBC 2194 : if (parsetree == NULL)
8160 tgl 995 LBC 0 : return parsetree;
8160 tgl 996 CBC 2194 : if (parsetree->commandType != CMD_INSERT)
8160 tgl 997 GIC 1230 : return parsetree;
8053 bruce 998 ECB :
999 : /*
1000 : * Currently, this is ONLY applied to rule-action queries, and so we
1001 : * expect to find the OLD and NEW placeholder entries in the given query.
1002 : * If they're not there, it must be an INSERT/SELECT in which they've been
4790 1003 : * pushed down to the SELECT.
8160 tgl 1004 : */
6888 neilc 1005 GIC 964 : if (list_length(parsetree->rtable) >= 2 &&
6385 bruce 1006 CBC 964 : strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
4903 tgl 1007 882 : "old") == 0 &&
6385 bruce 1008 GIC 882 : strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
4903 tgl 1009 ECB : "new") == 0)
8160 tgl 1010 GIC 882 : return parsetree;
1011 82 : Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
6888 neilc 1012 82 : if (list_length(parsetree->jointree->fromlist) != 1)
7198 tgl 1013 UIC 0 : elog(ERROR, "expected to find SELECT subquery");
6892 neilc 1014 CBC 82 : rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
45 dean.a.rasheed 1015 GIC 82 : if (!IsA(rtr, RangeTblRef))
45 dean.a.rasheed 1016 UIC 0 : elog(ERROR, "expected to find SELECT subquery");
8160 tgl 1017 GIC 82 : selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
45 dean.a.rasheed 1018 CBC 82 : if (!(selectrte->rtekind == RTE_SUBQUERY &&
1019 82 : selectrte->subquery &&
45 dean.a.rasheed 1020 GIC 82 : IsA(selectrte->subquery, Query) &&
1021 82 : selectrte->subquery->commandType == CMD_SELECT))
7198 tgl 1022 UIC 0 : elog(ERROR, "expected to find SELECT subquery");
45 dean.a.rasheed 1023 GIC 82 : selectquery = selectrte->subquery;
6888 neilc 1024 82 : if (list_length(selectquery->rtable) >= 2 &&
6385 bruce 1025 CBC 82 : strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
4903 tgl 1026 GIC 82 : "old") == 0 &&
6385 bruce 1027 82 : strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
1028 : "new") == 0)
1029 : {
8160 tgl 1030 82 : if (subquery_ptr)
8053 bruce 1031 30 : *subquery_ptr = &(selectrte->subquery);
8160 tgl 1032 82 : return selectquery;
1033 : }
7198 tgl 1034 UIC 0 : elog(ERROR, "could not find rule placeholders");
1035 : return NULL; /* not reached */
1036 : }
1037 :
1038 :
1039 : /*
1040 : * Add the given qualifier condition to the query's WHERE clause
1041 : */
1042 : void
9344 bruce 1043 GIC 1699 : AddQual(Query *parsetree, Node *qual)
1044 : {
1045 : Node *copy;
9345 bruce 1046 ECB :
9345 bruce 1047 GIC 1699 : if (qual == NULL)
1048 831 : return;
1049 :
8107 tgl 1050 868 : if (parsetree->commandType == CMD_UTILITY)
1051 : {
8107 tgl 1052 ECB : /*
7884 1053 : * There's noplace to put the qual on a utility statement.
1054 : *
6347 bruce 1055 : * If it's a NOTIFY, silently ignore the qual; this means that the
6347 bruce 1056 EUB : * NOTIFY will execute, whether or not there are any qualifying rows.
6347 bruce 1057 ECB : * While clearly wrong, this is much more useful than refusing to
1058 : * execute the rule at all, and extra NOTIFY events are harmless for
1059 : * typical uses of NOTIFY.
1060 : *
1061 : * If it isn't a NOTIFY, error out, since unconditional execution of
1062 : * other utility stmts is unlikely to be wanted. (This case is not
1063 : * currently allowed anyway, but keep the test for safety.)
1064 : */
8107 tgl 1065 UIC 0 : if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
7884 tgl 1066 LBC 0 : return;
8107 tgl 1067 ECB : else
7198 tgl 1068 LBC 0 : ereport(ERROR,
7198 tgl 1069 ECB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1070 : errmsg("conditional utility statements are not implemented")));
8107 1071 : }
1072 :
7207 tgl 1073 CBC 868 : if (parsetree->setOperations != NULL)
7207 tgl 1074 EUB : {
7207 tgl 1075 ECB : /*
6385 bruce 1076 : * There's noplace to put the qual on a setop statement, either. (This
6385 bruce 1077 EUB : * could be fixed, but right now the planner simply ignores any qual
6385 bruce 1078 ECB : * condition on a setop query.)
7207 tgl 1079 : */
7198 tgl 1080 LBC 0 : ereport(ERROR,
7198 tgl 1081 ECB : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1082 : errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
7207 tgl 1083 EUB : }
7207 tgl 1084 ECB :
1406 michael 1085 : /* INTERSECT wants the original, but we need to copy - Jan */
8826 JanWieck 1086 CBC 868 : copy = copyObject(qual);
8847 bruce 1087 ECB :
8227 tgl 1088 CBC 868 : parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
1089 : copy);
1090 :
8424 tgl 1091 ECB : /*
6604 1092 : * We had better not have stuck an aggregate into the WHERE clause.
8424 1093 : */
3894 tgl 1094 GIC 868 : Assert(!contain_aggs_of_level(copy, 0));
8424 tgl 1095 EUB :
1096 : /*
1097 : * Make sure query is marked correctly if added qual has sublinks. Need
1098 : * not search qual when query is already marked.
1099 : */
7111 tgl 1100 GIC 868 : if (!parsetree->hasSubLinks)
1101 865 : parsetree->hasSubLinks = checkExprHasSubLink(copy);
1102 : }
1103 :
9030 bruce 1104 ECB :
1105 : /*
1106 : * Invert the given clause and add it to the WHERE qualifications of the
1107 : * given querytree. Inversion means "x IS NOT TRUE", not just "NOT x",
7476 tgl 1108 : * else we will do the wrong thing when x evaluates to NULL.
1109 : */
1110 : void
7476 tgl 1111 CBC 222 : AddInvertedQual(Query *parsetree, Node *qual)
1112 : {
1113 : BooleanTest *invqual;
1114 :
9345 bruce 1115 GIC 222 : if (qual == NULL)
9345 bruce 1116 UIC 0 : return;
1117 :
1118 : /* Need not copy input qual, because AddQual will... */
7476 tgl 1119 GIC 222 : invqual = makeNode(BooleanTest);
7423 1120 222 : invqual->arg = (Expr *) qual;
7476 1121 222 : invqual->booltesttype = IS_NOT_TRUE;
2968 1122 222 : invqual->location = -1;
1123 :
7476 1124 222 : AddQual(parsetree, (Node *) invqual);
1125 : }
9770 scrappy 1126 EUB :
8733 JanWieck 1127 :
1128 : /*
1129 : * add_nulling_relids() finds Vars and PlaceHolderVars that belong to any
1130 : * of the target_relids, and adds added_relids to their varnullingrels
1131 : * and phnullingrels fields.
1132 : */
1133 : Node *
69 tgl 1134 GNC 1642 : add_nulling_relids(Node *node,
1135 : const Bitmapset *target_relids,
1136 : const Bitmapset *added_relids)
1137 : {
1138 : add_nulling_relids_context context;
1139 :
1140 1642 : context.target_relids = target_relids;
1141 1642 : context.added_relids = added_relids;
1142 1642 : context.sublevels_up = 0;
1143 1642 : return query_or_expression_tree_mutator(node,
1144 : add_nulling_relids_mutator,
1145 : &context,
1146 : 0);
1147 : }
1148 :
1149 : static Node *
1150 8234 : add_nulling_relids_mutator(Node *node,
1151 : add_nulling_relids_context *context)
1152 : {
1153 8234 : if (node == NULL)
69 tgl 1154 UNC 0 : return NULL;
69 tgl 1155 GNC 8234 : if (IsA(node, Var))
1156 : {
1157 3287 : Var *var = (Var *) node;
1158 :
1159 6574 : if (var->varlevelsup == context->sublevels_up &&
1160 3287 : bms_is_member(var->varno, context->target_relids))
1161 : {
1162 1648 : Relids newnullingrels = bms_union(var->varnullingrels,
1163 : context->added_relids);
1164 :
1165 : /* Copy the Var ... */
1166 1648 : var = copyObject(var);
1167 : /* ... and replace the copy's varnullingrels field */
1168 1648 : var->varnullingrels = newnullingrels;
1169 1648 : return (Node *) var;
1170 : }
1171 : /* Otherwise fall through to copy the Var normally */
1172 : }
1173 4947 : else if (IsA(node, PlaceHolderVar))
1174 : {
1175 3 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
1176 :
1177 6 : if (phv->phlevelsup == context->sublevels_up &&
1178 3 : bms_overlap(phv->phrels, context->target_relids))
1179 : {
1180 3 : Relids newnullingrels = bms_union(phv->phnullingrels,
1181 : context->added_relids);
1182 :
1183 : /*
1184 : * We don't modify the contents of the PHV's expression, only add
1185 : * to phnullingrels. This corresponds to assuming that the PHV
1186 : * will be evaluated at the same level as before, then perhaps be
1187 : * nulled as it bubbles up. Hence, just flat-copy the node ...
1188 : */
1189 3 : phv = makeNode(PlaceHolderVar);
1190 3 : memcpy(phv, node, sizeof(PlaceHolderVar));
1191 : /* ... and replace the copy's phnullingrels field */
1192 3 : phv->phnullingrels = newnullingrels;
1193 3 : return (Node *) phv;
1194 : }
1195 : /* Otherwise fall through to copy the PlaceHolderVar normally */
1196 : }
1197 4944 : else if (IsA(node, Query))
1198 : {
1199 : /* Recurse into RTE or sublink subquery */
1200 : Query *newnode;
1201 :
69 tgl 1202 UNC 0 : context->sublevels_up++;
1203 0 : newnode = query_tree_mutator((Query *) node,
1204 : add_nulling_relids_mutator,
1205 : (void *) context,
1206 : 0);
1207 0 : context->sublevels_up--;
1208 0 : return (Node *) newnode;
1209 : }
69 tgl 1210 GNC 6583 : return expression_tree_mutator(node, add_nulling_relids_mutator,
1211 : (void *) context);
1212 : }
1213 :
1214 : /*
1215 : * remove_nulling_relids() removes mentions of the specified RT index(es)
1216 : * in Var.varnullingrels and PlaceHolderVar.phnullingrels fields within
1217 : * the given expression, except in nodes belonging to rels listed in
1218 : * except_relids.
1219 : */
1220 : Node *
1221 3074 : remove_nulling_relids(Node *node,
1222 : const Bitmapset *removable_relids,
1223 : const Bitmapset *except_relids)
1224 : {
1225 : remove_nulling_relids_context context;
1226 :
1227 3074 : context.removable_relids = removable_relids;
1228 3074 : context.except_relids = except_relids;
1229 3074 : context.sublevels_up = 0;
1230 3074 : return query_or_expression_tree_mutator(node,
1231 : remove_nulling_relids_mutator,
1232 : &context,
1233 : 0);
1234 : }
1235 :
1236 : static Node *
1237 60868 : remove_nulling_relids_mutator(Node *node,
1238 : remove_nulling_relids_context *context)
1239 : {
1240 60868 : if (node == NULL)
1241 15667 : return NULL;
1242 45201 : if (IsA(node, Var))
1243 : {
1244 11968 : Var *var = (Var *) node;
1245 :
1246 11968 : if (var->varlevelsup == context->sublevels_up &&
1247 20925 : !bms_is_member(var->varno, context->except_relids) &&
1248 10439 : bms_overlap(var->varnullingrels, context->removable_relids))
1249 : {
1250 : /* Copy the Var ... */
1251 3303 : var = copyObject(var);
1252 : /* ... and replace the copy's varnullingrels field */
38 1253 3303 : var->varnullingrels = bms_difference(var->varnullingrels,
1254 : context->removable_relids);
69 1255 3303 : return (Node *) var;
1256 : }
1257 : /* Otherwise fall through to copy the Var normally */
1258 : }
1259 33233 : else if (IsA(node, PlaceHolderVar))
1260 : {
1261 142 : PlaceHolderVar *phv = (PlaceHolderVar *) node;
1262 :
1263 142 : if (phv->phlevelsup == context->sublevels_up &&
1264 142 : !bms_overlap(phv->phrels, context->except_relids))
1265 : {
1266 : /*
1267 : * Note: it might seem desirable to remove the PHV altogether if
1268 : * phnullingrels goes to empty. Currently we dare not do that
1269 : * because we use PHVs in some cases to enforce separate identity
1270 : * of subexpressions; see wrap_non_vars usages in prepjointree.c.
1271 : */
1272 : /* Copy the PlaceHolderVar and mutate what's below ... */
1273 : phv = (PlaceHolderVar *)
1274 142 : expression_tree_mutator(node,
1275 : remove_nulling_relids_mutator,
1276 : (void *) context);
1277 : /* ... and replace the copy's phnullingrels field */
38 1278 142 : phv->phnullingrels = bms_difference(phv->phnullingrels,
1279 : context->removable_relids);
1280 : /* We must also update phrels, if it contains a removable RTI */
69 1281 142 : phv->phrels = bms_difference(phv->phrels,
1282 : context->removable_relids);
1283 142 : Assert(!bms_is_empty(phv->phrels));
1284 142 : return (Node *) phv;
1285 : }
1286 : /* Otherwise fall through to copy the PlaceHolderVar normally */
1287 : }
1288 33091 : else if (IsA(node, Query))
1289 : {
1290 : /* Recurse into RTE or sublink subquery */
1291 : Query *newnode;
1292 :
1293 66 : context->sublevels_up++;
1294 66 : newnode = query_tree_mutator((Query *) node,
1295 : remove_nulling_relids_mutator,
1296 : (void *) context,
1297 : 0);
1298 66 : context->sublevels_up--;
1299 66 : return (Node *) newnode;
1300 : }
1301 41690 : return expression_tree_mutator(node, remove_nulling_relids_mutator,
1302 : (void *) context);
1303 : }
1304 :
1305 :
1306 : /*
4967 tgl 1307 EUB : * replace_rte_variables() finds all Vars in an expression tree
1308 : * that reference a particular RTE, and replaces them with substitute
1309 : * expressions obtained from a caller-supplied callback function.
1310 : *
1311 : * When invoking replace_rte_variables on a portion of a Query, pass the
4967 tgl 1312 ECB : * address of the containing Query's hasSubLinks field as outer_hasSubLinks.
1313 : * Otherwise, pass NULL, but inserting a SubLink into a non-Query expression
1314 : * will then cause an error.
1315 : *
1316 : * Note: the business with inserted_sublink is needed to update hasSubLinks
1317 : * in subqueries when the replacement adds a subquery inside a subquery.
1318 : * Messy, isn't it? We do not need to do similar pushups for hasAggs,
7111 tgl 1319 EUB : * because it isn't possible for this transformation to insert a level-zero
1320 : * aggregate reference into a subquery --- it could only insert outer aggs.
1321 : * Likewise for hasWindowFuncs.
1322 : *
1323 : * Note: usually, we'd not expose the mutator function or context struct
1324 : * for a function like this. We do so because callbacks often find it
4967 tgl 1325 ECB : * convenient to recurse directly to the mutator on sub-expressions of
1326 : * what they will return.
8591 1327 : */
1328 : Node *
4967 tgl 1329 GIC 71383 : replace_rte_variables(Node *node, int target_varno, int sublevels_up,
1330 : replace_rte_variables_callback callback,
1331 : void *callback_arg,
1332 : bool *outer_hasSubLinks)
8397 bruce 1333 ECB : {
1334 : Node *result;
1335 : replace_rte_variables_context context;
1336 :
4967 tgl 1337 GIC 71383 : context.callback = callback;
1338 71383 : context.callback_arg = callback_arg;
4967 tgl 1339 CBC 71383 : context.target_varno = target_varno;
1340 71383 : context.sublevels_up = sublevels_up;
1341 :
1342 : /*
1343 : * We try to initialize inserted_sublink to true if there is no need to
1344 : * detect new sublinks because the query already has some.
1345 : */
4967 tgl 1346 GIC 71383 : if (node && IsA(node, Query))
1347 1879 : context.inserted_sublink = ((Query *) node)->hasSubLinks;
1348 69504 : else if (outer_hasSubLinks)
1349 69504 : context.inserted_sublink = *outer_hasSubLinks;
4967 tgl 1350 ECB : else
4967 tgl 1351 UIC 0 : context.inserted_sublink = false;
1352 :
1353 : /*
4967 tgl 1354 ECB : * Must be prepared to start with a Query or a bare expression tree; if
4967 tgl 1355 EUB : * it's a Query, we don't want to increment sublevels_up.
1356 : */
4967 tgl 1357 GIC 71383 : result = query_or_expression_tree_mutator(node,
4967 tgl 1358 ECB : replace_rte_variables_mutator,
1359 : (void *) &context,
1360 : 0);
1361 :
4967 tgl 1362 GIC 71380 : if (context.inserted_sublink)
6908 tgl 1363 ECB : {
4967 tgl 1364 GIC 17597 : if (result && IsA(result, Query))
1365 45 : ((Query *) result)->hasSubLinks = true;
1366 17552 : else if (outer_hasSubLinks)
1367 17552 : *outer_hasSubLinks = true;
1368 : else
4967 tgl 1369 UIC 0 : elog(ERROR, "replace_rte_variables inserted a SubLink, but has noplace to record it");
1370 : }
1371 :
4967 tgl 1372 GIC 71380 : return result;
6908 tgl 1373 ECB : }
1374 :
1375 : Node *
4967 tgl 1376 GIC 347591 : replace_rte_variables_mutator(Node *node,
1377 : replace_rte_variables_context *context)
1378 : {
9345 bruce 1379 CBC 347591 : if (node == NULL)
8591 tgl 1380 88159 : return NULL;
1381 259432 : if (IsA(node, Var))
9770 scrappy 1382 ECB : {
8591 tgl 1383 GIC 93991 : Var *var = (Var *) node;
1384 :
4967 1385 93991 : if (var->varno == context->target_varno &&
1386 60342 : var->varlevelsup == context->sublevels_up)
1387 : {
1388 : /* Found a matching variable, make the substitution */
4967 tgl 1389 ECB : Node *newnode;
1390 :
2040 peter_e 1391 GIC 57171 : newnode = context->callback(var, context);
4967 tgl 1392 ECB : /* Detect if we are adding a sublink to query */
4967 tgl 1393 GBC 57171 : if (!context->inserted_sublink)
4967 tgl 1394 CBC 47753 : context->inserted_sublink = checkExprHasSubLink(newnode);
4967 tgl 1395 GIC 57171 : return newnode;
8591 tgl 1396 ECB : }
1397 : /* otherwise fall through to copy the var normally */
1398 : }
5781 tgl 1399 CBC 165441 : else if (IsA(node, CurrentOfExpr))
1400 : {
1401 3 : CurrentOfExpr *cexpr = (CurrentOfExpr *) node;
1402 :
4967 tgl 1403 GIC 3 : if (cexpr->cvarno == context->target_varno &&
5781 1404 3 : context->sublevels_up == 0)
5781 tgl 1405 ECB : {
1406 : /*
5624 bruce 1407 : * We get here if a WHERE CURRENT OF expression turns out to apply
1408 : * to a view. Someday we might be able to translate the
1409 : * expression to apply to an underlying table of the view, but
1410 : * right now it's not implemented.
1411 : */
5781 tgl 1412 CBC 3 : ereport(ERROR,
1413 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2118 tgl 1414 ECB : errmsg("WHERE CURRENT OF on a view is not implemented")));
1415 : }
5781 1416 : /* otherwise fall through to copy the expr normally */
1417 : }
5781 tgl 1418 GIC 165438 : else if (IsA(node, Query))
8591 tgl 1419 ECB : {
1420 : /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1421 : Query *newnode;
1422 : bool save_inserted_sublink;
1423 :
8221 tgl 1424 GIC 753 : context->sublevels_up++;
7111 1425 753 : save_inserted_sublink = context->inserted_sublink;
4967 1426 753 : context->inserted_sublink = ((Query *) node)->hasSubLinks;
7387 1427 753 : newnode = query_tree_mutator((Query *) node,
4967 tgl 1428 ECB : replace_rte_variables_mutator,
7387 1429 : (void *) context,
1430 : 0);
7111 tgl 1431 CBC 753 : newnode->hasSubLinks |= context->inserted_sublink;
1432 753 : context->inserted_sublink = save_inserted_sublink;
8221 tgl 1433 GIC 753 : context->sublevels_up--;
8591 1434 753 : return (Node *) newnode;
1435 : }
4967 tgl 1436 CBC 201505 : return expression_tree_mutator(node, replace_rte_variables_mutator,
1437 : (void *) context);
1438 : }
1439 :
1440 :
3935 tgl 1441 EUB : /*
1442 : * map_variable_attnos() finds all user-column Vars in an expression tree
1443 : * that reference a particular RTE, and adjusts their varattnos according
1444 : * to the given mapping array (varattno n is replaced by attno_map[n-1]).
1445 : * Vars for system columns are not modified.
1446 : *
1447 : * A zero in the mapping array represents a dropped column, which should not
1448 : * appear in the expression.
3935 tgl 1449 ECB : *
1450 : * If the expression tree contains a whole-row Var for the target RTE,
1451 : * *found_whole_row is set to true. In addition, if to_rowtype is
1452 : * not InvalidOid, we replace the Var with a Var of that vartype, inserting
1453 : * a ConvertRowtypeExpr to map back to the rowtype expected by the expression.
1454 : * (Therefore, to_rowtype had better be a child rowtype of the rowtype of the
1455 : * RTE we're changing references to.) Callers that don't provide to_rowtype
1456 : * should report an error if *found_whole_row is true; we don't do that here
1457 : * because we don't know exactly what wording for the error message would
1458 : * be most appropriate. The caller will be aware of the context.
1459 : *
1460 : * This could be built using replace_rte_variables and a callback function,
1461 : * but since we don't ever need to insert sublinks, replace_rte_variables is
1462 : * overly complicated.
1463 : */
1464 :
1465 : typedef struct
1466 : {
3602 bruce 1467 : int target_varno; /* RTE index to search for */
1468 : int sublevels_up; /* (current) nesting depth */
1208 michael 1469 : const AttrMap *attno_map; /* map array for user attnos */
1470 : Oid to_rowtype; /* change whole-row Vars to this type */
1471 : bool *found_whole_row; /* output flag */
1472 : } map_variable_attnos_context;
1473 :
1474 : static Node *
3935 tgl 1475 GIC 48440 : map_variable_attnos_mutator(Node *node,
3935 tgl 1476 ECB : map_variable_attnos_context *context)
1477 : {
3935 tgl 1478 GIC 48440 : if (node == NULL)
3935 tgl 1479 CBC 452 : return NULL;
1480 47988 : if (IsA(node, Var))
3935 tgl 1481 ECB : {
3935 tgl 1482 GIC 11224 : Var *var = (Var *) node;
3935 tgl 1483 ECB :
3935 tgl 1484 GIC 11224 : if (var->varno == context->target_varno &&
3935 tgl 1485 CBC 11116 : var->varlevelsup == context->sublevels_up)
3935 tgl 1486 ECB : {
1487 : /* Found a matching variable, make the substitution */
3602 bruce 1488 GIC 11116 : Var *newvar = (Var *) palloc(sizeof(Var));
1489 11116 : int attno = var->varattno;
3935 tgl 1490 ECB :
2004 tgl 1491 GIC 11116 : *newvar = *var; /* initially copy all fields of the Var */
2004 tgl 1492 ECB :
3935 tgl 1493 GIC 11116 : if (attno > 0)
3935 tgl 1494 ECB : {
1495 : /* user-defined column, replace attno */
1208 michael 1496 GIC 11053 : if (attno > context->attno_map->maplen ||
1497 11053 : context->attno_map->attnums[attno - 1] == 0)
3935 tgl 1498 LBC 0 : elog(ERROR, "unexpected varattno %d in expression to be mapped",
1499 : attno);
1186 tgl 1500 CBC 11053 : newvar->varattno = context->attno_map->attnums[attno - 1];
1501 : /* If the syntactic referent is same RTE, fix it too */
1502 11053 : if (newvar->varnosyn == context->target_varno)
1503 11014 : newvar->varattnosyn = newvar->varattno;
1504 : }
3935 tgl 1505 GIC 63 : else if (attno == 0)
1506 : {
1507 : /* whole-row variable, warn caller */
1508 27 : *(context->found_whole_row) = true;
1509 :
1510 : /* If the caller expects us to convert the Var, do so. */
2004 1511 27 : if (OidIsValid(context->to_rowtype) &&
1512 24 : context->to_rowtype != var->vartype)
2075 rhaas 1513 ECB : {
1514 : ConvertRowtypeExpr *r;
1515 :
1516 : /* This certainly won't work for a RECORD variable. */
2075 rhaas 1517 CBC 24 : Assert(var->vartype != RECORDOID);
1518 :
1519 : /* Var itself is changed to the requested type. */
2004 tgl 1520 24 : newvar->vartype = context->to_rowtype;
1521 :
2004 tgl 1522 ECB : /*
1523 : * Add a conversion node on top to convert back to the
1524 : * original type expected by the expression.
1525 : */
2004 tgl 1526 GIC 24 : r = makeNode(ConvertRowtypeExpr);
2004 tgl 1527 CBC 24 : r->arg = (Expr *) newvar;
2004 tgl 1528 GIC 24 : r->resulttype = var->vartype;
1529 24 : r->convertformat = COERCE_IMPLICIT_CAST;
1530 24 : r->location = -1;
1531 :
2004 tgl 1532 CBC 24 : return (Node *) r;
2075 rhaas 1533 ECB : }
1534 : }
3935 tgl 1535 GIC 11092 : return (Node *) newvar;
1536 : }
3935 tgl 1537 ECB : /* otherwise fall through to copy the var normally */
1538 : }
2005 rhaas 1539 GIC 36764 : else if (IsA(node, ConvertRowtypeExpr))
2005 rhaas 1540 ECB : {
2005 rhaas 1541 GIC 18 : ConvertRowtypeExpr *r = (ConvertRowtypeExpr *) node;
2004 tgl 1542 18 : Var *var = (Var *) r->arg;
1543 :
1544 : /*
1545 : * If this is coercing a whole-row Var that we need to convert, then
1546 : * just convert the Var without adding an extra ConvertRowtypeExpr.
1547 : * Effectively we're simplifying var::parenttype::grandparenttype into
1548 : * just var::grandparenttype. This avoids building stacks of CREs if
1549 : * this function is applied repeatedly.
1550 : */
1551 18 : if (IsA(var, Var) &&
1552 12 : var->varno == context->target_varno &&
1553 9 : var->varlevelsup == context->sublevels_up &&
1554 9 : var->varattno == 0 &&
1555 9 : OidIsValid(context->to_rowtype) &&
1556 9 : context->to_rowtype != var->vartype)
1557 : {
1558 : ConvertRowtypeExpr *newnode;
1559 9 : Var *newvar = (Var *) palloc(sizeof(Var));
1560 :
1561 : /* whole-row variable, warn caller */
1562 9 : *(context->found_whole_row) = true;
1563 :
1564 9 : *newvar = *var; /* initially copy all fields of the Var */
1565 :
1566 : /* This certainly won't work for a RECORD variable. */
1567 9 : Assert(var->vartype != RECORDOID);
2004 tgl 1568 ECB :
1569 : /* Var itself is changed to the requested type. */
2004 tgl 1570 GIC 9 : newvar->vartype = context->to_rowtype;
1571 :
2005 rhaas 1572 9 : newnode = (ConvertRowtypeExpr *) palloc(sizeof(ConvertRowtypeExpr));
2004 tgl 1573 9 : *newnode = *r; /* initially copy all fields of the CRE */
1574 9 : newnode->arg = (Expr *) newvar;
1575 :
2005 rhaas 1576 CBC 9 : return (Node *) newnode;
2005 rhaas 1577 ECB : }
2004 tgl 1578 : /* otherwise fall through to process the expression normally */
2005 rhaas 1579 : }
3935 tgl 1580 GIC 36746 : else if (IsA(node, Query))
1581 : {
1582 : /* Recurse into RTE subquery or not-yet-planned sublink subquery */
1583 : Query *newnode;
1584 :
3935 tgl 1585 LBC 0 : context->sublevels_up++;
1586 0 : newnode = query_tree_mutator((Query *) node,
3935 tgl 1587 ECB : map_variable_attnos_mutator,
1588 : (void *) context,
1589 : 0);
3935 tgl 1590 UBC 0 : context->sublevels_up--;
3935 tgl 1591 UIC 0 : return (Node *) newnode;
1592 : }
3935 tgl 1593 GIC 36863 : return expression_tree_mutator(node, map_variable_attnos_mutator,
1594 : (void *) context);
1595 : }
3935 tgl 1596 ECB :
1597 : Node *
3935 tgl 1598 GIC 4172 : map_variable_attnos(Node *node,
1599 : int target_varno, int sublevels_up,
1600 : const AttrMap *attno_map,
2075 rhaas 1601 ECB : Oid to_rowtype, bool *found_whole_row)
1602 : {
3935 tgl 1603 : map_variable_attnos_context context;
1604 :
3935 tgl 1605 CBC 4172 : context.target_varno = target_varno;
1606 4172 : context.sublevels_up = sublevels_up;
3935 tgl 1607 GIC 4172 : context.attno_map = attno_map;
2075 rhaas 1608 GBC 4172 : context.to_rowtype = to_rowtype;
3935 tgl 1609 GIC 4172 : context.found_whole_row = found_whole_row;
1610 :
3935 tgl 1611 CBC 4172 : *found_whole_row = false;
1612 :
1613 : /*
1614 : * Must be prepared to start with a Query or a bare expression tree; if
3935 tgl 1615 ECB : * it's a Query, we don't want to increment sublevels_up.
1616 : */
3935 tgl 1617 GIC 4172 : return query_or_expression_tree_mutator(node,
3935 tgl 1618 ECB : map_variable_attnos_mutator,
1619 : (void *) &context,
1620 : 0);
1621 : }
1622 :
1623 :
4967 1624 : /*
3804 1625 : * ReplaceVarsFromTargetList - replace Vars with items from a targetlist
1626 : *
1627 : * Vars matching target_varno and sublevels_up are replaced by the
1628 : * entry with matching resno from targetlist, if there is one.
1629 : *
1630 : * If there is no matching resno for such a Var, the action depends on the
1631 : * nomatch_option:
1632 : * REPLACEVARS_REPORT_ERROR: throw an error
1633 : * REPLACEVARS_CHANGE_VARNO: change Var's varno to nomatch_varno
1634 : * REPLACEVARS_SUBSTITUTE_NULL: replace Var with a NULL Const of same type
1635 : *
1636 : * The caller must also provide target_rte, the RTE describing the target
1637 : * relation. This is needed to handle whole-row Vars referencing the target.
4967 1638 : * We expand such Vars into RowExpr constructs.
1639 : *
1640 : * outer_hasSubLinks works the same as for replace_rte_variables().
1641 : */
1642 :
1643 : typedef struct
1644 : {
1645 : RangeTblEntry *target_rte;
1646 : List *targetlist;
1647 : ReplaceVarsNoMatchOption nomatch_option;
1648 : int nomatch_varno;
1649 : } ReplaceVarsFromTargetList_context;
1650 :
1651 : static Node *
3804 tgl 1652 GIC 3573 : ReplaceVarsFromTargetList_callback(Var *var,
1653 : replace_rte_variables_context *context)
1654 : {
1655 3573 : ReplaceVarsFromTargetList_context *rcon = (ReplaceVarsFromTargetList_context *) context->callback_arg;
1656 : TargetEntry *tle;
4967 tgl 1657 ECB :
4967 tgl 1658 GIC 3573 : if (var->varattno == InvalidAttrNumber)
1659 : {
1660 : /* Must expand whole-tuple reference into RowExpr */
1661 : RowExpr *rowexpr;
1662 : List *colnames;
4967 tgl 1663 ECB : List *fields;
1664 :
1665 : /*
4790 bruce 1666 : * If generating an expansion for a var of a named rowtype (ie, this
1667 : * is a plain relation RTE), then we must include dummy items for
1668 : * dropped columns. If the var is RECORD (ie, this is a JOIN), then
1669 : * omit dropped columns. In the latter case, attach column names to
388 tgl 1670 : * the RowExpr for use of the executor and ruleutils.c.
4967 1671 : */
4967 tgl 1672 CBC 27 : expandRTE(rcon->target_rte,
1673 27 : var->varno, var->varlevelsup, var->location,
4967 tgl 1674 GIC 27 : (var->vartype != RECORDOID),
4967 tgl 1675 ECB : &colnames, &fields);
1676 : /* Adjust the generated per-field Vars... */
4967 tgl 1677 GIC 27 : fields = (List *) replace_rte_variables_mutator((Node *) fields,
1678 : context);
1679 27 : rowexpr = makeNode(RowExpr);
1680 27 : rowexpr->args = fields;
1681 27 : rowexpr->row_typeid = var->vartype;
1682 27 : rowexpr->row_format = COERCE_IMPLICIT_CAST;
388 1683 27 : rowexpr->colnames = (var->vartype == RECORDOID) ? colnames : NIL;
4967 1684 27 : rowexpr->location = var->location;
1685 :
1686 27 : return (Node *) rowexpr;
1687 : }
1688 :
1689 : /* Normal case referencing one targetlist element */
1690 3546 : tle = get_tle_by_resno(rcon->targetlist, var->varattno);
1691 :
4564 1692 3546 : if (tle == NULL || tle->resjunk)
1693 : {
1694 : /* Failed to find column in targetlist */
3804 1695 195 : switch (rcon->nomatch_option)
1696 : {
3804 tgl 1697 UIC 0 : case REPLACEVARS_REPORT_ERROR:
1698 : /* fall through, throw error below */
1699 0 : break;
1700 :
3804 tgl 1701 GIC 120 : case REPLACEVARS_CHANGE_VARNO:
1702 120 : var = (Var *) copyObject(var);
1703 120 : var->varno = rcon->nomatch_varno;
1704 : /* we leave the syntactic referent alone */
1705 120 : return (Node *) var;
1706 :
1707 75 : case REPLACEVARS_SUBSTITUTE_NULL:
1708 :
1709 : /*
1710 : * If Var is of domain type, we should add a CoerceToDomain
1711 : * node, in case there is a NOT NULL domain constraint.
1712 : */
1713 75 : return coerce_to_domain((Node *) makeNullConst(var->vartype,
3804 tgl 1714 ECB : var->vartypmod,
1715 : var->varcollid),
1716 : InvalidOid, -1,
1717 : var->vartype,
2017 1718 : COERCION_IMPLICIT,
3804 1719 : COERCE_IMPLICIT_CAST,
1720 : -1,
1721 : false);
1722 : }
3804 tgl 1723 LBC 0 : elog(ERROR, "could not find replacement targetlist entry for attno %d",
3804 tgl 1724 ECB : var->varattno);
1725 : return NULL; /* keep compiler quiet */
1726 : }
4967 1727 : else
1728 : {
1729 : /* Make a copy of the tlist item to return */
2222 peter_e 1730 CBC 3351 : Expr *newnode = copyObject(tle->expr);
1731 :
4967 tgl 1732 ECB : /* Must adjust varlevelsup if tlist item is from higher query */
4967 tgl 1733 GIC 3351 : if (var->varlevelsup > 0)
2222 peter_e 1734 81 : IncrementVarSublevelsUp((Node *) newnode, var->varlevelsup, 0);
4967 tgl 1735 ECB :
3217 1736 : /*
3217 tgl 1737 EUB : * Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
1738 : * and throw error if so. This case could only happen when expanding
3217 tgl 1739 ECB : * an ON UPDATE rule's NEW variable and the referenced tlist item in
1740 : * the original UPDATE command is part of a multiple assignment. There
1741 : * seems no practical way to handle such cases without multiple
1742 : * evaluation of the multiple assignment's sub-select, which would
1743 : * create semantic oddities that users of rules would probably prefer
1744 : * not to cope with. So treat it as an unimplemented feature.
1745 : */
2222 peter_e 1746 GIC 3351 : if (contains_multiexpr_param((Node *) newnode, NULL))
3217 tgl 1747 LBC 0 : ereport(ERROR,
1748 : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1749 : errmsg("NEW variables in ON UPDATE rules cannot reference columns that are part of a multiple assignment in the subject UPDATE command")));
3217 tgl 1750 ECB :
2222 peter_e 1751 CBC 3351 : return (Node *) newnode;
1752 : }
1753 : }
1754 :
1755 : Node *
3804 tgl 1756 2495 : ReplaceVarsFromTargetList(Node *node,
1757 : int target_varno, int sublevels_up,
1758 : RangeTblEntry *target_rte,
3804 tgl 1759 ECB : List *targetlist,
1760 : ReplaceVarsNoMatchOption nomatch_option,
1761 : int nomatch_varno,
1762 : bool *outer_hasSubLinks)
1763 : {
1764 : ReplaceVarsFromTargetList_context context;
8591 1765 :
6518 tgl 1766 CBC 2495 : context.target_rte = target_rte;
8227 1767 2495 : context.targetlist = targetlist;
3804 1768 2495 : context.nomatch_option = nomatch_option;
1769 2495 : context.nomatch_varno = nomatch_varno;
1770 :
4967 1771 2495 : return replace_rte_variables(node, target_varno, sublevels_up,
1772 : ReplaceVarsFromTargetList_callback,
1773 : (void *) &context,
4967 tgl 1774 ECB : outer_hasSubLinks);
1775 : }
|