summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2011-10-11 14:20:06 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2011-10-11 14:21:30 -0400
commita0185461dd94c8d31d8d55a7f2839b0d2f172ab9 (patch)
tree3bd68d4e123336bbdefa8fd92372f0af7fb6d64f /src/backend/optimizer/plan
parentfa351d5a0db0672b6f586315720302e493116f27 (diff)
downloadpostgresql-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.c138
-rw-r--r--src/backend/optimizer/plan/setrefs.c138
-rw-r--r--src/backend/optimizer/plan/subselect.c12
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);