Skip to content

Commit 007a778

Browse files
macdiceavamingli
authored andcommitted
Fix PHJ match bit initialization.
Hash join tuples reuse the HOT status bit to indicate match status during hash join execution. Correct reuse requires clearing the bit in all tuples. Serial hash join and parallel multi-batch hash join do so upon inserting the tuple into the hashtable. Single batch parallel hash join and batch 0 of unexpected multi-batch hash joins forgot to do this. It hadn't come up before because hashtable tuple match bits are only used for right and full outer joins and parallel ROJ and FOJ were unsupported. 11c2d6f introduced support for parallel ROJ/FOJ but neglected to ensure the match bits were reset. Author: Melanie Plageman <melanieplageman@gmail.com> Reported-by: Richard Guo <guofenglinux@gmail.com> Discussion: https://postgr.es/m/flat/CAMbWs48Nde1Mv%3DBJv6_vXmRKHMuHZm2Q_g4F6Z3_pn%2B3EV6BGQ%40mail.gmail.com
1 parent b75378a commit 007a778

3 files changed

Lines changed: 65 additions & 0 deletions

File tree

src/backend/executor/nodeHash.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2004,6 +2004,7 @@ ExecParallelHashTableInsert(HashJoinTable hashtable,
20042004
/* Store the hash value in the HashJoinTuple header. */
20052005
hashTuple->hashvalue = hashvalue;
20062006
memcpy(HJTUPLE_MINTUPLE(hashTuple), tuple, tuple->t_len);
2007+
HeapTupleHeaderClearMatch(HJTUPLE_MINTUPLE(hashTuple));
20072008

20082009
/* Push it onto the front of the bucket's list */
20092010
ExecParallelHashPushTuple(&hashtable->buckets.shared[bucketno],

src/test/regress/expected/join_hash.out

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,43 @@ explain (costs off) select * from join_hash_t_small, join_hash_t_big where a = b
10311031
(7 rows)
10321032

10331033
rollback to settings;
1034+
-- Hash join reuses the HOT status bit to indicate match status. This can only
1035+
-- be guaranteed to produce correct results if all the hash join tuple match
1036+
-- bits are reset before reuse. This is done upon loading them into the
1037+
-- hashtable.
1038+
SAVEPOINT settings;
1039+
SET enable_parallel_hash = on;
1040+
SET min_parallel_table_scan_size = 0;
1041+
SET parallel_setup_cost = 0;
1042+
SET parallel_tuple_cost = 0;
1043+
CREATE TABLE hjtest_matchbits_t1(id int);
1044+
CREATE TABLE hjtest_matchbits_t2(id int);
1045+
INSERT INTO hjtest_matchbits_t1 VALUES (1);
1046+
INSERT INTO hjtest_matchbits_t2 VALUES (2);
1047+
-- Update should create a HOT tuple. If this status bit isn't cleared, we won't
1048+
-- correctly emit the NULL-extended unmatching tuple in full hash join.
1049+
UPDATE hjtest_matchbits_t2 set id = 2;
1050+
SELECT * FROM hjtest_matchbits_t1 t1 FULL JOIN hjtest_matchbits_t2 t2 ON t1.id = t2.id;
1051+
id | id
1052+
----+----
1053+
1 |
1054+
| 2
1055+
(2 rows)
1056+
1057+
-- Test serial full hash join.
1058+
-- Resetting parallel_setup_cost should force a serial plan.
1059+
-- Just to be safe, however, set enable_parallel_hash to off, as parallel full
1060+
-- hash joins are only supported with shared hashtables.
1061+
RESET parallel_setup_cost;
1062+
SET enable_parallel_hash = off;
1063+
SELECT * FROM hjtest_matchbits_t1 t1 FULL JOIN hjtest_matchbits_t2 t2 ON t1.id = t2.id;
1064+
id | id
1065+
----+----
1066+
1 |
1067+
| 2
1068+
(2 rows)
1069+
1070+
ROLLBACK TO settings;
10341071
rollback;
10351072
-- Verify that hash key expressions reference the correct
10361073
-- nodes. Hashjoin's hashkeys need to reference its outer plan, Hash's

src/test/regress/sql/join_hash.sql

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,33 @@ rollback to settings;
539539

540540
rollback;
541541

542+
-- Hash join reuses the HOT status bit to indicate match status. This can only
543+
-- be guaranteed to produce correct results if all the hash join tuple match
544+
-- bits are reset before reuse. This is done upon loading them into the
545+
-- hashtable.
546+
SAVEPOINT settings;
547+
SET enable_parallel_hash = on;
548+
SET min_parallel_table_scan_size = 0;
549+
SET parallel_setup_cost = 0;
550+
SET parallel_tuple_cost = 0;
551+
CREATE TABLE hjtest_matchbits_t1(id int);
552+
CREATE TABLE hjtest_matchbits_t2(id int);
553+
INSERT INTO hjtest_matchbits_t1 VALUES (1);
554+
INSERT INTO hjtest_matchbits_t2 VALUES (2);
555+
-- Update should create a HOT tuple. If this status bit isn't cleared, we won't
556+
-- correctly emit the NULL-extended unmatching tuple in full hash join.
557+
UPDATE hjtest_matchbits_t2 set id = 2;
558+
SELECT * FROM hjtest_matchbits_t1 t1 FULL JOIN hjtest_matchbits_t2 t2 ON t1.id = t2.id;
559+
-- Test serial full hash join.
560+
-- Resetting parallel_setup_cost should force a serial plan.
561+
-- Just to be safe, however, set enable_parallel_hash to off, as parallel full
562+
-- hash joins are only supported with shared hashtables.
563+
RESET parallel_setup_cost;
564+
SET enable_parallel_hash = off;
565+
SELECT * FROM hjtest_matchbits_t1 t1 FULL JOIN hjtest_matchbits_t2 t2 ON t1.id = t2.id;
566+
ROLLBACK TO settings;
567+
568+
rollback;
542569

543570
-- Verify that hash key expressions reference the correct
544571
-- nodes. Hashjoin's hashkeys need to reference its outer plan, Hash's

0 commit comments

Comments
 (0)