diff options
-rw-r--r-- | src/backend/executor/execGrouping.c | 5 | ||||
-rw-r--r-- | src/backend/executor/nodeAgg.c | 1 | ||||
-rw-r--r-- | src/backend/executor/nodeRecursiveunion.c | 2 | ||||
-rw-r--r-- | src/backend/executor/nodeSetOp.c | 1 | ||||
-rw-r--r-- | src/backend/executor/nodeSubplan.c | 7 | ||||
-rw-r--r-- | src/include/executor/executor.h | 1 | ||||
-rw-r--r-- | src/test/regress/expected/with.out | 20 | ||||
-rw-r--r-- | src/test/regress/sql/with.sql | 14 |
8 files changed, 50 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, diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 494ec4f2e5d..c8e6befca88 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -140,6 +140,7 @@ extern TupleHashTable BuildTupleHashTable(PlanState *parent, MemoryContext tempcxt, bool use_variable_hash_iv); extern TupleHashTable BuildTupleHashTableExt(PlanState *parent, TupleDesc inputDesc, + const TupleTableSlotOps *inputOps, int numCols, AttrNumber *keyColIdx, const Oid *eqfuncoids, FmgrInfo *hashfunctions, diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index 08cfa5463fb..ff9754603bd 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -329,6 +329,26 @@ SELECT * FROM subdepartment ORDER BY name; 1 | 0 | A (1 row) +-- exercise the deduplication code of a UNION with mixed input slot types +WITH RECURSIVE subdepartment AS +( + -- select all columns to prevent projection + SELECT id, parent_department, name FROM department WHERE name = 'A' + UNION + -- joins do projection + SELECT d.id, d.parent_department, d.name FROM department AS d + INNER JOIN subdepartment AS sd ON d.parent_department = sd.id +) +SELECT * FROM subdepartment ORDER BY name; + id | parent_department | name +----+-------------------+------ + 1 | 0 | A + 2 | 1 | B + 3 | 2 | C + 4 | 2 | D + 6 | 4 | F +(5 rows) + -- inside subqueries SELECT count(*) FROM ( WITH RECURSIVE t(n) AS ( diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql index 8f6e6c0b405..aca7bae6ddd 100644 --- a/src/test/regress/sql/with.sql +++ b/src/test/regress/sql/with.sql @@ -216,6 +216,20 @@ WITH RECURSIVE subdepartment AS ) SELECT * FROM subdepartment ORDER BY name; +-- exercise the deduplication code of a UNION with mixed input slot types +WITH RECURSIVE subdepartment AS +( + -- select all columns to prevent projection + SELECT id, parent_department, name FROM department WHERE name = 'A' + + UNION + + -- joins do projection + SELECT d.id, d.parent_department, d.name FROM department AS d + INNER JOIN subdepartment AS sd ON d.parent_department = sd.id +) +SELECT * FROM subdepartment ORDER BY name; + -- inside subqueries SELECT count(*) FROM ( WITH RECURSIVE t(n) AS ( |