aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2012-10-11 12:21:24 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2012-10-11 12:21:24 -0400
commit55eaeef0b9314c40b7124ae37b33e0d61383bf3d (patch)
treedf8baad0ca000faa5f8d17fb370c1bbd19029f89
parentfacc2047feda0c6fc4d2028f36f5a73d6c5cfc76 (diff)
downloadpostgresql-55eaeef0b9314c40b7124ae37b33e0d61383bf3d.tar.gz
postgresql-55eaeef0b9314c40b7124ae37b33e0d61383bf3d.zip
Fix cross-type case in partial row matching for hashed subplans.
When hashing a subplan like "WHERE (a, b) NOT IN (SELECT x, y FROM ...)", findPartialMatch() attempted to match rows using the hashtable's internal equality operators, which of course are for x and y's datatypes. What we need to use are the potentially cross-type operators for a=x, b=y, etc. Failure to do that leads to wrong answers or even crashes. The scope for problems is limited to cases where we have different types with compatible hash functions (else we'd not be using a hashed subplan), but for example int4 vs int8 can cause the problem. Per bug #7597 from Bo Jensen. This has been wrong since the hashed-subplan code was written, so patch all the way back.
-rw-r--r--src/backend/executor/nodeSubplan.c17
-rw-r--r--src/test/regress/expected/subselect.out17
-rw-r--r--src/test/regress/sql/subselect.sql15
3 files changed, 43 insertions, 6 deletions
diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c
index e69eb5c6edf..b2c771f410b 100644
--- a/src/backend/executor/nodeSubplan.c
+++ b/src/backend/executor/nodeSubplan.c
@@ -44,7 +44,8 @@ static Datum ExecScanSubPlan(SubPlanState *node,
ExprContext *econtext,
bool *isNull);
static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
-static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
+static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
+ FmgrInfo *eqfunctions);
static bool slotAllNulls(TupleTableSlot *slot);
static bool slotNoNulls(TupleTableSlot *slot);
@@ -151,7 +152,7 @@ ExecHashSubPlan(SubPlanState *node,
return BoolGetDatum(true);
}
if (node->havenullrows &&
- findPartialMatch(node->hashnulls, slot))
+ findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
{
ExecClearTuple(slot);
*isNull = true;
@@ -184,14 +185,14 @@ ExecHashSubPlan(SubPlanState *node,
}
/* Scan partly-null table first, since more likely to get a match */
if (node->havenullrows &&
- findPartialMatch(node->hashnulls, slot))
+ findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
{
ExecClearTuple(slot);
*isNull = true;
return BoolGetDatum(false);
}
if (node->havehashrows &&
- findPartialMatch(node->hashtable, slot))
+ findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
{
ExecClearTuple(slot);
*isNull = true;
@@ -571,9 +572,13 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
* We have to scan the whole hashtable; we can't usefully use hashkeys
* to guide probing, since we might get partial matches on tuples with
* hashkeys quite unrelated to what we'd get from the given tuple.
+ *
+ * Caller must provide the equality functions to use, since in cross-type
+ * cases these are different from the hashtable's internal functions.
*/
static bool
-findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot)
+findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
+ FmgrInfo *eqfunctions)
{
int numCols = hashtable->numCols;
AttrNumber *keyColIdx = hashtable->keyColIdx;
@@ -586,7 +591,7 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot)
ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
if (!execTuplesUnequal(slot, hashtable->tableslot,
numCols, keyColIdx,
- hashtable->cur_eq_funcs,
+ eqfunctions,
hashtable->tempcxt))
{
TermTupleHashIterator(&hashiter);
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index 6fd4354913d..eae1b611dc8 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -547,6 +547,23 @@ from
(0 rows)
--
+-- Test case for cross-type partial matching in hashed subplan (bug #7597)
+--
+create temp table outer_7597 (f1 int4, f2 int4);
+insert into outer_7597 values (0, 0);
+insert into outer_7597 values (1, 0);
+insert into outer_7597 values (0, null);
+insert into outer_7597 values (1, null);
+create temp table inner_7597(c1 int8, c2 int8);
+insert into inner_7597 values(0, null);
+select * from outer_7597 where (f1, f2) not in (select * from inner_7597);
+ f1 | f2
+----+----
+ 1 | 0
+ 1 |
+(2 rows)
+
+--
-- Test case for premature memory release during hashing of subplan output
--
select '1'::text in (select '1'::name union all select '1'::name);
diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql
index 74a2b06d887..7d7830dfe23 100644
--- a/src/test/regress/sql/subselect.sql
+++ b/src/test/regress/sql/subselect.sql
@@ -346,6 +346,21 @@ from
int4_tbl i4 on dummy = i4.f1;
--
+-- Test case for cross-type partial matching in hashed subplan (bug #7597)
+--
+
+create temp table outer_7597 (f1 int4, f2 int4);
+insert into outer_7597 values (0, 0);
+insert into outer_7597 values (1, 0);
+insert into outer_7597 values (0, null);
+insert into outer_7597 values (1, null);
+
+create temp table inner_7597(c1 int8, c2 int8);
+insert into inner_7597 values(0, null);
+
+select * from outer_7597 where (f1, f2) not in (select * from inner_7597);
+
+--
-- Test case for premature memory release during hashing of subplan output
--