Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit d96d1d5

Browse files
committed
Fix incorrect slot type in BuildTupleHashTableExt
0f57382 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
1 parent 84f1b0b commit d96d1d5

File tree

8 files changed

+50
-1
lines changed

8 files changed

+50
-1
lines changed

src/backend/executor/execGrouping.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ execTuplesHashPrepare(int numCols,
135135
/*
136136
* Construct an empty TupleHashTable
137137
*
138+
* inputOps: slot ops for input hash values, or NULL if unknown or not fixed
138139
* numCols, keyColIdx: identify the tuple fields to use as lookup key
139140
* eqfunctions: equality comparison functions to use
140141
* hashfunctions: datatype-specific hashing functions to use
@@ -154,6 +155,7 @@ execTuplesHashPrepare(int numCols,
154155
TupleHashTable
155156
BuildTupleHashTableExt(PlanState *parent,
156157
TupleDesc inputDesc,
158+
const TupleTableSlotOps *inputOps,
157159
int numCols, AttrNumber *keyColIdx,
158160
const Oid *eqfuncoids,
159161
FmgrInfo *hashfunctions,
@@ -225,7 +227,7 @@ BuildTupleHashTableExt(PlanState *parent,
225227

226228
/* build hash ExprState for all columns */
227229
hashtable->tab_hash_expr = ExecBuildHash32FromAttrs(inputDesc,
228-
&TTSOpsMinimalTuple,
230+
inputOps,
229231
hashfunctions,
230232
collations,
231233
numCols,
@@ -274,6 +276,7 @@ BuildTupleHashTable(PlanState *parent,
274276
{
275277
return BuildTupleHashTableExt(parent,
276278
inputDesc,
279+
NULL,
277280
numCols, keyColIdx,
278281
eqfuncoids,
279282
hashfunctions,

src/backend/executor/nodeAgg.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@ build_hash_table(AggState *aggstate, int setno, long nbuckets)
15201520

15211521
perhash->hashtable = BuildTupleHashTableExt(&aggstate->ss.ps,
15221522
perhash->hashslot->tts_tupleDescriptor,
1523+
perhash->hashslot->tts_ops,
15231524
perhash->numCols,
15241525
perhash->hashGrpColIdxHash,
15251526
perhash->eqfuncoids,

src/backend/executor/nodeRecursiveunion.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@ build_hash_table(RecursiveUnionState *rustate)
3737
Assert(node->numCols > 0);
3838
Assert(node->numGroups > 0);
3939

40+
/* XXX is it worth working a bit harder to determine the inputOps here? */
4041
rustate->hashtable = BuildTupleHashTableExt(&rustate->ps,
4142
desc,
43+
NULL,
4244
node->numCols,
4345
node->dupColIdx,
4446
rustate->eqfuncoids,

src/backend/executor/nodeSetOp.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ build_hash_table(SetOpState *setopstate)
128128

129129
setopstate->hashtable = BuildTupleHashTableExt(&setopstate->ps,
130130
desc,
131+
NULL,
131132
node->numCols,
132133
node->dupColIdx,
133134
setopstate->eqfuncoids,

src/backend/executor/nodeSubplan.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,11 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
519519
*
520520
* If it's not necessary to distinguish FALSE and UNKNOWN, then we don't
521521
* need to store subplan output rows that contain NULL.
522+
*
523+
* Because the input slot for each hash table is always the slot resulting
524+
* from an ExecProject(), we can use TTSOpsVirtual for the input ops. This
525+
* saves a needless fetch inner op step for the hashing ExprState created
526+
* in BuildTupleHashTableExt().
522527
*/
523528
MemoryContextReset(node->hashtablecxt);
524529
node->havehashrows = false;
@@ -533,6 +538,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
533538
else
534539
node->hashtable = BuildTupleHashTableExt(node->parent,
535540
node->descRight,
541+
&TTSOpsVirtual,
536542
ncols,
537543
node->keyColIdx,
538544
node->tab_eq_funcoids,
@@ -561,6 +567,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
561567
else
562568
node->hashnulls = BuildTupleHashTableExt(node->parent,
563569
node->descRight,
570+
&TTSOpsVirtual,
564571
ncols,
565572
node->keyColIdx,
566573
node->tab_eq_funcoids,

src/include/executor/executor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ extern TupleHashTable BuildTupleHashTable(PlanState *parent,
140140
MemoryContext tempcxt, bool use_variable_hash_iv);
141141
extern TupleHashTable BuildTupleHashTableExt(PlanState *parent,
142142
TupleDesc inputDesc,
143+
const TupleTableSlotOps *inputOps,
143144
int numCols, AttrNumber *keyColIdx,
144145
const Oid *eqfuncoids,
145146
FmgrInfo *hashfunctions,

src/test/regress/expected/with.out

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,26 @@ SELECT * FROM subdepartment ORDER BY name;
329329
1 | 0 | A
330330
(1 row)
331331

332+
-- exercise the deduplication code of a UNION with mixed input slot types
333+
WITH RECURSIVE subdepartment AS
334+
(
335+
-- select all columns to prevent projection
336+
SELECT id, parent_department, name FROM department WHERE name = 'A'
337+
UNION
338+
-- joins do projection
339+
SELECT d.id, d.parent_department, d.name FROM department AS d
340+
INNER JOIN subdepartment AS sd ON d.parent_department = sd.id
341+
)
342+
SELECT * FROM subdepartment ORDER BY name;
343+
id | parent_department | name
344+
----+-------------------+------
345+
1 | 0 | A
346+
2 | 1 | B
347+
3 | 2 | C
348+
4 | 2 | D
349+
6 | 4 | F
350+
(5 rows)
351+
332352
-- inside subqueries
333353
SELECT count(*) FROM (
334354
WITH RECURSIVE t(n) AS (

src/test/regress/sql/with.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,20 @@ WITH RECURSIVE subdepartment AS
216216
)
217217
SELECT * FROM subdepartment ORDER BY name;
218218

219+
-- exercise the deduplication code of a UNION with mixed input slot types
220+
WITH RECURSIVE subdepartment AS
221+
(
222+
-- select all columns to prevent projection
223+
SELECT id, parent_department, name FROM department WHERE name = 'A'
224+
225+
UNION
226+
227+
-- joins do projection
228+
SELECT d.id, d.parent_department, d.name FROM department AS d
229+
INNER JOIN subdepartment AS sd ON d.parent_department = sd.id
230+
)
231+
SELECT * FROM subdepartment ORDER BY name;
232+
219233
-- inside subqueries
220234
SELECT count(*) FROM (
221235
WITH RECURSIVE t(n) AS (

0 commit comments

Comments
 (0)