From b175576d844e5bca2f1947bb7323eafe8d29e2a1 Mon Sep 17 00:00:00 2001 From: Fariha Shaikh Date: Fri, 16 Jan 2026 18:59:54 +0000 Subject: [PATCH 1/2] Fix partition pruning with non-constant defaults regression Fix regression caused by the original fix of the bug #37397306. The original changes to set_used_partition() only check partition key fields explicitly provided in the INSERT column list. When a partition key field is omitted and uses a non-constant default (e.g. CURRENT_TIMESTAMP), this is not detected, causing incorrect partition selection and error 1748. Fix this by counting partition key fields provided in the INSERT statement. If this count is lower than the total number of partition key fields, skip constant-based partition pruning. Add test in partition_pruning.test in the main suite to test this regression and its fix. This contribution is under the OCA signed by Amazon and covering submissions to the MySQL project. --- mysql-test/r/partition_pruning.result | 57 ++++++++++++++++++++ mysql-test/t/partition_pruning.test | 77 +++++++++++++++++++++++++++ sql/partition_info.cc | 9 ++++ 3 files changed, 143 insertions(+) diff --git a/mysql-test/r/partition_pruning.result b/mysql-test/r/partition_pruning.result index 8f1f2b0d1123..0146b7692c32 100644 --- a/mysql-test/r/partition_pruning.result +++ b/mysql-test/r/partition_pruning.result @@ -6440,3 +6440,60 @@ id select_type table partitions type possible_keys key key_len ref rows filtered Warnings: Note 1003 insert into `test`.`t1` values (20,rand()) DROP TABLE t1; + +# Test for Bug#37397306 - partition pruning regression with CURRENT_TIMESTAMP default +# This test verifies that INSERT with CURRENT_TIMESTAMP default values +# works correctly with partitioned tables using RANGE partitioning on timestamp +DROP DATABASE IF EXISTS test_partition_regression; +CREATE DATABASE test_partition_regression; +USE test_partition_regression; +CREATE PROCEDURE create_partition_table() +BEGIN +DECLARE start_time DATETIME; +DECLARE partition_sql TEXT; +DECLARE i INT DEFAULT 0; +# Start 10 seconds ago, create 41 partitions (covers ~40 seconds ahead) +SET start_time = DATE_FORMAT(NOW() - INTERVAL 10 SECOND, '%Y-%m-%d %H:%i:%s'); +SET partition_sql = CONCAT( +'CREATE TABLE `dp_tb_partition_issue_test` (\n', +' `id` bigint NOT NULL,\n', +' `col1` bigint NOT NULL,\n', +' `pt_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n', +' PRIMARY KEY (`id`,`pt_timestamp`)\n', +') ENGINE=InnoDB DEFAULT CHARSET=utf8mb3\n', +'PARTITION BY RANGE (UNIX_TIMESTAMP(`pt_timestamp`))\n(\n' ); +WHILE i < 41 DO +SET partition_sql = CONCAT( +partition_sql, +' PARTITION p', DATE_FORMAT(start_time + INTERVAL i SECOND, '%Y%m%d%H%i%s'), +' VALUES LESS THAN (UNIX_TIMESTAMP(''', +DATE_FORMAT(start_time + INTERVAL (i+1) SECOND, '%Y-%m-%d %H:%i:%s'), +''')) ENGINE = InnoDB,\n' + ); +SET i = i + 1; +END WHILE; +SET partition_sql = CONCAT(partition_sql, ' PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = InnoDB\n);'); +DROP TABLE IF EXISTS dp_tb_partition_issue_test; +# Create table +SET @sql = partition_sql; +PREPARE stmt FROM @sql; +EXECUTE stmt; +DEALLOCATE PREPARE stmt; +END| +CREATE PROCEDURE `dp_insert_row`(IN i BIGINT) +BEGIN +INSERT INTO `dp_tb_partition_issue_test` (`id`, `col1`) VALUES (i, 999999); +END| +CALL create_partition_table(); +CALL dp_insert_row(1); +SELECT SLEEP(2); +SLEEP(2) +0 +CALL dp_insert_row(1); +SELECT COUNT(*) FROM dp_tb_partition_issue_test WHERE id = 1; +COUNT(*) +2 +DROP PROCEDURE create_partition_table; +DROP PROCEDURE dp_insert_row; +DROP TABLE dp_tb_partition_issue_test; +DROP DATABASE test_partition_regression; diff --git a/mysql-test/t/partition_pruning.test b/mysql-test/t/partition_pruning.test index fa4a51b4ebc4..494fc1af9ce1 100644 --- a/mysql-test/t/partition_pruning.test +++ b/mysql-test/t/partition_pruning.test @@ -2586,3 +2586,80 @@ EXPLAIN INSERT INTO t1 (id, f1) VALUES (1,RAND()); EXPLAIN INSERT INTO t1 VALUES (20,RAND()); DROP TABLE t1; + +--echo # Test for Bug#37397306 - partition pruning regression with CURRENT_TIMESTAMP default +--echo # This test verifies that INSERT with CURRENT_TIMESTAMP default values +--echo # works correctly with partitioned tables using RANGE partitioning on timestamp + +--disable_warnings +DROP DATABASE IF EXISTS test_partition_regression; +--enable_warnings +CREATE DATABASE test_partition_regression; +USE test_partition_regression; + +delimiter |; +CREATE PROCEDURE create_partition_table() +BEGIN + DECLARE start_time DATETIME; + DECLARE partition_sql TEXT; + DECLARE i INT DEFAULT 0; + + # Start 10 seconds ago, create 41 partitions (covers ~40 seconds ahead) + SET start_time = DATE_FORMAT(NOW() - INTERVAL 10 SECOND, '%Y-%m-%d %H:%i:%s'); + SET partition_sql = CONCAT( + 'CREATE TABLE `dp_tb_partition_issue_test` (\n', + ' `id` bigint NOT NULL,\n', + ' `col1` bigint NOT NULL,\n', + ' `pt_timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,\n', + ' PRIMARY KEY (`id`,`pt_timestamp`)\n', + ') ENGINE=InnoDB DEFAULT CHARSET=utf8mb3\n', + 'PARTITION BY RANGE (UNIX_TIMESTAMP(`pt_timestamp`))\n(\n' ); + WHILE i < 41 DO + SET partition_sql = CONCAT( + partition_sql, + ' PARTITION p', DATE_FORMAT(start_time + INTERVAL i SECOND, '%Y%m%d%H%i%s'), + ' VALUES LESS THAN (UNIX_TIMESTAMP(''', + DATE_FORMAT(start_time + INTERVAL (i+1) SECOND, '%Y-%m-%d %H:%i:%s'), + ''')) ENGINE = InnoDB,\n' + ); + SET i = i + 1; + END WHILE; + + SET partition_sql = CONCAT(partition_sql, ' PARTITION pmax VALUES LESS THAN MAXVALUE ENGINE = InnoDB\n);'); + + DROP TABLE IF EXISTS dp_tb_partition_issue_test; + + # Create table + SET @sql = partition_sql; + PREPARE stmt FROM @sql; + EXECUTE stmt; + DEALLOCATE PREPARE stmt; +END| + +CREATE PROCEDURE `dp_insert_row`(IN i BIGINT) +BEGIN + INSERT INTO `dp_tb_partition_issue_test` (`id`, `col1`) VALUES (i, 999999); +END| +delimiter ;| + +# Test the partition pruning regression +CALL create_partition_table(); + +# First insert should succeed +CALL dp_insert_row(1); + +# Wait 2 seconds to ensure timestamp changes +SELECT SLEEP(2); + +# Second insert with same id should succeed (different timestamp due to CURRENT_TIMESTAMP) +# This would fail with ERROR 1748 before the fix +CALL dp_insert_row(1); + +# Verify both rows were inserted +SELECT COUNT(*) FROM dp_tb_partition_issue_test WHERE id = 1; + +# Cleanup +DROP PROCEDURE create_partition_table; +DROP PROCEDURE dp_insert_row; +DROP TABLE dp_tb_partition_issue_test; +DROP DATABASE test_partition_regression; diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 8fc560ef1958..407d3f0b169d 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -483,16 +483,25 @@ bool partition_info::set_used_partition( const-for-execution. */ if (!fields.empty()) { + uint part_fields_provided = 0; auto value_it = values.begin(); for (Item *fld : fields) { Item *value = *value_it++; Item_field *field = fld->field_for_view_update(); if (bitmap_is_set(&full_part_field_set, field->field->field_index())) { + part_fields_provided++; if (!(value->const_item() || (tables_locked && value->const_for_execution()))) return true; } } + /* + If any partition key field is not explicitly provided, it will + use its default value. Defaults like CURRENT_TIMESTAMP are + non-constant, so we cannot do constant-based partition pruning. + */ + if (part_fields_provided < bitmap_bits_set(&full_part_field_set)) + return true; } else { Field *field = nullptr; for (Item *value : values) { From fafeee6da1510b9504afd8362277ac3bd10cf67e Mon Sep 17 00:00:00 2001 From: Fariha Shaikh Date: Fri, 16 Jan 2026 19:07:53 +0000 Subject: [PATCH 2/2] Fix table->field pointer modification in set_used_partition() The else branch in the set_used_partition() directly increments the table->field pointer instead of using a local copy. This could cause issues if the pointer is used elsewhere after this function returns. Fix this by using a local pointer variable for iteration. This contribution is under the OCA signed by Amazon and covering submissions to the MySQL project. --- sql/partition_info.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/partition_info.cc b/sql/partition_info.cc index 407d3f0b169d..4efbda47a5b3 100644 --- a/sql/partition_info.cc +++ b/sql/partition_info.cc @@ -503,9 +503,9 @@ bool partition_info::set_used_partition( if (part_fields_provided < bitmap_bits_set(&full_part_field_set)) return true; } else { - Field *field = nullptr; + Field **field_ptr = table->field; for (Item *value : values) { - field = *table->field++; + Field *field = *field_ptr++; if (bitmap_is_set(&full_part_field_set, field->field_index())) { if (!(value->const_item() || (tables_locked && value->const_for_execution())))