aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/path/allpaths.c14
-rw-r--r--src/backend/optimizer/path/costsize.c26
-rw-r--r--src/backend/optimizer/path/tidpath.c41
-rw-r--r--src/include/optimizer/paths.h2
4 files changed, 48 insertions, 35 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 4895cee9944..aa78c0af0cd 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -772,6 +772,17 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
*/
required_outer = rel->lateral_relids;
+ /*
+ * Consider TID scans.
+ *
+ * If create_tidscan_paths returns true, then a TID scan path is forced.
+ * This happens when rel->baserestrictinfo contains CurrentOfExpr, because
+ * the executor can't handle any other type of path for such queries.
+ * Hence, we return without adding any other paths.
+ */
+ if (create_tidscan_paths(root, rel))
+ return;
+
/* Consider sequential scan */
add_path(rel, create_seqscan_path(root, rel, required_outer, 0));
@@ -781,9 +792,6 @@ set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
/* Consider index scans */
create_index_paths(root, rel);
-
- /* Consider TID scans */
- create_tidscan_paths(root, rel);
}
/*
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index ee23ed7835d..2021c481b46 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -1251,7 +1251,6 @@ cost_tidscan(Path *path, PlannerInfo *root,
{
Cost startup_cost = 0;
Cost run_cost = 0;
- bool isCurrentOf = false;
QualCost qpqual_cost;
Cost cpu_per_tuple;
QualCost tid_qual_cost;
@@ -1287,7 +1286,6 @@ cost_tidscan(Path *path, PlannerInfo *root,
else if (IsA(qual, CurrentOfExpr))
{
/* CURRENT OF yields 1 tuple */
- isCurrentOf = true;
ntuples++;
}
else
@@ -1298,22 +1296,6 @@ cost_tidscan(Path *path, PlannerInfo *root,
}
/*
- * We must force TID scan for WHERE CURRENT OF, because only nodeTidscan.c
- * understands how to do it correctly. Therefore, honor enable_tidscan
- * only when CURRENT OF isn't present. Also note that cost_qual_eval
- * counts a CurrentOfExpr as having startup cost disable_cost, which we
- * subtract off here; that's to prevent other plan types such as seqscan
- * from winning.
- */
- if (isCurrentOf)
- {
- Assert(baserel->baserestrictcost.startup >= disable_cost);
- startup_cost -= disable_cost;
- }
- else if (!enable_tidscan)
- startup_cost += disable_cost;
-
- /*
* The TID qual expressions will be computed once, any other baserestrict
* quals once per retrieved tuple.
*/
@@ -1399,9 +1381,6 @@ cost_tidrangescan(Path *path, PlannerInfo *root,
ntuples = selectivity * baserel->tuples;
nseqpages = pages - 1.0;
- if (!enable_tidscan)
- startup_cost += disable_cost;
-
/*
* The TID qual expressions will be computed once, any other baserestrict
* quals once per retrieved tuple.
@@ -4884,11 +4863,6 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
/* Treat all these as having cost 1 */
context->total.per_tuple += cpu_operator_cost;
}
- else if (IsA(node, CurrentOfExpr))
- {
- /* Report high cost to prevent selection of anything but TID scan */
- context->total.startup += disable_cost;
- }
else if (IsA(node, SubLink))
{
/* This routine should not be applied to un-planned expressions */
diff --git a/src/backend/optimizer/path/tidpath.c b/src/backend/optimizer/path/tidpath.c
index eb11bc79c79..b0323b26eca 100644
--- a/src/backend/optimizer/path/tidpath.c
+++ b/src/backend/optimizer/path/tidpath.c
@@ -42,6 +42,7 @@
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/cost.h"
#include "optimizer/optimizer.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
@@ -277,12 +278,15 @@ RestrictInfoIsTidQual(PlannerInfo *root, RestrictInfo *rinfo, RelOptInfo *rel)
* that there's more than one choice.
*/
static List *
-TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel)
+TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel,
+ bool *isCurrentOf)
{
RestrictInfo *tidclause = NULL; /* best simple CTID qual so far */
List *orlist = NIL; /* best OR'ed CTID qual so far */
ListCell *l;
+ *isCurrentOf = false;
+
foreach(l, rlist)
{
RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
@@ -305,9 +309,13 @@ TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel)
if (is_andclause(orarg))
{
List *andargs = ((BoolExpr *) orarg)->args;
+ bool sublistIsCurrentOf;
/* Recurse in case there are sub-ORs */
- sublist = TidQualFromRestrictInfoList(root, andargs, rel);
+ sublist = TidQualFromRestrictInfoList(root, andargs, rel,
+ &sublistIsCurrentOf);
+ if (sublistIsCurrentOf)
+ elog(ERROR, "IS CURRENT OF within OR clause");
}
else
{
@@ -353,7 +361,10 @@ TidQualFromRestrictInfoList(PlannerInfo *root, List *rlist, RelOptInfo *rel)
{
/* We can stop immediately if it's a CurrentOfExpr */
if (IsCurrentOfClause(rinfo, rel))
+ {
+ *isCurrentOf = true;
return list_make1(rinfo);
+ }
/*
* Otherwise, remember the first non-OR CTID qual. We could
@@ -483,19 +494,24 @@ ec_member_matches_ctid(PlannerInfo *root, RelOptInfo *rel,
*
* Candidate paths are added to the rel's pathlist (using add_path).
*/
-void
+bool
create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
{
List *tidquals;
List *tidrangequals;
+ bool isCurrentOf;
/*
* If any suitable quals exist in the rel's baserestrict list, generate a
* plain (unparameterized) TidPath with them.
+ *
+ * We skip this when enable_tidscan = false, except when the qual is
+ * CurrentOfExpr. In that case, a TID scan is the only correct path.
*/
- tidquals = TidQualFromRestrictInfoList(root, rel->baserestrictinfo, rel);
+ tidquals = TidQualFromRestrictInfoList(root, rel->baserestrictinfo, rel,
+ &isCurrentOf);
- if (tidquals != NIL)
+ if (tidquals != NIL && (enable_tidscan || isCurrentOf))
{
/*
* This path uses no join clauses, but it could still have required
@@ -505,8 +521,21 @@ create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
add_path(rel, (Path *) create_tidscan_path(root, rel, tidquals,
required_outer));
+
+ /*
+ * When the qual is CurrentOfExpr, the path that we just added is the
+ * only one the executor can handle, so we should return before adding
+ * any others. Returning true lets the caller know not to add any
+ * others, either.
+ */
+ if (isCurrentOf)
+ return true;
}
+ /* Skip the rest if TID scans are disabled. */
+ if (!enable_tidscan)
+ return false;
+
/*
* If there are range quals in the baserestrict list, generate a
* TidRangePath.
@@ -553,4 +582,6 @@ create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel)
* join quals, for example.
*/
BuildParameterizedTidPaths(root, rel, rel->joininfo);
+
+ return false;
}
diff --git a/src/include/optimizer/paths.h b/src/include/optimizer/paths.h
index 5e88c0224a4..5c029b6b620 100644
--- a/src/include/optimizer/paths.h
+++ b/src/include/optimizer/paths.h
@@ -83,7 +83,7 @@ extern void check_index_predicates(PlannerInfo *root, RelOptInfo *rel);
* tidpath.c
* routines to generate tid paths
*/
-extern void create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel);
+extern bool create_tidscan_paths(PlannerInfo *root, RelOptInfo *rel);
/*
* joinpath.c