1 /*------------------------------------------------------------------------- 2 * 3 * setrefs.c 4 * Post-processing of a completed plan tree: fix references to subplan 5 * vars, compute regproc values for operators, etc 6 * 7 * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group 8 * Portions Copyright (c) 1994, Regents of the University of California 9 * 10 * 11 * IDENTIFICATION 12 * src/backend/optimizer/plan/setrefs.c 13 * 14 *------------------------------------------------------------------------- 15 */ 16 #include "postgres.h" 17 18 #include "access/transam.h" 19 #include "catalog/pg_type.h" 20 #include "nodes/makefuncs.h" 21 #include "nodes/nodeFuncs.h" 22 #include "optimizer/optimizer.h" 23 #include "optimizer/pathnode.h" 24 #include "optimizer/planmain.h" 25 #include "optimizer/planner.h" 26 #include "optimizer/tlist.h" 27 #include "tcop/utility.h" 28 #include "utils/lsyscache.h" 29 #include "utils/syscache.h" 30 31 32 typedef struct 33 { 34 Index varno; /* RT index of Var */ 35 AttrNumber varattno; /* attr number of Var */ 36 AttrNumber resno; /* TLE position of Var */ 37 } tlist_vinfo; 38 39 typedef struct 40 { 41 List *tlist; /* underlying target list */ 42 int num_vars; /* number of plain Var tlist entries */ 43 bool has_ph_vars; /* are there PlaceHolderVar entries? */ 44 bool has_non_vars; /* are there other entries? */ 45 tlist_vinfo vars[FLEXIBLE_ARRAY_MEMBER]; /* has num_vars entries */ 46 } indexed_tlist; 47 48 typedef struct 49 { 50 PlannerInfo *root; 51 int rtoffset; 52 } fix_scan_expr_context; 53 54 typedef struct 55 { 56 PlannerInfo *root; 57 indexed_tlist *outer_itlist; 58 indexed_tlist *inner_itlist; 59 Index acceptable_rel; 60 int rtoffset; 61 } fix_join_expr_context; 62 63 typedef struct 64 { 65 PlannerInfo *root; 66 indexed_tlist *subplan_itlist; 67 Index newvarno; 68 int rtoffset; 69 } fix_upper_expr_context; 70 71 /* 72 * Check if a Const node is a regclass value. We accept plain OID too, 73 * since a regclass Const will get folded to that type if it's an argument 74 * to oideq or similar operators. (This might result in some extraneous 75 * values in a plan's list of relation dependencies, but the worst result 76 * would be occasional useless replans.) 77 */ 78 #define ISREGCLASSCONST(con) \ 79 (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \ 80 !(con)->constisnull) 81 82 #define fix_scan_list(root, lst, rtoffset) \ 83 ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset)) 84 85 static void add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing); 86 static void flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte); 87 static bool flatten_rtes_walker(Node *node, PlannerGlobal *glob); 88 static void add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte); 89 static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset); 90 static Plan *set_indexonlyscan_references(PlannerInfo *root, 91 IndexOnlyScan *plan, 92 int rtoffset); 93 static Plan *set_subqueryscan_references(PlannerInfo *root, 94 SubqueryScan *plan, 95 int rtoffset); 96 static bool trivial_subqueryscan(SubqueryScan *plan); 97 static Plan *clean_up_removed_plan_level(Plan *parent, Plan *child); 98 static void set_foreignscan_references(PlannerInfo *root, 99 ForeignScan *fscan, 100 int rtoffset); 101 static void set_customscan_references(PlannerInfo *root, 102 CustomScan *cscan, 103 int rtoffset); 104 static Plan *set_append_references(PlannerInfo *root, 105 Append *aplan, 106 int rtoffset); 107 static Plan *set_mergeappend_references(PlannerInfo *root, 108 MergeAppend *mplan, 109 int rtoffset); 110 static void set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset); 111 static Relids offset_relid_set(Relids relids, int rtoffset); 112 static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset); 113 static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context); 114 static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context); 115 static void set_join_references(PlannerInfo *root, Join *join, int rtoffset); 116 static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset); 117 static void set_param_references(PlannerInfo *root, Plan *plan); 118 static Node *convert_combining_aggrefs(Node *node, void *context); 119 static void set_dummy_tlist_references(Plan *plan, int rtoffset); 120 static indexed_tlist *build_tlist_index(List *tlist); 121 static Var *search_indexed_tlist_for_var(Var *var, 122 indexed_tlist *itlist, 123 Index newvarno, 124 int rtoffset); 125 static Var *search_indexed_tlist_for_non_var(Expr *node, 126 indexed_tlist *itlist, 127 Index newvarno); 128 static Var *search_indexed_tlist_for_sortgroupref(Expr *node, 129 Index sortgroupref, 130 indexed_tlist *itlist, 131 Index newvarno); 132 static List *fix_join_expr(PlannerInfo *root, 133 List *clauses, 134 indexed_tlist *outer_itlist, 135 indexed_tlist *inner_itlist, 136 Index acceptable_rel, int rtoffset); 137 static Node *fix_join_expr_mutator(Node *node, 138 fix_join_expr_context *context); 139 static Node *fix_upper_expr(PlannerInfo *root, 140 Node *node, 141 indexed_tlist *subplan_itlist, 142 Index newvarno, 143 int rtoffset); 144 static Node *fix_upper_expr_mutator(Node *node, 145 fix_upper_expr_context *context); 146 static List *set_returning_clause_references(PlannerInfo *root, 147 List *rlist, 148 Plan *topplan, 149 Index resultRelation, 150 int rtoffset); 151 152 153 /***************************************************************************** 154 * 155 * SUBPLAN REFERENCES 156 * 157 *****************************************************************************/ 158 159 /* 160 * set_plan_references 161 * 162 * This is the final processing pass of the planner/optimizer. The plan 163 * tree is complete; we just have to adjust some representational details 164 * for the convenience of the executor: 165 * 166 * 1. We flatten the various subquery rangetables into a single list, and 167 * zero out RangeTblEntry fields that are not useful to the executor. 168 * 169 * 2. We adjust Vars in scan nodes to be consistent with the flat rangetable. 170 * 171 * 3. We adjust Vars in upper plan nodes to refer to the outputs of their 172 * subplans. 173 * 174 * 4. Aggrefs in Agg plan nodes need to be adjusted in some cases involving 175 * partial aggregation or minmax aggregate optimization. 176 * 177 * 5. PARAM_MULTIEXPR Params are replaced by regular PARAM_EXEC Params, 178 * now that we have finished planning all MULTIEXPR subplans. 179 * 180 * 6. We compute regproc OIDs for operators (ie, we look up the function 181 * that implements each op). 182 * 183 * 7. We create lists of specific objects that the plan depends on. 184 * This will be used by plancache.c to drive invalidation of cached plans. 185 * Relation dependencies are represented by OIDs, and everything else by 186 * PlanInvalItems (this distinction is motivated by the shared-inval APIs). 187 * Currently, relations, user-defined functions, and domains are the only 188 * types of objects that are explicitly tracked this way. 189 * 190 * 8. We assign every plan node in the tree a unique ID. 191 * 192 * We also perform one final optimization step, which is to delete 193 * SubqueryScan, Append, and MergeAppend plan nodes that aren't doing 194 * anything useful. The reason for doing this last is that 195 * it can't readily be done before set_plan_references, because it would 196 * break set_upper_references: the Vars in the child plan's top tlist 197 * wouldn't match up with the Vars in the outer plan tree. A SubqueryScan 198 * serves a necessary function as a buffer between outer query and subquery 199 * variable numbering ... but after we've flattened the rangetable this is 200 * no longer a problem, since then there's only one rtindex namespace. 201 * Likewise, Append and MergeAppend buffer between the parent and child vars 202 * of an appendrel, but we don't need to worry about that once we've done 203 * set_plan_references. 204 * 205 * set_plan_references recursively traverses the whole plan tree. 206 * 207 * The return value is normally the same Plan node passed in, but can be 208 * different when the passed-in Plan is a node we decide isn't needed. 209 * 210 * The flattened rangetable entries are appended to root->glob->finalrtable. 211 * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the 212 * RT indexes of ModifyTable result relations to root->glob->resultRelations, 213 * and flattened AppendRelInfos are appended to root->glob->appendRelations. 214 * Plan dependencies are appended to root->glob->relationOids (for relations) 215 * and root->glob->invalItems (for everything else). 216 * 217 * Notice that we modify Plan nodes in-place, but use expression_tree_mutator 218 * to process targetlist and qual expressions. We can assume that the Plan 219 * nodes were just built by the planner and are not multiply referenced, but 220 * it's not so safe to assume that for expression tree nodes. 221 */ 222 Plan * 223 set_plan_references(PlannerInfo *root, Plan *plan) 224 { 225 PlannerGlobal *glob = root->glob; 226 int rtoffset = list_length(glob->finalrtable); 227 ListCell *lc; 228 229 /* 230 * Add all the query's RTEs to the flattened rangetable. The live ones 231 * will have their rangetable indexes increased by rtoffset. (Additional 232 * RTEs, not referenced by the Plan tree, might get added after those.) 233 */ 234 add_rtes_to_flat_rtable(root, false); 235 236 /* 237 * Adjust RT indexes of PlanRowMarks and add to final rowmarks list 238 */ 239 foreach(lc, root->rowMarks) 240 { 241 PlanRowMark *rc = lfirst_node(PlanRowMark, lc); 242 PlanRowMark *newrc; 243 244 /* flat copy is enough since all fields are scalars */ 245 newrc = (PlanRowMark *) palloc(sizeof(PlanRowMark)); 246 memcpy(newrc, rc, sizeof(PlanRowMark)); 247 248 /* adjust indexes ... but *not* the rowmarkId */ 249 newrc->rti += rtoffset; 250 newrc->prti += rtoffset; 251 252 glob->finalrowmarks = lappend(glob->finalrowmarks, newrc); 253 } 254 255 /* 256 * Adjust RT indexes of AppendRelInfos and add to final appendrels list. 257 * We assume the AppendRelInfos were built during planning and don't need 258 * to be copied. 259 */ 260 foreach(lc, root->append_rel_list) 261 { 262 AppendRelInfo *appinfo = lfirst_node(AppendRelInfo, lc); 263 264 /* adjust RT indexes */ 265 appinfo->parent_relid += rtoffset; 266 appinfo->child_relid += rtoffset; 267 268 /* 269 * Rather than adjust the translated_vars entries, just drop 'em. 270 * Neither the executor nor EXPLAIN currently need that data. 271 */ 272 appinfo->translated_vars = NIL; 273 274 glob->appendRelations = lappend(glob->appendRelations, appinfo); 275 } 276 277 /* Now fix the Plan tree */ 278 return set_plan_refs(root, plan, rtoffset); 279 } 280 281 /* 282 * Extract RangeTblEntries from the plan's rangetable, and add to flat rtable 283 * 284 * This can recurse into subquery plans; "recursing" is true if so. 285 */ 286 static void 287 add_rtes_to_flat_rtable(PlannerInfo *root, bool recursing) 288 { 289 PlannerGlobal *glob = root->glob; 290 Index rti; 291 ListCell *lc; 292 293 /* 294 * Add the query's own RTEs to the flattened rangetable. 295 * 296 * At top level, we must add all RTEs so that their indexes in the 297 * flattened rangetable match up with their original indexes. When 298 * recursing, we only care about extracting relation RTEs. 299 */ 300 foreach(lc, root->parse->rtable) 301 { 302 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); 303 304 if (!recursing || rte->rtekind == RTE_RELATION) 305 add_rte_to_flat_rtable(glob, rte); 306 } 307 308 /* 309 * If there are any dead subqueries, they are not referenced in the Plan 310 * tree, so we must add RTEs contained in them to the flattened rtable 311 * separately. (If we failed to do this, the executor would not perform 312 * expected permission checks for tables mentioned in such subqueries.) 313 * 314 * Note: this pass over the rangetable can't be combined with the previous 315 * one, because that would mess up the numbering of the live RTEs in the 316 * flattened rangetable. 317 */ 318 rti = 1; 319 foreach(lc, root->parse->rtable) 320 { 321 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); 322 323 /* 324 * We should ignore inheritance-parent RTEs: their contents have been 325 * pulled up into our rangetable already. Also ignore any subquery 326 * RTEs without matching RelOptInfos, as they likewise have been 327 * pulled up. 328 */ 329 if (rte->rtekind == RTE_SUBQUERY && !rte->inh && 330 rti < root->simple_rel_array_size) 331 { 332 RelOptInfo *rel = root->simple_rel_array[rti]; 333 334 if (rel != NULL) 335 { 336 Assert(rel->relid == rti); /* sanity check on array */ 337 338 /* 339 * The subquery might never have been planned at all, if it 340 * was excluded on the basis of self-contradictory constraints 341 * in our query level. In this case apply 342 * flatten_unplanned_rtes. 343 * 344 * If it was planned but the result rel is dummy, we assume 345 * that it has been omitted from our plan tree (see 346 * set_subquery_pathlist), and recurse to pull up its RTEs. 347 * 348 * Otherwise, it should be represented by a SubqueryScan node 349 * somewhere in our plan tree, and we'll pull up its RTEs when 350 * we process that plan node. 351 * 352 * However, if we're recursing, then we should pull up RTEs 353 * whether the subquery is dummy or not, because we've found 354 * that some upper query level is treating this one as dummy, 355 * and so we won't scan this level's plan tree at all. 356 */ 357 if (rel->subroot == NULL) 358 flatten_unplanned_rtes(glob, rte); 359 else if (recursing || 360 IS_DUMMY_REL(fetch_upper_rel(rel->subroot, 361 UPPERREL_FINAL, NULL))) 362 add_rtes_to_flat_rtable(rel->subroot, true); 363 } 364 } 365 rti++; 366 } 367 } 368 369 /* 370 * Extract RangeTblEntries from a subquery that was never planned at all 371 */ 372 static void 373 flatten_unplanned_rtes(PlannerGlobal *glob, RangeTblEntry *rte) 374 { 375 /* Use query_tree_walker to find all RTEs in the parse tree */ 376 (void) query_tree_walker(rte->subquery, 377 flatten_rtes_walker, 378 (void *) glob, 379 QTW_EXAMINE_RTES_BEFORE); 380 } 381 382 static bool 383 flatten_rtes_walker(Node *node, PlannerGlobal *glob) 384 { 385 if (node == NULL) 386 return false; 387 if (IsA(node, RangeTblEntry)) 388 { 389 RangeTblEntry *rte = (RangeTblEntry *) node; 390 391 /* As above, we need only save relation RTEs */ 392 if (rte->rtekind == RTE_RELATION) 393 add_rte_to_flat_rtable(glob, rte); 394 return false; 395 } 396 if (IsA(node, Query)) 397 { 398 /* Recurse into subselects */ 399 return query_tree_walker((Query *) node, 400 flatten_rtes_walker, 401 (void *) glob, 402 QTW_EXAMINE_RTES_BEFORE); 403 } 404 return expression_tree_walker(node, flatten_rtes_walker, 405 (void *) glob); 406 } 407 408 /* 409 * Add (a copy of) the given RTE to the final rangetable 410 * 411 * In the flat rangetable, we zero out substructure pointers that are not 412 * needed by the executor; this reduces the storage space and copying cost 413 * for cached plans. We keep only the ctename, alias and eref Alias fields, 414 * which are needed by EXPLAIN, and the selectedCols, insertedCols, 415 * updatedCols, and extraUpdatedCols bitmaps, which are needed for 416 * executor-startup permissions checking and for trigger event checking. 417 */ 418 static void 419 add_rte_to_flat_rtable(PlannerGlobal *glob, RangeTblEntry *rte) 420 { 421 RangeTblEntry *newrte; 422 423 /* flat copy to duplicate all the scalar fields */ 424 newrte = (RangeTblEntry *) palloc(sizeof(RangeTblEntry)); 425 memcpy(newrte, rte, sizeof(RangeTblEntry)); 426 427 /* zap unneeded sub-structure */ 428 newrte->tablesample = NULL; 429 newrte->subquery = NULL; 430 newrte->joinaliasvars = NIL; 431 newrte->joinleftcols = NIL; 432 newrte->joinrightcols = NIL; 433 newrte->functions = NIL; 434 newrte->tablefunc = NULL; 435 newrte->values_lists = NIL; 436 newrte->coltypes = NIL; 437 newrte->coltypmods = NIL; 438 newrte->colcollations = NIL; 439 newrte->securityQuals = NIL; 440 441 glob->finalrtable = lappend(glob->finalrtable, newrte); 442 443 /* 444 * Check for RT index overflow; it's very unlikely, but if it did happen, 445 * the executor would get confused by varnos that match the special varno 446 * values. 447 */ 448 if (IS_SPECIAL_VARNO(list_length(glob->finalrtable))) 449 ereport(ERROR, 450 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), 451 errmsg("too many range table entries"))); 452 453 /* 454 * If it's a plain relation RTE, add the table to relationOids. 455 * 456 * We do this even though the RTE might be unreferenced in the plan tree; 457 * this would correspond to cases such as views that were expanded, child 458 * tables that were eliminated by constraint exclusion, etc. Schema 459 * invalidation on such a rel must still force rebuilding of the plan. 460 * 461 * Note we don't bother to avoid making duplicate list entries. We could, 462 * but it would probably cost more cycles than it would save. 463 */ 464 if (newrte->rtekind == RTE_RELATION) 465 glob->relationOids = lappend_oid(glob->relationOids, newrte->relid); 466 } 467 468 /* 469 * set_plan_refs: recurse through the Plan nodes of a single subquery level 470 */ 471 static Plan * 472 set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) 473 { 474 ListCell *l; 475 476 if (plan == NULL) 477 return NULL; 478 479 /* Assign this node a unique ID. */ 480 plan->plan_node_id = root->glob->lastPlanNodeId++; 481 482 /* 483 * Plan-type-specific fixes 484 */ 485 switch (nodeTag(plan)) 486 { 487 case T_SeqScan: 488 { 489 SeqScan *splan = (SeqScan *) plan; 490 491 splan->scanrelid += rtoffset; 492 splan->plan.targetlist = 493 fix_scan_list(root, splan->plan.targetlist, rtoffset); 494 splan->plan.qual = 495 fix_scan_list(root, splan->plan.qual, rtoffset); 496 } 497 break; 498 case T_SampleScan: 499 { 500 SampleScan *splan = (SampleScan *) plan; 501 502 splan->scan.scanrelid += rtoffset; 503 splan->scan.plan.targetlist = 504 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 505 splan->scan.plan.qual = 506 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 507 splan->tablesample = (TableSampleClause *) 508 fix_scan_expr(root, (Node *) splan->tablesample, rtoffset); 509 } 510 break; 511 case T_IndexScan: 512 { 513 IndexScan *splan = (IndexScan *) plan; 514 515 splan->scan.scanrelid += rtoffset; 516 splan->scan.plan.targetlist = 517 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 518 splan->scan.plan.qual = 519 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 520 splan->indexqual = 521 fix_scan_list(root, splan->indexqual, rtoffset); 522 splan->indexqualorig = 523 fix_scan_list(root, splan->indexqualorig, rtoffset); 524 splan->indexorderby = 525 fix_scan_list(root, splan->indexorderby, rtoffset); 526 splan->indexorderbyorig = 527 fix_scan_list(root, splan->indexorderbyorig, rtoffset); 528 } 529 break; 530 case T_IndexOnlyScan: 531 { 532 IndexOnlyScan *splan = (IndexOnlyScan *) plan; 533 534 return set_indexonlyscan_references(root, splan, rtoffset); 535 } 536 break; 537 case T_BitmapIndexScan: 538 { 539 BitmapIndexScan *splan = (BitmapIndexScan *) plan; 540 541 splan->scan.scanrelid += rtoffset; 542 /* no need to fix targetlist and qual */ 543 Assert(splan->scan.plan.targetlist == NIL); 544 Assert(splan->scan.plan.qual == NIL); 545 splan->indexqual = 546 fix_scan_list(root, splan->indexqual, rtoffset); 547 splan->indexqualorig = 548 fix_scan_list(root, splan->indexqualorig, rtoffset); 549 } 550 break; 551 case T_BitmapHeapScan: 552 { 553 BitmapHeapScan *splan = (BitmapHeapScan *) plan; 554 555 splan->scan.scanrelid += rtoffset; 556 splan->scan.plan.targetlist = 557 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 558 splan->scan.plan.qual = 559 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 560 splan->bitmapqualorig = 561 fix_scan_list(root, splan->bitmapqualorig, rtoffset); 562 } 563 break; 564 case T_TidScan: 565 { 566 TidScan *splan = (TidScan *) plan; 567 568 splan->scan.scanrelid += rtoffset; 569 splan->scan.plan.targetlist = 570 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 571 splan->scan.plan.qual = 572 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 573 splan->tidquals = 574 fix_scan_list(root, splan->tidquals, rtoffset); 575 } 576 break; 577 case T_SubqueryScan: 578 /* Needs special treatment, see comments below */ 579 return set_subqueryscan_references(root, 580 (SubqueryScan *) plan, 581 rtoffset); 582 case T_FunctionScan: 583 { 584 FunctionScan *splan = (FunctionScan *) plan; 585 586 splan->scan.scanrelid += rtoffset; 587 splan->scan.plan.targetlist = 588 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 589 splan->scan.plan.qual = 590 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 591 splan->functions = 592 fix_scan_list(root, splan->functions, rtoffset); 593 } 594 break; 595 case T_TableFuncScan: 596 { 597 TableFuncScan *splan = (TableFuncScan *) plan; 598 599 splan->scan.scanrelid += rtoffset; 600 splan->scan.plan.targetlist = 601 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 602 splan->scan.plan.qual = 603 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 604 splan->tablefunc = (TableFunc *) 605 fix_scan_expr(root, (Node *) splan->tablefunc, rtoffset); 606 } 607 break; 608 case T_ValuesScan: 609 { 610 ValuesScan *splan = (ValuesScan *) plan; 611 612 splan->scan.scanrelid += rtoffset; 613 splan->scan.plan.targetlist = 614 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 615 splan->scan.plan.qual = 616 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 617 splan->values_lists = 618 fix_scan_list(root, splan->values_lists, rtoffset); 619 } 620 break; 621 case T_CteScan: 622 { 623 CteScan *splan = (CteScan *) plan; 624 625 splan->scan.scanrelid += rtoffset; 626 splan->scan.plan.targetlist = 627 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 628 splan->scan.plan.qual = 629 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 630 } 631 break; 632 case T_NamedTuplestoreScan: 633 { 634 NamedTuplestoreScan *splan = (NamedTuplestoreScan *) plan; 635 636 splan->scan.scanrelid += rtoffset; 637 splan->scan.plan.targetlist = 638 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 639 splan->scan.plan.qual = 640 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 641 } 642 break; 643 case T_WorkTableScan: 644 { 645 WorkTableScan *splan = (WorkTableScan *) plan; 646 647 splan->scan.scanrelid += rtoffset; 648 splan->scan.plan.targetlist = 649 fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); 650 splan->scan.plan.qual = 651 fix_scan_list(root, splan->scan.plan.qual, rtoffset); 652 } 653 break; 654 case T_ForeignScan: 655 set_foreignscan_references(root, (ForeignScan *) plan, rtoffset); 656 break; 657 case T_CustomScan: 658 set_customscan_references(root, (CustomScan *) plan, rtoffset); 659 break; 660 661 case T_NestLoop: 662 case T_MergeJoin: 663 case T_HashJoin: 664 set_join_references(root, (Join *) plan, rtoffset); 665 break; 666 667 case T_Gather: 668 case T_GatherMerge: 669 { 670 set_upper_references(root, plan, rtoffset); 671 set_param_references(root, plan); 672 } 673 break; 674 675 case T_Hash: 676 set_hash_references(root, plan, rtoffset); 677 break; 678 679 case T_Material: 680 case T_Sort: 681 case T_IncrementalSort: 682 case T_Unique: 683 case T_SetOp: 684 685 /* 686 * These plan types don't actually bother to evaluate their 687 * targetlists, because they just return their unmodified input 688 * tuples. Even though the targetlist won't be used by the 689 * executor, we fix it up for possible use by EXPLAIN (not to 690 * mention ease of debugging --- wrong varnos are very confusing). 691 */ 692 set_dummy_tlist_references(plan, rtoffset); 693 694 /* 695 * Since these plan types don't check quals either, we should not 696 * find any qual expression attached to them. 697 */ 698 Assert(plan->qual == NIL); 699 break; 700 case T_LockRows: 701 { 702 LockRows *splan = (LockRows *) plan; 703 704 /* 705 * Like the plan types above, LockRows doesn't evaluate its 706 * tlist or quals. But we have to fix up the RT indexes in 707 * its rowmarks. 708 */ 709 set_dummy_tlist_references(plan, rtoffset); 710 Assert(splan->plan.qual == NIL); 711 712 foreach(l, splan->rowMarks) 713 { 714 PlanRowMark *rc = (PlanRowMark *) lfirst(l); 715 716 rc->rti += rtoffset; 717 rc->prti += rtoffset; 718 } 719 } 720 break; 721 case T_Limit: 722 { 723 Limit *splan = (Limit *) plan; 724 725 /* 726 * Like the plan types above, Limit doesn't evaluate its tlist 727 * or quals. It does have live expressions for limit/offset, 728 * however; and those cannot contain subplan variable refs, so 729 * fix_scan_expr works for them. 730 */ 731 set_dummy_tlist_references(plan, rtoffset); 732 Assert(splan->plan.qual == NIL); 733 734 splan->limitOffset = 735 fix_scan_expr(root, splan->limitOffset, rtoffset); 736 splan->limitCount = 737 fix_scan_expr(root, splan->limitCount, rtoffset); 738 } 739 break; 740 case T_Agg: 741 { 742 Agg *agg = (Agg *) plan; 743 744 /* 745 * If this node is combining partial-aggregation results, we 746 * must convert its Aggrefs to contain references to the 747 * partial-aggregate subexpressions that will be available 748 * from the child plan node. 749 */ 750 if (DO_AGGSPLIT_COMBINE(agg->aggsplit)) 751 { 752 plan->targetlist = (List *) 753 convert_combining_aggrefs((Node *) plan->targetlist, 754 NULL); 755 plan->qual = (List *) 756 convert_combining_aggrefs((Node *) plan->qual, 757 NULL); 758 } 759 760 set_upper_references(root, plan, rtoffset); 761 } 762 break; 763 case T_Group: 764 set_upper_references(root, plan, rtoffset); 765 break; 766 case T_WindowAgg: 767 { 768 WindowAgg *wplan = (WindowAgg *) plan; 769 770 set_upper_references(root, plan, rtoffset); 771 772 /* 773 * Like Limit node limit/offset expressions, WindowAgg has 774 * frame offset expressions, which cannot contain subplan 775 * variable refs, so fix_scan_expr works for them. 776 */ 777 wplan->startOffset = 778 fix_scan_expr(root, wplan->startOffset, rtoffset); 779 wplan->endOffset = 780 fix_scan_expr(root, wplan->endOffset, rtoffset); 781 } 782 break; 783 case T_Result: 784 { 785 Result *splan = (Result *) plan; 786 787 /* 788 * Result may or may not have a subplan; if not, it's more 789 * like a scan node than an upper node. 790 */ 791 if (splan->plan.lefttree != NULL) 792 set_upper_references(root, plan, rtoffset); 793 else 794 { 795 splan->plan.targetlist = 796 fix_scan_list(root, splan->plan.targetlist, rtoffset); 797 splan->plan.qual = 798 fix_scan_list(root, splan->plan.qual, rtoffset); 799 } 800 /* resconstantqual can't contain any subplan variable refs */ 801 splan->resconstantqual = 802 fix_scan_expr(root, splan->resconstantqual, rtoffset); 803 } 804 break; 805 case T_ProjectSet: 806 set_upper_references(root, plan, rtoffset); 807 break; 808 case T_ModifyTable: 809 { 810 ModifyTable *splan = (ModifyTable *) plan; 811 812 Assert(splan->plan.targetlist == NIL); 813 Assert(splan->plan.qual == NIL); 814 815 splan->withCheckOptionLists = 816 fix_scan_list(root, splan->withCheckOptionLists, rtoffset); 817 818 if (splan->returningLists) 819 { 820 List *newRL = NIL; 821 ListCell *lcrl, 822 *lcrr, 823 *lcp; 824 825 /* 826 * Pass each per-subplan returningList through 827 * set_returning_clause_references(). 828 */ 829 Assert(list_length(splan->returningLists) == list_length(splan->resultRelations)); 830 Assert(list_length(splan->returningLists) == list_length(splan->plans)); 831 forthree(lcrl, splan->returningLists, 832 lcrr, splan->resultRelations, 833 lcp, splan->plans) 834 { 835 List *rlist = (List *) lfirst(lcrl); 836 Index resultrel = lfirst_int(lcrr); 837 Plan *subplan = (Plan *) lfirst(lcp); 838 839 rlist = set_returning_clause_references(root, 840 rlist, 841 subplan, 842 resultrel, 843 rtoffset); 844 newRL = lappend(newRL, rlist); 845 } 846 splan->returningLists = newRL; 847 848 /* 849 * Set up the visible plan targetlist as being the same as 850 * the first RETURNING list. This is for the use of 851 * EXPLAIN; the executor won't pay any attention to the 852 * targetlist. We postpone this step until here so that 853 * we don't have to do set_returning_clause_references() 854 * twice on identical targetlists. 855 */ 856 splan->plan.targetlist = copyObject(linitial(newRL)); 857 } 858 859 /* 860 * We treat ModifyTable with ON CONFLICT as a form of 'pseudo 861 * join', where the inner side is the EXCLUDED tuple. 862 * Therefore use fix_join_expr to setup the relevant variables 863 * to INNER_VAR. We explicitly don't create any OUTER_VARs as 864 * those are already used by RETURNING and it seems better to 865 * be non-conflicting. 866 */ 867 if (splan->onConflictSet) 868 { 869 indexed_tlist *itlist; 870 871 itlist = build_tlist_index(splan->exclRelTlist); 872 873 splan->onConflictSet = 874 fix_join_expr(root, splan->onConflictSet, 875 NULL, itlist, 876 linitial_int(splan->resultRelations), 877 rtoffset); 878 879 splan->onConflictWhere = (Node *) 880 fix_join_expr(root, (List *) splan->onConflictWhere, 881 NULL, itlist, 882 linitial_int(splan->resultRelations), 883 rtoffset); 884 885 pfree(itlist); 886 887 splan->exclRelTlist = 888 fix_scan_list(root, splan->exclRelTlist, rtoffset); 889 } 890 891 splan->nominalRelation += rtoffset; 892 if (splan->rootRelation) 893 splan->rootRelation += rtoffset; 894 splan->exclRelRTI += rtoffset; 895 896 foreach(l, splan->resultRelations) 897 { 898 lfirst_int(l) += rtoffset; 899 } 900 foreach(l, splan->rowMarks) 901 { 902 PlanRowMark *rc = (PlanRowMark *) lfirst(l); 903 904 rc->rti += rtoffset; 905 rc->prti += rtoffset; 906 } 907 foreach(l, splan->plans) 908 { 909 lfirst(l) = set_plan_refs(root, 910 (Plan *) lfirst(l), 911 rtoffset); 912 } 913 914 /* 915 * Append this ModifyTable node's final result relation RT 916 * index(es) to the global list for the plan, and set its 917 * resultRelIndex to reflect their starting position in the 918 * global list. 919 */ 920 splan->resultRelIndex = list_length(root->glob->resultRelations); 921 root->glob->resultRelations = 922 list_concat(root->glob->resultRelations, 923 splan->resultRelations); 924 925 /* 926 * If the main target relation is a partitioned table, also 927 * add the partition root's RT index to rootResultRelations, 928 * and remember its index in that list in rootResultRelIndex. 929 */ 930 if (splan->rootRelation) 931 { 932 splan->rootResultRelIndex = 933 list_length(root->glob->rootResultRelations); 934 root->glob->rootResultRelations = 935 lappend_int(root->glob->rootResultRelations, 936 splan->rootRelation); 937 } 938 } 939 break; 940 case T_Append: 941 /* Needs special treatment, see comments below */ 942 return set_append_references(root, 943 (Append *) plan, 944 rtoffset); 945 case T_MergeAppend: 946 /* Needs special treatment, see comments below */ 947 return set_mergeappend_references(root, 948 (MergeAppend *) plan, 949 rtoffset); 950 case T_RecursiveUnion: 951 /* This doesn't evaluate targetlist or check quals either */ 952 set_dummy_tlist_references(plan, rtoffset); 953 Assert(plan->qual == NIL); 954 break; 955 case T_BitmapAnd: 956 { 957 BitmapAnd *splan = (BitmapAnd *) plan; 958 959 /* BitmapAnd works like Append, but has no tlist */ 960 Assert(splan->plan.targetlist == NIL); 961 Assert(splan->plan.qual == NIL); 962 foreach(l, splan->bitmapplans) 963 { 964 lfirst(l) = set_plan_refs(root, 965 (Plan *) lfirst(l), 966 rtoffset); 967 } 968 } 969 break; 970 case T_BitmapOr: 971 { 972 BitmapOr *splan = (BitmapOr *) plan; 973 974 /* BitmapOr works like Append, but has no tlist */ 975 Assert(splan->plan.targetlist == NIL); 976 Assert(splan->plan.qual == NIL); 977 foreach(l, splan->bitmapplans) 978 { 979 lfirst(l) = set_plan_refs(root, 980 (Plan *) lfirst(l), 981 rtoffset); 982 } 983 } 984 break; 985 default: 986 elog(ERROR, "unrecognized node type: %d", 987 (int) nodeTag(plan)); 988 break; 989 } 990 991 /* 992 * Now recurse into child plans, if any 993 * 994 * NOTE: it is essential that we recurse into child plans AFTER we set 995 * subplan references in this plan's tlist and quals. If we did the 996 * reference-adjustments bottom-up, then we would fail to match this 997 * plan's var nodes against the already-modified nodes of the children. 998 */ 999 plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset); 1000 plan->righttree = set_plan_refs(root, plan->righttree, rtoffset); 1001 1002 return plan; 1003 } 1004 1005 /* 1006 * set_indexonlyscan_references 1007 * Do set_plan_references processing on an IndexOnlyScan 1008 * 1009 * This is unlike the handling of a plain IndexScan because we have to 1010 * convert Vars referencing the heap into Vars referencing the index. 1011 * We can use the fix_upper_expr machinery for that, by working from a 1012 * targetlist describing the index columns. 1013 */ 1014 static Plan * 1015 set_indexonlyscan_references(PlannerInfo *root, 1016 IndexOnlyScan *plan, 1017 int rtoffset) 1018 { 1019 indexed_tlist *index_itlist; 1020 1021 index_itlist = build_tlist_index(plan->indextlist); 1022 1023 plan->scan.scanrelid += rtoffset; 1024 plan->scan.plan.targetlist = (List *) 1025 fix_upper_expr(root, 1026 (Node *) plan->scan.plan.targetlist, 1027 index_itlist, 1028 INDEX_VAR, 1029 rtoffset); 1030 plan->scan.plan.qual = (List *) 1031 fix_upper_expr(root, 1032 (Node *) plan->scan.plan.qual, 1033 index_itlist, 1034 INDEX_VAR, 1035 rtoffset); 1036 /* indexqual is already transformed to reference index columns */ 1037 plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset); 1038 /* indexorderby is already transformed to reference index columns */ 1039 plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset); 1040 /* indextlist must NOT be transformed to reference index columns */ 1041 plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset); 1042 1043 pfree(index_itlist); 1044 1045 return (Plan *) plan; 1046 } 1047 1048 /* 1049 * set_subqueryscan_references 1050 * Do set_plan_references processing on a SubqueryScan 1051 * 1052 * We try to strip out the SubqueryScan entirely; if we can't, we have 1053 * to do the normal processing on it. 1054 */ 1055 static Plan * 1056 set_subqueryscan_references(PlannerInfo *root, 1057 SubqueryScan *plan, 1058 int rtoffset) 1059 { 1060 RelOptInfo *rel; 1061 Plan *result; 1062 1063 /* Need to look up the subquery's RelOptInfo, since we need its subroot */ 1064 rel = find_base_rel(root, plan->scan.scanrelid); 1065 1066 /* Recursively process the subplan */ 1067 plan->subplan = set_plan_references(rel->subroot, plan->subplan); 1068 1069 if (trivial_subqueryscan(plan)) 1070 { 1071 /* 1072 * We can omit the SubqueryScan node and just pull up the subplan. 1073 */ 1074 result = clean_up_removed_plan_level((Plan *) plan, plan->subplan); 1075 } 1076 else 1077 { 1078 /* 1079 * Keep the SubqueryScan node. We have to do the processing that 1080 * set_plan_references would otherwise have done on it. Notice we do 1081 * not do set_upper_references() here, because a SubqueryScan will 1082 * always have been created with correct references to its subplan's 1083 * outputs to begin with. 1084 */ 1085 plan->scan.scanrelid += rtoffset; 1086 plan->scan.plan.targetlist = 1087 fix_scan_list(root, plan->scan.plan.targetlist, rtoffset); 1088 plan->scan.plan.qual = 1089 fix_scan_list(root, plan->scan.plan.qual, rtoffset); 1090 1091 result = (Plan *) plan; 1092 } 1093 1094 return result; 1095 } 1096 1097 /* 1098 * trivial_subqueryscan 1099 * Detect whether a SubqueryScan can be deleted from the plan tree. 1100 * 1101 * We can delete it if it has no qual to check and the targetlist just 1102 * regurgitates the output of the child plan. 1103 */ 1104 static bool 1105 trivial_subqueryscan(SubqueryScan *plan) 1106 { 1107 int attrno; 1108 ListCell *lp, 1109 *lc; 1110 1111 if (plan->scan.plan.qual != NIL) 1112 return false; 1113 1114 if (list_length(plan->scan.plan.targetlist) != 1115 list_length(plan->subplan->targetlist)) 1116 return false; /* tlists not same length */ 1117 1118 attrno = 1; 1119 forboth(lp, plan->scan.plan.targetlist, lc, plan->subplan->targetlist) 1120 { 1121 TargetEntry *ptle = (TargetEntry *) lfirst(lp); 1122 TargetEntry *ctle = (TargetEntry *) lfirst(lc); 1123 1124 if (ptle->resjunk != ctle->resjunk) 1125 return false; /* tlist doesn't match junk status */ 1126 1127 /* 1128 * We accept either a Var referencing the corresponding element of the 1129 * subplan tlist, or a Const equaling the subplan element. See 1130 * generate_setop_tlist() for motivation. 1131 */ 1132 if (ptle->expr && IsA(ptle->expr, Var)) 1133 { 1134 Var *var = (Var *) ptle->expr; 1135 1136 Assert(var->varno == plan->scan.scanrelid); 1137 Assert(var->varlevelsup == 0); 1138 if (var->varattno != attrno) 1139 return false; /* out of order */ 1140 } 1141 else if (ptle->expr && IsA(ptle->expr, Const)) 1142 { 1143 if (!equal(ptle->expr, ctle->expr)) 1144 return false; 1145 } 1146 else 1147 return false; 1148 1149 attrno++; 1150 } 1151 1152 return true; 1153 } 1154 1155 /* 1156 * clean_up_removed_plan_level 1157 * Do necessary cleanup when we strip out a SubqueryScan, Append, etc 1158 * 1159 * We are dropping the "parent" plan in favor of returning just its "child". 1160 * A few small tweaks are needed. 1161 */ 1162 static Plan * 1163 clean_up_removed_plan_level(Plan *parent, Plan *child) 1164 { 1165 /* We have to be sure we don't lose any initplans */ 1166 child->initPlan = list_concat(parent->initPlan, 1167 child->initPlan); 1168 1169 /* 1170 * We also have to transfer the parent's column labeling info into the 1171 * child, else columns sent to client will be improperly labeled if this 1172 * is the topmost plan level. resjunk and so on may be important too. 1173 */ 1174 apply_tlist_labeling(child->targetlist, parent->targetlist); 1175 1176 return child; 1177 } 1178 1179 /* 1180 * set_foreignscan_references 1181 * Do set_plan_references processing on a ForeignScan 1182 */ 1183 static void 1184 set_foreignscan_references(PlannerInfo *root, 1185 ForeignScan *fscan, 1186 int rtoffset) 1187 { 1188 /* Adjust scanrelid if it's valid */ 1189 if (fscan->scan.scanrelid > 0) 1190 fscan->scan.scanrelid += rtoffset; 1191 1192 if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0) 1193 { 1194 /* 1195 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals to reference 1196 * foreign scan tuple 1197 */ 1198 indexed_tlist *itlist = build_tlist_index(fscan->fdw_scan_tlist); 1199 1200 fscan->scan.plan.targetlist = (List *) 1201 fix_upper_expr(root, 1202 (Node *) fscan->scan.plan.targetlist, 1203 itlist, 1204 INDEX_VAR, 1205 rtoffset); 1206 fscan->scan.plan.qual = (List *) 1207 fix_upper_expr(root, 1208 (Node *) fscan->scan.plan.qual, 1209 itlist, 1210 INDEX_VAR, 1211 rtoffset); 1212 fscan->fdw_exprs = (List *) 1213 fix_upper_expr(root, 1214 (Node *) fscan->fdw_exprs, 1215 itlist, 1216 INDEX_VAR, 1217 rtoffset); 1218 fscan->fdw_recheck_quals = (List *) 1219 fix_upper_expr(root, 1220 (Node *) fscan->fdw_recheck_quals, 1221 itlist, 1222 INDEX_VAR, 1223 rtoffset); 1224 pfree(itlist); 1225 /* fdw_scan_tlist itself just needs fix_scan_list() adjustments */ 1226 fscan->fdw_scan_tlist = 1227 fix_scan_list(root, fscan->fdw_scan_tlist, rtoffset); 1228 } 1229 else 1230 { 1231 /* 1232 * Adjust tlist, qual, fdw_exprs, fdw_recheck_quals in the standard 1233 * way 1234 */ 1235 fscan->scan.plan.targetlist = 1236 fix_scan_list(root, fscan->scan.plan.targetlist, rtoffset); 1237 fscan->scan.plan.qual = 1238 fix_scan_list(root, fscan->scan.plan.qual, rtoffset); 1239 fscan->fdw_exprs = 1240 fix_scan_list(root, fscan->fdw_exprs, rtoffset); 1241 fscan->fdw_recheck_quals = 1242 fix_scan_list(root, fscan->fdw_recheck_quals, rtoffset); 1243 } 1244 1245 fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset); 1246 } 1247 1248 /* 1249 * set_customscan_references 1250 * Do set_plan_references processing on a CustomScan 1251 */ 1252 static void 1253 set_customscan_references(PlannerInfo *root, 1254 CustomScan *cscan, 1255 int rtoffset) 1256 { 1257 ListCell *lc; 1258 1259 /* Adjust scanrelid if it's valid */ 1260 if (cscan->scan.scanrelid > 0) 1261 cscan->scan.scanrelid += rtoffset; 1262 1263 if (cscan->custom_scan_tlist != NIL || cscan->scan.scanrelid == 0) 1264 { 1265 /* Adjust tlist, qual, custom_exprs to reference custom scan tuple */ 1266 indexed_tlist *itlist = build_tlist_index(cscan->custom_scan_tlist); 1267 1268 cscan->scan.plan.targetlist = (List *) 1269 fix_upper_expr(root, 1270 (Node *) cscan->scan.plan.targetlist, 1271 itlist, 1272 INDEX_VAR, 1273 rtoffset); 1274 cscan->scan.plan.qual = (List *) 1275 fix_upper_expr(root, 1276 (Node *) cscan->scan.plan.qual, 1277 itlist, 1278 INDEX_VAR, 1279 rtoffset); 1280 cscan->custom_exprs = (List *) 1281 fix_upper_expr(root, 1282 (Node *) cscan->custom_exprs, 1283 itlist, 1284 INDEX_VAR, 1285 rtoffset); 1286 pfree(itlist); 1287 /* custom_scan_tlist itself just needs fix_scan_list() adjustments */ 1288 cscan->custom_scan_tlist = 1289 fix_scan_list(root, cscan->custom_scan_tlist, rtoffset); 1290 } 1291 else 1292 { 1293 /* Adjust tlist, qual, custom_exprs in the standard way */ 1294 cscan->scan.plan.targetlist = 1295 fix_scan_list(root, cscan->scan.plan.targetlist, rtoffset); 1296 cscan->scan.plan.qual = 1297 fix_scan_list(root, cscan->scan.plan.qual, rtoffset); 1298 cscan->custom_exprs = 1299 fix_scan_list(root, cscan->custom_exprs, rtoffset); 1300 } 1301 1302 /* Adjust child plan-nodes recursively, if needed */ 1303 foreach(lc, cscan->custom_plans) 1304 { 1305 lfirst(lc) = set_plan_refs(root, (Plan *) lfirst(lc), rtoffset); 1306 } 1307 1308 cscan->custom_relids = offset_relid_set(cscan->custom_relids, rtoffset); 1309 } 1310 1311 /* 1312 * set_append_references 1313 * Do set_plan_references processing on an Append 1314 * 1315 * We try to strip out the Append entirely; if we can't, we have 1316 * to do the normal processing on it. 1317 */ 1318 static Plan * 1319 set_append_references(PlannerInfo *root, 1320 Append *aplan, 1321 int rtoffset) 1322 { 1323 ListCell *l; 1324 1325 /* 1326 * Append, like Sort et al, doesn't actually evaluate its targetlist or 1327 * check quals. If it's got exactly one child plan, then it's not doing 1328 * anything useful at all, and we can strip it out. 1329 */ 1330 Assert(aplan->plan.qual == NIL); 1331 1332 /* First, we gotta recurse on the children */ 1333 foreach(l, aplan->appendplans) 1334 { 1335 lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); 1336 } 1337 1338 /* Now, if there's just one, forget the Append and return that child */ 1339 if (list_length(aplan->appendplans) == 1) 1340 return clean_up_removed_plan_level((Plan *) aplan, 1341 (Plan *) linitial(aplan->appendplans)); 1342 1343 /* 1344 * Otherwise, clean up the Append as needed. It's okay to do this after 1345 * recursing to the children, because set_dummy_tlist_references doesn't 1346 * look at those. 1347 */ 1348 set_dummy_tlist_references((Plan *) aplan, rtoffset); 1349 1350 aplan->apprelids = offset_relid_set(aplan->apprelids, rtoffset); 1351 1352 if (aplan->part_prune_info) 1353 { 1354 foreach(l, aplan->part_prune_info->prune_infos) 1355 { 1356 List *prune_infos = lfirst(l); 1357 ListCell *l2; 1358 1359 foreach(l2, prune_infos) 1360 { 1361 PartitionedRelPruneInfo *pinfo = lfirst(l2); 1362 1363 pinfo->rtindex += rtoffset; 1364 } 1365 } 1366 } 1367 1368 /* We don't need to recurse to lefttree or righttree ... */ 1369 Assert(aplan->plan.lefttree == NULL); 1370 Assert(aplan->plan.righttree == NULL); 1371 1372 return (Plan *) aplan; 1373 } 1374 1375 /* 1376 * set_mergeappend_references 1377 * Do set_plan_references processing on a MergeAppend 1378 * 1379 * We try to strip out the MergeAppend entirely; if we can't, we have 1380 * to do the normal processing on it. 1381 */ 1382 static Plan * 1383 set_mergeappend_references(PlannerInfo *root, 1384 MergeAppend *mplan, 1385 int rtoffset) 1386 { 1387 ListCell *l; 1388 1389 /* 1390 * MergeAppend, like Sort et al, doesn't actually evaluate its targetlist 1391 * or check quals. If it's got exactly one child plan, then it's not 1392 * doing anything useful at all, and we can strip it out. 1393 */ 1394 Assert(mplan->plan.qual == NIL); 1395 1396 /* First, we gotta recurse on the children */ 1397 foreach(l, mplan->mergeplans) 1398 { 1399 lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); 1400 } 1401 1402 /* Now, if there's just one, forget the MergeAppend and return that child */ 1403 if (list_length(mplan->mergeplans) == 1) 1404 return clean_up_removed_plan_level((Plan *) mplan, 1405 (Plan *) linitial(mplan->mergeplans)); 1406 1407 /* 1408 * Otherwise, clean up the MergeAppend as needed. It's okay to do this 1409 * after recursing to the children, because set_dummy_tlist_references 1410 * doesn't look at those. 1411 */ 1412 set_dummy_tlist_references((Plan *) mplan, rtoffset); 1413 1414 mplan->apprelids = offset_relid_set(mplan->apprelids, rtoffset); 1415 1416 if (mplan->part_prune_info) 1417 { 1418 foreach(l, mplan->part_prune_info->prune_infos) 1419 { 1420 List *prune_infos = lfirst(l); 1421 ListCell *l2; 1422 1423 foreach(l2, prune_infos) 1424 { 1425 PartitionedRelPruneInfo *pinfo = lfirst(l2); 1426 1427 pinfo->rtindex += rtoffset; 1428 } 1429 } 1430 } 1431 1432 /* We don't need to recurse to lefttree or righttree ... */ 1433 Assert(mplan->plan.lefttree == NULL); 1434 Assert(mplan->plan.righttree == NULL); 1435 1436 return (Plan *) mplan; 1437 } 1438 1439 /* 1440 * set_hash_references 1441 * Do set_plan_references processing on a Hash node 1442 */ 1443 static void 1444 set_hash_references(PlannerInfo *root, Plan *plan, int rtoffset) 1445 { 1446 Hash *hplan = (Hash *) plan; 1447 Plan *outer_plan = plan->lefttree; 1448 indexed_tlist *outer_itlist; 1449 1450 /* 1451 * Hash's hashkeys are used when feeding tuples into the hashtable, 1452 * therefore have them reference Hash's outer plan (which itself is the 1453 * inner plan of the HashJoin). 1454 */ 1455 outer_itlist = build_tlist_index(outer_plan->targetlist); 1456 hplan->hashkeys = (List *) 1457 fix_upper_expr(root, 1458 (Node *) hplan->hashkeys, 1459 outer_itlist, 1460 OUTER_VAR, 1461 rtoffset); 1462 1463 /* Hash doesn't project */ 1464 set_dummy_tlist_references(plan, rtoffset); 1465 1466 /* Hash nodes don't have their own quals */ 1467 Assert(plan->qual == NIL); 1468 } 1469 1470 /* 1471 * offset_relid_set 1472 * Apply rtoffset to the members of a Relids set. 1473 */ 1474 static Relids 1475 offset_relid_set(Relids relids, int rtoffset) 1476 { 1477 Relids result = NULL; 1478 int rtindex; 1479 1480 /* If there's no offset to apply, we needn't recompute the value */ 1481 if (rtoffset == 0) 1482 return relids; 1483 rtindex = -1; 1484 while ((rtindex = bms_next_member(relids, rtindex)) >= 0) 1485 result = bms_add_member(result, rtindex + rtoffset); 1486 return result; 1487 } 1488 1489 /* 1490 * copyVar 1491 * Copy a Var node. 1492 * 1493 * fix_scan_expr and friends do this enough times that it's worth having 1494 * a bespoke routine instead of using the generic copyObject() function. 1495 */ 1496 static inline Var * 1497 copyVar(Var *var) 1498 { 1499 Var *newvar = (Var *) palloc(sizeof(Var)); 1500 1501 *newvar = *var; 1502 return newvar; 1503 } 1504 1505 /* 1506 * fix_expr_common 1507 * Do generic set_plan_references processing on an expression node 1508 * 1509 * This is code that is common to all variants of expression-fixing. 1510 * We must look up operator opcode info for OpExpr and related nodes, 1511 * add OIDs from regclass Const nodes into root->glob->relationOids, and 1512 * add PlanInvalItems for user-defined functions into root->glob->invalItems. 1513 * We also fill in column index lists for GROUPING() expressions. 1514 * 1515 * We assume it's okay to update opcode info in-place. So this could possibly 1516 * scribble on the planner's input data structures, but it's OK. 1517 */ 1518 static void 1519 fix_expr_common(PlannerInfo *root, Node *node) 1520 { 1521 /* We assume callers won't call us on a NULL pointer */ 1522 if (IsA(node, Aggref)) 1523 { 1524 record_plan_function_dependency(root, 1525 ((Aggref *) node)->aggfnoid); 1526 } 1527 else if (IsA(node, WindowFunc)) 1528 { 1529 record_plan_function_dependency(root, 1530 ((WindowFunc *) node)->winfnoid); 1531 } 1532 else if (IsA(node, FuncExpr)) 1533 { 1534 record_plan_function_dependency(root, 1535 ((FuncExpr *) node)->funcid); 1536 } 1537 else if (IsA(node, OpExpr)) 1538 { 1539 set_opfuncid((OpExpr *) node); 1540 record_plan_function_dependency(root, 1541 ((OpExpr *) node)->opfuncid); 1542 } 1543 else if (IsA(node, DistinctExpr)) 1544 { 1545 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ 1546 record_plan_function_dependency(root, 1547 ((DistinctExpr *) node)->opfuncid); 1548 } 1549 else if (IsA(node, NullIfExpr)) 1550 { 1551 set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ 1552 record_plan_function_dependency(root, 1553 ((NullIfExpr *) node)->opfuncid); 1554 } 1555 else if (IsA(node, ScalarArrayOpExpr)) 1556 { 1557 set_sa_opfuncid((ScalarArrayOpExpr *) node); 1558 record_plan_function_dependency(root, 1559 ((ScalarArrayOpExpr *) node)->opfuncid); 1560 } 1561 else if (IsA(node, Const)) 1562 { 1563 Const *con = (Const *) node; 1564 1565 /* Check for regclass reference */ 1566 if (ISREGCLASSCONST(con)) 1567 root->glob->relationOids = 1568 lappend_oid(root->glob->relationOids, 1569 DatumGetObjectId(con->constvalue)); 1570 } 1571 else if (IsA(node, GroupingFunc)) 1572 { 1573 GroupingFunc *g = (GroupingFunc *) node; 1574 AttrNumber *grouping_map = root->grouping_map; 1575 1576 /* If there are no grouping sets, we don't need this. */ 1577 1578 Assert(grouping_map || g->cols == NIL); 1579 1580 if (grouping_map) 1581 { 1582 ListCell *lc; 1583 List *cols = NIL; 1584 1585 foreach(lc, g->refs) 1586 { 1587 cols = lappend_int(cols, grouping_map[lfirst_int(lc)]); 1588 } 1589 1590 Assert(!g->cols || equal(cols, g->cols)); 1591 1592 if (!g->cols) 1593 g->cols = cols; 1594 } 1595 } 1596 } 1597 1598 /* 1599 * fix_param_node 1600 * Do set_plan_references processing on a Param 1601 * 1602 * If it's a PARAM_MULTIEXPR, replace it with the appropriate Param from 1603 * root->multiexpr_params; otherwise no change is needed. 1604 * Just for paranoia's sake, we make a copy of the node in either case. 1605 */ 1606 static Node * 1607 fix_param_node(PlannerInfo *root, Param *p) 1608 { 1609 if (p->paramkind == PARAM_MULTIEXPR) 1610 { 1611 int subqueryid = p->paramid >> 16; 1612 int colno = p->paramid & 0xFFFF; 1613 List *params; 1614 1615 if (subqueryid <= 0 || 1616 subqueryid > list_length(root->multiexpr_params)) 1617 elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid); 1618 params = (List *) list_nth(root->multiexpr_params, subqueryid - 1); 1619 if (colno <= 0 || colno > list_length(params)) 1620 elog(ERROR, "unexpected PARAM_MULTIEXPR ID: %d", p->paramid); 1621 return copyObject(list_nth(params, colno - 1)); 1622 } 1623 return (Node *) copyObject(p); 1624 } 1625 1626 /* 1627 * fix_scan_expr 1628 * Do set_plan_references processing on a scan-level expression 1629 * 1630 * This consists of incrementing all Vars' varnos by rtoffset, 1631 * replacing PARAM_MULTIEXPR Params, expanding PlaceHolderVars, 1632 * replacing Aggref nodes that should be replaced by initplan output Params, 1633 * looking up operator opcode info for OpExpr and related nodes, 1634 * and adding OIDs from regclass Const nodes into root->glob->relationOids. 1635 */ 1636 static Node * 1637 fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset) 1638 { 1639 fix_scan_expr_context context; 1640 1641 context.root = root; 1642 context.rtoffset = rtoffset; 1643 1644 if (rtoffset != 0 || 1645 root->multiexpr_params != NIL || 1646 root->glob->lastPHId != 0 || 1647 root->minmax_aggs != NIL) 1648 { 1649 return fix_scan_expr_mutator(node, &context); 1650 } 1651 else 1652 { 1653 /* 1654 * If rtoffset == 0, we don't need to change any Vars, and if there 1655 * are no MULTIEXPR subqueries then we don't need to replace 1656 * PARAM_MULTIEXPR Params, and if there are no placeholders anywhere 1657 * we won't need to remove them, and if there are no minmax Aggrefs we 1658 * won't need to replace them. Then it's OK to just scribble on the 1659 * input node tree instead of copying (since the only change, filling 1660 * in any unset opfuncid fields, is harmless). This saves just enough 1661 * cycles to be noticeable on trivial queries. 1662 */ 1663 (void) fix_scan_expr_walker(node, &context); 1664 return node; 1665 } 1666 } 1667 1668 static Node * 1669 fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context) 1670 { 1671 if (node == NULL) 1672 return NULL; 1673 if (IsA(node, Var)) 1674 { 1675 Var *var = copyVar((Var *) node); 1676 1677 Assert(var->varlevelsup == 0); 1678 1679 /* 1680 * We should not see any Vars marked INNER_VAR or OUTER_VAR. But an 1681 * indexqual expression could contain INDEX_VAR Vars. 1682 */ 1683 Assert(var->varno != INNER_VAR); 1684 Assert(var->varno != OUTER_VAR); 1685 if (!IS_SPECIAL_VARNO(var->varno)) 1686 var->varno += context->rtoffset; 1687 if (var->varnosyn > 0) 1688 var->varnosyn += context->rtoffset; 1689 return (Node *) var; 1690 } 1691 if (IsA(node, Param)) 1692 return fix_param_node(context->root, (Param *) node); 1693 if (IsA(node, Aggref)) 1694 { 1695 Aggref *aggref = (Aggref *) node; 1696 1697 /* See if the Aggref should be replaced by a Param */ 1698 if (context->root->minmax_aggs != NIL && 1699 list_length(aggref->args) == 1) 1700 { 1701 TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args); 1702 ListCell *lc; 1703 1704 foreach(lc, context->root->minmax_aggs) 1705 { 1706 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc); 1707 1708 if (mminfo->aggfnoid == aggref->aggfnoid && 1709 equal(mminfo->target, curTarget->expr)) 1710 return (Node *) copyObject(mminfo->param); 1711 } 1712 } 1713 /* If no match, just fall through to process it normally */ 1714 } 1715 if (IsA(node, CurrentOfExpr)) 1716 { 1717 CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node); 1718 1719 Assert(cexpr->cvarno != INNER_VAR); 1720 Assert(cexpr->cvarno != OUTER_VAR); 1721 if (!IS_SPECIAL_VARNO(cexpr->cvarno)) 1722 cexpr->cvarno += context->rtoffset; 1723 return (Node *) cexpr; 1724 } 1725 if (IsA(node, PlaceHolderVar)) 1726 { 1727 /* At scan level, we should always just evaluate the contained expr */ 1728 PlaceHolderVar *phv = (PlaceHolderVar *) node; 1729 1730 return fix_scan_expr_mutator((Node *) phv->phexpr, context); 1731 } 1732 fix_expr_common(context->root, node); 1733 return expression_tree_mutator(node, fix_scan_expr_mutator, 1734 (void *) context); 1735 } 1736 1737 static bool 1738 fix_scan_expr_walker(Node *node, fix_scan_expr_context *context) 1739 { 1740 if (node == NULL) 1741 return false; 1742 Assert(!IsA(node, PlaceHolderVar)); 1743 fix_expr_common(context->root, node); 1744 return expression_tree_walker(node, fix_scan_expr_walker, 1745 (void *) context); 1746 } 1747 1748 /* 1749 * set_join_references 1750 * Modify the target list and quals of a join node to reference its 1751 * subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting 1752 * attno values to the result domain number of either the corresponding 1753 * outer or inner join tuple item. Also perform opcode lookup for these 1754 * expressions, and add regclass OIDs to root->glob->relationOids. 1755 */ 1756 static void 1757 set_join_references(PlannerInfo *root, Join *join, int rtoffset) 1758 { 1759 Plan *outer_plan = join->plan.lefttree; 1760 Plan *inner_plan = join->plan.righttree; 1761 indexed_tlist *outer_itlist; 1762 indexed_tlist *inner_itlist; 1763 1764 outer_itlist = build_tlist_index(outer_plan->targetlist); 1765 inner_itlist = build_tlist_index(inner_plan->targetlist); 1766 1767 /* 1768 * First process the joinquals (including merge or hash clauses). These 1769 * are logically below the join so they can always use all values 1770 * available from the input tlists. It's okay to also handle 1771 * NestLoopParams now, because those couldn't refer to nullable 1772 * subexpressions. 1773 */ 1774 join->joinqual = fix_join_expr(root, 1775 join->joinqual, 1776 outer_itlist, 1777 inner_itlist, 1778 (Index) 0, 1779 rtoffset); 1780 1781 /* Now do join-type-specific stuff */ 1782 if (IsA(join, NestLoop)) 1783 { 1784 NestLoop *nl = (NestLoop *) join; 1785 ListCell *lc; 1786 1787 foreach(lc, nl->nestParams) 1788 { 1789 NestLoopParam *nlp = (NestLoopParam *) lfirst(lc); 1790 1791 nlp->paramval = (Var *) fix_upper_expr(root, 1792 (Node *) nlp->paramval, 1793 outer_itlist, 1794 OUTER_VAR, 1795 rtoffset); 1796 /* Check we replaced any PlaceHolderVar with simple Var */ 1797 if (!(IsA(nlp->paramval, Var) && 1798 nlp->paramval->varno == OUTER_VAR)) 1799 elog(ERROR, "NestLoopParam was not reduced to a simple Var"); 1800 } 1801 } 1802 else if (IsA(join, MergeJoin)) 1803 { 1804 MergeJoin *mj = (MergeJoin *) join; 1805 1806 mj->mergeclauses = fix_join_expr(root, 1807 mj->mergeclauses, 1808 outer_itlist, 1809 inner_itlist, 1810 (Index) 0, 1811 rtoffset); 1812 } 1813 else if (IsA(join, HashJoin)) 1814 { 1815 HashJoin *hj = (HashJoin *) join; 1816 1817 hj->hashclauses = fix_join_expr(root, 1818 hj->hashclauses, 1819 outer_itlist, 1820 inner_itlist, 1821 (Index) 0, 1822 rtoffset); 1823 1824 /* 1825 * HashJoin's hashkeys are used to look for matching tuples from its 1826 * outer plan (not the Hash node!) in the hashtable. 1827 */ 1828 hj->hashkeys = (List *) fix_upper_expr(root, 1829 (Node *) hj->hashkeys, 1830 outer_itlist, 1831 OUTER_VAR, 1832 rtoffset); 1833 } 1834 1835 /* 1836 * Now we need to fix up the targetlist and qpqual, which are logically 1837 * above the join. This means they should not re-use any input expression 1838 * that was computed in the nullable side of an outer join. Vars and 1839 * PlaceHolderVars are fine, so we can implement this restriction just by 1840 * clearing has_non_vars in the indexed_tlist structs. 1841 * 1842 * XXX This is a grotty workaround for the fact that we don't clearly 1843 * distinguish between a Var appearing below an outer join and the "same" 1844 * Var appearing above it. If we did, we'd not need to hack the matching 1845 * rules this way. 1846 */ 1847 switch (join->jointype) 1848 { 1849 case JOIN_LEFT: 1850 case JOIN_SEMI: 1851 case JOIN_ANTI: 1852 inner_itlist->has_non_vars = false; 1853 break; 1854 case JOIN_RIGHT: 1855 outer_itlist->has_non_vars = false; 1856 break; 1857 case JOIN_FULL: 1858 outer_itlist->has_non_vars = false; 1859 inner_itlist->has_non_vars = false; 1860 break; 1861 default: 1862 break; 1863 } 1864 1865 join->plan.targetlist = fix_join_expr(root, 1866 join->plan.targetlist, 1867 outer_itlist, 1868 inner_itlist, 1869 (Index) 0, 1870 rtoffset); 1871 join->plan.qual = fix_join_expr(root, 1872 join->plan.qual, 1873 outer_itlist, 1874 inner_itlist, 1875 (Index) 0, 1876 rtoffset); 1877 1878 pfree(outer_itlist); 1879 pfree(inner_itlist); 1880 } 1881 1882 /* 1883 * set_upper_references 1884 * Update the targetlist and quals of an upper-level plan node 1885 * to refer to the tuples returned by its lefttree subplan. 1886 * Also perform opcode lookup for these expressions, and 1887 * add regclass OIDs to root->glob->relationOids. 1888 * 1889 * This is used for single-input plan types like Agg, Group, Result. 1890 * 1891 * In most cases, we have to match up individual Vars in the tlist and 1892 * qual expressions with elements of the subplan's tlist (which was 1893 * generated by flattening these selfsame expressions, so it should have all 1894 * the required variables). There is an important exception, however: 1895 * depending on where we are in the plan tree, sort/group columns may have 1896 * been pushed into the subplan tlist unflattened. If these values are also 1897 * needed in the output then we want to reference the subplan tlist element 1898 * rather than recomputing the expression. 1899 */ 1900 static void 1901 set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset) 1902 { 1903 Plan *subplan = plan->lefttree; 1904 indexed_tlist *subplan_itlist; 1905 List *output_targetlist; 1906 ListCell *l; 1907 1908 subplan_itlist = build_tlist_index(subplan->targetlist); 1909 1910 output_targetlist = NIL; 1911 foreach(l, plan->targetlist) 1912 { 1913 TargetEntry *tle = (TargetEntry *) lfirst(l); 1914 Node *newexpr; 1915 1916 /* If it's a sort/group item, first try to match by sortref */ 1917 if (tle->ressortgroupref != 0) 1918 { 1919 newexpr = (Node *) 1920 search_indexed_tlist_for_sortgroupref(tle->expr, 1921 tle->ressortgroupref, 1922 subplan_itlist, 1923 OUTER_VAR); 1924 if (!newexpr) 1925 newexpr = fix_upper_expr(root, 1926 (Node *) tle->expr, 1927 subplan_itlist, 1928 OUTER_VAR, 1929 rtoffset); 1930 } 1931 else 1932 newexpr = fix_upper_expr(root, 1933 (Node *) tle->expr, 1934 subplan_itlist, 1935 OUTER_VAR, 1936 rtoffset); 1937 tle = flatCopyTargetEntry(tle); 1938 tle->expr = (Expr *) newexpr; 1939 output_targetlist = lappend(output_targetlist, tle); 1940 } 1941 plan->targetlist = output_targetlist; 1942 1943 plan->qual = (List *) 1944 fix_upper_expr(root, 1945 (Node *) plan->qual, 1946 subplan_itlist, 1947 OUTER_VAR, 1948 rtoffset); 1949 1950 pfree(subplan_itlist); 1951 } 1952 1953 /* 1954 * set_param_references 1955 * Initialize the initParam list in Gather or Gather merge node such that 1956 * it contains reference of all the params that needs to be evaluated 1957 * before execution of the node. It contains the initplan params that are 1958 * being passed to the plan nodes below it. 1959 */ 1960 static void 1961 set_param_references(PlannerInfo *root, Plan *plan) 1962 { 1963 Assert(IsA(plan, Gather) || IsA(plan, GatherMerge)); 1964 1965 if (plan->lefttree->extParam) 1966 { 1967 PlannerInfo *proot; 1968 Bitmapset *initSetParam = NULL; 1969 ListCell *l; 1970 1971 for (proot = root; proot != NULL; proot = proot->parent_root) 1972 { 1973 foreach(l, proot->init_plans) 1974 { 1975 SubPlan *initsubplan = (SubPlan *) lfirst(l); 1976 ListCell *l2; 1977 1978 foreach(l2, initsubplan->setParam) 1979 { 1980 initSetParam = bms_add_member(initSetParam, lfirst_int(l2)); 1981 } 1982 } 1983 } 1984 1985 /* 1986 * Remember the list of all external initplan params that are used by 1987 * the children of Gather or Gather merge node. 1988 */ 1989 if (IsA(plan, Gather)) 1990 ((Gather *) plan)->initParam = 1991 bms_intersect(plan->lefttree->extParam, initSetParam); 1992 else 1993 ((GatherMerge *) plan)->initParam = 1994 bms_intersect(plan->lefttree->extParam, initSetParam); 1995 } 1996 } 1997 1998 /* 1999 * Recursively scan an expression tree and convert Aggrefs to the proper 2000 * intermediate form for combining aggregates. This means (1) replacing each 2001 * one's argument list with a single argument that is the original Aggref 2002 * modified to show partial aggregation and (2) changing the upper Aggref to 2003 * show combining aggregation. 2004 * 2005 * After this step, set_upper_references will replace the partial Aggrefs 2006 * with Vars referencing the lower Agg plan node's outputs, so that the final 2007 * form seen by the executor is a combining Aggref with a Var as input. 2008 * 2009 * It's rather messy to postpone this step until setrefs.c; ideally it'd be 2010 * done in createplan.c. The difficulty is that once we modify the Aggref 2011 * expressions, they will no longer be equal() to their original form and 2012 * so cross-plan-node-level matches will fail. So this has to happen after 2013 * the plan node above the Agg has resolved its subplan references. 2014 */ 2015 static Node * 2016 convert_combining_aggrefs(Node *node, void *context) 2017 { 2018 if (node == NULL) 2019 return NULL; 2020 if (IsA(node, Aggref)) 2021 { 2022 Aggref *orig_agg = (Aggref *) node; 2023 Aggref *child_agg; 2024 Aggref *parent_agg; 2025 2026 /* Assert we've not chosen to partial-ize any unsupported cases */ 2027 Assert(orig_agg->aggorder == NIL); 2028 Assert(orig_agg->aggdistinct == NIL); 2029 2030 /* 2031 * Since aggregate calls can't be nested, we needn't recurse into the 2032 * arguments. But for safety, flat-copy the Aggref node itself rather 2033 * than modifying it in-place. 2034 */ 2035 child_agg = makeNode(Aggref); 2036 memcpy(child_agg, orig_agg, sizeof(Aggref)); 2037 2038 /* 2039 * For the parent Aggref, we want to copy all the fields of the 2040 * original aggregate *except* the args list, which we'll replace 2041 * below, and the aggfilter expression, which should be applied only 2042 * by the child not the parent. Rather than explicitly knowing about 2043 * all the other fields here, we can momentarily modify child_agg to 2044 * provide a suitable source for copyObject. 2045 */ 2046 child_agg->args = NIL; 2047 child_agg->aggfilter = NULL; 2048 parent_agg = copyObject(child_agg); 2049 child_agg->args = orig_agg->args; 2050 child_agg->aggfilter = orig_agg->aggfilter; 2051 2052 /* 2053 * Now, set up child_agg to represent the first phase of partial 2054 * aggregation. For now, assume serialization is required. 2055 */ 2056 mark_partial_aggref(child_agg, AGGSPLIT_INITIAL_SERIAL); 2057 2058 /* 2059 * And set up parent_agg to represent the second phase. 2060 */ 2061 parent_agg->args = list_make1(makeTargetEntry((Expr *) child_agg, 2062 1, NULL, false)); 2063 mark_partial_aggref(parent_agg, AGGSPLIT_FINAL_DESERIAL); 2064 2065 return (Node *) parent_agg; 2066 } 2067 return expression_tree_mutator(node, convert_combining_aggrefs, 2068 (void *) context); 2069 } 2070 2071 /* 2072 * set_dummy_tlist_references 2073 * Replace the targetlist of an upper-level plan node with a simple 2074 * list of OUTER_VAR references to its child. 2075 * 2076 * This is used for plan types like Sort and Append that don't evaluate 2077 * their targetlists. Although the executor doesn't care at all what's in 2078 * the tlist, EXPLAIN needs it to be realistic. 2079 * 2080 * Note: we could almost use set_upper_references() here, but it fails for 2081 * Append for lack of a lefttree subplan. Single-purpose code is faster 2082 * anyway. 2083 */ 2084 static void 2085 set_dummy_tlist_references(Plan *plan, int rtoffset) 2086 { 2087 List *output_targetlist; 2088 ListCell *l; 2089 2090 output_targetlist = NIL; 2091 foreach(l, plan->targetlist) 2092 { 2093 TargetEntry *tle = (TargetEntry *) lfirst(l); 2094 Var *oldvar = (Var *) tle->expr; 2095 Var *newvar; 2096 2097 /* 2098 * As in search_indexed_tlist_for_non_var(), we prefer to keep Consts 2099 * as Consts, not Vars referencing Consts. Here, there's no speed 2100 * advantage to be had, but it makes EXPLAIN output look cleaner, and 2101 * again it avoids confusing the executor. 2102 */ 2103 if (IsA(oldvar, Const)) 2104 { 2105 /* just reuse the existing TLE node */ 2106 output_targetlist = lappend(output_targetlist, tle); 2107 continue; 2108 } 2109 2110 newvar = makeVar(OUTER_VAR, 2111 tle->resno, 2112 exprType((Node *) oldvar), 2113 exprTypmod((Node *) oldvar), 2114 exprCollation((Node *) oldvar), 2115 0); 2116 if (IsA(oldvar, Var) && 2117 oldvar->varnosyn > 0) 2118 { 2119 newvar->varnosyn = oldvar->varnosyn + rtoffset; 2120 newvar->varattnosyn = oldvar->varattnosyn; 2121 } 2122 else 2123 { 2124 newvar->varnosyn = 0; /* wasn't ever a plain Var */ 2125 newvar->varattnosyn = 0; 2126 } 2127 2128 tle = flatCopyTargetEntry(tle); 2129 tle->expr = (Expr *) newvar; 2130 output_targetlist = lappend(output_targetlist, tle); 2131 } 2132 plan->targetlist = output_targetlist; 2133 2134 /* We don't touch plan->qual here */ 2135 } 2136 2137 2138 /* 2139 * build_tlist_index --- build an index data structure for a child tlist 2140 * 2141 * In most cases, subplan tlists will be "flat" tlists with only Vars, 2142 * so we try to optimize that case by extracting information about Vars 2143 * in advance. Matching a parent tlist to a child is still an O(N^2) 2144 * operation, but at least with a much smaller constant factor than plain 2145 * tlist_member() searches. 2146 * 2147 * The result of this function is an indexed_tlist struct to pass to 2148 * search_indexed_tlist_for_var() or search_indexed_tlist_for_non_var(). 2149 * When done, the indexed_tlist may be freed with a single pfree(). 2150 */ 2151 static indexed_tlist * 2152 build_tlist_index(List *tlist) 2153 { 2154 indexed_tlist *itlist; 2155 tlist_vinfo *vinfo; 2156 ListCell *l; 2157 2158 /* Create data structure with enough slots for all tlist entries */ 2159 itlist = (indexed_tlist *) 2160 palloc(offsetof(indexed_tlist, vars) + 2161 list_length(tlist) * sizeof(tlist_vinfo)); 2162 2163 itlist->tlist = tlist; 2164 itlist->has_ph_vars = false; 2165 itlist->has_non_vars = false; 2166 2167 /* Find the Vars and fill in the index array */ 2168 vinfo = itlist->vars; 2169 foreach(l, tlist) 2170 { 2171 TargetEntry *tle = (TargetEntry *) lfirst(l); 2172 2173 if (tle->expr && IsA(tle->expr, Var)) 2174 { 2175 Var *var = (Var *) tle->expr; 2176 2177 vinfo->varno = var->varno; 2178 vinfo->varattno = var->varattno; 2179 vinfo->resno = tle->resno; 2180 vinfo++; 2181 } 2182 else if (tle->expr && IsA(tle->expr, PlaceHolderVar)) 2183 itlist->has_ph_vars = true; 2184 else 2185 itlist->has_non_vars = true; 2186 } 2187 2188 itlist->num_vars = (vinfo - itlist->vars); 2189 2190 return itlist; 2191 } 2192 2193 /* 2194 * build_tlist_index_other_vars --- build a restricted tlist index 2195 * 2196 * This is like build_tlist_index, but we only index tlist entries that 2197 * are Vars belonging to some rel other than the one specified. We will set 2198 * has_ph_vars (allowing PlaceHolderVars to be matched), but not has_non_vars 2199 * (so nothing other than Vars and PlaceHolderVars can be matched). 2200 */ 2201 static indexed_tlist * 2202 build_tlist_index_other_vars(List *tlist, Index ignore_rel) 2203 { 2204 indexed_tlist *itlist; 2205 tlist_vinfo *vinfo; 2206 ListCell *l; 2207 2208 /* Create data structure with enough slots for all tlist entries */ 2209 itlist = (indexed_tlist *) 2210 palloc(offsetof(indexed_tlist, vars) + 2211 list_length(tlist) * sizeof(tlist_vinfo)); 2212 2213 itlist->tlist = tlist; 2214 itlist->has_ph_vars = false; 2215 itlist->has_non_vars = false; 2216 2217 /* Find the desired Vars and fill in the index array */ 2218 vinfo = itlist->vars; 2219 foreach(l, tlist) 2220 { 2221 TargetEntry *tle = (TargetEntry *) lfirst(l); 2222 2223 if (tle->expr && IsA(tle->expr, Var)) 2224 { 2225 Var *var = (Var *) tle->expr; 2226 2227 if (var->varno != ignore_rel) 2228 { 2229 vinfo->varno = var->varno; 2230 vinfo->varattno = var->varattno; 2231 vinfo->resno = tle->resno; 2232 vinfo++; 2233 } 2234 } 2235 else if (tle->expr && IsA(tle->expr, PlaceHolderVar)) 2236 itlist->has_ph_vars = true; 2237 } 2238 2239 itlist->num_vars = (vinfo - itlist->vars); 2240 2241 return itlist; 2242 } 2243 2244 /* 2245 * search_indexed_tlist_for_var --- find a Var in an indexed tlist 2246 * 2247 * If a match is found, return a copy of the given Var with suitably 2248 * modified varno/varattno (to wit, newvarno and the resno of the TLE entry). 2249 * Also ensure that varnosyn is incremented by rtoffset. 2250 * If no match, return NULL. 2251 */ 2252 static Var * 2253 search_indexed_tlist_for_var(Var *var, indexed_tlist *itlist, 2254 Index newvarno, int rtoffset) 2255 { 2256 Index varno = var->varno; 2257 AttrNumber varattno = var->varattno; 2258 tlist_vinfo *vinfo; 2259 int i; 2260 2261 vinfo = itlist->vars; 2262 i = itlist->num_vars; 2263 while (i-- > 0) 2264 { 2265 if (vinfo->varno == varno && vinfo->varattno == varattno) 2266 { 2267 /* Found a match */ 2268 Var *newvar = copyVar(var); 2269 2270 newvar->varno = newvarno; 2271 newvar->varattno = vinfo->resno; 2272 if (newvar->varnosyn > 0) 2273 newvar->varnosyn += rtoffset; 2274 return newvar; 2275 } 2276 vinfo++; 2277 } 2278 return NULL; /* no match */ 2279 } 2280 2281 /* 2282 * search_indexed_tlist_for_non_var --- find a non-Var in an indexed tlist 2283 * 2284 * If a match is found, return a Var constructed to reference the tlist item. 2285 * If no match, return NULL. 2286 * 2287 * NOTE: it is a waste of time to call this unless itlist->has_ph_vars or 2288 * itlist->has_non_vars. Furthermore, set_join_references() relies on being 2289 * able to prevent matching of non-Vars by clearing itlist->has_non_vars, 2290 * so there's a correctness reason not to call it unless that's set. 2291 */ 2292 static Var * 2293 search_indexed_tlist_for_non_var(Expr *node, 2294 indexed_tlist *itlist, Index newvarno) 2295 { 2296 TargetEntry *tle; 2297 2298 /* 2299 * If it's a simple Const, replacing it with a Var is silly, even if there 2300 * happens to be an identical Const below; a Var is more expensive to 2301 * execute than a Const. What's more, replacing it could confuse some 2302 * places in the executor that expect to see simple Consts for, eg, 2303 * dropped columns. 2304 */ 2305 if (IsA(node, Const)) 2306 return NULL; 2307 2308 tle = tlist_member(node, itlist->tlist); 2309 if (tle) 2310 { 2311 /* Found a matching subplan output expression */ 2312 Var *newvar; 2313 2314 newvar = makeVarFromTargetEntry(newvarno, tle); 2315 newvar->varnosyn = 0; /* wasn't ever a plain Var */ 2316 newvar->varattnosyn = 0; 2317 return newvar; 2318 } 2319 return NULL; /* no match */ 2320 } 2321 2322 /* 2323 * search_indexed_tlist_for_sortgroupref --- find a sort/group expression 2324 * 2325 * If a match is found, return a Var constructed to reference the tlist item. 2326 * If no match, return NULL. 2327 * 2328 * This is needed to ensure that we select the right subplan TLE in cases 2329 * where there are multiple textually-equal()-but-volatile sort expressions. 2330 * And it's also faster than search_indexed_tlist_for_non_var. 2331 */ 2332 static Var * 2333 search_indexed_tlist_for_sortgroupref(Expr *node, 2334 Index sortgroupref, 2335 indexed_tlist *itlist, 2336 Index newvarno) 2337 { 2338 ListCell *lc; 2339 2340 foreach(lc, itlist->tlist) 2341 { 2342 TargetEntry *tle = (TargetEntry *) lfirst(lc); 2343 2344 /* The equal() check should be redundant, but let's be paranoid */ 2345 if (tle->ressortgroupref == sortgroupref && 2346 equal(node, tle->expr)) 2347 { 2348 /* Found a matching subplan output expression */ 2349 Var *newvar; 2350 2351 newvar = makeVarFromTargetEntry(newvarno, tle); 2352 newvar->varnosyn = 0; /* wasn't ever a plain Var */ 2353 newvar->varattnosyn = 0; 2354 return newvar; 2355 } 2356 } 2357 return NULL; /* no match */ 2358 } 2359 2360 /* 2361 * fix_join_expr 2362 * Create a new set of targetlist entries or join qual clauses by 2363 * changing the varno/varattno values of variables in the clauses 2364 * to reference target list values from the outer and inner join 2365 * relation target lists. Also perform opcode lookup and add 2366 * regclass OIDs to root->glob->relationOids. 2367 * 2368 * This is used in three different scenarios: 2369 * 1) a normal join clause, where all the Vars in the clause *must* be 2370 * replaced by OUTER_VAR or INNER_VAR references. In this case 2371 * acceptable_rel should be zero so that any failure to match a Var will be 2372 * reported as an error. 2373 * 2) RETURNING clauses, which may contain both Vars of the target relation 2374 * and Vars of other relations. In this case we want to replace the 2375 * other-relation Vars by OUTER_VAR references, while leaving target Vars 2376 * alone. Thus inner_itlist = NULL and acceptable_rel = the ID of the 2377 * target relation should be passed. 2378 * 3) ON CONFLICT UPDATE SET/WHERE clauses. Here references to EXCLUDED are 2379 * to be replaced with INNER_VAR references, while leaving target Vars (the 2380 * to-be-updated relation) alone. Correspondingly inner_itlist is to be 2381 * EXCLUDED elements, outer_itlist = NULL and acceptable_rel the target 2382 * relation. 2383 * 2384 * 'clauses' is the targetlist or list of join clauses 2385 * 'outer_itlist' is the indexed target list of the outer join relation, 2386 * or NULL 2387 * 'inner_itlist' is the indexed target list of the inner join relation, 2388 * or NULL 2389 * 'acceptable_rel' is either zero or the rangetable index of a relation 2390 * whose Vars may appear in the clause without provoking an error 2391 * 'rtoffset': how much to increment varnos by 2392 * 2393 * Returns the new expression tree. The original clause structure is 2394 * not modified. 2395 */ 2396 static List * 2397 fix_join_expr(PlannerInfo *root, 2398 List *clauses, 2399 indexed_tlist *outer_itlist, 2400 indexed_tlist *inner_itlist, 2401 Index acceptable_rel, 2402 int rtoffset) 2403 { 2404 fix_join_expr_context context; 2405 2406 context.root = root; 2407 context.outer_itlist = outer_itlist; 2408 context.inner_itlist = inner_itlist; 2409 context.acceptable_rel = acceptable_rel; 2410 context.rtoffset = rtoffset; 2411 return (List *) fix_join_expr_mutator((Node *) clauses, &context); 2412 } 2413 2414 static Node * 2415 fix_join_expr_mutator(Node *node, fix_join_expr_context *context) 2416 { 2417 Var *newvar; 2418 2419 if (node == NULL) 2420 return NULL; 2421 if (IsA(node, Var)) 2422 { 2423 Var *var = (Var *) node; 2424 2425 /* Look for the var in the input tlists, first in the outer */ 2426 if (context->outer_itlist) 2427 { 2428 newvar = search_indexed_tlist_for_var(var, 2429 context->outer_itlist, 2430 OUTER_VAR, 2431 context->rtoffset); 2432 if (newvar) 2433 return (Node *) newvar; 2434 } 2435 2436 /* then in the inner. */ 2437 if (context->inner_itlist) 2438 { 2439 newvar = search_indexed_tlist_for_var(var, 2440 context->inner_itlist, 2441 INNER_VAR, 2442 context->rtoffset); 2443 if (newvar) 2444 return (Node *) newvar; 2445 } 2446 2447 /* If it's for acceptable_rel, adjust and return it */ 2448 if (var->varno == context->acceptable_rel) 2449 { 2450 var = copyVar(var); 2451 var->varno += context->rtoffset; 2452 if (var->varnosyn > 0) 2453 var->varnosyn += context->rtoffset; 2454 return (Node *) var; 2455 } 2456 2457 /* No referent found for Var */ 2458 elog(ERROR, "variable not found in subplan target lists"); 2459 } 2460 if (IsA(node, PlaceHolderVar)) 2461 { 2462 PlaceHolderVar *phv = (PlaceHolderVar *) node; 2463 2464 /* See if the PlaceHolderVar has bubbled up from a lower plan node */ 2465 if (context->outer_itlist && context->outer_itlist->has_ph_vars) 2466 { 2467 newvar = search_indexed_tlist_for_non_var((Expr *) phv, 2468 context->outer_itlist, 2469 OUTER_VAR); 2470 if (newvar) 2471 return (Node *) newvar; 2472 } 2473 if (context->inner_itlist && context->inner_itlist->has_ph_vars) 2474 { 2475 newvar = search_indexed_tlist_for_non_var((Expr *) phv, 2476 context->inner_itlist, 2477 INNER_VAR); 2478 if (newvar) 2479 return (Node *) newvar; 2480 } 2481 2482 /* If not supplied by input plans, evaluate the contained expr */ 2483 return fix_join_expr_mutator((Node *) phv->phexpr, context); 2484 } 2485 /* Try matching more complex expressions too, if tlists have any */ 2486 if (context->outer_itlist && context->outer_itlist->has_non_vars) 2487 { 2488 newvar = search_indexed_tlist_for_non_var((Expr *) node, 2489 context->outer_itlist, 2490 OUTER_VAR); 2491 if (newvar) 2492 return (Node *) newvar; 2493 } 2494 if (context->inner_itlist && context->inner_itlist->has_non_vars) 2495 { 2496 newvar = search_indexed_tlist_for_non_var((Expr *) node, 2497 context->inner_itlist, 2498 INNER_VAR); 2499 if (newvar) 2500 return (Node *) newvar; 2501 } 2502 /* Special cases (apply only AFTER failing to match to lower tlist) */ 2503 if (IsA(node, Param)) 2504 return fix_param_node(context->root, (Param *) node); 2505 fix_expr_common(context->root, node); 2506 return expression_tree_mutator(node, 2507 fix_join_expr_mutator, 2508 (void *) context); 2509 } 2510 2511 /* 2512 * fix_upper_expr 2513 * Modifies an expression tree so that all Var nodes reference outputs 2514 * of a subplan. Also looks for Aggref nodes that should be replaced 2515 * by initplan output Params. Also performs opcode lookup, and adds 2516 * regclass OIDs to root->glob->relationOids. 2517 * 2518 * This is used to fix up target and qual expressions of non-join upper-level 2519 * plan nodes, as well as index-only scan nodes. 2520 * 2521 * An error is raised if no matching var can be found in the subplan tlist 2522 * --- so this routine should only be applied to nodes whose subplans' 2523 * targetlists were generated by flattening the expressions used in the 2524 * parent node. 2525 * 2526 * If itlist->has_non_vars is true, then we try to match whole subexpressions 2527 * against elements of the subplan tlist, so that we can avoid recomputing 2528 * expressions that were already computed by the subplan. (This is relatively 2529 * expensive, so we don't want to try it in the common case where the 2530 * subplan tlist is just a flattened list of Vars.) 2531 * 2532 * 'node': the tree to be fixed (a target item or qual) 2533 * 'subplan_itlist': indexed target list for subplan (or index) 2534 * 'newvarno': varno to use for Vars referencing tlist elements 2535 * 'rtoffset': how much to increment varnos by 2536 * 2537 * The resulting tree is a copy of the original in which all Var nodes have 2538 * varno = newvarno, varattno = resno of corresponding targetlist element. 2539 * The original tree is not modified. 2540 */ 2541 static Node * 2542 fix_upper_expr(PlannerInfo *root, 2543 Node *node, 2544 indexed_tlist *subplan_itlist, 2545 Index newvarno, 2546 int rtoffset) 2547 { 2548 fix_upper_expr_context context; 2549 2550 context.root = root; 2551 context.subplan_itlist = subplan_itlist; 2552 context.newvarno = newvarno; 2553 context.rtoffset = rtoffset; 2554 return fix_upper_expr_mutator(node, &context); 2555 } 2556 2557 static Node * 2558 fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) 2559 { 2560 Var *newvar; 2561 2562 if (node == NULL) 2563 return NULL; 2564 if (IsA(node, Var)) 2565 { 2566 Var *var = (Var *) node; 2567 2568 newvar = search_indexed_tlist_for_var(var, 2569 context->subplan_itlist, 2570 context->newvarno, 2571 context->rtoffset); 2572 if (!newvar) 2573 elog(ERROR, "variable not found in subplan target list"); 2574 return (Node *) newvar; 2575 } 2576 if (IsA(node, PlaceHolderVar)) 2577 { 2578 PlaceHolderVar *phv = (PlaceHolderVar *) node; 2579 2580 /* See if the PlaceHolderVar has bubbled up from a lower plan node */ 2581 if (context->subplan_itlist->has_ph_vars) 2582 { 2583 newvar = search_indexed_tlist_for_non_var((Expr *) phv, 2584 context->subplan_itlist, 2585 context->newvarno); 2586 if (newvar) 2587 return (Node *) newvar; 2588 } 2589 /* If not supplied by input plan, evaluate the contained expr */ 2590 return fix_upper_expr_mutator((Node *) phv->phexpr, context); 2591 } 2592 /* Try matching more complex expressions too, if tlist has any */ 2593 if (context->subplan_itlist->has_non_vars) 2594 { 2595 newvar = search_indexed_tlist_for_non_var((Expr *) node, 2596 context->subplan_itlist, 2597 context->newvarno); 2598 if (newvar) 2599 return (Node *) newvar; 2600 } 2601 /* Special cases (apply only AFTER failing to match to lower tlist) */ 2602 if (IsA(node, Param)) 2603 return fix_param_node(context->root, (Param *) node); 2604 if (IsA(node, Aggref)) 2605 { 2606 Aggref *aggref = (Aggref *) node; 2607 2608 /* See if the Aggref should be replaced by a Param */ 2609 if (context->root->minmax_aggs != NIL && 2610 list_length(aggref->args) == 1) 2611 { 2612 TargetEntry *curTarget = (TargetEntry *) linitial(aggref->args); 2613 ListCell *lc; 2614 2615 foreach(lc, context->root->minmax_aggs) 2616 { 2617 MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc); 2618 2619 if (mminfo->aggfnoid == aggref->aggfnoid && 2620 equal(mminfo->target, curTarget->expr)) 2621 return (Node *) copyObject(mminfo->param); 2622 } 2623 } 2624 /* If no match, just fall through to process it normally */ 2625 } 2626 fix_expr_common(context->root, node); 2627 return expression_tree_mutator(node, 2628 fix_upper_expr_mutator, 2629 (void *) context); 2630 } 2631 2632 /* 2633 * set_returning_clause_references 2634 * Perform setrefs.c's work on a RETURNING targetlist 2635 * 2636 * If the query involves more than just the result table, we have to 2637 * adjust any Vars that refer to other tables to reference junk tlist 2638 * entries in the top subplan's targetlist. Vars referencing the result 2639 * table should be left alone, however (the executor will evaluate them 2640 * using the actual heap tuple, after firing triggers if any). In the 2641 * adjusted RETURNING list, result-table Vars will have their original 2642 * varno (plus rtoffset), but Vars for other rels will have varno OUTER_VAR. 2643 * 2644 * We also must perform opcode lookup and add regclass OIDs to 2645 * root->glob->relationOids. 2646 * 2647 * 'rlist': the RETURNING targetlist to be fixed 2648 * 'topplan': the top subplan node that will be just below the ModifyTable 2649 * node (note it's not yet passed through set_plan_refs) 2650 * 'resultRelation': RT index of the associated result relation 2651 * 'rtoffset': how much to increment varnos by 2652 * 2653 * Note: the given 'root' is for the parent query level, not the 'topplan'. 2654 * This does not matter currently since we only access the dependency-item 2655 * lists in root->glob, but it would need some hacking if we wanted a root 2656 * that actually matches the subplan. 2657 * 2658 * Note: resultRelation is not yet adjusted by rtoffset. 2659 */ 2660 static List * 2661 set_returning_clause_references(PlannerInfo *root, 2662 List *rlist, 2663 Plan *topplan, 2664 Index resultRelation, 2665 int rtoffset) 2666 { 2667 indexed_tlist *itlist; 2668 2669 /* 2670 * We can perform the desired Var fixup by abusing the fix_join_expr 2671 * machinery that formerly handled inner indexscan fixup. We search the 2672 * top plan's targetlist for Vars of non-result relations, and use 2673 * fix_join_expr to convert RETURNING Vars into references to those tlist 2674 * entries, while leaving result-rel Vars as-is. 2675 * 2676 * PlaceHolderVars will also be sought in the targetlist, but no 2677 * more-complex expressions will be. Note that it is not possible for a 2678 * PlaceHolderVar to refer to the result relation, since the result is 2679 * never below an outer join. If that case could happen, we'd have to be 2680 * prepared to pick apart the PlaceHolderVar and evaluate its contained 2681 * expression instead. 2682 */ 2683 itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation); 2684 2685 rlist = fix_join_expr(root, 2686 rlist, 2687 itlist, 2688 NULL, 2689 resultRelation, 2690 rtoffset); 2691 2692 pfree(itlist); 2693 2694 return rlist; 2695 } 2696 2697 2698 /***************************************************************************** 2699 * QUERY DEPENDENCY MANAGEMENT 2700 *****************************************************************************/ 2701 2702 /* 2703 * record_plan_function_dependency 2704 * Mark the current plan as depending on a particular function. 2705 * 2706 * This is exported so that the function-inlining code can record a 2707 * dependency on a function that it's removed from the plan tree. 2708 */ 2709 void 2710 record_plan_function_dependency(PlannerInfo *root, Oid funcid) 2711 { 2712 /* 2713 * For performance reasons, we don't bother to track built-in functions; 2714 * we just assume they'll never change (or at least not in ways that'd 2715 * invalidate plans using them). For this purpose we can consider a 2716 * built-in function to be one with OID less than FirstBootstrapObjectId. 2717 * Note that the OID generator guarantees never to generate such an OID 2718 * after startup, even at OID wraparound. 2719 */ 2720 if (funcid >= (Oid) FirstBootstrapObjectId) 2721 { 2722 PlanInvalItem *inval_item = makeNode(PlanInvalItem); 2723 2724 /* 2725 * It would work to use any syscache on pg_proc, but the easiest is 2726 * PROCOID since we already have the function's OID at hand. Note 2727 * that plancache.c knows we use PROCOID. 2728 */ 2729 inval_item->cacheId = PROCOID; 2730 inval_item->hashValue = GetSysCacheHashValue1(PROCOID, 2731 ObjectIdGetDatum(funcid)); 2732 2733 root->glob->invalItems = lappend(root->glob->invalItems, inval_item); 2734 } 2735 } 2736 2737 /* 2738 * record_plan_type_dependency 2739 * Mark the current plan as depending on a particular type. 2740 * 2741 * This is exported so that eval_const_expressions can record a 2742 * dependency on a domain that it's removed a CoerceToDomain node for. 2743 * 2744 * We don't currently need to record dependencies on domains that the 2745 * plan contains CoerceToDomain nodes for, though that might change in 2746 * future. Hence, this isn't actually called in this module, though 2747 * someday fix_expr_common might call it. 2748 */ 2749 void 2750 record_plan_type_dependency(PlannerInfo *root, Oid typid) 2751 { 2752 /* 2753 * As in record_plan_function_dependency, ignore the possibility that 2754 * someone would change a built-in domain. 2755 */ 2756 if (typid >= (Oid) FirstBootstrapObjectId) 2757 { 2758 PlanInvalItem *inval_item = makeNode(PlanInvalItem); 2759 2760 /* 2761 * It would work to use any syscache on pg_type, but the easiest is 2762 * TYPEOID since we already have the type's OID at hand. Note that 2763 * plancache.c knows we use TYPEOID. 2764 */ 2765 inval_item->cacheId = TYPEOID; 2766 inval_item->hashValue = GetSysCacheHashValue1(TYPEOID, 2767 ObjectIdGetDatum(typid)); 2768 2769 root->glob->invalItems = lappend(root->glob->invalItems, inval_item); 2770 } 2771 } 2772 2773 /* 2774 * extract_query_dependencies 2775 * Given a rewritten, but not yet planned, query or queries 2776 * (i.e. a Query node or list of Query nodes), extract dependencies 2777 * just as set_plan_references would do. Also detect whether any 2778 * rewrite steps were affected by RLS. 2779 * 2780 * This is needed by plancache.c to handle invalidation of cached unplanned 2781 * queries. 2782 * 2783 * Note: this does not go through eval_const_expressions, and hence doesn't 2784 * reflect its additions of inlined functions and elided CoerceToDomain nodes 2785 * to the invalItems list. This is obviously OK for functions, since we'll 2786 * see them in the original query tree anyway. For domains, it's OK because 2787 * we don't care about domains unless they get elided. That is, a plan might 2788 * have domain dependencies that the query tree doesn't. 2789 */ 2790 void 2791 extract_query_dependencies(Node *query, 2792 List **relationOids, 2793 List **invalItems, 2794 bool *hasRowSecurity) 2795 { 2796 PlannerGlobal glob; 2797 PlannerInfo root; 2798 2799 /* Make up dummy planner state so we can use this module's machinery */ 2800 MemSet(&glob, 0, sizeof(glob)); 2801 glob.type = T_PlannerGlobal; 2802 glob.relationOids = NIL; 2803 glob.invalItems = NIL; 2804 /* Hack: we use glob.dependsOnRole to collect hasRowSecurity flags */ 2805 glob.dependsOnRole = false; 2806 2807 MemSet(&root, 0, sizeof(root)); 2808 root.type = T_PlannerInfo; 2809 root.glob = &glob; 2810 2811 (void) extract_query_dependencies_walker(query, &root); 2812 2813 *relationOids = glob.relationOids; 2814 *invalItems = glob.invalItems; 2815 *hasRowSecurity = glob.dependsOnRole; 2816 } 2817 2818 /* 2819 * Tree walker for extract_query_dependencies. 2820 * 2821 * This is exported so that expression_planner_with_deps can call it on 2822 * simple expressions (post-planning, not before planning, in that case). 2823 * In that usage, glob.dependsOnRole isn't meaningful, but the relationOids 2824 * and invalItems lists are added to as needed. 2825 */ 2826 bool 2827 extract_query_dependencies_walker(Node *node, PlannerInfo *context) 2828 { 2829 if (node == NULL) 2830 return false; 2831 Assert(!IsA(node, PlaceHolderVar)); 2832 if (IsA(node, Query)) 2833 { 2834 Query *query = (Query *) node; 2835 ListCell *lc; 2836 2837 if (query->commandType == CMD_UTILITY) 2838 { 2839 /* 2840 * Ignore utility statements, except those (such as EXPLAIN) that 2841 * contain a parsed-but-not-planned query. 2842 */ 2843 query = UtilityContainsQuery(query->utilityStmt); 2844 if (query == NULL) 2845 return false; 2846 } 2847 2848 /* Remember if any Query has RLS quals applied by rewriter */ 2849 if (query->hasRowSecurity) 2850 context->glob->dependsOnRole = true; 2851 2852 /* Collect relation OIDs in this Query's rtable */ 2853 foreach(lc, query->rtable) 2854 { 2855 RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); 2856 2857 if (rte->rtekind == RTE_RELATION) 2858 context->glob->relationOids = 2859 lappend_oid(context->glob->relationOids, rte->relid); 2860 else if (rte->rtekind == RTE_NAMEDTUPLESTORE && 2861 OidIsValid(rte->relid)) 2862 context->glob->relationOids = 2863 lappend_oid(context->glob->relationOids, 2864 rte->relid); 2865 } 2866 2867 /* And recurse into the query's subexpressions */ 2868 return query_tree_walker(query, extract_query_dependencies_walker, 2869 (void *) context, 0); 2870 } 2871 /* Extract function dependencies and check for regclass Consts */ 2872 fix_expr_common(context, node); 2873 return expression_tree_walker(node, extract_query_dependencies_walker, 2874 (void *) context); 2875 } 2876