aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--src/include/executor/executor.h1
-rw-r--r--src/test/regress/expected/with.out20
-rw-r--r--src/test/regress/sql/with.sql14
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 (