A 库下处理hash分区遇到null值输入报错问题

This commit is contained in:
zhubin79
2025-03-12 11:02:04 +08:00
parent 582047e719
commit 5c0b4e5cd3
6 changed files with 215 additions and 29 deletions

View File

@ -404,6 +404,7 @@ Oid getHashPartitionOid(PartitionMap* partMap, Const** partKeyValue, int32* part
Oid result = InvalidOid;
int keyNums = 0;
int hit = -1;
bool hasNull = false;
Assert(PointerIsValid(partMap));
Assert(PointerIsValid(partKeyValue));
@ -417,6 +418,10 @@ Oid getHashPartitionOid(PartitionMap* partMap, Const** partKeyValue, int32* part
uint32 hash_value = 0;
while (i < keyNums) {
if (partKeyValue[i]->constisnull) {
if (DB_IS_CMPT(A_FORMAT)) {
hasNull = true;
break;
}
if (PointerIsValid(partSeq)) {
*partSeq = hit;
}
@ -428,16 +433,19 @@ Oid getHashPartitionOid(PartitionMap* partMap, Const** partKeyValue, int32* part
i++;
}
hit = hash_value % (uint32)(hashPartMap->hashElementsNum);
hit = hashPartMap->hashElementsNum - hit - 1;
if (hasNull && DB_IS_CMPT(A_FORMAT)) {
/* If null exists for hash partition, force route to first partition */
hit = 0;
} else {
hit = hash_value % (uint32)(hashPartMap->hashElementsNum);
hit = hashPartMap->hashElementsNum - hit - 1;
}
if (PointerIsValid(partSeq)) {
*partSeq = hit;
}
if (hit >= 0) {
result = hashPartMap->hashElements[hit].partitionOid;
}
result = hashPartMap->hashElements[hit].partitionOid;
decre_partmap_refcount(partMap);
return result;

View File

@ -990,8 +990,21 @@ static PruningResult* partitionPruningFromNullTest(PartitionType partType, NullT
return result;
}
if (expr->nulltesttype != IS_NULL) {
/* For IS_NOT_NULL, we don't try to verify that the first partition is all NULL,
* so do not perform pruning here.
*/
result->state = PRUNING_RESULT_FULL;
} else {
if (DB_IS_CMPT(A_FORMAT)) {
/* Clause hash partition for null value always route to first partition,
* so for IS_NULL, we return the first partition.
*/
result->isPbeSinlePartition = true;
result->boundary = NULL;
result->state = PRUNING_RESULT_SUBSET;
result->bm_rangeSelectedPartitions = bms_make_singleton(0);
return result;
}
result->state = PRUNING_RESULT_EMPTY;
}
result->isPbeSinlePartition = false;

View File

@ -24,15 +24,18 @@ partition by hash (a)
insert into test_partition_for_null_hash values (0, 0, 0, 0);
insert into test_partition_for_null_hash values (1, 1, 1, 1);
insert into test_partition_for_null_hash values (5, 5, 5, 5);
-- failed: inserted partition key does not map to any table partition
-- success
insert into test_partition_for_null_hash values (null, null, null, null);
ERROR: inserted partition key does not map to any table partition
-- success
insert into test_partition_for_null_hash values (0, null, null, null);
-- failed: The partition number is invalid or out-of-range
-- success
select * from test_partition_for_null_hash partition for (null) order by 1, 2, 3, 4;
ERROR: Cannot find partition by the value
DETAIL: N/A.
a | b | c | d
---+---+---+---
1 | 1 | 1 | 1
| | |
(2 rows)
-- success
select * from test_partition_for_null_hash partition for (0) order by 1, 2, 3, 4;
a | b | c | d
@ -41,17 +44,17 @@ select * from test_partition_for_null_hash partition for (0) order by 1, 2, 3, 4
0 | | |
(2 rows)
-- failed: The partition number is invalid or out-of-range
alter table test_partition_for_null_hash rename partition for (null) to test_partition_for_null_hash_part1;
ERROR: The partition number is invalid or out-of-range
-- success
alter table test_partition_for_null_hash rename partition for (null) to test_partition_for_null_hash_part1;
-- failed, same partition name test_partition_for_null_hash_part1 is already exists
alter table test_partition_for_null_hash rename partition for (0) to test_partition_for_null_hash_part1;
ERROR: partition "test_partition_for_null_hash_part1" of relation "test_partition_for_null_hash" already exists
-- success
select * from test_partition_for_null_hash partition (test_partition_for_null_hash_part1) order by 1, 2, 3, 4;
a | b | c | d
---+---+---+---
0 | 0 | 0 | 0
0 | | |
1 | 1 | 1 | 1
| | |
(2 rows)
alter table test_partition_for_null_hash drop partition for (NULL);
@ -61,10 +64,10 @@ ERROR: Droping hash partition is unsupported.
CREATE TABLE select_hash_partition_table_000_3(
C_CHAR_1 CHAR(1),
C_CHAR_2 CHAR(10),
C_CHAR_3 CHAR(102400),
C_CHAR_3 CHAR(20),
C_VARCHAR_1 VARCHAR(1),
C_VARCHAR_2 VARCHAR(10),
C_VARCHAR_3 VARCHAR(1024),
C_VARCHAR_3 VARCHAR(20),
C_INT INTEGER,
C_BIGINT BIGINT,
C_SMALLINT SMALLINT,
@ -95,10 +98,17 @@ INSERT INTO select_hash_partition_table_000_3 VALUES('I','IJK','IJKLMNO','i','ij
INSERT INTO select_hash_partition_table_000_3 VALUES('I','IJK','IJKLMNO','i','ijk','ijklmno',1100,999999,99,9.9,9.99,9.999,'2000-09-09','2000-09-09 09:09:09','2000-09-09 09:09:09+09');
INSERT INTO select_hash_partition_table_000_3 VALUES('I','IJK','IJKLMNO','i','ijk','ijklmno',1600,999999,99,9.9,9.99,9.999,'2000-09-09','2000-09-09 09:09:09','2000-09-09 09:09:09+09');
select * from select_hash_partition_table_000_3 partition for (NULL) order by C_INT;
ERROR: Cannot find partition by the value
DETAIL: N/A.
c_char_1 | c_char_2 | c_char_3 | c_varchar_1 | c_varchar_2 | c_varchar_3 | c_int | c_bigint | c_smallint | c_float | c_numeric | c_dp | c_date | c_ts_without | c_ts_with
----------+------------+----------------------+-------------+-------------+-------------+-------+----------+------------+---------+-----------+-------+--------------------------+--------------------------+------------------------------
A | ABC | ABCDEFG | a | abc | abcdefg | 111 | 111111 | 11 | 1.1 | 1.11000 | 1.111 | Sat Jan 01 00:00:00 2000 | Sat Jan 01 01:01:01 2000 | Fri Dec 31 16:01:01 1999 PST
E | EFG | EFGHIJK | e | efg | efghijk | 555 | 555555 | 55 | 5.5 | 5.55000 | 5.555 | Fri May 05 00:00:00 2000 | Fri May 05 05:05:05 2000 | Thu May 04 17:05:05 2000 PDT
F | FGH | FGHIJKL | f | fgh | fghijkl | 666 | 666666 | 66 | 6.6 | 6.66000 | 6.666 | Tue Jun 06 00:00:00 2000 | Tue Jun 06 06:06:06 2000 | Mon Jun 05 17:06:06 2000 PDT
G | GHI | GHIJKLM | g | ghi | ghijklm | 777 | 777777 | 77 | 7.7 | 7.77000 | 7.777 | Fri Jul 07 00:00:00 2000 | Fri Jul 07 07:07:07 2000 | Thu Jul 06 17:07:07 2000 PDT
I | IJK | IJKLMNO | i | ijk | ijklmno | 999 | 999999 | 99 | 9.9 | 9.99000 | 9.999 | Sat Sep 09 00:00:00 2000 | Sat Sep 09 09:09:09 2000 | Fri Sep 08 17:09:09 2000 PDT
I | IJK | IJKLMNO | i | ijk | ijklmno | 999 | 999999 | 99 | 9.9 | 9.99000 | 9.999 | Sat Sep 09 00:00:00 2000 | Sat Sep 09 09:09:09 2000 | Fri Sep 08 17:09:09 2000 PDT
(6 rows)
alter table select_hash_partition_table_000_3 rename partition for (NULL) to select_hash_partition_table_000_3_p1;
ERROR: The partition number is invalid or out-of-range
alter table select_hash_partition_table_000_3 drop partition for (NULL);
ERROR: Droping hash partition is unsupported.
CREATE TABLE partition_wise_join_table_001_1 (ID INT NOT NULL,NAME VARCHAR(50) NOT NULL,SCORE NUMERIC(4,1),BIRTHDAY TIMESTAMP WITHOUT TIME ZONE,ADDRESS TEXT,SALARY double precision,RANK SMALLINT)

View File

@ -22,9 +22,8 @@ select * from test_partition_for_null_hash order by a;
5 | 5 | 5 | 5
(6 rows)
-- failed: inserted partition key does not map to any table partition
-- success
insert into test_partition_for_null_hash values (null, null, null, null);
ERROR: inserted partition key does not map to any table partition
-- success
insert into test_partition_for_null_hash values (0, null, null, null);
CREATE TABLE select_hash_partition_table_000_3(
@ -180,6 +179,108 @@ select count(*) from hw_partition_select_test;
4
(1 row)
create table hw_hash_partition_inert_null (c1 int, c2 timestamp)
partition by hash (c2)
(
partition hw_hash_partition_inert_null_p1,
partition hw_hash_partition_inert_null_p2,
partition hw_hash_partition_inert_null_p3,
partition hw_hash_partition_inert_null_p4,
partition hw_hash_partition_inert_null_p5
);
insert into hw_hash_partition_inert_null values (generate_series(1, 1000), null);
insert into hw_hash_partition_inert_null values (1001, '2025-02-24 00:00:00'::timestamp);
insert into hw_hash_partition_inert_null values (1002, '2024-01-01 00:00:00'::timestamp);
insert into hw_hash_partition_inert_null values (1003, '2024-06-06 00:00:00'::timestamp);
select p.relname, ta.row_count from (select tableoid::regclass as partition_id, count(*) as row_count from hw_hash_partition_inert_null group by partition_id) as ta left join pg_partition p on p.oid = ta.partition_id order by p.oid;
relname | row_count
---------------------------------+-----------
hw_hash_partition_inert_null_p1 | 1000
hw_hash_partition_inert_null_p2 | 1
hw_hash_partition_inert_null_p3 | 1
hw_hash_partition_inert_null_p4 | 1
(4 rows)
drop table hw_hash_partition_inert_null;
-- non index partition key
drop table if exists t1_part;
NOTICE: table "t1_part" does not exist, skipping
create table t1_part (c1 int, c2 int) partition by hash (c2) partitions 6;
insert into t1_part values (generate_series(1, 1000), null);
insert into t1_part values (1001, generate_series(1, 100));
explain (costs off) select * from t1_part where c2 is null;
QUERY PLAN
---------------------------------
Partitioned Seq Scan on t1_part
Filter: (c2 IS NULL)
Selected Partitions: 1
(3 rows)
explain (costs off) select * from t1_part where c2 = 20;
QUERY PLAN
---------------------------------
Partitioned Seq Scan on t1_part
Filter: (c2 = 20)
Selected Partitions: 5
(3 rows)
drop table t1_part;
-- local index partition key
drop table if exists t1_partindex;
NOTICE: table "t1_partindex" does not exist, skipping
create table t1_partindex (c1 int, c2 int) partition by hash (c2) partitions 6;
create index t1_partindex_c2_ind on t1_partindex (c2) local;
insert into t1_partindex values (generate_series(1, 1000), null);
insert into t1_partindex values (2000, generate_series(1, 100));
explain (costs off) select * from t1_partindex where c2 is null;
QUERY PLAN
------------------------------------------------------------
Partitioned Bitmap Heap Scan on t1_partindex
Recheck Cond: (c2 IS NULL)
Selected Partitions: 1
-> Partitioned Bitmap Index Scan on t1_partindex_c2_ind
Index Cond: (c2 IS NULL)
Selected Partitions: 1
(6 rows)
explain (costs off) select * from t1_partindex where c2 = 20;
QUERY PLAN
------------------------------------------------------------
Partitioned Bitmap Heap Scan on t1_partindex
Recheck Cond: (c2 = 20)
Selected Partitions: 5
-> Partitioned Bitmap Index Scan on t1_partindex_c2_ind
Index Cond: (c2 = 20)
Selected Partitions: 5
(6 rows)
drop table t1_partindex;
-- global index partition key
drop table if exists t1_partindex_global;
NOTICE: table "t1_partindex_global" does not exist, skipping
create table t1_partindex_global (c1 int, c2 int) partition by hash (c2) partitions 6;
create index t1_partindex_global_c2_ind on t1_partindex_global (c2);
insert into t1_partindex_global values (generate_series(1, 1000), null);
insert into t1_partindex_global values (2000, generate_series(1, 100));
explain (costs off) select * from t1_partindex_global where c2 is null;
QUERY PLAN
-------------------------------------------------------
Bitmap Heap Scan on t1_partindex_global
Recheck Cond: (c2 IS NULL)
-> Bitmap Index Scan on t1_partindex_global_c2_ind
Index Cond: (c2 IS NULL)
(4 rows)
explain (costs off) select * from t1_partindex_global where c2 = 20;
QUERY PLAN
-------------------------------------------------------
Bitmap Heap Scan on t1_partindex_global
Recheck Cond: (c2 = 20)
-> Bitmap Index Scan on t1_partindex_global_c2_ind
Index Cond: (c2 = 20)
(4 rows)
drop table t1_partindex_global;
drop schema FVT_COMPRESS_QWER cascade;
NOTICE: drop cascades to 9 other objects
DETAIL: drop cascades to table test_partition_for_null_hash

View File

@ -31,21 +31,21 @@ insert into test_partition_for_null_hash values (0, 0, 0, 0);
insert into test_partition_for_null_hash values (1, 1, 1, 1);
insert into test_partition_for_null_hash values (5, 5, 5, 5);
-- failed: inserted partition key does not map to any table partition
-- success
insert into test_partition_for_null_hash values (null, null, null, null);
-- success
insert into test_partition_for_null_hash values (0, null, null, null);
-- failed: The partition number is invalid or out-of-range
-- success
select * from test_partition_for_null_hash partition for (null) order by 1, 2, 3, 4;
-- success
select * from test_partition_for_null_hash partition for (0) order by 1, 2, 3, 4;
-- failed: The partition number is invalid or out-of-range
alter table test_partition_for_null_hash rename partition for (null) to test_partition_for_null_hash_part1;
-- success
alter table test_partition_for_null_hash rename partition for (null) to test_partition_for_null_hash_part1;
-- failed, same partition name test_partition_for_null_hash_part1 is already exists
alter table test_partition_for_null_hash rename partition for (0) to test_partition_for_null_hash_part1;
-- success
select * from test_partition_for_null_hash partition (test_partition_for_null_hash_part1) order by 1, 2, 3, 4;
@ -56,10 +56,10 @@ alter table test_partition_for_null_hash drop partition for (0);
CREATE TABLE select_hash_partition_table_000_3(
C_CHAR_1 CHAR(1),
C_CHAR_2 CHAR(10),
C_CHAR_3 CHAR(102400),
C_CHAR_3 CHAR(20),
C_VARCHAR_1 VARCHAR(1),
C_VARCHAR_2 VARCHAR(10),
C_VARCHAR_3 VARCHAR(1024),
C_VARCHAR_3 VARCHAR(20),
C_INT INTEGER,
C_BIGINT BIGINT,
C_SMALLINT SMALLINT,

View File

@ -13,7 +13,7 @@ insert into test_partition_for_null_hash values (1, 1, 1, 1);
insert into test_partition_for_null_hash values (5, 5, 5, 5);
insert into test_partition_for_null_hash select * from test_partition_for_null_hash;
select * from test_partition_for_null_hash order by a;
-- failed: inserted partition key does not map to any table partition
-- success
insert into test_partition_for_null_hash values (null, null, null, null);
-- success
insert into test_partition_for_null_hash values (0, null, null, null);
@ -148,4 +148,58 @@ insert into hw_partition_select_test values(555);
insert into hw_partition_select_test values(888);
insert into hw_partition_select_test values(100);
select count(*) from hw_partition_select_test;
create table hw_hash_partition_inert_null (c1 int, c2 timestamp)
partition by hash (c2)
(
partition hw_hash_partition_inert_null_p1,
partition hw_hash_partition_inert_null_p2,
partition hw_hash_partition_inert_null_p3,
partition hw_hash_partition_inert_null_p4,
partition hw_hash_partition_inert_null_p5
);
insert into hw_hash_partition_inert_null values (generate_series(1, 1000), null);
insert into hw_hash_partition_inert_null values (1001, '2025-02-24 00:00:00'::timestamp);
insert into hw_hash_partition_inert_null values (1002, '2024-01-01 00:00:00'::timestamp);
insert into hw_hash_partition_inert_null values (1003, '2024-06-06 00:00:00'::timestamp);
select p.relname, ta.row_count from (select tableoid::regclass as partition_id, count(*) as row_count from hw_hash_partition_inert_null group by partition_id) as ta left join pg_partition p on p.oid = ta.partition_id order by p.oid;
drop table hw_hash_partition_inert_null;
-- non index partition key
drop table if exists t1_part;
create table t1_part (c1 int, c2 int) partition by hash (c2) partitions 6;
insert into t1_part values (generate_series(1, 1000), null);
insert into t1_part values (1001, generate_series(1, 100));
explain (costs off) select * from t1_part where c2 is null;
explain (costs off) select * from t1_part where c2 = 20;
drop table t1_part;
-- local index partition key
drop table if exists t1_partindex;
create table t1_partindex (c1 int, c2 int) partition by hash (c2) partitions 6;
create index t1_partindex_c2_ind on t1_partindex (c2) local;
insert into t1_partindex values (generate_series(1, 1000), null);
insert into t1_partindex values (2000, generate_series(1, 100));
explain (costs off) select * from t1_partindex where c2 is null;
explain (costs off) select * from t1_partindex where c2 = 20;
drop table t1_partindex;
-- global index partition key
drop table if exists t1_partindex_global;
create table t1_partindex_global (c1 int, c2 int) partition by hash (c2) partitions 6;
create index t1_partindex_global_c2_ind on t1_partindex_global (c2);
insert into t1_partindex_global values (generate_series(1, 1000), null);
insert into t1_partindex_global values (2000, generate_series(1, 100));
explain (costs off) select * from t1_partindex_global where c2 is null;
explain (costs off) select * from t1_partindex_global where c2 = 20;
drop table t1_partindex_global;
drop schema FVT_COMPRESS_QWER cascade;