diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2011-10-11 14:20:06 -0400 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2011-10-11 14:21:30 -0400 |
| commit | a0185461dd94c8d31d8d55a7f2839b0d2f172ab9 (patch) | |
| tree | 3bd68d4e123336bbdefa8fd92372f0af7fb6d64f /src/backend/optimizer/plan | |
| parent | fa351d5a0db0672b6f586315720302e493116f27 (diff) | |
| download | postgresql-a0185461dd94c8d31d8d55a7f2839b0d2f172ab9.tar.gz | |
Rearrange the implementation of index-only scans.
This commit changes index-only scans so that data is read directly from the
index tuple without first generating a faux heap tuple. The only immediate
benefit is that indexes on system columns (such as OID) can be used in
index-only scans, but this is necessary infrastructure if we are ever to
support index-only scans on expression indexes. The executor is now ready
for that, though the planner still needs substantial work to recognize
the possibility.
To do this, Vars in index-only plan nodes have to refer to index columns
not heap columns. I introduced a new special varno, INDEX_VAR, to mark
such Vars to avoid confusion. (In passing, this commit renames the two
existing special varnos to OUTER_VAR and INNER_VAR.) This allows
ruleutils.c to handle them with logic similar to what we use for subplan
reference Vars.
Since index-only scans are now fundamentally different from regular
indexscans so far as their expression subtrees are concerned, I also chose
to change them to have their own plan node type (and hence, their own
executor source file).
Diffstat (limited to 'src/backend/optimizer/plan')
| -rw-r--r-- | src/backend/optimizer/plan/createplan.c | 138 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 138 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/subselect.c | 12 |
3 files changed, 220 insertions, 68 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index 36ee7c5648..a76f2c603c 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -53,8 +53,8 @@ static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path static Plan *create_unique_plan(PlannerInfo *root, UniquePath *best_path); static SeqScan *create_seqscan_plan(PlannerInfo *root, Path *best_path, List *tlist, List *scan_clauses); -static IndexScan *create_indexscan_plan(PlannerInfo *root, IndexPath *best_path, - List *tlist, List *scan_clauses); +static Scan *create_indexscan_plan(PlannerInfo *root, IndexPath *best_path, + List *tlist, List *scan_clauses, bool indexonly); static BitmapHeapScan *create_bitmap_scan_plan(PlannerInfo *root, BitmapHeapPath *best_path, List *tlist, List *scan_clauses); @@ -95,7 +95,12 @@ static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, Oid indexid, List *indexqual, List *indexqualorig, List *indexorderby, List *indexorderbyorig, - ScanDirection indexscandir, bool indexonly); + ScanDirection indexscandir); +static IndexOnlyScan *make_indexonlyscan(List *qptlist, List *qpqual, + Index scanrelid, Oid indexid, + List *indexqual, List *indexorderby, + List *indextlist, + ScanDirection indexscandir); static BitmapIndexScan *make_bitmap_indexscan(Index scanrelid, Oid indexid, List *indexqual, List *indexqualorig); @@ -206,6 +211,7 @@ create_plan_recurse(PlannerInfo *root, Path *best_path) { case T_SeqScan: case T_IndexScan: + case T_IndexOnlyScan: case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: @@ -274,10 +280,18 @@ create_scan_plan(PlannerInfo *root, Path *best_path) */ if (use_physical_tlist(root, rel)) { - tlist = build_physical_tlist(root, rel); - /* if fail because of dropped cols, use regular method */ - if (tlist == NIL) - tlist = build_relation_tlist(rel); + if (best_path->pathtype == T_IndexOnlyScan) + { + /* For index-only scan, the preferred tlist is the index's */ + tlist = copyObject(((IndexPath *) best_path)->indexinfo->indextlist); + } + else + { + tlist = build_physical_tlist(root, rel); + /* if fail because of dropped cols, use regular method */ + if (tlist == NIL) + tlist = build_relation_tlist(rel); + } } else tlist = build_relation_tlist(rel); @@ -302,7 +316,16 @@ create_scan_plan(PlannerInfo *root, Path *best_path) plan = (Plan *) create_indexscan_plan(root, (IndexPath *) best_path, tlist, - scan_clauses); + scan_clauses, + false); + break; + + case T_IndexOnlyScan: + plan = (Plan *) create_indexscan_plan(root, + (IndexPath *) best_path, + tlist, + scan_clauses, + true); break; case T_BitmapHeapScan: @@ -476,6 +499,7 @@ disuse_physical_tlist(Plan *plan, Path *path) { case T_SeqScan: case T_IndexScan: + case T_IndexOnlyScan: case T_BitmapHeapScan: case T_TidScan: case T_SubqueryScan: @@ -1044,16 +1068,23 @@ create_seqscan_plan(PlannerInfo *root, Path *best_path, * Returns an indexscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. * + * We use this for both plain IndexScans and IndexOnlyScans, because the + * qual preprocessing work is the same for both. Note that the caller tells + * us which to build --- we don't look at best_path->path.pathtype, because + * create_bitmap_subplan needs to be able to override the prior decision. + * * The indexquals list of the path contains implicitly-ANDed qual conditions. * The list can be empty --- then no index restrictions will be applied during * the scan. */ -static IndexScan * +static Scan * create_indexscan_plan(PlannerInfo *root, IndexPath *best_path, List *tlist, - List *scan_clauses) + List *scan_clauses, + bool indexonly) { + Scan *scan_plan; List *indexquals = best_path->indexquals; List *indexorderbys = best_path->indexorderbys; Index baserelid = best_path->path.parent->relid; @@ -1063,7 +1094,6 @@ create_indexscan_plan(PlannerInfo *root, List *fixed_indexquals; List *fixed_indexorderbys; ListCell *l; - IndexScan *scan_plan; /* it should be a base rel... */ Assert(baserelid > 0); @@ -1077,7 +1107,7 @@ create_indexscan_plan(PlannerInfo *root, /* * The executor needs a copy with the indexkey on the left of each clause - * and with index attr numbers substituted for table ones. + * and with index Vars substituted for table ones. */ fixed_indexquals = fix_indexqual_references(root, best_path, indexquals); @@ -1175,20 +1205,29 @@ create_indexscan_plan(PlannerInfo *root, } /* Finally ready to build the plan node */ - scan_plan = make_indexscan(tlist, - qpqual, - baserelid, - indexoid, - fixed_indexquals, - stripped_indexquals, - fixed_indexorderbys, - indexorderbys, - best_path->indexscandir, - best_path->indexonly); - - copy_path_costsize(&scan_plan->scan.plan, &best_path->path); + if (indexonly) + scan_plan = (Scan *) make_indexonlyscan(tlist, + qpqual, + baserelid, + indexoid, + fixed_indexquals, + fixed_indexorderbys, + best_path->indexinfo->indextlist, + best_path->indexscandir); + else + scan_plan = (Scan *) make_indexscan(tlist, + qpqual, + baserelid, + indexoid, + fixed_indexquals, + stripped_indexquals, + fixed_indexorderbys, + indexorderbys, + best_path->indexscandir); + + copy_path_costsize(&scan_plan->plan, &best_path->path); /* use the indexscan-specific rows estimate, not the parent rel's */ - scan_plan->scan.plan.plan_rows = best_path->rows; + scan_plan->plan.plan_rows = best_path->rows; return scan_plan; } @@ -1440,7 +1479,9 @@ create_bitmap_subplan(PlannerInfo *root, Path *bitmapqual, ListCell *l; /* Use the regular indexscan plan build machinery... */ - iscan = create_indexscan_plan(root, ipath, NIL, NIL); + iscan = (IndexScan *) create_indexscan_plan(root, ipath, + NIL, NIL, false); + Assert(IsA(iscan, IndexScan)); /* then convert to a bitmap indexscan */ plan = (Plan *) make_bitmap_indexscan(iscan->scan.scanrelid, iscan->indexid, @@ -2549,17 +2590,13 @@ fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path, /* * fix_indexqual_operand * Convert an indexqual expression to a Var referencing the index column. + * + * We represent index keys by Var nodes having varno == INDEX_VAR and varattno + * equal to the index's attribute number (index column position). */ static Node * fix_indexqual_operand(Node *node, IndexOptInfo *index) { - /* - * We represent index keys by Var nodes having the varno of the base table - * but varattno equal to the index's attribute number (index column - * position). This is a bit hokey ... would be cleaner to use a - * special-purpose node type that could not be mistaken for a regular Var. - * But it will do for now. - */ Var *result; int pos; ListCell *indexpr_item; @@ -2583,6 +2620,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index) if (index->indexkeys[pos] == varatt) { result = (Var *) copyObject(node); + result->varno = INDEX_VAR; result->varattno = pos + 1; return (Node *) result; } @@ -2606,7 +2644,7 @@ fix_indexqual_operand(Node *node, IndexOptInfo *index) if (equal(node, indexkey)) { /* Found a match */ - result = makeVar(index->rel->relid, pos + 1, + result = makeVar(INDEX_VAR, pos + 1, exprType(lfirst(indexpr_item)), -1, exprCollation(lfirst(indexpr_item)), 0); @@ -2842,8 +2880,7 @@ make_indexscan(List *qptlist, List *indexqualorig, List *indexorderby, List *indexorderbyorig, - ScanDirection indexscandir, - bool indexonly) + ScanDirection indexscandir) { IndexScan *node = makeNode(IndexScan); Plan *plan = &node->scan.plan; @@ -2860,7 +2897,34 @@ make_indexscan(List *qptlist, node->indexorderby = indexorderby; node->indexorderbyorig = indexorderbyorig; node->indexorderdir = indexscandir; - node->indexonly = indexonly; + + return node; +} + +static IndexOnlyScan * +make_indexonlyscan(List *qptlist, + List *qpqual, + Index scanrelid, + Oid indexid, + List *indexqual, + List *indexorderby, + List *indextlist, + ScanDirection indexscandir) +{ + IndexOnlyScan *node = makeNode(IndexOnlyScan); + Plan *plan = &node->scan.plan; + + /* cost should be inserted by caller */ + plan->targetlist = qptlist; + plan->qual = qpqual; + plan->lefttree = NULL; + plan->righttree = NULL; + node->scan.scanrelid = scanrelid; + node->indexid = indexid; + node->indexqual = indexqual; + node->indexorderby = indexorderby; + node->indextlist = indextlist; + node->indexorderdir = indexscandir; return node; } diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index d60163379b..493103a1db 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -63,6 +63,7 @@ typedef struct { PlannerInfo *root; indexed_tlist *subplan_itlist; + Index newvarno; int rtoffset; } fix_upper_expr_context; @@ -81,6 +82,9 @@ typedef struct ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset)) static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset); +static Plan *set_indexonlyscan_references(PlannerInfo *root, + IndexOnlyScan *plan, + int rtoffset); static Plan *set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset); @@ -113,6 +117,7 @@ static Node *fix_join_expr_mutator(Node *node, static Node *fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, + Index newvarno, int rtoffset); static Node *fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context); @@ -235,6 +240,16 @@ set_plan_references(PlannerInfo *root, Plan *plan) } /* + * Check for RT index overflow; it's very unlikely, but if it did happen, + * the executor would get confused by varnos that match the special varno + * values. + */ + if (IS_SPECIAL_VARNO(list_length(glob->finalrtable))) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("too many range table entries"))); + + /* * Adjust RT indexes of PlanRowMarks and add to final rowmarks list */ foreach(lc, root->rowMarks) @@ -305,6 +320,13 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) fix_scan_list(root, splan->indexorderbyorig, rtoffset); } break; + case T_IndexOnlyScan: + { + IndexOnlyScan *splan = (IndexOnlyScan *) plan; + + return set_indexonlyscan_references(root, splan, rtoffset); + } + break; case T_BitmapIndexScan: { BitmapIndexScan *splan = (BitmapIndexScan *) plan; @@ -653,6 +675,49 @@ set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) } /* + * set_indexonlyscan_references + * Do set_plan_references processing on an IndexOnlyScan + * + * This is unlike the handling of a plain IndexScan because we have to + * convert Vars referencing the heap into Vars referencing the index. + * We can use the fix_upper_expr machinery for that, by working from a + * targetlist describing the index columns. + */ +static Plan * +set_indexonlyscan_references(PlannerInfo *root, + IndexOnlyScan *plan, + int rtoffset) +{ + indexed_tlist *index_itlist; + + index_itlist = build_tlist_index(plan->indextlist); + + plan->scan.scanrelid += rtoffset; + plan->scan.plan.targetlist = (List *) + fix_upper_expr(root, + (Node *) plan->scan.plan.targetlist, + index_itlist, + INDEX_VAR, + rtoffset); + plan->scan.plan.qual = (List *) + fix_upper_expr(root, + (Node *) plan->scan.plan.qual, + index_itlist, + INDEX_VAR, + rtoffset); + /* indexqual is already transformed to reference index columns */ + plan->indexqual = fix_scan_list(root, plan->indexqual, rtoffset); + /* indexorderby is already transformed to reference index columns */ + plan->indexorderby = fix_scan_list(root, plan->indexorderby, rtoffset); + /* indextlist must NOT be transformed to reference index columns */ + plan->indextlist = fix_scan_list(root, plan->indextlist, rtoffset); + + pfree(index_itlist); + + return (Plan *) plan; +} + +/* * set_subqueryscan_references * Do set_plan_references processing on a SubqueryScan * @@ -919,11 +984,13 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context) Assert(var->varlevelsup == 0); /* - * We should not see any Vars marked INNER or OUTER. + * We should not see any Vars marked INNER_VAR or OUTER_VAR. But an + * indexqual expression could contain INDEX_VAR Vars. */ - Assert(var->varno != INNER); - Assert(var->varno != OUTER); - var->varno += context->rtoffset; + Assert(var->varno != INNER_VAR); + Assert(var->varno != OUTER_VAR); + if (!IS_SPECIAL_VARNO(var->varno)) + var->varno += context->rtoffset; if (var->varnoold > 0) var->varnoold += context->rtoffset; return (Node *) var; @@ -932,9 +999,10 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context) { CurrentOfExpr *cexpr = (CurrentOfExpr *) copyObject(node); - Assert(cexpr->cvarno != INNER); - Assert(cexpr->cvarno != OUTER); - cexpr->cvarno += context->rtoffset; + Assert(cexpr->cvarno != INNER_VAR); + Assert(cexpr->cvarno != OUTER_VAR); + if (!IS_SPECIAL_VARNO(cexpr->cvarno)) + cexpr->cvarno += context->rtoffset; return (Node *) cexpr; } if (IsA(node, PlaceHolderVar)) @@ -963,9 +1031,9 @@ fix_scan_expr_walker(Node *node, fix_scan_expr_context *context) /* * set_join_references * Modify the target list and quals of a join node to reference its - * subplans, by setting the varnos to OUTER or INNER and setting attno - * values to the result domain number of either the corresponding outer - * or inner join tuple item. Also perform opcode lookup for these + * subplans, by setting the varnos to OUTER_VAR or INNER_VAR and setting + * attno values to the result domain number of either the corresponding + * outer or inner join tuple item. Also perform opcode lookup for these * expressions. and add regclass OIDs to root->glob->relationOids. */ static void @@ -1012,6 +1080,7 @@ set_join_references(PlannerInfo *root, Join *join, int rtoffset) nlp->paramval = (Var *) fix_upper_expr(root, (Node *) nlp->paramval, outer_itlist, + OUTER_VAR, rtoffset); } } @@ -1083,17 +1152,19 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset) search_indexed_tlist_for_sortgroupref((Node *) tle->expr, tle->ressortgroupref, subplan_itlist, - OUTER); + OUTER_VAR); if (!newexpr) newexpr = fix_upper_expr(root, (Node *) tle->expr, subplan_itlist, + OUTER_VAR, rtoffset); } else newexpr = fix_upper_expr(root, (Node *) tle->expr, subplan_itlist, + OUTER_VAR, rtoffset); tle = flatCopyTargetEntry(tle); tle->expr = (Expr *) newexpr; @@ -1105,6 +1176,7 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset) fix_upper_expr(root, (Node *) plan->qual, subplan_itlist, + OUTER_VAR, rtoffset); pfree(subplan_itlist); @@ -1113,7 +1185,7 @@ set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset) /* * set_dummy_tlist_references * Replace the targetlist of an upper-level plan node with a simple - * list of OUTER references to its child. + * list of OUTER_VAR references to its child. * * This is used for plan types like Sort and Append that don't evaluate * their targetlists. Although the executor doesn't care at all what's in @@ -1136,7 +1208,7 @@ set_dummy_tlist_references(Plan *plan, int rtoffset) Var *oldvar = (Var *) tle->expr; Var *newvar; - newvar = makeVar(OUTER, + newvar = makeVar(OUTER_VAR, tle->resno, exprType((Node *) oldvar), exprTypmod((Node *) oldvar), @@ -1382,11 +1454,12 @@ search_indexed_tlist_for_sortgroupref(Node *node, * relation target lists. Also perform opcode lookup and add * regclass OIDs to root->glob->relationOids. * - * This is used in two different scenarios: a normal join clause, where - * all the Vars in the clause *must* be replaced by OUTER or INNER references; - * and a RETURNING clause, which may contain both Vars of the target relation - * and Vars of other relations. In the latter case we want to replace the - * other-relation Vars by OUTER references, while leaving target Vars alone. + * This is used in two different scenarios: a normal join clause, where all + * the Vars in the clause *must* be replaced by OUTER_VAR or INNER_VAR + * references; and a RETURNING clause, which may contain both Vars of the + * target relation and Vars of other relations. In the latter case we want + * to replace the other-relation Vars by OUTER_VAR references, while leaving + * target Vars alone. * * For a normal join, acceptable_rel should be zero so that any failure to * match a Var will be reported as an error. For the RETURNING case, pass @@ -1435,7 +1508,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) /* First look for the var in the input tlists */ newvar = search_indexed_tlist_for_var(var, context->outer_itlist, - OUTER, + OUTER_VAR, context->rtoffset); if (newvar) return (Node *) newvar; @@ -1443,7 +1516,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) { newvar = search_indexed_tlist_for_var(var, context->inner_itlist, - INNER, + INNER_VAR, context->rtoffset); if (newvar) return (Node *) newvar; @@ -1470,7 +1543,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) { newvar = search_indexed_tlist_for_non_var((Node *) phv, context->outer_itlist, - OUTER); + OUTER_VAR); if (newvar) return (Node *) newvar; } @@ -1478,7 +1551,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) { newvar = search_indexed_tlist_for_non_var((Node *) phv, context->inner_itlist, - INNER); + INNER_VAR); if (newvar) return (Node *) newvar; } @@ -1491,7 +1564,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) { newvar = search_indexed_tlist_for_non_var(node, context->outer_itlist, - OUTER); + OUTER_VAR); if (newvar) return (Node *) newvar; } @@ -1499,7 +1572,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) { newvar = search_indexed_tlist_for_non_var(node, context->inner_itlist, - INNER); + INNER_VAR); if (newvar) return (Node *) newvar; } @@ -1516,7 +1589,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) * root->glob->relationOids. * * This is used to fix up target and qual expressions of non-join upper-level - * plan nodes. + * plan nodes, as well as index-only scan nodes. * * An error is raised if no matching var can be found in the subplan tlist * --- so this routine should only be applied to nodes whose subplans' @@ -1529,23 +1602,26 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) * subplan tlist is just a flattened list of Vars.) * * 'node': the tree to be fixed (a target item or qual) - * 'subplan_itlist': indexed target list for subplan + * 'subplan_itlist': indexed target list for subplan (or index) + * 'newvarno': varno to use for Vars referencing tlist elements * 'rtoffset': how much to increment varnoold by * * The resulting tree is a copy of the original in which all Var nodes have - * varno = OUTER, varattno = resno of corresponding subplan target. + * varno = newvarno, varattno = resno of corresponding targetlist element. * The original tree is not modified. */ static Node * fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, + Index newvarno, int rtoffset) { fix_upper_expr_context context; context.root = root; context.subplan_itlist = subplan_itlist; + context.newvarno = newvarno; context.rtoffset = rtoffset; return fix_upper_expr_mutator(node, &context); } @@ -1563,7 +1639,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) newvar = search_indexed_tlist_for_var(var, context->subplan_itlist, - OUTER, + context->newvarno, context->rtoffset); if (!newvar) elog(ERROR, "variable not found in subplan target list"); @@ -1578,7 +1654,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) { newvar = search_indexed_tlist_for_non_var((Node *) phv, context->subplan_itlist, - OUTER); + context->newvarno); if (newvar) return (Node *) newvar; } @@ -1590,7 +1666,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) { newvar = search_indexed_tlist_for_non_var(node, context->subplan_itlist, - OUTER); + context->newvarno); if (newvar) return (Node *) newvar; } @@ -1610,7 +1686,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) * table should be left alone, however (the executor will evaluate them * using the actual heap tuple, after firing triggers if any). In the * adjusted RETURNING list, result-table Vars will still have their - * original varno, but Vars for other rels will have varno OUTER. + * original varno, but Vars for other rels will have varno OUTER_VAR. * * We also must perform opcode lookup and add regclass OIDs to * root->glob->relationOids. diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 2e308c625a..c4046ca534 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -1974,6 +1974,18 @@ finalize_plan(PlannerInfo *root, Plan *plan, Bitmapset *valid_params, context.paramids = bms_add_members(context.paramids, scan_params); break; + case T_IndexOnlyScan: + finalize_primnode((Node *) ((IndexOnlyScan *) plan)->indexqual, + &context); + finalize_primnode((Node *) ((IndexOnlyScan *) plan)->indexorderby, + &context); + + /* + * we need not look at indextlist, since it cannot contain Params. + */ + context.paramids = bms_add_members(context.paramids, scan_params); + break; + case T_BitmapIndexScan: finalize_primnode((Node *) ((BitmapIndexScan *) plan)->indexqual, &context); |
