From 4642bc2d746bf42a37dbd96b5519d2765f26f82b Mon Sep 17 00:00:00 2001 From: Mingli Zhang Date: Fri, 12 Aug 2022 22:35:29 +0800 Subject: [PATCH vn] Fix HashJoin crash. In ExecChooseHashTableSize(), commit b154ee63bb uses func pg_nextpower2_size_t whose param must not be 0. There is a potential risk that hash_table_bytes < bucket_size in some corner cases. Reproduce sql: --create a wide enough table to reproduce the bug DO language 'plpgsql' $$ DECLARE var_sql text := 'CREATE TABLE t_1600_columns(' || string_agg('field' || i::text || ' varchar(255)', ',') || ');' FROM generate_series(1,1600) As i; BEGIN EXECUTE var_sql; END; $$ ; create table j1(field1 text); set work_mem = 64; set hash_mem_multiplier = 1; set enable_nestloop = off; set enable_mergejoin = off; explain select * from j1 inner join t_1600_columns using(field1); server closed the connection unexpectedly This probably means the server terminated abnormally before or while processing the request. The connection to the server was lost. Attempting reset: Succeeded --- src/backend/executor/nodeHash.c | 5 ++++- src/test/regress/expected/join_hash.out | 28 +++++++++++++++++++++++++ src/test/regress/sql/join_hash.sql | 24 +++++++++++++++++++++ 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/backend/executor/nodeHash.c b/src/backend/executor/nodeHash.c index 123079c16c..268b6ee9dd 100644 --- a/src/backend/executor/nodeHash.c +++ b/src/backend/executor/nodeHash.c @@ -832,7 +832,10 @@ ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, * overhead for the hash code, pointer to the next tuple, etc. */ bucket_size = (tupsize * NTUP_PER_BUCKET + sizeof(HashJoinTuple)); - sbuckets = pg_nextpower2_size_t(hash_table_bytes / bucket_size); + if (hash_table_bytes < bucket_size) + sbuckets = 1; + else + sbuckets = pg_nextpower2_size_t(hash_table_bytes / bucket_size); sbuckets = Min(sbuckets, max_pointers); nbuckets = (int) sbuckets; nbuckets = pg_nextpower2_32(nbuckets); diff --git a/src/test/regress/expected/join_hash.out b/src/test/regress/expected/join_hash.out index 3ec07bc1af..b13b824f7f 100644 --- a/src/test/regress/expected/join_hash.out +++ b/src/test/regress/expected/join_hash.out @@ -1031,3 +1031,31 @@ WHERE (1 row) ROLLBACK; +-- Verify that hash join on wide table with little memory. +BEGIN; +-- create a wide enough table to reproduce the bug. +DO language 'plpgsql' +$$ +DECLARE var_sql text := 'CREATE TABLE t_1600_columns(' + || string_agg('field' || i::text || ' varchar(255)', ',') || ');' + FROM generate_series(1,1600) As i; +BEGIN + EXECUTE var_sql; +END; +$$ ; +create table j1(field1 text); +set local work_mem = 64; +set local hash_mem_multiplier = 1; +set local enable_nestloop = off; +set local enable_mergejoin = off; +explain (costs off) select * from j1 inner join t_1600_columns using(field1); + QUERY PLAN +---------------------------------------------------------- + Hash Join + Hash Cond: ((t_1600_columns.field1)::text = j1.field1) + -> Seq Scan on t_1600_columns + -> Hash + -> Seq Scan on j1 +(5 rows) + +ROLLBACK; diff --git a/src/test/regress/sql/join_hash.sql b/src/test/regress/sql/join_hash.sql index 77dbc182d5..bd4172d541 100644 --- a/src/test/regress/sql/join_hash.sql +++ b/src/test/regress/sql/join_hash.sql @@ -556,3 +556,27 @@ WHERE AND hjtest_1.a <> hjtest_2.b; ROLLBACK; + +-- Verify that hash join on wide table with little memory. +BEGIN; +-- create a wide enough table to reproduce the bug. +DO language 'plpgsql' +$$ +DECLARE var_sql text := 'CREATE TABLE t_1600_columns(' + || string_agg('field' || i::text || ' varchar(255)', ',') || ');' + FROM generate_series(1,1600) As i; +BEGIN + EXECUTE var_sql; +END; +$$ ; + +create table j1(field1 text); + +set local work_mem = 64; +set local hash_mem_multiplier = 1; +set local enable_nestloop = off; +set local enable_mergejoin = off; + +explain (costs off) select * from j1 inner join t_1600_columns using(field1); + +ROLLBACK; \ No newline at end of file -- 2.34.1