aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorDavid Rowley <drowley@postgresql.org>2024-12-18 12:05:55 +1300
committerDavid Rowley <drowley@postgresql.org>2024-12-18 12:05:55 +1300
commitd96d1d5152f30d15678e08e75b42756101b7cab6 (patch)
treeaa68356a1d930a1a4ed2fdcdf052c4bdb29997b7 /src/backend/executor
parent84f1b0b031e6914c41623102b93fed8ab0e51253 (diff)
downloadpostgresql-d96d1d5152f30d15678e08e75b42756101b7cab6.tar.gz
postgresql-d96d1d5152f30d15678e08e75b42756101b7cab6.zip
Fix incorrect slot type in BuildTupleHashTableExt
0f5738202 adjusted the execGrouping.c code so it made use of ExprStates to generate hash values. That commit made a wrong assumption that the slot type to pass to ExecBuildHash32FromAttrs() is always &TTSOpsMinimalTuple. That's not the case as the slot type depends on the slot type passed to LookupTupleHashEntry(), which for nodeRecursiveunion.c, could be any of the current slot types. Here we fix this by adding a new parameter to BuildTupleHashTableExt() to allow the slot type to be passed in. In the case of nodeSubplan.c and nodeAgg.c the slot type is always &TTSOpsVirtual, so for both of those cases, it's beneficial to pass the known slot type as that allows ExecBuildHash32FromAttrs() to skip adding the tuple deform step to the resulting ExprState. Another possible fix would have been to have ExecBuildHash32FromAttrs() set "fetch.kind" to NULL so that ExecComputeSlotInfo() always determines the EEOP_INNER_FETCHSOME is required, however, that option isn't favorable as slows down aggregation and hashed subplan evaluation due to the extra (needless) deform step. Thanks to Nathan Bossart for bisecting to find the offending commit based on Paul's report. Reported-by: Paul Ramsey <pramsey@cleverelephant.ca> Discussion: https://postgr.es/m/99F064C1-B3EB-4BE7-97D2-D2A0AA487A71@cleverelephant.ca
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execGrouping.c5
-rw-r--r--src/backend/executor/nodeAgg.c1
-rw-r--r--src/backend/executor/nodeRecursiveunion.c2
-rw-r--r--src/backend/executor/nodeSetOp.c1
-rw-r--r--src/backend/executor/nodeSubplan.c7
5 files changed, 15 insertions, 1 deletions
diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c
index 9a88fc65249..4a8f72305ce 100644
--- a/src/backend/executor/execGrouping.c
+++ b/src/backend/executor/execGrouping.c
@@ -135,6 +135,7 @@ execTuplesHashPrepare(int numCols,
/*
* Construct an empty TupleHashTable
*
+ * inputOps: slot ops for input hash values, or NULL if unknown or not fixed
* numCols, keyColIdx: identify the tuple fields to use as lookup key
* eqfunctions: equality comparison functions to use
* hashfunctions: datatype-specific hashing functions to use
@@ -154,6 +155,7 @@ execTuplesHashPrepare(int numCols,
TupleHashTable
BuildTupleHashTableExt(PlanState *parent,
TupleDesc inputDesc,
+ const TupleTableSlotOps *inputOps,
int numCols, AttrNumber *keyColIdx,
const Oid *eqfuncoids,
FmgrInfo *hashfunctions,
@@ -225,7 +227,7 @@ BuildTupleHashTableExt(PlanState *parent,
/* build hash ExprState for all columns */
hashtable->tab_hash_expr = ExecBuildHash32FromAttrs(inputDesc,
- &TTSOpsMinimalTuple,
+ inputOps,
hashfunctions,
collations,
numCols,
@@ -274,6 +276,7 @@ BuildTupleHashTable(PlanState *parent,
{
return BuildTupleHashTableExt(parent,
inputDesc,
+ NULL,
numCols, keyColIdx,
eqfuncoids,
hashfunctions,
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c
index 84d33fdebc6..53931c82853 100644
--- a/src/backend/executor/nodeAgg.c
+++ b/src/backend/executor/nodeAgg.c
@@ -1520,6 +1520,7 @@ build_hash_table(AggState *aggstate, int setno, long nbuckets)
perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
perhash->hashslot->tts_tupleDescriptor,
+ perhash->hashslot->tts_ops,
perhash->numCols,
perhash->hashGrpColIdxHash,
perhash->eqfuncoids,
diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c
index 22e7b83b2e6..39be4cdc3b1 100644
--- a/src/backend/executor/nodeRecursiveunion.c
+++ b/src/backend/executor/nodeRecursiveunion.c
@@ -37,8 +37,10 @@ build_hash_table(RecursiveUnionState *rustate)
Assert(node->numCols > 0);
Assert(node->numGroups > 0);
+ /* XXX is it worth working a bit harder to determine the inputOps here? */
rustate->hashtable = BuildTupleHashTableExt(&rustate->ps,
desc,
+ NULL,
node->numCols,
node->dupColIdx,
rustate->eqfuncoids,
diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c
index a8ac68b4826..b40d81f3ffa 100644
--- a/src/backend/executor/nodeSetOp.c
+++ b/src/backend/executor/nodeSetOp.c
@@ -128,6 +128,7 @@ build_hash_table(SetOpState *setopstate)
setopstate->hashtable = BuildTupleHashTableExt(&setopstate->ps,
desc,
+ NULL,
node->numCols,
node->dupColIdx,
setopstate->eqfuncoids,
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index f26c883c67d..bb4a0219194 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -519,6 +519,11 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
*
* If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
* need to store subplan output rows that contain NULL.
+ *
+ * Because the input slot for each hash table is always the slot resulting
+ * from an ExecProject(), we can use TTSOpsVirtual for the input ops. This
+ * saves a needless fetch inner op step for the hashing ExprState created
+ * in BuildTupleHashTableExt().
*/
MemoryContextReset(node->hashtablecxt);
node->havehashrows = false;
@@ -533,6 +538,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
else
node->hashtable = BuildTupleHashTableExt(node->parent,
node->descRight,
+ &TTSOpsVirtual,
ncols,
node->keyColIdx,
node->tab_eq_funcoids,
@@ -561,6 +567,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
else
node->hashnulls = BuildTupleHashTableExt(node->parent,
node->descRight,
+ &TTSOpsVirtual,
ncols,
node->keyColIdx,
node->tab_eq_funcoids,