aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeLimit.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2017-08-21 14:43:01 -0400
committerRobert Haas <rhaas@postgresql.org>2017-08-21 14:19:44 -0400
commit1f6d515a67ec98194c23a5db25660856c9aab944 (patch)
tree11ea85be0cf33a654d1578baf13530422cf938e3 /src/backend/executor/nodeLimit.c
parent79ccd7cbd5ca44bee0191d12e9e65abf702899e7 (diff)
downloadpostgresql-1f6d515a67ec98194c23a5db25660856c9aab944.tar.gz
postgresql-1f6d515a67ec98194c23a5db25660856c9aab944.zip
Push limit through subqueries to underlying sort, where possible.
Douglas Doole, reviewed by Ashutosh Bapat and by me. Minor formatting change by me. Discussion: http://postgr.es/m/CADE5jYLuugnEEUsyW6Q_4mZFYTxHxaVCQmGAsF0yiY8ZDggi-w@mail.gmail.com
Diffstat (limited to 'src/backend/executor/nodeLimit.c')
-rw-r--r--src/backend/executor/nodeLimit.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index ac5a2ff0e60..09af1a5d8b3 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -308,6 +308,9 @@ recompute_limits(LimitState *node)
* since the MergeAppend surely need read no more than that many tuples from
* any one input. We also have to be prepared to look through a Result,
* since the planner might stick one atop MergeAppend for projection purposes.
+ * We can also accept one or more levels of subqueries that have no quals or
+ * SRFs (that is, each subquery is just projecting columns) between the LIMIT
+ * and any of the above.
*
* This is a bit of a kluge, but we don't have any more-abstract way of
* communicating between the two nodes; and it doesn't seem worth trying
@@ -320,6 +323,29 @@ recompute_limits(LimitState *node)
static void
pass_down_bound(LimitState *node, PlanState *child_node)
{
+ /*
+ * If the child is a subquery that does no filtering (no predicates)
+ * and does not have any SRFs in the target list then we can potentially
+ * push the limit through the subquery. It is possible that we could have
+ * multiple subqueries, so tunnel through them all.
+ */
+ while (IsA(child_node, SubqueryScanState))
+ {
+ SubqueryScanState *subqueryScanState;
+
+ subqueryScanState = (SubqueryScanState *) child_node;
+
+ /*
+ * Non-empty predicates or an SRF means we cannot push down the limit.
+ */
+ if (subqueryScanState->ss.ps.qual != NULL ||
+ expression_returns_set((Node *) child_node->plan->targetlist))
+ return;
+
+ /* Use the child in the following checks */
+ child_node = subqueryScanState->subplan;
+ }
+
if (IsA(child_node, SortState))
{
SortState *sortState = (SortState *) child_node;