aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/nodeAgg.c
diff options
context:
space:
mode:
authorAndres Freund <andres@anarazel.de>2019-07-25 14:22:52 -0700
committerAndres Freund <andres@anarazel.de>2019-07-25 14:28:55 -0700
commitaf3deff3f2ac79585481181cb198b04c67486c09 (patch)
treefdd0685787f8b5e0d547d21eba4349b65d3e60e2 /src/backend/executor/nodeAgg.c
parentcb9bb15783f2d6b2e66f7c18bc35e849df623dfa (diff)
downloadpostgresql-af3deff3f2ac79585481181cb198b04c67486c09.tar.gz
postgresql-af3deff3f2ac79585481181cb198b04c67486c09.zip
Fix slot type handling for Agg nodes performing internal sorts.
Since 15d8f8312 we assert that - and since 7ef04e4d2cb2, 4da597edf1 rely on - the slot type for an expression's ecxt_{outer,inner,scan}tuple not changing, unless explicitly flagged as such. That allows to either skip deforming (for a virtual tuple slot) or optimize the code for JIT accelerated deforming appropriately (for other known slot types). This assumption was sometimes violated for grouping sets, when nodeAgg.c internally uses tuplesorts, and the child node doesn't return a TTSOpsMinimalTuple type slot. Detect that case, and flag that the outer slot might not be "fixed". It's probably worthwhile to optimize this further in the future, and more granularly determine whether the slot is fixed. As we already instantiate per-phase transition and equal expressions, we could cheaply set the slot type appropriately for each phase. But that's a separate change from this bugfix. This commit does include a very minor optimization by avoiding to create a slot for handling tuplesorts, if no such sorts are performed. Previously we created that slot unnecessarily in the common case of computing all grouping sets via hashing. The code looked too confusing without that, as the conditions for needing a sort slot and flagging that the slot type isn't fixed, are the same. Reported-By: Ashutosh Sharma Author: Andres Freund Discussion: https://postgr.es/m/CAE9k0PmNaMD2oHTEAhRyxnxpaDaYkuBYkLa1dpOpn=RS0iS2AQ@mail.gmail.com Backpatch: 12-, where the bug was introduced in 15d8f8312
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r--src/backend/executor/nodeAgg.c34
1 files changed, 32 insertions, 2 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 2342ca30185..a9a1fd022a5 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -2231,13 +2231,43 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
/*
* initialize source tuple type.
*/
+ aggstate->ss.ps.outerops =
+ ExecGetResultSlotOps(outerPlanState(&aggstate->ss),
+ &aggstate->ss.ps.outeropsfixed);
+ aggstate->ss.ps.outeropsset = true;
+
ExecCreateScanSlotFromOuterPlan(estate, &aggstate->ss,
- ExecGetResultSlotOps(outerPlanState(&aggstate->ss), NULL));
+ aggstate->ss.ps.outerops);
scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor;
- if (node->chain)
+
+ /*
+ * If there are more than two phases (including a potential dummy phase
+ * 0), input will be resorted using tuplesort. Need a slot for that.
+ */
+ if (numPhases > 2)
+ {
aggstate->sort_slot = ExecInitExtraTupleSlot(estate, scanDesc,
&TTSOpsMinimalTuple);
+ /*
+ * The output of the tuplesort, and the output from the outer child
+ * might not use the same type of slot. In most cases the child will
+ * be a Sort, and thus return a TTSOpsMinimalTuple type slot - but the
+ * input can also be be presorted due an index, in which case it could
+ * be a different type of slot.
+ *
+ * XXX: For efficiency it would be good to instead/additionally
+ * generate expressions with corresponding settings of outerops* for
+ * the individual phases - deforming is often a bottleneck for
+ * aggregations with lots of rows per group. If there's multiple
+ * sorts, we know that all but the first use TTSOpsMinimalTuple (via
+ * the nodeAgg.c internal tuplesort).
+ */
+ if (aggstate->ss.ps.outeropsfixed &&
+ aggstate->ss.ps.outerops != &TTSOpsMinimalTuple)
+ aggstate->ss.ps.outeropsfixed = false;
+ }
+
/*
* Initialize result type, slot and projection.
*/