From eb2fd01a50ef46fd7f988762f0d3ba0f4cd10995 Mon Sep 17 00:00:00 2001 From: Jason Mo Date: Wed, 27 Dec 2023 18:54:27 +0800 Subject: [PATCH] planner: fix stmt for partition table --- pkg/planner/core/rule_partition_processor.go | 59 +++++++++++--- .../r/executor/partition/issues.result | 76 +++++++++++++++++++ .../t/executor/partition/issues.test | 64 ++++++++++++++++ 3 files changed, 187 insertions(+), 12 deletions(-) diff --git a/pkg/planner/core/rule_partition_processor.go b/pkg/planner/core/rule_partition_processor.go index ab2b6c84098b4..c57ea117f1a88 100644 --- a/pkg/planner/core/rule_partition_processor.go +++ b/pkg/planner/core/rule_partition_processor.go @@ -180,17 +180,31 @@ func (s *partitionProcessor) getUsedHashPartitions(ctx sessionctx.Context, posHigh-- } - var rangeScalar float64 + var rangeScalar uint64 + var offset int64 if mysql.HasUnsignedFlag(col.RetType.GetFlag()) { - rangeScalar = float64(uint64(posHigh)) - float64(uint64(posLow)) // use float64 to avoid integer overflow + // Avoid integer overflow + if uint64(posHigh) < uint64(posLow) { + rangeScalar = 0 + } else { + rangeScalar = uint64(posHigh) - uint64(posLow) + offset = int64(uint64(posLow) % uint64(numPartitions)) + } } else { - rangeScalar = float64(posHigh) - float64(posLow) // use float64 to avoid integer overflow + // Avoid integer overflow + if posHigh < posLow { + rangeScalar = 0 + } else { + rangeScalar = uint64(posHigh-posLow) + offset = mathutil.Abs(posLow % int64(numPartitions)) + } } // if range is less than the number of partitions, there will be unused partitions we can prune out. - if rangeScalar < float64(numPartitions) && !highIsNull && !lowIsNull { - for i := posLow; i <= posHigh; i++ { - idx := mathutil.Abs(i % int64(pi.Num)) + if rangeScalar < uint64(numPartitions) && !highIsNull && !lowIsNull { + var i int64 + for i = 0; i <= int64(rangeScalar); i++ { + idx := (offset + i) % int64(numPartitions) if len(partitionNames) > 0 && !s.findByName(partitionNames, pi.Definitions[idx].Name.L) { continue } @@ -280,26 +294,47 @@ func (s *partitionProcessor) getUsedKeyPartitions(ctx sessionctx.Context, posHigh-- } - var rangeScalar float64 + var rangeScalar uint64 if mysql.HasUnsignedFlag(col.RetType.GetFlag()) { - rangeScalar = float64(uint64(posHigh)) - float64(uint64(posLow)) // use float64 to avoid integer overflow + // Avoid integer overflow + if uint64(posHigh) < uint64(posLow) { + rangeScalar = 0 + } else { + rangeScalar = uint64(posHigh) - uint64(posLow) + } } else { - rangeScalar = float64(posHigh) - float64(posLow) // use float64 to avoid integer overflow + // Avoid integer overflow + if posHigh < posLow { + rangeScalar = 0 + } else { + rangeScalar = uint64(posHigh-posLow) + } } // if range is less than the number of partitions, there will be unused partitions we can prune out. - if rangeScalar < float64(pi.Num) && !highIsNull && !lowIsNull { - for i := posLow; i <= posHigh; i++ { - d := types.NewIntDatum(i) + if rangeScalar < pi.Num && !highIsNull && !lowIsNull { + m := make(map[int]struct{}) + for i := 0; i <= int(rangeScalar); i++ { + var d types.Datum + if mysql.HasUnsignedFlag(col.RetType.GetFlag()) { + d = types.NewUintDatum(uint64(posLow) + uint64(i)) + } else { + d = types.NewIntDatum(posLow + int64(i)) + } idx, err := pe.LocateKeyPartition(pi.Num, []types.Datum{d}) if err != nil { // If we failed to get the point position, we can just skip and ignore it. continue } + if _, ok := m[idx]; ok { + // Keys maybe in a same partition, we should skip. + continue + } if len(partitionNames) > 0 && !s.findByName(partitionNames, pi.Definitions[idx].Name.L) { continue } used = append(used, idx) + m[idx] = struct{}{} } continue } diff --git a/tests/integrationtest/r/executor/partition/issues.result b/tests/integrationtest/r/executor/partition/issues.result index 36acea78dcc46..cb0f4dee576cb 100644 --- a/tests/integrationtest/r/executor/partition/issues.result +++ b/tests/integrationtest/r/executor/partition/issues.result @@ -459,3 +459,79 @@ IndexJoin_20 0.80 root inner join, inner:TableReader_19, outer key:executor__pa └─TableRangeScan_17 0.80 cop[tikv] table:c range: decided by [eq(executor__partition__issues.c.txt_account_id, executor__partition__issues.t.txn_account_id) eq(executor__partition__issues.c.serial_id, executor__partition__issues.t.serial_id) eq(executor__partition__issues.c.occur_trade_date, 2022-11-17 00:00:00.000000)], keep order:false set @@tidb_opt_advanced_join_hint=default; set tidb_partition_prune_mode=default; +drop table if exists t; +CREATE TABLE `t` ( +`col_51` bigint(20) unsigned NOT NULL, +PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, +UNIQUE KEY `idx_28` (`col_51`), +KEY `idx_29` (`col_51`), +KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY HASH (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (9223372036854775808), (9223372036854775809); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; +id estRows task access object operator info +TableReader_6 2.00 root partition:p2,p3 data:TableRangeScan_5 +└─TableRangeScan_5 2.00 cop[tikv] table:t range:[9223372036854775807,9223372036854775808], keep order:false +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; +col_51 +9223372036854775807 +9223372036854775808 +drop table if exists t; +CREATE TABLE `t` ( +`col_51` bigint(20) NOT NULL, +PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, +UNIQUE KEY `idx_28` (`col_51`), +KEY `idx_29` (`col_51`), +KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY HASH (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (-9223372036854775808); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807; +id estRows task access object operator info +TableReader_6 2.00 root partition:all data:TableFullScan_5 +└─TableFullScan_5 2.00 cop[tikv] table:t keep order:false +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807; +col_51 +-9223372036854775808 +9223372036854775807 +drop table if exists t; +CREATE TABLE `t` ( +`col_51` bigint(20) unsigned NOT NULL, +PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, +UNIQUE KEY `idx_28` (`col_51`), +KEY `idx_29` (`col_51`), +KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY KEY (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (9223372036854775808), (9223372036854775809); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; +id estRows task access object operator info +TableReader_6 2.00 root partition:p2 data:TableRangeScan_5 +└─TableRangeScan_5 2.00 cop[tikv] table:t range:[9223372036854775807,9223372036854775808], keep order:false +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; +col_51 +9223372036854775807 +9223372036854775808 +drop table if exists t; +CREATE TABLE `t` ( +`col_51` bigint(20) NOT NULL, +PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, +UNIQUE KEY `idx_28` (`col_51`), +KEY `idx_29` (`col_51`), +KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY KEY (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (-9223372036854775808); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807; +id estRows task access object operator info +TableReader_6 2.00 root partition:all data:TableFullScan_5 +└─TableFullScan_5 2.00 cop[tikv] table:t keep order:false +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807; +col_51 +-9223372036854775808 +9223372036854775807 diff --git a/tests/integrationtest/t/executor/partition/issues.test b/tests/integrationtest/t/executor/partition/issues.test index 5ffd753115768..64d00c009eb47 100644 --- a/tests/integrationtest/t/executor/partition/issues.test +++ b/tests/integrationtest/t/executor/partition/issues.test @@ -253,3 +253,67 @@ from and c.occur_trade_date = '2022-11-17' and c.serial_id = t.serial_id; set @@tidb_opt_advanced_join_hint=default; set tidb_partition_prune_mode=default; + + +# TestIssue49842 +## For Hash partition +drop table if exists t; +CREATE TABLE `t` ( + `col_51` bigint(20) unsigned NOT NULL, + PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, + UNIQUE KEY `idx_28` (`col_51`), + KEY `idx_29` (`col_51`), + KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY HASH (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (9223372036854775808), (9223372036854775809); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; +--sorted_result +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; + +drop table if exists t; +CREATE TABLE `t` ( + `col_51` bigint(20) NOT NULL, + PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, + UNIQUE KEY `idx_28` (`col_51`), + KEY `idx_29` (`col_51`), + KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY HASH (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (-9223372036854775808); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807; +--sorted_result +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807; + +## For Key partition +drop table if exists t; +CREATE TABLE `t` ( + `col_51` bigint(20) unsigned NOT NULL, + PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, + UNIQUE KEY `idx_28` (`col_51`), + KEY `idx_29` (`col_51`), + KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY KEY (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (9223372036854775808), (9223372036854775809); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; +--sorted_result +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN 9223372036854775807 AND 9223372036854775808; + +drop table if exists t; +CREATE TABLE `t` ( + `col_51` bigint(20) NOT NULL, + PRIMARY KEY (`col_51`) /*T![clustered_index] CLUSTERED */, + UNIQUE KEY `idx_28` (`col_51`), + KEY `idx_29` (`col_51`), + KEY `idx_31` (`col_51`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin +PARTITION BY KEY (`col_51`) PARTITIONS 5; +insert into t values (9223372036854775807), (-9223372036854775808); +analyze table t; +desc SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807; +--sorted_result +SELECT * FROM `t` WHERE `t`.`col_51` BETWEEN -9223372036854775808 AND 9223372036854775807;