aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c57
1 files changed, 56 insertions, 1 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 670776b032b..db91b8277d9 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -68,6 +68,7 @@ static void preprocess_rowmarks(PlannerInfo *root);
static double preprocess_limit(PlannerInfo *root,
double tuple_fraction,
int64 *offset_est, int64 *count_est);
+static bool limit_needed(Query *parse);
static void preprocess_groupclause(PlannerInfo *root);
static bool choose_hashed_grouping(PlannerInfo *root,
double tuple_fraction, double limit_tuples,
@@ -1825,7 +1826,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
/*
* Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node.
*/
- if (parse->limitCount || parse->limitOffset)
+ if (limit_needed(parse))
{
result_plan = (Plan *) make_limit(result_plan,
parse->limitOffset,
@@ -2296,6 +2297,60 @@ preprocess_limit(PlannerInfo *root, double tuple_fraction,
return tuple_fraction;
}
+/*
+ * limit_needed - do we actually need a Limit plan node?
+ *
+ * If we have constant-zero OFFSET and constant-null LIMIT, we can skip adding
+ * a Limit node. This is worth checking for because "OFFSET 0" is a common
+ * locution for an optimization fence. (Because other places in the planner
+ * merely check whether parse->limitOffset isn't NULL, it will still work as
+ * an optimization fence --- we're just suppressing unnecessary run-time
+ * overhead.)
+ *
+ * This might look like it could be merged into preprocess_limit, but there's
+ * a key distinction: here we need hard constants in OFFSET/LIMIT, whereas
+ * in preprocess_limit it's good enough to consider estimated values.
+ */
+static bool
+limit_needed(Query *parse)
+{
+ Node *node;
+
+ node = parse->limitCount;
+ if (node)
+ {
+ if (IsA(node, Const))
+ {
+ /* NULL indicates LIMIT ALL, ie, no limit */
+ if (!((Const *) node)->constisnull)
+ return true; /* LIMIT with a constant value */
+ }
+ else
+ return true; /* non-constant LIMIT */
+ }
+
+ node = parse->limitOffset;
+ if (node)
+ {
+ if (IsA(node, Const))
+ {
+ /* Treat NULL as no offset; the executor would too */
+ if (!((Const *) node)->constisnull)
+ {
+ int64 offset = DatumGetInt64(((Const *) node)->constvalue);
+
+ /* Executor would treat less-than-zero same as zero */
+ if (offset > 0)
+ return true; /* OFFSET with a positive value */
+ }
+ }
+ else
+ return true; /* non-constant OFFSET */
+ }
+
+ return false; /* don't need a Limit plan node */
+}
+
/*
* preprocess_groupclause - do preparatory work on GROUP BY clause