diff options
author | David Rowley <drowley@postgresql.org> | 2024-01-04 20:38:25 +1300 |
---|---|---|
committer | David Rowley <drowley@postgresql.org> | 2024-01-04 20:38:25 +1300 |
commit | ae69c4fcf1337af399a788ab8d96af540bd1cd8e (patch) | |
tree | cee1c57e2bb438f6206500b7b5b1cf421d2c6007 /src/backend/executor/execExprInterp.c | |
parent | 007693f2a3ac2ac19affcb03ad43cdb36ccff5b5 (diff) | |
download | postgresql-ae69c4fcf1337af399a788ab8d96af540bd1cd8e.tar.gz postgresql-ae69c4fcf1337af399a788ab8d96af540bd1cd8e.zip |
Fix use of incorrect TupleTableSlot in DISTINCT aggregates
1349d2790 added code to allow DISTINCT and ORDER BY aggregates to work
more efficiently by using presorted input. That commit added some code
that made use of the AggState's tmpcontext and adjusted the
ecxt_outertuple and ecxt_innertuple slots before checking if the current
row is distinct from the previously seen row. That code forgot to set the
TupleTableSlots back to what they were originally, which could result in
errors such as:
ERROR: attribute 1 of type record has wrong type
This only affects aggregate functions which have multiple arguments when
DISTINCT is used. For example: string_agg(DISTINCT col, ', ')
Thanks to Tom Lane for identifying the breaking commit.
Bug: #18264
Reported-by: Vojtěch Beneš
Discussion: https://postgr.es/m/18264-e363593d7e9feb7d@postgresql.org
Backpatch-through: 16, where 1349d2790 was added
Diffstat (limited to 'src/backend/executor/execExprInterp.c')
-rw-r--r-- | src/backend/executor/execExprInterp.c | 20 |
1 files changed, 17 insertions, 3 deletions
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index b1f92e013e2..3c17cc6b1e1 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -4579,12 +4579,16 @@ ExecEvalPreOrderedDistinctSingle(AggState *aggstate, AggStatePerTrans pertrans) /* * ExecEvalPreOrderedDistinctMulti * Returns true when the aggregate input is distinct from the previous - * input and returns false when the input matches the previous input. + * input and returns false when the input matches the previous input, or + * when there was no previous input. */ bool ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans) { ExprContext *tmpcontext = aggstate->tmpcontext; + bool isdistinct = false; /* for now */ + TupleTableSlot *save_outer; + TupleTableSlot *save_inner; for (int i = 0; i < pertrans->numTransInputs; i++) { @@ -4596,6 +4600,10 @@ ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans) pertrans->sortslot->tts_nvalid = pertrans->numInputs; ExecStoreVirtualTuple(pertrans->sortslot); + /* save the previous slots before we overwrite them */ + save_outer = tmpcontext->ecxt_outertuple; + save_inner = tmpcontext->ecxt_innertuple; + tmpcontext->ecxt_outertuple = pertrans->sortslot; tmpcontext->ecxt_innertuple = pertrans->uniqslot; @@ -4607,9 +4615,15 @@ ExecEvalPreOrderedDistinctMulti(AggState *aggstate, AggStatePerTrans pertrans) pertrans->haslast = true; ExecCopySlot(pertrans->uniqslot, pertrans->sortslot); - return true; + + isdistinct = true; } - return false; + + /* restore the original slots */ + tmpcontext->ecxt_outertuple = save_outer; + tmpcontext->ecxt_innertuple = save_inner; + + return isdistinct; } /* |