summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksey Midenkov <midenok@gmail.com>2018-10-09 03:38:58 +1000
committerNikita Malyavin <nikitamalyavin@gmail.com>2019-10-08 13:16:15 +1000
commit999a1c21c3181c791c47ad17afe6c42249acb275 (patch)
tree968e19a1a8113cf8720718079bf28f7066181c16
parent04b7c37f68a84c39e55701f3e394ffac2e14b00d (diff)
downloadmariadb-git-999a1c21c3181c791c47ad17afe6c42249acb275.tar.gz
MDEV-17333 Assertion in update_auto_increment() upon exotic LOAD
While `handler::next_insert_id` is restored on duplicate key errors `part_share->next_auto_inc_val` is not restored which causes discrepancy. [Fixes tempesta-tech/mariadb#545]
-rw-r--r--mysql-test/main/auto_increment_ranges.inc20
-rw-r--r--mysql-test/main/auto_increment_ranges_innodb.result11
-rw-r--r--mysql-test/main/auto_increment_ranges_myisam.result11
-rw-r--r--sql/ha_partition.h15
-rw-r--r--sql/handler.h16
-rw-r--r--sql/sql_insert.cc10
6 files changed, 77 insertions, 6 deletions
diff --git a/mysql-test/main/auto_increment_ranges.inc b/mysql-test/main/auto_increment_ranges.inc
index 526900ea86e..9aae0b21a22 100644
--- a/mysql-test/main/auto_increment_ranges.inc
+++ b/mysql-test/main/auto_increment_ranges.inc
@@ -254,3 +254,23 @@ let $mysqld_datadir= `select @@datadir`;
--remove_file $mysqld_datadir/test/load.data
drop table t1;
drop table t2;
+
+--echo #
+--echo # MDEV-17333 Assertion in update_auto_increment() upon exotic LOAD
+--echo #
+--source include/have_partition.inc
+let $mysqld_datadir= `select @@datadir`;
+--write_file $mysqld_datadir/test/load.data
+1 1
+0 2
+3 3
+4 1
+0 1
+6 6
+EOF
+create or replace table t1 (pk int auto_increment, x int, primary key(pk), unique key(x))
+with system versioning partition by system_time interval 2 day
+(partition p1 history, partition pn current);
+load data infile 'load.data' ignore into table t1;
+--remove_file $mysqld_datadir/test/load.data
+drop table t1;
diff --git a/mysql-test/main/auto_increment_ranges_innodb.result b/mysql-test/main/auto_increment_ranges_innodb.result
index d99d12ea970..34d62fdbb2d 100644
--- a/mysql-test/main/auto_increment_ranges_innodb.result
+++ b/mysql-test/main/auto_increment_ranges_innodb.result
@@ -298,3 +298,14 @@ pk f
6 <===
drop table t1;
drop table t2;
+#
+# MDEV-17333 Assertion in update_auto_increment() upon exotic LOAD
+#
+create or replace table t1 (pk int auto_increment, x int, primary key(pk), unique key(x))
+with system versioning partition by system_time interval 2 day
+(partition p1 history, partition pn current);
+load data infile 'load.data' ignore into table t1;
+Warnings:
+Warning 1062 Duplicate entry '1' for key 'x'
+Warning 1062 Duplicate entry '1' for key 'x'
+drop table t1;
diff --git a/mysql-test/main/auto_increment_ranges_myisam.result b/mysql-test/main/auto_increment_ranges_myisam.result
index 9388a062d5e..2e81c0ac4d1 100644
--- a/mysql-test/main/auto_increment_ranges_myisam.result
+++ b/mysql-test/main/auto_increment_ranges_myisam.result
@@ -290,3 +290,14 @@ pk f
6 <===
drop table t1;
drop table t2;
+#
+# MDEV-17333 Assertion in update_auto_increment() upon exotic LOAD
+#
+create or replace table t1 (pk int auto_increment, x int, primary key(pk), unique key(x))
+with system versioning partition by system_time interval 2 day
+(partition p1 history, partition pn current);
+load data infile 'load.data' ignore into table t1;
+Warnings:
+Warning 1062 Duplicate entry '1' for key 'x'
+Warning 1062 Duplicate entry '1' for key 'x'
+drop table t1;
diff --git a/sql/ha_partition.h b/sql/ha_partition.h
index 2148926c1ed..4bec0855d74 100644
--- a/sql/ha_partition.h
+++ b/sql/ha_partition.h
@@ -92,6 +92,7 @@ public:
bool auto_inc_initialized;
mysql_mutex_t auto_inc_mutex; /**< protecting auto_inc val */
ulonglong next_auto_inc_val; /**< first non reserved value */
+ ulonglong prev_auto_inc_val; /**< stored next_auto_inc_val */
/**
Hash of partition names. Initialized in the first ha_partition::open()
for the table_share. After that it is read-only, i.e. no locking required.
@@ -103,6 +104,7 @@ public:
Partition_share()
: auto_inc_initialized(false),
next_auto_inc_val(0),
+ prev_auto_inc_val(0),
partition_name_hash_initialized(false),
partition_names(NULL)
{
@@ -371,6 +373,19 @@ private:
MY_BITMAP m_locked_partitions;
/** Stores shared auto_increment etc. */
Partition_share *part_share;
+ /** Store and restore next_auto_inc_val over duplicate key errors. */
+ virtual void store_auto_increment()
+ {
+ DBUG_ASSERT(part_share);
+ part_share->prev_auto_inc_val= part_share->next_auto_inc_val;
+ handler::store_auto_increment();
+ }
+ virtual void restore_auto_increment()
+ {
+ DBUG_ASSERT(part_share);
+ part_share->next_auto_inc_val= part_share->prev_auto_inc_val;
+ handler::restore_auto_increment();
+ }
/** Temporary storage for new partitions Handler_shares during ALTER */
List<Parts_share_refs> m_new_partitions_share_refs;
/** Sorted array of partition ids in descending order of number of rows. */
diff --git a/sql/handler.h b/sql/handler.h
index 63d0bf2215c..32e012c2bc0 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -3123,6 +3123,10 @@ private:
*/
Handler_share **ha_share;
+ /** Stores next_insert_id for handling duplicate key errors. */
+ ulonglong m_prev_insert_id;
+
+
public:
handler(handlerton *ht_arg, TABLE_SHARE *share_arg)
:table_share(share_arg), table(0),
@@ -3147,7 +3151,7 @@ public:
auto_inc_intervals_count(0),
m_psi(NULL), set_top_table_fields(FALSE), top_table(0),
top_table_field(0), top_table_fields(0),
- m_lock_type(F_UNLCK), ha_share(NULL)
+ m_lock_type(F_UNLCK), ha_share(NULL), m_prev_insert_id(0)
{
DBUG_PRINT("info",
("handler created F_UNLCK %d F_RDLCK %d F_WRLCK %d",
@@ -3826,6 +3830,16 @@ public:
insert_id_for_cur_row;
}
+ /** Store and restore next_insert_id over duplicate key errors. */
+ virtual void store_auto_increment()
+ {
+ m_prev_insert_id= next_insert_id;
+ }
+ virtual void restore_auto_increment()
+ {
+ restore_auto_increment(m_prev_insert_id);
+ }
+
virtual void update_create_info(HA_CREATE_INFO *create_info) {}
int check_old_types();
virtual int assign_to_keycache(THD* thd, HA_CHECK_OPT* check_opt)
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index e8e320e8439..15f1b017fd3 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -1697,7 +1697,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
int error, trg_error= 0;
char *key=0;
MY_BITMAP *save_read_set, *save_write_set;
- ulonglong prev_insert_id= table->file->next_insert_id;
+ table->file->store_auto_increment();
ulonglong insert_id_for_cur_row= 0;
ulonglong prev_insert_id_for_cur_row= 0;
DBUG_ENTER("write_record");
@@ -1851,7 +1851,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (res == VIEW_CHECK_ERROR)
goto before_trg_err;
- table->file->restore_auto_increment(prev_insert_id);
+ table->file->restore_auto_increment();
info->touched++;
if (different_records)
{
@@ -2026,7 +2026,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
*/
if (table->file->insert_id_for_cur_row == 0)
table->file->insert_id_for_cur_row= insert_id_for_cur_row;
-
+
/*
Restore column maps if they where replaced during an duplicate key
problem.
@@ -2044,7 +2044,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
if (!(thd->variables.old_behavior &
OLD_MODE_NO_DUP_KEY_WARNINGS_WITH_IGNORE))
table->file->print_error(error, MYF(ME_WARNING));
- table->file->restore_auto_increment(prev_insert_id);
+ table->file->restore_auto_increment();
goto ok_or_after_trg_err;
}
@@ -2067,7 +2067,7 @@ err:
table->file->print_error(error,MYF(0));
before_trg_err:
- table->file->restore_auto_increment(prev_insert_id);
+ table->file->restore_auto_increment();
if (key)
my_safe_afree(key, table->s->max_unique_length);
table->column_bitmaps_set(save_read_set, save_write_set);