Skip to content

Commit 5c07de4

Browse files
committed
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.
1 parent 6975dcd commit 5c07de4

File tree

3 files changed

+43
-6
lines changed

3 files changed

+43
-6
lines changed

src/backend/executor/nodeSubplan.c

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ static Datum ExecScanSubPlan(SubPlanState *node,
4444
ExprContext *econtext,
4545
bool *isNull);
4646
static void buildSubPlanHash(SubPlanState *node, ExprContext *econtext);
47-
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot);
47+
static bool findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
48+
FmgrInfo *eqfunctions);
4849
static bool slotAllNulls(TupleTableSlot *slot);
4950
static bool slotNoNulls(TupleTableSlot *slot);
5051

@@ -151,7 +152,7 @@ ExecHashSubPlan(SubPlanState *node,
151152
return BoolGetDatum(true);
152153
}
153154
if (node->havenullrows &&
154-
findPartialMatch(node->hashnulls, slot))
155+
findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
155156
{
156157
ExecClearTuple(slot);
157158
*isNull = true;
@@ -184,14 +185,14 @@ ExecHashSubPlan(SubPlanState *node,
184185
}
185186
/* Scan partly-null table first, since more likely to get a match */
186187
if (node->havenullrows &&
187-
findPartialMatch(node->hashnulls, slot))
188+
findPartialMatch(node->hashnulls, slot, node->cur_eq_funcs))
188189
{
189190
ExecClearTuple(slot);
190191
*isNull = true;
191192
return BoolGetDatum(false);
192193
}
193194
if (node->havehashrows &&
194-
findPartialMatch(node->hashtable, slot))
195+
findPartialMatch(node->hashtable, slot, node->cur_eq_funcs))
195196
{
196197
ExecClearTuple(slot);
197198
*isNull = true;
@@ -571,9 +572,13 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
571572
* We have to scan the whole hashtable; we can't usefully use hashkeys
572573
* to guide probing, since we might get partial matches on tuples with
573574
* hashkeys quite unrelated to what we'd get from the given tuple.
575+
*
576+
* Caller must provide the equality functions to use, since in cross-type
577+
* cases these are different from the hashtable's internal functions.
574578
*/
575579
static bool
576-
findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot)
580+
findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
581+
FmgrInfo *eqfunctions)
577582
{
578583
int numCols = hashtable->numCols;
579584
AttrNumber *keyColIdx = hashtable->keyColIdx;
@@ -586,7 +591,7 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot)
586591
ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
587592
if (!execTuplesUnequal(slot, hashtable->tableslot,
588593
numCols, keyColIdx,
589-
hashtable->cur_eq_funcs,
594+
eqfunctions,
590595
hashtable->tempcxt))
591596
{
592597
TermTupleHashIterator(&hashiter);

src/test/regress/expected/subselect.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,23 @@ from
546546
-----
547547
(0 rows)
548548

549+
--
550+
-- Test case for cross-type partial matching in hashed subplan (bug #7597)
551+
--
552+
create temp table outer_7597 (f1 int4, f2 int4);
553+
insert into outer_7597 values (0, 0);
554+
insert into outer_7597 values (1, 0);
555+
insert into outer_7597 values (0, null);
556+
insert into outer_7597 values (1, null);
557+
create temp table inner_7597(c1 int8, c2 int8);
558+
insert into inner_7597 values(0, null);
559+
select * from outer_7597 where (f1, f2) not in (select * from inner_7597);
560+
f1 | f2
561+
----+----
562+
1 | 0
563+
1 |
564+
(2 rows)
565+
549566
--
550567
-- Test case for premature memory release during hashing of subplan output
551568
--

src/test/regress/sql/subselect.sql

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,21 @@ from
345345
join
346346
int4_tbl i4 on dummy = i4.f1;
347347

348+
--
349+
-- Test case for cross-type partial matching in hashed subplan (bug #7597)
350+
--
351+
352+
create temp table outer_7597 (f1 int4, f2 int4);
353+
insert into outer_7597 values (0, 0);
354+
insert into outer_7597 values (1, 0);
355+
insert into outer_7597 values (0, null);
356+
insert into outer_7597 values (1, null);
357+
358+
create temp table inner_7597(c1 int8, c2 int8);
359+
insert into inner_7597 values(0, null);
360+
361+
select * from outer_7597 where (f1, f2) not in (select * from inner_7597);
362+
348363
--
349364
-- Test case for premature memory release during hashing of subplan output
350365
--

0 commit comments

Comments
 (0)