aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeLimit.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2010-11-18 00:30:10 -0500
committerTom Lane <tgl@sss.pgh.pa.us>2010-11-18 00:30:10 -0500
commit6fbc323c8042303a737028f9da7616896bccc517 (patch)
tree8335501afc6e883ea14d0f88b3ca4f48f8a759ec /src/backend/executor/nodeLimit.c
parent45768d10e3abd513b4c959efeb5907798f2fac3f (diff)
downloadpostgresql-6fbc323c8042303a737028f9da7616896bccc517.tar.gz
postgresql-6fbc323c8042303a737028f9da7616896bccc517.zip
Further fallout from the MergeAppend patch.
Fix things so that top-N sorting can be used in child Sort nodes of a MergeAppend node, when there is a LIMIT and no intervening joins or grouping. Actually doing this on the executor side isn't too bad, but it's a bit messier to get the planner to cost it properly. Per gripe from Robert Haas. In passing, fix an oversight in the original top-N-sorting patch: query_planner should not assume that a LIMIT can be used to make an explicit sort cheaper when there will be grouping or aggregation in between. Possibly this should be back-patched, but I'm not sure the mistake is serious enough to be a real problem in practice.
Diffstat (limited to 'src/backend/executor/nodeLimit.c')
-rw-r--r--src/backend/executor/nodeLimit.c57
1 files changed, 40 insertions, 17 deletions
diff --git a/src/backend/executor/nodeLimit.c b/src/backend/executor/nodeLimit.c
index ce24f1b00af..5ed8664f66f 100644
--- a/src/backend/executor/nodeLimit.c
+++ b/src/backend/executor/nodeLimit.c
@@ -25,6 +25,7 @@
#include "executor/nodeLimit.h"
static void recompute_limits(LimitState *node);
+static void pass_down_bound(LimitState *node, PlanState *child_node);
/* ----------------------------------------------------------------
@@ -293,26 +294,35 @@ recompute_limits(LimitState *node)
/* Set state-machine state */
node->lstate = LIMIT_RESCAN;
- /*
- * If we have a COUNT, and our input is a Sort node, notify it that it can
- * use bounded sort.
- *
- * 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
- * to invent one without some more examples of special communication
- * needs.
- *
- * Note: it is the responsibility of nodeSort.c to react properly to
- * changes of these parameters. If we ever do redesign this, it'd be a
- * good idea to integrate this signaling with the parameter-change
- * mechanism.
- */
- if (IsA(outerPlanState(node), SortState))
+ /* Notify child node about limit, if useful */
+ pass_down_bound(node, outerPlanState(node));
+}
+
+/*
+ * If we have a COUNT, and our input is a Sort node, notify it that it can
+ * use bounded sort. Also, if our input is a MergeAppend, we can apply the
+ * same bound to any Sorts that are direct children of the MergeAppend,
+ * 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.
+ *
+ * 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
+ * to invent one without some more examples of special communication needs.
+ *
+ * Note: it is the responsibility of nodeSort.c to react properly to
+ * changes of these parameters. If we ever do redesign this, it'd be a
+ * good idea to integrate this signaling with the parameter-change mechanism.
+ */
+static void
+pass_down_bound(LimitState *node, PlanState *child_node)
+{
+ if (IsA(child_node, SortState))
{
- SortState *sortState = (SortState *) outerPlanState(node);
+ SortState *sortState = (SortState *) child_node;
int64 tuples_needed = node->count + node->offset;
- /* negative test checks for overflow */
+ /* negative test checks for overflow in sum */
if (node->noCount || tuples_needed < 0)
{
/* make sure flag gets reset if needed upon rescan */
@@ -324,6 +334,19 @@ recompute_limits(LimitState *node)
sortState->bound = tuples_needed;
}
}
+ else if (IsA(child_node, MergeAppendState))
+ {
+ MergeAppendState *maState = (MergeAppendState *) child_node;
+ int i;
+
+ for (i = 0; i < maState->ms_nplans; i++)
+ pass_down_bound(node, maState->mergeplans[i]);
+ }
+ else if (IsA(child_node, ResultState))
+ {
+ if (outerPlanState(child_node))
+ pass_down_bound(node, outerPlanState(child_node));
+ }
}
/* ----------------------------------------------------------------