From 18a0f0c17839e3662ac86a22975ae45886ae4cf6 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Wed, 19 Oct 2022 16:41:24 +1100 Subject: [PATCH 01/38] Fix AIX compulation (break addr resolution) Revert c92c1615852ecd4be2d04203600efd3eba578a02, casting to void* cannot fool gcc. The AIX address resolution was broken anyway, so just avoid the problem and make it compile well. --- mysys/my_addr_resolve.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c index 444a47bb7c5..4948ad3e698 100644 --- a/mysys/my_addr_resolve.c +++ b/mysys/my_addr_resolve.c @@ -319,12 +319,20 @@ int my_addr_resolve(void *ptr, my_addr_loc *loc) /* Save result for future comparisons. */ strnmov(addr2line_binary, info.dli_fname, sizeof(addr2line_binary)); +#ifdef _AIX + /* + info.dli_fbase is a char on AIX and casting it doesn't fool gcc. + leave backtracing broken on AIX until a real solution can be found. + */ + addr_offset= NULL; +#else /* Check if we should use info.dli_fbase as an offset or not for the base program. This is depending on if the compilation is done with PIE or not. */ - addr_offset= (void*) info.dli_fbase; + addr_offset= info.dli_fbase; +#endif #ifndef __PIE__ if (strcmp(info.dli_fname, my_progname) == 0 && addr_resolve((void*) my_addr_resolve, loc) == 0 && From 899cedb33c8e92a0067f2d74015300454c6235ae Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Wed, 26 Oct 2022 19:52:17 -0400 Subject: [PATCH 02/38] Fix building my_gethwaddr() on OpenBSD --- mysys/my_gethwaddr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index 70e1d549e15..5bb0ed75fb3 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -33,8 +33,14 @@ static my_bool memcpy_and_test(uchar *to, uchar *from, uint len) return res; } -#if defined(__APPLE__) || defined(__FreeBSD__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) +#ifdef __OpenBSD__ +#include +#include +#include +#else #include +#endif #include #include #include From ab81aefef6e54ec872622f996ed66626700e4d8e Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Wed, 26 Oct 2022 20:30:47 -0400 Subject: [PATCH 03/38] Fix building my_gethwaddr() on OpenBSD - part for 10.5 and newer --- mysys/my_gethwaddr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_gethwaddr.c b/mysys/my_gethwaddr.c index 6bba553a549..a2b159cf3b0 100644 --- a/mysys/my_gethwaddr.c +++ b/mysys/my_gethwaddr.c @@ -23,7 +23,7 @@ #ifndef MAIN -#if defined(_AIX) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__) || defined(__sun) || defined(_WIN32) +#if defined(_AIX) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__) || defined(__sun) || defined(_WIN32) static my_bool memcpy_and_test(uchar *to, uchar *from, uint len) { uint i, res= 1; From ce443c855478e931b77058f3a7108c07500220d7 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 26 Oct 2022 14:48:03 +0400 Subject: [PATCH 04/38] MDEV-29495 Generalize can_convert_xxx() hook engine API to cover any arbitrary data type --- sql/field.h | 22 ------------------- sql/ha_partition.cc | 31 ++++----------------------- sql/ha_partition.h | 12 ++--------- sql/handler.h | 19 ++-------------- sql/sql_table.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 22 ++++++++++++++++++- storage/innobase/handler/ha_innodb.h | 22 +++++++++++-------- 7 files changed, 43 insertions(+), 87 deletions(-) diff --git a/sql/field.h b/sql/field.h index 9d40caf0932..40ff99a5b2e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -1552,12 +1552,6 @@ public: Used by the ALTER TABLE */ virtual bool is_equal(const Column_definition &new_field) const= 0; - // Used as double dispatch pattern: calls virtual method of handler - virtual bool - can_be_converted_by_engine(const Column_definition &new_type) const - { - return false; - } /* convert decimal to longlong with overflow check */ longlong convert_decimal2longlong(const my_decimal *val, bool unsigned_flag, int *err); @@ -3621,10 +3615,6 @@ public: void sql_type(String &str) const; void sql_rpl_type(String*) const; bool is_equal(const Column_definition &new_field) const; - bool can_be_converted_by_engine(const Column_definition &new_type) const - { - return table->file->can_convert_string(this, new_type); - } virtual uchar *pack(uchar *to, const uchar *from, uint max_length); virtual const uchar *unpack(uchar* to, const uchar *from, @@ -3751,10 +3741,6 @@ public: uchar *new_ptr, uint32 length, uchar *new_null_ptr, uint new_null_bit); bool is_equal(const Column_definition &new_field) const; - bool can_be_converted_by_engine(const Column_definition &new_type) const - { - return table->file->can_convert_varstring(this, new_type); - } void hash(ulong *nr, ulong *nr2); uint length_size() const { return length_bytes; } void print_key_value(String *out, uint32 length); @@ -4128,10 +4114,6 @@ public: uint32 char_length() const; uint32 character_octet_length() const; bool is_equal(const Column_definition &new_field) const; - bool can_be_converted_by_engine(const Column_definition &new_type) const - { - return table->file->can_convert_blob(this, new_type); - } void print_key_value(String *out, uint32 length); friend void TABLE::remember_blob_values(String *blob_storage); @@ -4247,10 +4229,6 @@ public: !table->copy_blobs; } bool is_equal(const Column_definition &new_field) const; - bool can_be_converted_by_engine(const Column_definition &new_type) const - { - return table->file->can_convert_geom(this, new_type); - } int store(const char *to, size_t length, CHARSET_INFO *charset); int store(double nr); diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index 18a8cd5e027..06ae329ee3a 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2019, Oracle and/or its affiliates. - Copyright (c) 2009, 2021, MariaDB + Copyright (c) 2009, 2022, MariaDB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -12021,35 +12021,12 @@ void ha_partition::clear_top_table_fields() } bool -ha_partition::can_convert_string(const Field_string* field, - const Column_definition& new_type) const +ha_partition::can_convert_nocopy(const Field &field, + const Column_definition &new_type) const { for (uint index= 0; index < m_tot_parts; index++) { - if (!m_file[index]->can_convert_string(field, new_type)) - return false; - } - return true; -} - -bool -ha_partition::can_convert_varstring(const Field_varstring* field, - const Column_definition& new_type) const{ - for (uint index= 0; index < m_tot_parts; index++) - { - if (!m_file[index]->can_convert_varstring(field, new_type)) - return false; - } - return true; -} - -bool -ha_partition::can_convert_blob(const Field_blob* field, - const Column_definition& new_type) const -{ - for (uint index= 0; index < m_tot_parts; index++) - { - if (!m_file[index]->can_convert_blob(field, new_type)) + if (!m_file[index]->can_convert_nocopy(field, new_type)) return false; } return true; diff --git a/sql/ha_partition.h b/sql/ha_partition.h index 507db9efddf..2670784c759 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1624,16 +1624,8 @@ public: friend int cmp_key_rowid_part_id(void *ptr, uchar *ref1, uchar *ref2); friend int cmp_key_part_id(void *key_p, uchar *ref1, uchar *ref2); - bool can_convert_string( - const Field_string* field, - const Column_definition& new_field) const override; - bool can_convert_varstring( - const Field_varstring* field, - const Column_definition& new_field) const override; - - bool can_convert_blob( - const Field_blob* field, - const Column_definition& new_field) const override; + bool can_convert_nocopy(const Field &field, + const Column_definition &new_field) const override; }; #endif /* HA_PARTITION_INCLUDED */ diff --git a/sql/handler.h b/sql/handler.h index aa68c30480e..541c408178b 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -4851,23 +4851,8 @@ public: These functions check for such possibility. Implementation could be based on Field_xxx::is_equal() */ - virtual bool can_convert_string(const Field_string *field, - const Column_definition &new_type) const - { - return false; - } - virtual bool can_convert_varstring(const Field_varstring *field, - const Column_definition &new_type) const - { - return false; - } - virtual bool can_convert_blob(const Field_blob *field, - const Column_definition &new_type) const - { - return false; - } - virtual bool can_convert_geom(const Field_geom *field, - const Column_definition &new_type) const + virtual bool can_convert_nocopy(const Field &, + const Column_definition &) const { return false; } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index efa5c06dd2a..63289e3ba59 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -6948,7 +6948,7 @@ static bool fill_alter_inplace_info(THD *thd, TABLE *table, bool varchar, bool is_equal= field->is_equal(*new_field); if (!is_equal) { - if (field->can_be_converted_by_engine(*new_field)) + if (field->table->file->can_convert_nocopy(*field, *new_field)) { /* New column type differs from the old one, but storage engine can diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3fa2a0c4d30..7acbe79d732 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -21159,6 +21159,26 @@ bool ha_innobase::can_convert_blob(const Field_blob *field, return true; } + +bool ha_innobase::can_convert_nocopy(const Field &field, + const Column_definition &new_type) const +{ + if (const Field_string *tf= dynamic_cast(&field)) + return can_convert_string(tf, new_type); + + if (const Field_varstring *tf= dynamic_cast(&field)) + return can_convert_varstring(tf, new_type); + + if (dynamic_cast(&field)) + return false; + + if (const Field_blob *tf= dynamic_cast(&field)) + return can_convert_blob(tf, new_type); + + return false; +} + + Compare_keys ha_innobase::compare_key_parts( const Field &old_field, const Column_definition &new_field, const KEY_PART_INFO &old_part, const KEY_PART_INFO &new_part) const @@ -21169,7 +21189,7 @@ Compare_keys ha_innobase::compare_key_parts( if (!is_equal) { - if (!old_field.can_be_converted_by_engine(new_field)) + if (!old_field.table->file->can_convert_nocopy(old_field, new_field)) return Compare_keys::NotEqual; if (!Charset(old_cs).eq_collation_specific_names(new_cs)) diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 97f62f4b398..b5f9438921c 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -419,15 +419,9 @@ public: @retval false if pushed (always) */ bool rowid_filter_push(Rowid_filter *rowid_filter) override; - bool - can_convert_string(const Field_string* field, - const Column_definition& new_field) const override; - bool can_convert_varstring( - const Field_varstring* field, - const Column_definition& new_field) const override; - bool - can_convert_blob(const Field_blob* field, - const Column_definition& new_field) const override; + bool can_convert_nocopy(const Field &field, + const Column_definition& new_field) const + override; /** @return whether innodb_strict_mode is active */ static bool is_innodb_strict_mode(THD* thd); @@ -442,6 +436,16 @@ public: const KEY_PART_INFO& new_part) const override; protected: + bool + can_convert_string(const Field_string* field, + const Column_definition& new_field) const; + bool can_convert_varstring( + const Field_varstring* field, + const Column_definition& new_field) const; + bool + can_convert_blob(const Field_blob* field, + const Column_definition& new_field) const; + dberr_t innobase_get_autoinc(ulonglong* value); dberr_t innobase_lock_autoinc(); ulonglong innobase_peek_autoinc(); From 4ebc8d8c27446f884feb3d4771b0685e333f2892 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Fri, 28 Oct 2022 19:59:35 +1100 Subject: [PATCH 05/38] MDEV-29847: Wrong warning on rlimit capping of max_open_files (#2315) Per the code my_set_max_open_files 3 lines earlier, we attempt to set the nofile (number of open files), rlimit to max_open_files. We should use this in the warning because wanted_files may not be the number. --- sql/mysqld.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 5d58d42faf9..84c3b9fb0a6 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4580,8 +4580,8 @@ static int init_common_variables() files= my_set_max_open_files(max_open_files); SYSVAR_AUTOSIZE_IF_CHANGED(open_files_limit, files, ulong); - if (files < wanted_files && global_system_variables.log_warnings) - sql_print_warning("Could not increase number of max_open_files to more than %u (request: %u)", files, wanted_files); + if (files < max_open_files && global_system_variables.log_warnings) + sql_print_warning("Could not increase number of max_open_files to more than %u (request: %u)", files, max_open_files); /* If we required too much tc_instances than we reduce */ SYSVAR_AUTOSIZE_IF_CHANGED(tc_instances, From 7d96cb4703693cbf7a23308cfffee955022c86a9 Mon Sep 17 00:00:00 2001 From: Brad Smith Date: Sun, 30 Oct 2022 17:25:32 -0400 Subject: [PATCH 06/38] Fix warning with signal typedef for *BSD /usr/ports/pobj/mariadb-10.9.3/mariadb-10.9.3/mysys/my_lock.c:183:7: warning: incompatible function pointer types assigning to 'sig_return' (aka 'void (*)(void)') from 'void (*)(int)' [-Wincompatible-function-pointer-types] ALARM_INIT; ^~~~~~~~~~ /usr/ports/pobj/mariadb-10.9.3/mariadb-10.9.3/include/my_alarm.h:43:16: note: expanded from macro 'ALARM_INIT' alarm_signal=signal(SIGALRM,my_set_alarm_variable); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /usr/ports/pobj/mariadb-10.9.3/mariadb-10.9.3/mysys/my_lock.c:189:7: warning: incompatible function pointer types passing 'sig_return' (aka 'void (*)(void)') to parameter of type 'void (*)(int)' [-Wincompatible-function-pointer-types] ALARM_END; ^~~~~~~~~ /usr/ports/pobj/mariadb-10.9.3/mariadb-10.9.3/include/my_alarm.h:44:41: note: expanded from macro 'ALARM_END' ^~~~~~~~~~~~ /usr/include/sys/signal.h:199:27: note: passing argument to parameter here void (*signal(int, void (*)(int)))(int); ^ 2 warnings generated. The prototype is the same for all of the *BSD's. void (*signal(int sigcatch, void (*func)(int sigraised)))(int); --- include/my_alarm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/my_alarm.h b/include/my_alarm.h index bc0004476ca..287d226fbac 100644 --- a/include/my_alarm.h +++ b/include/my_alarm.h @@ -31,7 +31,9 @@ extern ulong my_time_to_wait_for_lock; #include #ifdef HAVE_SIGHANDLER_T #define sig_return sighandler_t -#elif defined(SOLARIS) || defined(__sun) || defined(__APPLE__) +#elif defined(SOLARIS) || defined(__sun) || defined(__APPLE__) || \ + defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || \ + defined(__DragonFly__) typedef void (*sig_return)(int); /* Returns type from signal */ #else typedef void (*sig_return)(void); /* Returns type from signal */ From 6f8fb41f213dd34b43ef6f3819b4be12f6b26c01 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 31 Oct 2022 16:17:17 +0300 Subject: [PATCH 07/38] MDEV-29841 More descriptive text for ER_PARTITION_WRONG_TYPE For commands (1) alter table t1 add partition (partition p2); (2) alter table t1 add partition (partition px history); It printed the same error message: Wrong partitioning type, expected type: `SYSTEM_TIME` For (1) it is not clear from the syntax that we are trying to add HASH partition. For (2) it is not clear that the table partitioning is different than SYSTEM_TIME. Now it prints what type we are trying to add to what type of partitioning. --- .../suite/versioning/r/partition.result | 4 +- sql/partition_info.h | 5 + sql/share/errmsg-utf8.txt | 6 +- sql/sql_lex.cc | 4 +- sql/sql_partition.cc | 108 +++++++++++++----- 5 files changed, 90 insertions(+), 37 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 3c20aff4f7f..031ad9b3f3b 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -150,7 +150,7 @@ partition by system_time limit 1; alter table t1 change x big int; create or replace table t1 (i int) engine myisam partition by hash(i) partitions 2; alter table t1 add partition (partition px history); -ERROR HY000: Wrong partitioning type, expected type: `SYSTEM_TIME` +ERROR HY000: Wrong partition type `SYSTEM_TIME` for partitioning by `HASH` ## INSERT, UPDATE, DELETE create or replace table t1 (x int) with system versioning @@ -1105,7 +1105,7 @@ drop table t1; create table t1 (a int) with system versioning partition by system_time (partition p1 history, partition pn current); alter table t1 add partition (partition p2); -ERROR HY000: Wrong partitioning type, expected type: `SYSTEM_TIME` +ERROR HY000: Wrong partition type `HASH` for partitioning by `SYSTEM_TIME` # MDEV-17891 Assertion failures in select_insert::abort_result_set and # mysql_load upon attempt to replace into a full table set @@max_heap_table_size= 1024*1024; diff --git a/sql/partition_info.h b/sql/partition_info.h index e95daec7d31..287aa6d2200 100644 --- a/sql/partition_info.h +++ b/sql/partition_info.h @@ -429,8 +429,13 @@ public: return NULL; } uint next_part_no(uint new_parts) const; + + int gen_part_type(THD *thd, String *str) const; }; +void part_type_error(THD *thd, partition_info *work_part_info, + const char *part_type, partition_info *tab_part_info); + uint32 get_next_partition_id_range(struct st_partition_iter* part_iter); bool check_partition_dirs(partition_info *part_info); diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 76da0b8f598..b61bfbfc199 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -9773,9 +9773,9 @@ ER_UNUSED_23 spa "Nunca debería vd de ver esto" ER_PARTITION_WRONG_TYPE - chi "错误的分区类型,预期类型:%`s" - eng "Wrong partitioning type, expected type: %`s" - spa "Tipo de partición equivocada, tipo esperado: %`s" + chi "错误的分区类型,预期类型:%`s for partitioning by %`s" + eng "Wrong partition type %`s for partitioning by %`s" + spa "Tipo de partición equivocada, tipo esperado: %`s for partitioning by %`s" WARN_VERS_PART_FULL chi "版本化表%`s.%`s:partition%`s已满,添加更多历史分区(out of %s)" diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 5a9e9ee1a62..0ba5baea1c9 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -9739,7 +9739,7 @@ bool LEX::part_values_current(THD *thd) { if (unlikely(part_info->part_type != VERSIONING_PARTITION)) { - my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME"); + part_type_error(thd, NULL, "CURRENT", part_info); return true; } } @@ -9766,7 +9766,7 @@ bool LEX::part_values_history(THD *thd) { if (unlikely(part_info->part_type != VERSIONING_PARTITION)) { - my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME"); + part_type_error(thd, NULL, "HISTORY", part_info); return true; } } diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 70de87afc1a..130484e4a0b 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -2455,7 +2455,7 @@ end: @retval != 0 Failure */ -static int add_key_with_algorithm(String *str, partition_info *part_info) +static int add_key_with_algorithm(String *str, const partition_info *part_info) { int err= 0; err+= str->append(STRING_WITH_LEN("KEY ")); @@ -2484,6 +2484,78 @@ char *generate_partition_syntax_for_frm(THD *thd, partition_info *part_info, return res; } + +/* + Generate the partition type syntax from the partition data structure. + + @return Operation status. + @retval 0 Success + @retval > 0 Failure + @retval -1 Fatal error +*/ + +int partition_info::gen_part_type(THD *thd, String *str) const +{ + int err= 0; + switch (part_type) + { + case RANGE_PARTITION: + err+= str->append(STRING_WITH_LEN("RANGE ")); + break; + case LIST_PARTITION: + err+= str->append(STRING_WITH_LEN("LIST ")); + break; + case HASH_PARTITION: + if (linear_hash_ind) + err+= str->append(STRING_WITH_LEN("LINEAR ")); + if (list_of_part_fields) + { + err+= add_key_with_algorithm(str, this); + err+= add_part_field_list(thd, str, part_field_list); + } + else + err+= str->append(STRING_WITH_LEN("HASH ")); + break; + case VERSIONING_PARTITION: + err+= str->append(STRING_WITH_LEN("SYSTEM_TIME ")); + break; + default: + DBUG_ASSERT(0); + /* We really shouldn't get here, no use in continuing from here */ + my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); + return -1; + } + return err; +} + + +void part_type_error(THD *thd, partition_info *work_part_info, + const char *part_type, + partition_info *tab_part_info) +{ + StringBuffer<256> tab_part_type; + if (tab_part_info->gen_part_type(thd, &tab_part_type) < 0) + return; + tab_part_type.length(tab_part_type.length() - 1); + if (work_part_info) + { + DBUG_ASSERT(!part_type); + StringBuffer<256> work_part_type; + if (work_part_info->gen_part_type(thd, &work_part_type) < 0) + return; + work_part_type.length(work_part_type.length() - 1); + my_error(ER_PARTITION_WRONG_TYPE, MYF(0), work_part_type.c_ptr(), + tab_part_type.c_ptr()); + } + else + { + DBUG_ASSERT(part_type); + my_error(ER_PARTITION_WRONG_TYPE, MYF(0), part_type, + tab_part_type.c_ptr()); + } +} + + /* Generate the partition syntax from the partition data structure. Useful for support of generating defaults, SHOW CREATE TABLES @@ -2527,34 +2599,10 @@ char *generate_partition_syntax(THD *thd, partition_info *part_info, DBUG_ENTER("generate_partition_syntax"); err+= str.append(STRING_WITH_LEN(" PARTITION BY ")); - switch (part_info->part_type) - { - case RANGE_PARTITION: - err+= str.append(STRING_WITH_LEN("RANGE ")); - break; - case LIST_PARTITION: - err+= str.append(STRING_WITH_LEN("LIST ")); - break; - case HASH_PARTITION: - if (part_info->linear_hash_ind) - err+= str.append(STRING_WITH_LEN("LINEAR ")); - if (part_info->list_of_part_fields) - { - err+= add_key_with_algorithm(&str, part_info); - err+= add_part_field_list(thd, &str, part_info->part_field_list); - } - else - err+= str.append(STRING_WITH_LEN("HASH ")); - break; - case VERSIONING_PARTITION: - err+= str.append(STRING_WITH_LEN("SYSTEM_TIME ")); - break; - default: - DBUG_ASSERT(0); - /* We really shouldn't get here, no use in continuing from here */ - my_error(ER_OUT_OF_RESOURCES, MYF(ME_FATAL)); - DBUG_RETURN(NULL); - } + int err2= part_info->gen_part_type(thd, &str); + if (err2 < 0) + DBUG_RETURN(NULL); + err+= err2; if (part_info->part_type == VERSIONING_PARTITION) { Vers_part_info *vers_info= part_info->vers_info; @@ -5044,7 +5092,7 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, else if (thd->work_part_info->part_type == VERSIONING_PARTITION || tab_part_info->part_type == VERSIONING_PARTITION) { - my_error(ER_PARTITION_WRONG_TYPE, MYF(0), "SYSTEM_TIME"); + part_type_error(thd, thd->work_part_info, NULL, tab_part_info); } else { From 2092881984117b9e10b5d2afc8d387ec90199287 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Mon, 31 Oct 2022 16:29:15 +0300 Subject: [PATCH 08/38] MDEV-29841 Partition by system_time can be converted into table but not back Wrong error code was returned because of prematurely tested condition for wrong partition type. Now the condition for CONVERT IN is tested first. --- mysql-test/suite/versioning/r/partition.result | 9 +++++++++ mysql-test/suite/versioning/t/partition.test | 10 ++++++++++ sql/sql_partition.cc | 14 +++++++------- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/mysql-test/suite/versioning/r/partition.result b/mysql-test/suite/versioning/r/partition.result index 031ad9b3f3b..015ceae983f 100644 --- a/mysql-test/suite/versioning/r/partition.result +++ b/mysql-test/suite/versioning/r/partition.result @@ -2049,6 +2049,15 @@ t1 CREATE TABLE `t1` ( PARTITION `pn` VALUES LESS THAN MAXVALUE ENGINE = X) drop tables t1, tp1; # +# MDEV-29841 Partition by system_time can be converted into table but not back +# +create or replace table t (a int) with system versioning +partition by system_time limit 10 partitions 3; +alter table t convert partition p0 to table tp; +alter table t convert table tp to partition p0; +ERROR HY000: CONVERT TABLE TO PARTITION can only be used on RANGE/LIST partitions +drop tables t, tp; +# # End of 10.7 tests # set global innodb_stats_persistent= @save_persistent; diff --git a/mysql-test/suite/versioning/t/partition.test b/mysql-test/suite/versioning/t/partition.test index de00bdce524..70685205bd0 100644 --- a/mysql-test/suite/versioning/t/partition.test +++ b/mysql-test/suite/versioning/t/partition.test @@ -1677,6 +1677,16 @@ show create table t1; drop tables t1, tp1; } +--echo # +--echo # MDEV-29841 Partition by system_time can be converted into table but not back +--echo # +create or replace table t (a int) with system versioning +partition by system_time limit 10 partitions 3; +alter table t convert partition p0 to table tp; +--error ER_ONLY_ON_RANGE_LIST_PARTITION +alter table t convert table tp to partition p0; +drop tables t, tp; + --echo # --echo # End of 10.7 tests --echo # diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc index 130484e4a0b..d7078278557 100644 --- a/sql/sql_partition.cc +++ b/sql/sql_partition.cc @@ -5057,6 +5057,13 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, if ((alter_info->partition_flags & ALTER_PARTITION_ADD) || (alter_info->partition_flags & ALTER_PARTITION_REORGANIZE)) { + if ((alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN) && + !(tab_part_info->part_type == RANGE_PARTITION || + tab_part_info->part_type == LIST_PARTITION)) + { + my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "CONVERT TABLE TO"); + goto err; + } if (thd->work_part_info->part_type != tab_part_info->part_type) { if (thd->work_part_info->part_type == NOT_A_PARTITION) @@ -5126,13 +5133,6 @@ uint prep_alter_part_table(THD *thd, TABLE *table, Alter_info *alter_info, } if (alter_info->partition_flags & ALTER_PARTITION_ADD) { - if ((alter_info->partition_flags & ALTER_PARTITION_CONVERT_IN) && - !(tab_part_info->part_type == RANGE_PARTITION || - tab_part_info->part_type == LIST_PARTITION)) - { - my_error(ER_ONLY_ON_RANGE_LIST_PARTITION, MYF(0), "CONVERT TABLE TO"); - goto err; - } if (*fast_alter_table && thd->locked_tables_mode) { MEM_ROOT *old_root= thd->mem_root; From 0d927a57d2bfb32384dd024b9b4d1009fa22555a Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Wed, 19 Oct 2022 13:26:19 +0400 Subject: [PATCH 09/38] MDEV-29624 MDEV-29655 Fix ASAN errors on pushdown of derived table Deallocation of TABLE_LIST::dt_handler and TABLE_LIST::pushdown_derived was performed in multiple places if code. This not only made the code more difficult to maintain but also led to memory leaks and ASAN heap-use-after-free errors. This commit puts deallocation of TABLE_LIST::dt_handler and TABLE_LIST::pushdown_derived to the single point - JOIN::cleanup() --- .../federatedx_create_handlers.result | 45 ++++++++++++++ .../federated/federatedx_create_handlers.test | 59 ++++++++++++++++++- sql/derived_handler.cc | 5 -- sql/sql_derived.cc | 5 -- sql/sql_select.cc | 34 +++++++++-- sql/sql_select.h | 3 +- 6 files changed, 132 insertions(+), 19 deletions(-) diff --git a/mysql-test/suite/federated/federatedx_create_handlers.result b/mysql-test/suite/federated/federatedx_create_handlers.result index 29ce2c4348b..612b89fa04e 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.result +++ b/mysql-test/suite/federated/federatedx_create_handlers.result @@ -469,6 +469,51 @@ a 1 2 3 +# +# MDEV-29655: ASAN heap-use-after-free in +# Pushdown_derived::Pushdown_derived +# +connection slave; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +id int(20) NOT NULL, +name varchar(16) NOT NULL default '' +) +DEFAULT CHARSET=latin1; +INSERT INTO federated.t1 VALUES +(3,'xxx'), (7,'yyy'), (4,'xxx'), (1,'zzz'), (5,'yyy'); +connection master; +DROP TABLE IF EXISTS federated.t1; +CREATE TABLE federated.t1 ( +id int(20) NOT NULL, +name varchar(16) NOT NULL default '' +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1'; +use federated; +SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3 +WHERE id=2) dt2) dt; +id name +connection slave; +CREATE TABLE federated.t10 (a INT,b INT); +CREATE TABLE federated.t11 (a INT, b INT); +INSERT INTO federated.t10 VALUES (1,1),(2,2); +INSERT INTO federated.t11 VALUES (1,1),(2,2); +connection master; +CREATE TABLE federated.t10 +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t10'; +CREATE TABLE federated.t11 +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t11'; +use federated; +SELECT * FROM t10 LEFT JOIN +(t11, (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3 +WHERE id=2) dt2) dt +) ON t10.a=t11.a; +a b a b id name +1 1 NULL NULL NULL NULL +2 2 NULL NULL NULL NULL set global federated_pushdown=0; connection master; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/suite/federated/federatedx_create_handlers.test b/mysql-test/suite/federated/federatedx_create_handlers.test index 2d6c2bc4197..f827c141f3d 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.test +++ b/mysql-test/suite/federated/federatedx_create_handlers.test @@ -267,7 +267,6 @@ INSERT INTO federated.t2 SELECT * FROM (SELECT * FROM federated.t1 LIMIT 70000) dt; SELECT COUNT(DISTINCT a) FROM federated.t2; - --echo # --echo # MDEV-29640 FederatedX does not properly handle pushdown --echo # in case of difference in local and remote table names @@ -314,6 +313,64 @@ CREATE TABLE federated.t3 (a INT) EXPLAIN SELECT * FROM federated.t3; SELECT * FROM federated.t3; +--echo # +--echo # MDEV-29655: ASAN heap-use-after-free in +--echo # Pushdown_derived::Pushdown_derived +--echo # + +connection slave; +DROP TABLE IF EXISTS federated.t1; + +CREATE TABLE federated.t1 ( + id int(20) NOT NULL, + name varchar(16) NOT NULL default '' +) +DEFAULT CHARSET=latin1; + +INSERT INTO federated.t1 VALUES + (3,'xxx'), (7,'yyy'), (4,'xxx'), (1,'zzz'), (5,'yyy'); + +connection master; +DROP TABLE IF EXISTS federated.t1; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.t1 ( + id int(20) NOT NULL, + name varchar(16) NOT NULL default '' +) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1'; + +use federated; +SELECT * FROM (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3 + WHERE id=2) dt2) dt; + +connection slave; +CREATE TABLE federated.t10 (a INT,b INT); +CREATE TABLE federated.t11 (a INT, b INT); +INSERT INTO federated.t10 VALUES (1,1),(2,2); +INSERT INTO federated.t11 VALUES (1,1),(2,2); + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.t10 +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t10'; + +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval +CREATE TABLE federated.t11 +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t11'; + +use federated; +SELECT * FROM t10 LEFT JOIN + (t11, (SELECT * FROM (SELECT * FROM (SELECT * FROM t1 where id=3) dt3 + WHERE id=2) dt2) dt + ) ON t10.a=t11.a; + set global federated_pushdown=0; source include/federated_cleanup.inc; diff --git a/sql/derived_handler.cc b/sql/derived_handler.cc index f48b95cbf76..70cc04bf9c7 100644 --- a/sql/derived_handler.cc +++ b/sql/derived_handler.cc @@ -44,11 +44,6 @@ Pushdown_derived::Pushdown_derived(TABLE_LIST *tbl, derived_handler *h) } -Pushdown_derived::~Pushdown_derived() -{ - delete handler; -} - int Pushdown_derived::execute() { diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index a4e0fd6b683..4dcc8a61985 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -1000,11 +1000,7 @@ bool mysql_derived_optimize(THD *thd, LEX *lex, TABLE_LIST *derived) /* Create an object for execution of the query specifying the table */ if (!(derived->pushdown_derived= new (thd->mem_root) Pushdown_derived(derived, derived->dt_handler))) - { - delete derived->dt_handler; - derived->dt_handler= NULL; DBUG_RETURN(TRUE); - } } lex->current_select= first_select; @@ -1229,7 +1225,6 @@ bool mysql_derived_fill(THD *thd, LEX *lex, TABLE_LIST *derived) /* Execute the query that specifies the derived table by a foreign engine */ res= derived->pushdown_derived->execute(); unit->executed= true; - delete derived->pushdown_derived; DBUG_RETURN(res); } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5ec88e5259c..c7a0bfe93ac 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -68,6 +68,7 @@ #include "select_handler.h" #include "my_json_writer.h" #include "opt_trace.h" +#include "derived_handler.h" /* A key part number that means we're using a fulltext scan. @@ -14086,6 +14087,7 @@ void JOIN::cleanup(bool full) } } } + free_pushdown_handlers(*join_list); } /* Restore ref array to original state */ if (current_ref_ptrs != items0) @@ -14096,6 +14098,32 @@ void JOIN::cleanup(bool full) DBUG_VOID_RETURN; } +/** + Clean up all derived pushdown handlers in this join. + + @detail + Note that dt_handler is picked at the prepare stage (as opposed + to optimization stage where one could expect this). + Because of that, we have to do cleanups in this function that is called + from JOIN::cleanup() and not in JOIN_TAB::cleanup. + */ +void JOIN::free_pushdown_handlers(List& join_list) +{ + List_iterator li(join_list); + TABLE_LIST *table_ref; + while ((table_ref= li++)) + { + if (table_ref->nested_join) + free_pushdown_handlers(table_ref->nested_join->join_list); + if (table_ref->pushdown_derived) + { + delete table_ref->pushdown_derived; + table_ref->pushdown_derived= NULL; + } + delete table_ref->dt_handler; + table_ref->dt_handler= NULL; + } +} /** Remove the following expressions from ORDER BY and GROUP BY: @@ -27400,12 +27428,6 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) result, unit, first); } - if (unit->derived && unit->derived->pushdown_derived) - { - delete unit->derived->pushdown_derived; - unit->derived->pushdown_derived= NULL; - } - DBUG_RETURN(res || thd->is_error()); } diff --git a/sql/sql_select.h b/sql/sql_select.h index ecfa4c6fd11..b3945c499f8 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -1840,6 +1840,7 @@ private: bool add_having_as_table_cond(JOIN_TAB *tab); bool make_aggr_tables_info(); bool add_fields_for_current_rowid(JOIN_TAB *cur, List *fields); + void free_pushdown_handlers(List& join_list); }; enum enum_with_bush_roots { WITH_BUSH_ROOTS, WITHOUT_BUSH_ROOTS}; @@ -2507,8 +2508,6 @@ public: Pushdown_derived(TABLE_LIST *tbl, derived_handler *h); - ~Pushdown_derived(); - int execute(); }; From e7be2d3142699aa73e8f50e01657a3ec2570c7ff Mon Sep 17 00:00:00 2001 From: Ian Gilfillan Date: Wed, 2 Nov 2022 16:24:36 +0200 Subject: [PATCH 10/38] Fix duplicate entry in mysqld_safe man page --- man/mysqld_safe.1 | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/man/mysqld_safe.1 b/man/mysqld_safe.1 index dbb50e11ac4..2b902ac123e 100644 --- a/man/mysqld_safe.1 +++ b/man/mysqld_safe.1 @@ -340,7 +340,9 @@ program to set the server\'s scheduling priority to the given value\&. .\} .\" mysqld_safe: no-auto-restart option .\" no-auto-restart option: mysqld_safe -\fB\-\-no\-auto\-restart\fR +\fB\-\-no\-auto\-restart\fR, +\fB\-\-nowatch\fR, +\fB\-\-no\-watch\fR .sp Exit after starting mysqld\&. .RE @@ -368,21 +370,6 @@ Do not read any option files\&. This must be the first option on the command lin .sp -1 .IP \(bu 2.3 .\} -.\" mysqld_safe: no-watch option -.\" no-watch option: mysqld_safe -\fB\-\-no\-auto\-restart\fR -.sp -Exit after starting mysqld\&. -.RE -.sp -.RS 4 -.ie n \{\ -\h'-04'\(bu\h'+03'\c -.\} -.el \{\ -.sp -1 -.IP \(bu 2.3 -.\} .\" mysqld_safe: numa-interleave option .\" numa-interleave option: mysqld_safe \fB\-\-numa\-interleave\fR From 92be8d20480ee0e2fb8ec72c005648f2573558ce Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Sat, 5 Nov 2022 18:36:43 +0100 Subject: [PATCH 11/38] MDEV-29951 server hang in crash handler When trying to output stacktrace, and addr2line is not installed, the child process forked by start_addr2line_fork() will fail to do exec(), and finish with exit(1). There is a problem with exit() though - it runs exit handlers, and for the forked copy of crashing process, it is a bad idea. In 10.5+ code for example, exit handlers include tpool::task_group static destructors, and it will hang infinitely waiting for completion of the outstanding tasks. The fix is to use _exit() instead, which skips the execution of exit handlers --- mysys/my_addr_resolve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_addr_resolve.c b/mysys/my_addr_resolve.c index f0c0d214171..ac1bdae187c 100644 --- a/mysys/my_addr_resolve.c +++ b/mysys/my_addr_resolve.c @@ -202,7 +202,7 @@ int start_addr2line_fork(const char *binary_path) close(out[0]); close(out[1]); execlp("addr2line", "addr2line", "-C", "-f", "-e", binary_path, NULL); - exit(1); + _exit(1); } close(in[0]); From 10132ad26119205e1b53e5d3389bedb71d444201 Mon Sep 17 00:00:00 2001 From: Sachin Date: Mon, 14 Sep 2020 15:27:02 +0100 Subject: [PATCH 12/38] MDEV-23264 Unique blobs allow duplicate values upon UPDATE Problem:- We are able to insert duplicate value in table because cmp_binary_offset is not able to differentiate between NULL and empty string. So check_duplicate_long_entry_key is never called and we don't check for duplicate. Solution Added a if condition with is_null() on field which can differentiate between NULL and empty string. --- mysql-test/main/long_unique_bugs.result | 9 +++++++++ mysql-test/main/long_unique_bugs.test | 11 +++++++++++ sql/handler.cc | 9 +++++++-- 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/long_unique_bugs.result b/mysql-test/main/long_unique_bugs.result index 1d896059289..f359913b5f4 100644 --- a/mysql-test/main/long_unique_bugs.result +++ b/mysql-test/main/long_unique_bugs.result @@ -314,6 +314,15 @@ ERROR 23000: Duplicate entry '1' for key 'v2' update t1,t2 set v1 = v2 , v5 = 0; ERROR 23000: Duplicate entry '-128' for key 'v1' drop table t1, t2; +CREATE TABLE t1 (f TEXT UNIQUE); +INSERT INTO t1 VALUES (NULL),(NULL); +UPDATE t1 SET f = ''; +ERROR 23000: Duplicate entry '' for key 'f' +SELECT * FROM t1; +f + +NULL +DROP TABLE t1; # # MDEV-21540 Initialization of already inited long unique index on reorganize partition # diff --git a/mysql-test/main/long_unique_bugs.test b/mysql-test/main/long_unique_bugs.test index f62ba2ac61a..9bef617ca90 100644 --- a/mysql-test/main/long_unique_bugs.test +++ b/mysql-test/main/long_unique_bugs.test @@ -396,6 +396,17 @@ update t1 set v2 = 1, v3 = -128; update t1,t2 set v1 = v2 , v5 = 0; drop table t1, t2; +# +# MDEV-23264 Unique blobs allow duplicate values upon UPDATE +# + +CREATE TABLE t1 (f TEXT UNIQUE); +INSERT INTO t1 VALUES (NULL),(NULL); +--error ER_DUP_ENTRY +UPDATE t1 SET f = ''; +SELECT * FROM t1; +DROP TABLE t1; + --echo # --echo # MDEV-21540 Initialization of already inited long unique index on reorganize partition --echo # diff --git a/sql/handler.cc b/sql/handler.cc index bf819733b81..5e9c9dc3a71 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -6750,8 +6750,13 @@ static int check_duplicate_long_entries_update(TABLE *table, handler *h, uchar * for (uint j= 0; j < key_parts; j++, keypart++) { field= keypart->field; - /* Compare fields if they are different then check for duplicates*/ - if(field->cmp_binary_offset(reclength)) + /* + Compare fields if they are different then check for duplicates + cmp_binary_offset cannot differentiate between null and empty string + So also check for that too + */ + if((field->is_null(0) != field->is_null(reclength)) || + field->cmp_binary_offset(reclength)) { if((error= check_duplicate_long_entry_key(table, table->update_handler, new_rec, i))) From f7e6198c0221112fdeb42668f89d29c828636156 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 7 Nov 2022 17:36:08 +0530 Subject: [PATCH 13/38] MDEV-27121 mariabackup incompatible with disabled dedicated undo log tablespaces - mariabackup fails to assign srv_undo_space_id_start when the dedicated undo tablespaces are disabled --- extra/mariabackup/xtrabackup.cc | 4 ---- mysql-test/suite/mariabackup/full_backup.opt | 1 + .../suite/mariabackup/full_backup.result | 14 +++++++++++ mysql-test/suite/mariabackup/full_backup.test | 24 +++++++++++++++++++ 4 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 mysql-test/suite/mariabackup/full_backup.opt diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 2b276856303..f7910fc9c23 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -3578,10 +3578,6 @@ static dberr_t xb_assign_undo_space_start() ulint space; int n_retries = 5; - if (srv_undo_tablespaces == 0) { - return error; - } - file = os_file_create(0, srv_sys_space.first_datafile()->filepath(), OS_FILE_OPEN, OS_FILE_NORMAL, OS_DATA_FILE, true, &ret); diff --git a/mysql-test/suite/mariabackup/full_backup.opt b/mysql-test/suite/mariabackup/full_backup.opt new file mode 100644 index 00000000000..7928cd812d0 --- /dev/null +++ b/mysql-test/suite/mariabackup/full_backup.opt @@ -0,0 +1 @@ +--innodb_undo_tablespaces=2 diff --git a/mysql-test/suite/mariabackup/full_backup.result b/mysql-test/suite/mariabackup/full_backup.result index 954151bbad7..10f4dc44ed4 100644 --- a/mysql-test/suite/mariabackup/full_backup.result +++ b/mysql-test/suite/mariabackup/full_backup.result @@ -12,3 +12,17 @@ SELECT * FROM t; i 1 DROP TABLE t; +# +# MDEV-27121 mariabackup incompatible with disabled dedicated +# undo log tablespaces +# +call mtr.add_suppression("InnoDB: innodb_undo_tablespaces=0 disables dedicated undo log tablespaces"); +# xtrabackup backup +# xtrabackup prepare +# shutdown server +# remove datadir +# xtrabackup move back +# restart server +# Display undo log files from target directory +undo001 +undo002 diff --git a/mysql-test/suite/mariabackup/full_backup.test b/mysql-test/suite/mariabackup/full_backup.test index 66bed34cf3d..a0243527438 100644 --- a/mysql-test/suite/mariabackup/full_backup.test +++ b/mysql-test/suite/mariabackup/full_backup.test @@ -29,3 +29,27 @@ SELECT * FROM t; DROP TABLE t; rmdir $targetdir; +--echo # +--echo # MDEV-27121 mariabackup incompatible with disabled dedicated +--echo # undo log tablespaces +--echo # +call mtr.add_suppression("InnoDB: innodb_undo_tablespaces=0 disables dedicated undo log tablespaces"); + +let $restart_parameters=--innodb_undo_tablespaces=0; +--source include/restart_mysqld.inc + +echo # xtrabackup backup; +--disable_result_log +exec $XTRABACKUP --defaults-file=$MYSQLTEST_VARDIR/my.cnf --backup --target-dir=$targetdir; +--enable_result_log + +echo # xtrabackup prepare; +--disable_result_log +exec $XTRABACKUP --prepare --target-dir=$targetdir; +-- source include/restart_and_restore.inc +--enable_result_log + +--echo # Display undo log files from target directory +list_files $targetdir undo*; + +rmdir $targetdir; From baa6b052a2ad012aaedb1db0e1e549de3c9e0c29 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 7 Nov 2022 08:08:55 -0500 Subject: [PATCH 14/38] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 92848892dc8..876e7c96e80 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=3 -MYSQL_VERSION_PATCH=37 +MYSQL_VERSION_PATCH=38 SERVER_MATURITY=stable From 625fff0d8f97e813676d9cfd8f4b4b326762037a Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 7 Nov 2022 08:35:15 -0500 Subject: [PATCH 15/38] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ec02fb54be8..156ceae1801 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=4 -MYSQL_VERSION_PATCH=27 +MYSQL_VERSION_PATCH=28 SERVER_MATURITY=stable From 9201cda37c43b9563cc0ae94e2724c99a2e225c9 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 7 Nov 2022 09:18:20 -0500 Subject: [PATCH 16/38] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 41ccccdc33f..0283e48b39c 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=18 +MYSQL_VERSION_PATCH=19 SERVER_MATURITY=stable From 118d39d3ee0c591e2697ad9c2bdf92f372979ff7 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 7 Nov 2022 09:45:23 -0500 Subject: [PATCH 17/38] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 084adac9be3..0acffd643c8 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=6 -MYSQL_VERSION_PATCH=11 +MYSQL_VERSION_PATCH=12 SERVER_MATURITY=stable From b75ad1af91261841fdd64d0c81749319fc195940 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 7 Nov 2022 11:07:47 -0500 Subject: [PATCH 18/38] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index cbe0f0b08c3..d3418c3d869 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=7 -MYSQL_VERSION_PATCH=7 +MYSQL_VERSION_PATCH=8 SERVER_MATURITY=stable From eabb3b35d5ab76ceacd9006bb388e310f7016315 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 08:53:49 +0200 Subject: [PATCH 19/38] MDEV-27121 fixup: mariabackup.mdev-14447 fault injection --- storage/innobase/buf/buf0buf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 01111157920..fe2c0c6b880 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -1141,7 +1141,7 @@ buf_page_is_corrupted( DBUG_EXECUTE_IF( "page_intermittent_checksum_mismatch", { static int page_counter; - if (page_counter++ == 2) return true; + if (page_counter++ == 3) return true; }); if ((checksum_field1 != crc32 From 456d4a508c510f4cb3798145944a47c8f3954465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 08:54:07 +0200 Subject: [PATCH 20/38] Remove an unused file The file plugin_exports became unused in commit fec844aca88e1c6b9c36bb0b811e92d9d023ffb9 --- storage/innobase/plugin_exports | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 storage/innobase/plugin_exports diff --git a/storage/innobase/plugin_exports b/storage/innobase/plugin_exports deleted file mode 100644 index 235ae3d5e72..00000000000 --- a/storage/innobase/plugin_exports +++ /dev/null @@ -1,14 +0,0 @@ -{ - global: - _maria_plugin_interface_version_; - _maria_sizeof_struct_st_plugin_; - _maria_plugin_declarations_; - my_snprintf_service; - thd_alloc_service; - thd_autoinc_service; - thd_error_context_service; - thd_kill_statement_service; - thd_wait_service; - local: - *; -}; From 314ed9f5eccc527654b0a63064561749a7b842f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 09:00:58 +0200 Subject: [PATCH 21/38] Work around MDEV-24813 in some tests Not creating explicit record locks will speed up the test. Also, disable the use of InnoDB persistent statistics in the test of MDEV-27270 to avoid intermittent failures in 10.6 or later (after commit 9608773f75e2ca21491ef6825c3616cdc96d1ca5) due to the nondeterministic scheduling of STATS_AUTO_PERSISTENT. --- mysql-test/main/order_by_innodb.result | 30 ++++++++++------------ mysql-test/main/order_by_innodb.test | 35 +++++++++++--------------- mysql-test/main/range_innodb.result | 15 ++++------- mysql-test/main/range_innodb.test | 22 +++++----------- 4 files changed, 38 insertions(+), 64 deletions(-) diff --git a/mysql-test/main/order_by_innodb.result b/mysql-test/main/order_by_innodb.result index 28922ef65f2..17d39eb12e6 100644 --- a/mysql-test/main/order_by_innodb.result +++ b/mysql-test/main/order_by_innodb.result @@ -1,8 +1,8 @@ -drop table if exists t0,t1,t2,t3; # # MDEV-6434: Wrong result (extra rows) with ORDER BY, multiple-column index, InnoDB # -CREATE TABLE t1 (a INT, b INT, c INT, d TEXT, KEY idx(a,b,c)) ENGINE=InnoDB; +CREATE TABLE t1 (a INT, b INT, c INT, d TEXT, KEY idx(a,b,c)) ENGINE=InnoDB +STATS_PERSISTENT=0; INSERT INTO t1 (a,c) VALUES (8, 9),(8, 10),(13, 15),(16, 17),(16, 18),(16, 19),(20, 21), (20, 22),(20, 24),(20, 25),(20, 26),(20, 27),(20, 28); @@ -14,8 +14,6 @@ DROP TABLE t1; # # MDEV-9457: Poor query plan chosen for ORDER BY query by a recent 10.1 # -create table t0 (a int); -insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t1 ( pk int primary key, key1 int, @@ -23,15 +21,9 @@ key2 int, col1 char(255), key(key1), key(key2) -) engine=innodb; -set @a=-1; +) engine=innodb stats_persistent=0; insert into t1 -select -@a:=@a+1, -@a, -@a, -repeat('abcd', 63) -from t0 A, t0 B, t0 C, t0 D; +select seq,seq,seq,repeat('abcd', 63) from seq_0_to_9999; # The following must NOT use 'index' on PK. # It should use index_merge(key1,key2) + filesort explain @@ -47,7 +39,7 @@ from t1 where key1<3 or key2<3; id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 index_merge key1,key2 key1,key2 5,5 NULL # Using sort_union(key1,key2); Using where -drop table t0, t1; +drop table t1; # # MDEV-18094: Query with order by limit picking index scan over filesort # @@ -78,9 +70,12 @@ drop table t1,t0; # MDEV-14071: wrong results with orderby_uses_equalities=on # (duplicate of MDEV-13994) # -CREATE TABLE t1 (i int, j int, z int,PRIMARY KEY (i,j), KEY (z)) ENGINE=InnoDB; -CREATE TABLE t2 (i int, j int, PRIMARY KEY (i,j)) ENGINE=InnoDB; -CREATE TABLE t3 (j int, n varchar(5), PRIMARY KEY (j)) ENGINE=InnoDB; +CREATE TABLE t1 (i int, j int, z int,PRIMARY KEY (i,j), KEY (z)) ENGINE=InnoDB +STATS_PERSISTENT=0; +CREATE TABLE t2 (i int, j int, PRIMARY KEY (i,j)) ENGINE=InnoDB +STATS_PERSISTENT=0; +CREATE TABLE t3 (j int, n varchar(5), PRIMARY KEY (j)) ENGINE=InnoDB +STATS_PERSISTENT=0; INSERT INTO t1 VALUES (127,0,1),(188,0,1),(206,0,1),(218,0,1),(292,0,1),(338,0,1),(375,0,1), (381,0,1),(409,0,1),(466,0,1),(469,0,1),(498,0,1),(656,0,1); @@ -150,7 +145,8 @@ DROP TABLE t1,t2,t3; # # MDEV-25858: Query results are incorrect when indexes are added # -CREATE TABLE t1 (id int NOT NULL PRIMARY KEY) engine=innodb; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY) engine=innodb +STATS_PERSISTENT=0; insert into t1 values (1),(2),(3); CREATE TABLE t2 ( id int NOT NULL PRIMARY KEY, diff --git a/mysql-test/main/order_by_innodb.test b/mysql-test/main/order_by_innodb.test index af12644c073..29b796f67bc 100644 --- a/mysql-test/main/order_by_innodb.test +++ b/mysql-test/main/order_by_innodb.test @@ -2,16 +2,14 @@ # ORDER BY handling (e.g. filesort) tests that require innodb # -- source include/have_innodb.inc - ---disable_warnings -drop table if exists t0,t1,t2,t3; ---enable_warnings +-- source include/have_sequence.inc --echo # --echo # MDEV-6434: Wrong result (extra rows) with ORDER BY, multiple-column index, InnoDB --echo # -CREATE TABLE t1 (a INT, b INT, c INT, d TEXT, KEY idx(a,b,c)) ENGINE=InnoDB; +CREATE TABLE t1 (a INT, b INT, c INT, d TEXT, KEY idx(a,b,c)) ENGINE=InnoDB +STATS_PERSISTENT=0; INSERT INTO t1 (a,c) VALUES (8, 9),(8, 10),(13, 15),(16, 17),(16, 18),(16, 19),(20, 21), @@ -24,9 +22,6 @@ DROP TABLE t1; --echo # --echo # MDEV-9457: Poor query plan chosen for ORDER BY query by a recent 10.1 --echo # -create table t0 (a int); -insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); - create table t1 ( pk int primary key, key1 int, @@ -34,16 +29,10 @@ create table t1 ( col1 char(255), key(key1), key(key2) -) engine=innodb; +) engine=innodb stats_persistent=0; -set @a=-1; insert into t1 -select - @a:=@a+1, - @a, - @a, - repeat('abcd', 63) -from t0 A, t0 B, t0 C, t0 D; +select seq,seq,seq,repeat('abcd', 63) from seq_0_to_9999; --echo # The following must NOT use 'index' on PK. --echo # It should use index_merge(key1,key2) + filesort @@ -60,7 +49,7 @@ select * from t1 where key1<3 or key2<3; -drop table t0, t1; +drop table t1; --echo # --echo # MDEV-18094: Query with order by limit picking index scan over filesort @@ -93,9 +82,12 @@ drop table t1,t0; --echo # (duplicate of MDEV-13994) --echo # -CREATE TABLE t1 (i int, j int, z int,PRIMARY KEY (i,j), KEY (z)) ENGINE=InnoDB; -CREATE TABLE t2 (i int, j int, PRIMARY KEY (i,j)) ENGINE=InnoDB; -CREATE TABLE t3 (j int, n varchar(5), PRIMARY KEY (j)) ENGINE=InnoDB; +CREATE TABLE t1 (i int, j int, z int,PRIMARY KEY (i,j), KEY (z)) ENGINE=InnoDB +STATS_PERSISTENT=0; +CREATE TABLE t2 (i int, j int, PRIMARY KEY (i,j)) ENGINE=InnoDB +STATS_PERSISTENT=0; +CREATE TABLE t3 (j int, n varchar(5), PRIMARY KEY (j)) ENGINE=InnoDB +STATS_PERSISTENT=0; INSERT INTO t1 VALUES (127,0,1),(188,0,1),(206,0,1),(218,0,1),(292,0,1),(338,0,1),(375,0,1), @@ -139,7 +131,8 @@ DROP TABLE t1,t2,t3; --echo # MDEV-25858: Query results are incorrect when indexes are added --echo # -CREATE TABLE t1 (id int NOT NULL PRIMARY KEY) engine=innodb; +CREATE TABLE t1 (id int NOT NULL PRIMARY KEY) engine=innodb +STATS_PERSISTENT=0; insert into t1 values (1),(2),(3); CREATE TABLE t2 ( diff --git a/mysql-test/main/range_innodb.result b/mysql-test/main/range_innodb.result index df111bc05be..cbe763bcf6e 100644 --- a/mysql-test/main/range_innodb.result +++ b/mysql-test/main/range_innodb.result @@ -1,15 +1,11 @@ # # Range optimizer (and related) tests that need InnoDB. # -drop table if exists t0, t1, t2; # # MDEV-6735: Range checked for each record used with key # create table t0(a int); insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); -create table t1(a int); -insert into t1 select A.a + B.a* 10 + C.a * 100 + D.a * 1000 -from t0 A, t0 B, t0 C, t0 D; create table t2 ( a int, b int, @@ -22,12 +18,12 @@ key(b) ) engine=innodb; insert into t2 select -a,a, +seq,seq, repeat('0123456789', 10), repeat('0123456789', 10), repeat('0123456789', 10), repeat('0123456789', 10) -from t1; +from seq_0_to_9999; analyze table t2; Table Op Msg_type Msg_text test.t2 analyze status OK @@ -36,7 +32,7 @@ explain select * from t0 left join t2 on t2.a Date: Tue, 8 Nov 2022 08:02:18 +0100 Subject: [PATCH 22/38] MDEV-29822 - make mysqltest fail loudly when out of memory When allocation failed, fail consistently with error message and abort() by using flags MY_WME|MY_FAE with my_malloc() and friends. This ensures that better diagnostic information is available when mysqltest fails. --- client/mysqltest.cc | 69 +++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/client/mysqltest.cc b/client/mysqltest.cc index 2c609bd9815..545e435e5cc 100644 --- a/client/mysqltest.cc +++ b/client/mysqltest.cc @@ -1748,7 +1748,8 @@ int cat_file(DYNAMIC_STRING* ds, const char* filename) len= (size_t) my_seek(fd, 0, SEEK_END, MYF(0)); my_seek(fd, 0, SEEK_SET, MYF(0)); if (len == (size_t)MY_FILEPOS_ERROR || - !(buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, len + 1, MYF(0)))) + !(buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, len + 1, + MYF(MY_WME|MY_FAE)))) { my_close(fd, MYF(0)); return 1; @@ -2407,7 +2408,7 @@ VAR *var_init(VAR *v, const char *name, size_t name_len, const char *val, size_t val_len= 0; val_alloc_len = val_len + 16; /* room to grow */ if (!(tmp_var=v) && !(tmp_var = (VAR*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*tmp_var) - + name_len+2, MYF(MY_WME)))) + + name_len+2, MYF(MY_WME|MY_FAE)))) die("Out of memory"); if (name != NULL) @@ -2421,7 +2422,8 @@ VAR *var_init(VAR *v, const char *name, size_t name_len, const char *val, size_t tmp_var->alloced = (v == 0); - if (!(tmp_var->str_val = (char*)my_malloc(PSI_NOT_INSTRUMENTED, val_alloc_len+1, MYF(MY_WME)))) + if (!(tmp_var->str_val = (char*)my_malloc(PSI_NOT_INSTRUMENTED, + val_alloc_len+1, MYF(MY_WME|MY_FAE)))) die("Out of memory"); if (val) @@ -2969,8 +2971,10 @@ void var_copy(VAR *dest, VAR *src) /* Alloc/realloc data for str_val in dest */ if (dest->alloced_len < src->alloced_len && !(dest->str_val= dest->str_val - ? (char*)my_realloc(PSI_NOT_INSTRUMENTED, dest->str_val, src->alloced_len, MYF(MY_WME)) - : (char*)my_malloc(PSI_NOT_INSTRUMENTED, src->alloced_len, MYF(MY_WME)))) + ? (char*)my_realloc(PSI_NOT_INSTRUMENTED, dest->str_val, src->alloced_len, + MYF(MY_WME|MY_FAE)) + : (char*)my_malloc(PSI_NOT_INSTRUMENTED, src->alloced_len, + MYF(MY_WME|MY_FAE)))) die("Out of memory"); else dest->alloced_len= src->alloced_len; @@ -3047,8 +3051,10 @@ void eval_expr(VAR *v, const char *p, const char **p_end, MIN_VAR_ALLOC : new_val_len + 1; if (!(v->str_val = v->str_val ? - (char*)my_realloc(PSI_NOT_INSTRUMENTED, v->str_val, v->alloced_len+1, MYF(MY_WME)) : - (char*)my_malloc(PSI_NOT_INSTRUMENTED, v->alloced_len+1, MYF(MY_WME)))) + (char*)my_realloc(PSI_NOT_INSTRUMENTED, v->str_val, v->alloced_len+1, + MYF(MY_WME|MY_FAE)) : + (char*)my_malloc(PSI_NOT_INSTRUMENTED, v->alloced_len+1, + MYF(MY_WME|MY_FAE)))) die("Out of memory"); } v->str_val_len = new_val_len; @@ -4784,7 +4790,8 @@ void do_sync_with_master(struct st_command *command) p++; while (*p && my_isspace(charset_info, *p)) p++; - start= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(p)+1,MYF(MY_WME | MY_FAE)); + start= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(p)+1, + MYF(MY_WME|MY_FAE)); get_string(&buff, &p, command); } command->last_argument= p; @@ -6924,7 +6931,7 @@ int read_command(struct st_command** command_ptr) } if (!(*command_ptr= command= (struct st_command*) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(*command), - MYF(MY_WME|MY_ZEROFILL))) || + MYF(MY_WME|MY_FAE|MY_ZEROFILL))) || insert_dynamic(&q_lines, &command)) die("Out of memory"); command->type= Q_UNKNOWN; @@ -7632,18 +7639,19 @@ void append_stmt_result(DYNAMIC_STRING *ds, MYSQL_STMT *stmt, /* Allocate array with bind structs, lengths and NULL flags */ my_bind= (MYSQL_BIND*) my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(MYSQL_BIND), - MYF(MY_WME | MY_FAE | MY_ZEROFILL)); + MYF(MY_WME|MY_FAE|MY_ZEROFILL)); length= (ulong*) my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(ulong), - MYF(MY_WME | MY_FAE)); + MYF(MY_WME|MY_FAE)); is_null= (my_bool*) my_malloc(PSI_NOT_INSTRUMENTED, num_fields * sizeof(my_bool), - MYF(MY_WME | MY_FAE)); + MYF(MY_WME|MY_FAE)); /* Allocate data for the result of each field */ for (i= 0; i < num_fields; i++) { uint max_length= fields[i].max_length + 1; my_bind[i].buffer_type= MYSQL_TYPE_STRING; - my_bind[i].buffer= my_malloc(PSI_NOT_INSTRUMENTED, max_length, MYF(MY_WME | MY_FAE)); + my_bind[i].buffer= my_malloc(PSI_NOT_INSTRUMENTED, max_length, + MYF(MY_WME|MY_FAE)); my_bind[i].buffer_length= max_length; my_bind[i].is_null= &is_null[i]; my_bind[i].length= &length[i]; @@ -8667,7 +8675,7 @@ void run_bind_stmt(struct st_connection *cn, struct st_command *command, cn->ps_params= ps_params = (MYSQL_BIND*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(MYSQL_BIND) * stmt->param_count, - MYF(MY_WME)); + MYF(MY_WME|MY_FAE)); bzero((char *) ps_params, sizeof(MYSQL_BIND) * stmt->param_count); int i=0; @@ -8682,7 +8690,8 @@ void run_bind_stmt(struct st_connection *cn, struct st_command *command, if (!*c) { ps_params[i].buffer_type= MYSQL_TYPE_LONG; - l= (long*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(long), MYF(MY_WME)); + l= (long*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(long), + MYF(MY_WME|MY_FAE)); *l= strtol(p, &c, 10); ps_params[i].buffer= (void*)l; ps_params[i].buffer_length= 8; @@ -8694,7 +8703,7 @@ void run_bind_stmt(struct st_connection *cn, struct st_command *command, { ps_params[i].buffer_type= MYSQL_TYPE_DECIMAL; d= (double*)my_malloc(PSI_NOT_INSTRUMENTED, sizeof(double), - MYF(MY_WME)); + MYF(MY_WME|MY_FAE)); *d= strtod(p, &c); ps_params[i].buffer= (void*)d; ps_params[i].buffer_length= 8; @@ -8702,7 +8711,8 @@ void run_bind_stmt(struct st_connection *cn, struct st_command *command, else { ps_params[i].buffer_type= MYSQL_TYPE_STRING; - ps_params[i].buffer= my_strdup(PSI_NOT_INSTRUMENTED, p, MYF(MY_WME)); + ps_params[i].buffer= my_strdup(PSI_NOT_INSTRUMENTED, p, + MYF(MY_WME|MY_FAE)); ps_params[i].buffer_length= (unsigned long)strlen(p); } } @@ -9740,7 +9750,7 @@ int main(int argc, char **argv) /* Init connections, allocate 1 extra as buffer + 1 for default */ connections= (struct st_connection*) my_malloc(PSI_NOT_INSTRUMENTED, (opt_max_connections+2) * sizeof(struct st_connection), - MYF(MY_WME | MY_ZEROFILL)); + MYF(MY_WME|MY_FAE|MY_ZEROFILL)); connections_end= connections + opt_max_connections +1; next_con= connections + 1; @@ -10462,7 +10472,8 @@ void do_get_replace_column(struct st_command *command) die("Missing argument in %s", command->query); /* Allocate a buffer for results */ - start= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(from)+1,MYF(MY_WME | MY_FAE)); + start= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(from)+1, + MYF(MY_WME|MY_FAE)); while (*from) { char *to; @@ -10475,7 +10486,8 @@ void do_get_replace_column(struct st_command *command) command->query); to= get_string(&buff, &from, command); my_free(replace_column[column_number-1]); - replace_column[column_number-1]= my_strdup(PSI_NOT_INSTRUMENTED, to, MYF(MY_WME | MY_FAE)); + replace_column[column_number-1]= my_strdup(PSI_NOT_INSTRUMENTED, to, + MYF(MY_WME|MY_FAE)); set_if_bigger(max_replace_column, column_number); } my_free(start); @@ -10542,7 +10554,8 @@ void do_get_replace(struct st_command *command) bzero(&from_array,sizeof(from_array)); if (!*from) die("Missing argument in %s", command->query); - start= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(from)+1,MYF(MY_WME | MY_FAE)); + start= buff= (char*)my_malloc(PSI_NOT_INSTRUMENTED, strlen(from)+1, + MYF(MY_WME|MY_FAE)); while (*from) { char *to= buff; @@ -11200,7 +11213,7 @@ REPLACE *init_replace(char * *from, char * *to,uint count, DBUG_RETURN(0); found_sets=0; if (!(found_set= (FOUND_SET*) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(FOUND_SET)*max_length*count, - MYF(MY_WME)))) + MYF(MY_WME|MY_FAE)))) { free_sets(&sets); DBUG_RETURN(0); @@ -11210,7 +11223,7 @@ REPLACE *init_replace(char * *from, char * *to,uint count, used_sets=-1; word_states=make_new_set(&sets); /* Start of new word */ start_states=make_new_set(&sets); /* This is first state */ - if (!(follow=(FOLLOWS*) my_malloc(PSI_NOT_INSTRUMENTED, (states+2)*sizeof(FOLLOWS),MYF(MY_WME)))) + if (!(follow=(FOLLOWS*) my_malloc(PSI_NOT_INSTRUMENTED, (states+2)*sizeof(FOLLOWS),MYF(MY_WME|MY_FAE)))) { free_sets(&sets); my_free(found_set); @@ -11377,7 +11390,7 @@ REPLACE *init_replace(char * *from, char * *to,uint count, if ((replace=(REPLACE*) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(REPLACE)*(sets.count)+ sizeof(REPLACE_STRING)*(found_sets+1)+ sizeof(char *)*count+result_len, - MYF(MY_WME | MY_ZEROFILL)))) + MYF(MY_WME|MY_FAE|MY_ZEROFILL)))) { rep_str=(REPLACE_STRING*) (replace+sets.count); to_array= (char **) (rep_str+found_sets+1); @@ -11420,10 +11433,10 @@ int init_sets(REP_SETS *sets,uint states) bzero(sets, sizeof(*sets)); sets->size_of_bits=((states+7)/8); if (!(sets->set_buffer=(REP_SET*) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(REP_SET)*SET_MALLOC_HUNC, - MYF(MY_WME)))) + MYF(MY_WME|MY_FAE)))) return 1; if (!(sets->bit_buffer=(uint*) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(uint)*sets->size_of_bits* - SET_MALLOC_HUNC,MYF(MY_WME)))) + SET_MALLOC_HUNC,MYF(MY_WME|MY_FAE)))) { my_free(sets->set); return 1; @@ -11619,10 +11632,10 @@ int insert_pointer_name(POINTER_ARRAY *pa,char * name) if (!(pa->typelib.type_names=(const char **) my_malloc(PSI_NOT_INSTRUMENTED, ((PC_MALLOC-MALLOC_OVERHEAD)/ (sizeof(char *)+sizeof(*pa->flag))* - (sizeof(char *)+sizeof(*pa->flag))),MYF(MY_WME)))) + (sizeof(char *)+sizeof(*pa->flag))),MYF(MY_WME|MY_FAE)))) DBUG_RETURN(-1); if (!(pa->str= (uchar*) my_malloc(PSI_NOT_INSTRUMENTED, PS_MALLOC - MALLOC_OVERHEAD, - MYF(MY_WME)))) + MYF(MY_WME|MY_FAE)))) { my_free(pa->typelib.type_names); DBUG_RETURN (-1); From 95e2595d8dd1e79b14c9038457d174324cd0defe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 10:30:03 +0200 Subject: [PATCH 23/38] MDEV-22512: Disable frequently failing tests InnoDB crash recovery can run out of memory before commit 50324ce62448f284522ee1e3be24d8f5ba3bf904 in MariaDB Server 10.5. Let us disable some frequently failing recovery tests in earlier versions. --- mysql-test/suite/innodb_gis/disabled.def | 1 + mysql-test/suite/innodb_zip/disabled.def | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/innodb_gis/disabled.def b/mysql-test/suite/innodb_gis/disabled.def index 2d4d3686dd1..ba492f4f033 100644 --- a/mysql-test/suite/innodb_gis/disabled.def +++ b/mysql-test/suite/innodb_gis/disabled.def @@ -13,3 +13,4 @@ rtree_concurrent_srch : MDEV-15284 COUNT(*) mismatch rtree_recovery : MDEV-15284 COUNT(*) mismatch rtree_compress2 : MDEV-16269 CHECK TABLE reports wrong count +types : MDEV-22512 recovery runs out of memory before 10.5 diff --git a/mysql-test/suite/innodb_zip/disabled.def b/mysql-test/suite/innodb_zip/disabled.def index 8b137891791..fcf7333f843 100644 --- a/mysql-test/suite/innodb_zip/disabled.def +++ b/mysql-test/suite/innodb_zip/disabled.def @@ -1 +1 @@ - +recover : MDEV-22512 recovery runs out of memory before 10.5 From 9ac8be4e2980aa995117147e39ae5b7ad79fc980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 10:39:29 +0200 Subject: [PATCH 24/38] Include some advice in the crash-upgrade message --- storage/innobase/log/log0recv.cc | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index d8b7bd2ce85..e7effd9224f 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -58,6 +58,7 @@ Created 9/20/1997 Heikki Tuuri #include "trx0roll.h" #include "row0merge.h" #include "fil0pagecompress.h" +#include "log.h" /** Log records are stored in the hash table in chunks at most of this size; this must be less than srv_page_size as it is stored in the buffer pool */ @@ -1137,7 +1138,7 @@ static dberr_t recv_log_format_0_recover(lsn_t lsn, bool crypt) byte* buf = log_sys.buf; static const char* NO_UPGRADE_RECOVERY_MSG = - "Upgrade after a crash is not supported." + "InnoDB: Upgrade after a crash is not supported." " This redo log was created before MariaDB 10.2.2"; fil_io(IORequestLogRead, true, @@ -1150,21 +1151,24 @@ static dberr_t recv_log_format_0_recover(lsn_t lsn, bool crypt) if (log_block_calc_checksum_format_0(buf) != log_block_get_checksum(buf) && !log_crypt_101_read_block(buf)) { - ib::error() << NO_UPGRADE_RECOVERY_MSG - << ", and it appears corrupted."; - return(DB_CORRUPTION); + sql_print_error("%s, and it appears corrupted.", + NO_UPGRADE_RECOVERY_MSG); + return DB_CORRUPTION; } if (log_block_get_data_len(buf) == (source_offset & (OS_FILE_LOG_BLOCK_SIZE - 1))) { } else if (crypt) { - ib::error() << "Cannot decrypt log for upgrading." - " The encrypted log was created" - " before MariaDB 10.2.2."; + sql_print_error("InnoDB: Cannot decrypt log for upgrading." + " The encrypted log was created" + " before MariaDB 10.2.2."); return DB_ERROR; } else { - ib::error() << NO_UPGRADE_RECOVERY_MSG << "."; - return(DB_ERROR); + sql_print_error("%s. You must start up and shut down" + " MariaDB 10.1 or MySQL 5.6 or earlier" + " on the data directory.", + NO_UPGRADE_RECOVERY_MSG); + return DB_ERROR; } /* Mark the redo log for upgrading. */ From 1e8189fceed795a16d31f484f844b7a4a048b920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 10:55:22 +0200 Subject: [PATCH 25/38] MDEV-13564 follow-up: Correct a bogus comment This fixes up commit e3c39c0be82e69acb813e7c5e0f2aea7d5546e31 --- storage/innobase/ibuf/ibuf0ibuf.cc | 2 +- storage/innobase/include/ibuf0ibuf.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index dbb19bec7a0..38f6a50f7bb 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -4661,7 +4661,7 @@ reset_bit: } /** Delete all change buffer entries for a tablespace, -in DISCARD TABLESPACE, IMPORT TABLESPACE, or crash recovery. +in DISCARD TABLESPACE, IMPORT TABLESPACE, or read-ahead. @param[in] space missing or to-be-discarded tablespace */ void ibuf_delete_for_discarded_space(ulint space) { diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h index 73f7054c9fb..79f9c7b1c07 100644 --- a/storage/innobase/include/ibuf0ibuf.h +++ b/storage/innobase/include/ibuf0ibuf.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2019, MariaDB Corporation. +Copyright (c) 2016, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -338,7 +338,7 @@ void ibuf_merge_or_delete_for_page(buf_block_t *block, const page_id_t page_id, ulint zip_size); /** Delete all change buffer entries for a tablespace, -in DISCARD TABLESPACE, IMPORT TABLESPACE, or crash recovery. +in DISCARD TABLESPACE, IMPORT TABLESPACE, or read-ahead. @param[in] space missing or to-be-discarded tablespace */ void ibuf_delete_for_discarded_space(ulint space); From 49a0ad695b83f98993e068d89c02bdcc15724a71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 11:24:49 +0200 Subject: [PATCH 26/38] MDEV-23371: Crash in _db_doprnt_ via que_thr_step() Something appears to be broken in the DBUG subsystem. Let us remove frequent calls to it from the InnoDB internal SQL interpreter that is used in the purge of transaction history. The DBUG_PRINT in que_eval_sql() can remain for now, because those operations are much less frequent. --- storage/innobase/que/que0que.cc | 76 +-------------------------------- 1 file changed, 2 insertions(+), 74 deletions(-) diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc index 67da45a64e4..91e44adbdee 100644 --- a/storage/innobase/que/que0que.cc +++ b/storage/innobase/que/que0que.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2021, MariaDB Corporation. +Copyright (c) 2017, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -402,17 +402,10 @@ que_graph_free_recursive( ind_node_t* cre_ind; purge_node_t* purge; - DBUG_ENTER("que_graph_free_recursive"); - if (node == NULL) { - - DBUG_VOID_RETURN; + return; } - DBUG_PRINT("que_graph_free_recursive", - ("node: %p, type: " ULINTPF, node, - que_node_get_type(node))); - switch (que_node_get_type(node)) { case QUE_NODE_FORK: @@ -558,8 +551,6 @@ que_graph_free_recursive( default: ut_error; } - - DBUG_VOID_RETURN; } /**********************************************************************//** @@ -892,65 +883,6 @@ que_node_get_containing_loop_node( return(node); } -#ifndef DBUG_OFF -/** Gets information of an SQL query graph node. -@return type description */ -static MY_ATTRIBUTE((warn_unused_result, nonnull)) -const char* -que_node_type_string( -/*=================*/ - const que_node_t* node) /*!< in: query graph node */ -{ - switch (que_node_get_type(node)) { - case QUE_NODE_SELECT: - return("SELECT"); - case QUE_NODE_INSERT: - return("INSERT"); - case QUE_NODE_UPDATE: - return("UPDATE"); - case QUE_NODE_WHILE: - return("WHILE"); - case QUE_NODE_ASSIGNMENT: - return("ASSIGNMENT"); - case QUE_NODE_IF: - return("IF"); - case QUE_NODE_FETCH: - return("FETCH"); - case QUE_NODE_OPEN: - return("OPEN"); - case QUE_NODE_PROC: - return("STORED PROCEDURE"); - case QUE_NODE_FUNC: - return("FUNCTION"); - case QUE_NODE_LOCK: - return("LOCK"); - case QUE_NODE_THR: - return("QUERY THREAD"); - case QUE_NODE_COMMIT: - return("COMMIT"); - case QUE_NODE_UNDO: - return("UNDO ROW"); - case QUE_NODE_PURGE: - return("PURGE ROW"); - case QUE_NODE_ROLLBACK: - return("ROLLBACK"); - case QUE_NODE_CREATE_TABLE: - return("CREATE TABLE"); - case QUE_NODE_CREATE_INDEX: - return("CREATE INDEX"); - case QUE_NODE_FOR: - return("FOR LOOP"); - case QUE_NODE_RETURN: - return("RETURN"); - case QUE_NODE_EXIT: - return("EXIT"); - default: - ut_ad(0); - return("UNKNOWN NODE TYPE"); - } -} -#endif /* !DBUG_OFF */ - /**********************************************************************//** Performs an execution step on a query thread. @return query thread to run next: it may differ from the input @@ -978,10 +910,6 @@ que_thr_step( old_thr = thr; - DBUG_PRINT("ib_que", ("Execute %u (%s) at %p", - unsigned(type), que_node_type_string(node), - (const void*) node)); - if (type & QUE_NODE_CONTROL_STAT) { if ((thr->prev_node != que_node_get_parent(node)) && que_node_get_next(thr->prev_node)) { From b737d09dbc6ab588f1b1a61bb98e33ed8000acd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 11:37:43 +0200 Subject: [PATCH 27/38] MDEV-29905 Change buffer operations fail to check for log file overflow Every operation that is going to write redo log is supposed to invoke log_free_check() before acquiring any latches. If there is a risk of log buffer overrun, a log checkpoint would be triggered by that call. ibuf_merge_space(), ibuf_merge_in_background(), ibuf_delete_for_discarded_space(): Invoke log_free_check() when the current thread is not holding any page latches. Unfortunately, in lower-level code called from ibuf_insert() or ibuf_merge_or_delete_for_page(), some page latches may be held and a call to log_free_check() could hang. ibuf_set_bitmap_for_bulk_load(): Use the caller's mini-transaction. The caller should have invoked log_free_check() while not holding any page latches. --- storage/innobase/btr/btr0bulk.cc | 5 +-- storage/innobase/ibuf/ibuf0ibuf.cc | 46 +++++++++------------------- storage/innobase/include/ibuf0ibuf.h | 23 ++++++-------- 3 files changed, 28 insertions(+), 46 deletions(-) diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 0b53438feb7..cf14ffc5376 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -398,8 +398,9 @@ PageBulk::finish() void PageBulk::commit(bool success) { finish(); - if (success && !dict_index_is_clust(m_index) && page_is_leaf(m_page)) - ibuf_set_bitmap_for_bulk_load(m_block, innobase_fill_factor == 100); + if (success && !m_index->is_clust() && page_is_leaf(m_page)) + ibuf_set_bitmap_for_bulk_load(m_block, &m_mtr, + innobase_fill_factor == 100); m_mtr.commit(); } diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index 65abacf3fd5..ce6705ea369 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -1067,12 +1067,12 @@ bitmap page) bitmap page if the page is not one of the fixed address ibuf pages, or NULL, in which case a new transaction is created. @return TRUE if level 2 or level 3 page */ -ibool +bool ibuf_page_low( const page_id_t page_id, const page_size_t& page_size, #ifdef UNIV_DEBUG - ibool x_latch, + bool x_latch, #endif /* UNIV_DEBUG */ const char* file, unsigned line, @@ -1954,10 +1954,7 @@ ibuf_data_too_much_free(void) Allocates a new page from the ibuf file segment and adds it to the free list. @return TRUE on success, FALSE if no space left */ -static -ibool -ibuf_add_free_page(void) -/*====================*/ +static bool ibuf_add_free_page() { mtr_t mtr; page_t* header_page; @@ -1966,7 +1963,7 @@ ibuf_add_free_page(void) page_t* root; page_t* bitmap_page; - mtr_start(&mtr); + mtr.start(); /* Acquire the fsp latch before the ibuf header, obeying the latching order */ mtr_x_lock_space(fil_system.sys_space, &mtr); @@ -1987,9 +1984,8 @@ ibuf_add_free_page(void) &mtr); if (block == NULL) { - mtr_commit(&mtr); - - return(FALSE); + mtr.commit(); + return false; } ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1); @@ -2023,8 +2019,7 @@ ibuf_add_free_page(void) IBUF_BITMAP_IBUF, TRUE, &mtr); ibuf_mtr_commit(&mtr); - - return(TRUE); + return true; } /*********************************************************************//** @@ -2520,6 +2515,7 @@ ibuf_merge_space( ut_ad(space < SRV_LOG_SPACE_FIRST_ID); + log_free_check(); ibuf_mtr_start(&mtr); /* Position the cursor on the first matching record. */ @@ -2675,6 +2671,8 @@ ibuf_merge_in_background( #endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */ while (sum_pages < n_pages) { + log_free_check(); + ulint n_bytes; n_bytes = ibuf_merge(&n_pag2, false); @@ -4729,6 +4727,7 @@ ibuf_delete_for_discarded_space( memset(dops, 0, sizeof(dops)); loop: + log_free_check(); ibuf_mtr_start(&mtr); /* Position pcur in the insert buffer at the first entry for the @@ -4886,9 +4885,6 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) } mtr_start(&mtr); - - mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO); - ibuf_enter(&mtr); bitmap_page = ibuf_bitmap_get_map_page( @@ -4978,36 +4974,24 @@ dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) return(DB_SUCCESS); } -/** Updates free bits and buffered bits for bulk loaded page. -@param[in] block index page -@param[in] reset flag if reset free val */ -void -ibuf_set_bitmap_for_bulk_load( - buf_block_t* block, - bool reset) +void ibuf_set_bitmap_for_bulk_load(buf_block_t *block, mtr_t *mtr, bool reset) { page_t* bitmap_page; - mtr_t mtr; ulint free_val; ut_a(page_is_leaf(buf_block_get_frame(block))); free_val = ibuf_index_page_calc_free(block); - mtr_start(&mtr); - mtr.set_named_space_id(block->page.id.space()); - bitmap_page = ibuf_bitmap_get_map_page(block->page.id, - block->page.size, &mtr); + block->page.size, mtr); free_val = reset ? 0 : ibuf_index_page_calc_free(block); ibuf_bitmap_page_set_bits( bitmap_page, block->page.id, block->page.size, - IBUF_BITMAP_FREE, free_val, &mtr); + IBUF_BITMAP_FREE, free_val, mtr); ibuf_bitmap_page_set_bits( bitmap_page, block->page.id, block->page.size, - IBUF_BITMAP_BUFFERED, FALSE, &mtr); - - mtr_commit(&mtr); + IBUF_BITMAP_BUFFERED, FALSE, mtr); } diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h index f9d9ab27549..94fd56c62d6 100644 --- a/storage/innobase/include/ibuf0ibuf.h +++ b/storage/innobase/include/ibuf0ibuf.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2016, 2019, MariaDB Corporation. +Copyright (c) 2016, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -261,12 +261,12 @@ bitmap page) bitmap page if the page is not one of the fixed address ibuf pages, or NULL, in which case a new transaction is created. @return TRUE if level 2 or level 3 page */ -ibool +bool ibuf_page_low( const page_id_t page_id, const page_size_t& page_size, #ifdef UNIV_DEBUG - ibool x_latch, + bool x_latch, #endif /* UNIV_DEBUG */ const char* file, unsigned line, @@ -274,7 +274,6 @@ ibuf_page_low( MY_ATTRIBUTE((warn_unused_result)); #ifdef UNIV_DEBUG - /** Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. Must not be called when recv_no_ibuf_operations==true. @param[in] page_id tablespace/page identifier @@ -284,7 +283,7 @@ Must not be called when recv_no_ibuf_operations==true. # define ibuf_page(page_id, page_size, mtr) \ ibuf_page_low(page_id, page_size, TRUE, __FILE__, __LINE__, mtr) -#else /* UVIV_DEBUG */ +#else /* UNIV_DEBUG */ /** Checks if a page is a level 2 or 3 page in the ibuf hierarchy of pages. Must not be called when recv_no_ibuf_operations==true. @@ -295,7 +294,7 @@ Must not be called when recv_no_ibuf_operations==true. # define ibuf_page(page_id, page_size, mtr) \ ibuf_page_low(page_id, page_size, __FILE__, __LINE__, mtr) -#endif /* UVIV_DEBUG */ +#endif /* UNIV_DEBUG */ /***********************************************************************//** Frees excess pages from the ibuf free list. This function is called when an OS thread calls fsp services to allocate a new file segment, or a new page to a @@ -418,13 +417,11 @@ ibuf_close(void); dberr_t ibuf_check_bitmap_on_import(const trx_t* trx, fil_space_t* space) MY_ATTRIBUTE((nonnull, warn_unused_result)); -/** Updates free bits and buffered bits for bulk loaded page. -@param[in] block index page -@param]in] reset flag if reset free val */ -void -ibuf_set_bitmap_for_bulk_load( - buf_block_t* block, - bool reset); +/** Update free bits and buffered bits for bulk loaded page. +@param block secondary index leaf page +@param mtr mini-transaction +@param reset whether the page is full */ +void ibuf_set_bitmap_for_bulk_load(buf_block_t *block, mtr_t *mtr, bool reset); #define IBUF_HEADER_PAGE_NO FSP_IBUF_HEADER_PAGE_NO #define IBUF_TREE_ROOT_PAGE_NO FSP_IBUF_TREE_ROOT_PAGE_NO From 689e951227af5ab65be83c4d07434bd27f3c0925 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 31 Oct 2022 13:34:25 +0530 Subject: [PATCH 28/38] MDEV-29518 ASAN Failure on i_s query when tablespace does rename operation - InnoDB information schema query access the tablespace name after getting freed by concurrent rename operation. To avoid this, InnoDB should take exclusive tablespace latch during rename operation and I_S query should take shared tablespace latch before accessing the name --- storage/innobase/dict/dict0dict.cc | 2 ++ storage/innobase/handler/i_s.cc | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index b74cd043439..43ccf8c4d09 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -1488,6 +1488,7 @@ dict_table_t::rename_tablespace(span new_name, bool replace) const err= DB_TABLESPACE_EXISTS; else { + space->x_lock(); err= space->rename(path, true, replace); if (data_dir) { @@ -1495,6 +1496,7 @@ dict_table_t::rename_tablespace(span new_name, bool replace) const new_name= {name.m_name, strlen(name.m_name)}; RemoteDatafile::delete_link_file(new_name); } + space->x_unlock(); } ut_free(path); diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc index 82b8968876f..bb2f1b6beda 100644 --- a/storage/innobase/handler/i_s.cc +++ b/storage/innobase/handler/i_s.cc @@ -6491,7 +6491,9 @@ static int i_s_sys_tablespaces_fill_table(THD *thd, TABLE_LIST *tables, Item*) { space.reacquire(); mysql_mutex_unlock(&fil_system.mutex); + space.s_lock(); err= i_s_sys_tablespaces_fill(thd, space, tables->table); + space.s_unlock(); mysql_mutex_lock(&fil_system.mutex); space.release(); if (err) @@ -6719,8 +6721,10 @@ i_s_tablespaces_encryption_fill_table( && !space.is_stopping()) { space.reacquire(); mysql_mutex_unlock(&fil_system.mutex); + space.s_lock(); err = i_s_dict_fill_tablespaces_encryption( thd, &space, tables->table); + space.s_unlock(); mysql_mutex_lock(&fil_system.mutex); space.release(); if (err) { From db85d8b0931f2ca170b2257695fc35acd58d6a57 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 3 Nov 2022 18:47:14 +0530 Subject: [PATCH 29/38] MDEV-29853 Assertion `!strstr(table->name.m_name, "/FTS_") || purge_sys.must_wait_FTS()' failed in trx_t::commit - Failing debug assertion is to indicate whether the purge thread is waiting when fts auxilary table is being dropped. But assertion fails if the table name contains FTS_. So in fts_drop_table(), InnoDB sets the auxilary table flag in transaction modified table list. --- storage/innobase/dict/drop.cc | 3 +-- storage/innobase/fts/fts0fts.cc | 7 +++++++ storage/innobase/include/trx0trx.h | 10 ++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/storage/innobase/dict/drop.cc b/storage/innobase/dict/drop.cc index edb6add0787..9013841ba5e 100644 --- a/storage/innobase/dict/drop.cc +++ b/storage/innobase/dict/drop.cc @@ -267,8 +267,7 @@ void trx_t::commit(std::vector &deleted) if (btr_defragment_active) btr_defragment_remove_table(table); const fil_space_t *space= table->space; - ut_ad(!strstr(table->name.m_name, "/FTS_") || - purge_sys.must_wait_FTS()); + ut_ad(!p.second.is_aux_table() || purge_sys.must_wait_FTS()); dict_sys.remove(table); if (const auto id= space ? space->id : 0) { diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 31c6523c700..efa15251bbe 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -1373,6 +1373,13 @@ static dberr_t fts_drop_table(trx_t *trx, const char *table_name, bool rename) return err; } +#ifdef UNIV_DEBUG + for (auto &p : trx->mod_tables) + { + if (p.first == table) + p.second.set_aux_table(); + } +#endif /* UNIV_DEBUG */ return DB_SUCCESS; } diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h index 2f8bee1bc4d..ad941b89691 100644 --- a/storage/innobase/include/trx0trx.h +++ b/storage/innobase/include/trx0trx.h @@ -429,6 +429,10 @@ class trx_mod_table_time_t /** First modification of a system versioned column (NONE= no versioning, BULK= the table was dropped) */ undo_no_t first_versioned= NONE; +#ifdef UNIV_DEBUG + /** Whether the modified table is a FTS auxiliary table */ + bool fts_aux_table= false; +#endif /* UNIV_DEBUG */ public: /** Constructor @param rows number of modified rows so far */ @@ -483,6 +487,12 @@ public: first_versioned= NONE; return false; } + +#ifdef UNIV_DEBUG + void set_aux_table() { fts_aux_table= true; } + + bool is_aux_table() const { return fts_aux_table; } +#endif /* UNIV_DEBUG */ }; /** Collection of persistent tables and their first modification From f4519fb772b2c2c0a6dcb0b93cb147e5dc1627b2 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Mon, 7 Nov 2022 17:14:07 +0530 Subject: [PATCH 30/38] MDEV-28797 Assertion `page_rec_is_user_rec(rec)' failed in PageBulk::getSplitRec - During alter operation of compressed table, page split operation chooses the first record of the page as split record and it leads to empty left page. This issue caused by the commit 77b3959b5c1528f33ada7aa4445cccf5b5e197b0 (MDEV-28457). page_rec_is_second(), page_rec_is_second_last(): Removed the functions since it is a deadcode. --- storage/innobase/btr/btr0bulk.cc | 2 +- storage/innobase/include/page0page.h | 22 ----------------- storage/innobase/include/page0page.inl | 34 -------------------------- 3 files changed, 1 insertion(+), 57 deletions(-) diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 3d5a0c2fb00..5fd07ed6d79 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -634,7 +634,7 @@ PageBulk::getSplitRec() < total_used_size / 2); /* Keep at least one record on left page */ - if (page_rec_is_second(rec, m_page)) { + if (page_rec_is_first(rec, m_page)) { rec = page_rec_get_next(rec); ut_ad(page_rec_is_user_rec(rec)); } diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index b0e2eb98d01..0ad42474f84 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -794,17 +794,6 @@ page_rec_is_first( const page_t* page) /*!< in: page */ MY_ATTRIBUTE((warn_unused_result)); -/************************************************************//** -true if the record is the second user record on a page. -@return true if the second user record */ -UNIV_INLINE -bool -page_rec_is_second( -/*===============*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ - MY_ATTRIBUTE((warn_unused_result)); - /************************************************************//** true if the record is the last user record on a page. @return true if the last user record */ @@ -816,17 +805,6 @@ page_rec_is_last( const page_t* page) /*!< in: page */ MY_ATTRIBUTE((warn_unused_result)); -/************************************************************//** -true if the record is the second last user record on a page. -@return true if the second last user record */ -UNIV_INLINE -bool -page_rec_is_second_last( -/*====================*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ - MY_ATTRIBUTE((warn_unused_result)); - /************************************************************//** Returns the maximum combined size of records which can be inserted on top of record heap. diff --git a/storage/innobase/include/page0page.inl b/storage/innobase/include/page0page.inl index 61c1b96ff79..6c0167edcf9 100644 --- a/storage/innobase/include/page0page.inl +++ b/storage/innobase/include/page0page.inl @@ -192,22 +192,6 @@ page_rec_is_first( return(page_rec_get_next_const(page_get_infimum_rec(page)) == rec); } -/************************************************************//** -true if the record is the second user record on a page. -@return true if the second user record */ -UNIV_INLINE -bool -page_rec_is_second( -/*===============*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ -{ - ut_ad(page_get_n_recs(page) > 1); - if (const rec_t *first= page_rec_get_next_const(page_get_infimum_rec(page))) - return page_rec_get_next_const(first) == rec; - return false; -} - /************************************************************//** true if the record is the last user record on a page. @return true if the last user record */ @@ -223,24 +207,6 @@ page_rec_is_last( return(page_rec_get_next_const(rec) == page_get_supremum_rec(page)); } -/************************************************************//** -true if the record is the second last user record on a page. -@return true if the second last user record */ -UNIV_INLINE -bool -page_rec_is_second_last( -/*====================*/ - const rec_t* rec, /*!< in: record */ - const page_t* page) /*!< in: page */ -{ - ut_ad(page_get_n_recs(page) > 1); - ut_ad(!page_rec_is_last(rec, page)); - - if (const rec_t *next= page_rec_get_next_const(rec)) - return page_rec_is_supremum(page_rec_get_next_const(next)); - return false; -} - /************************************************************//** Returns the middle record of the records on the page. If there is an even number of records in the list, returns the first record of the From 2ef2e2322a03b6decf4ad00721a27e6dc308847f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 15:26:34 +0200 Subject: [PATCH 31/38] MDEV-29856 heap-use-after-poison in row_merge_spatial_rows() w/ column prefix spatial_index_info: Replaces index_tuple_info_t. Always take a memory heap as a parameter to the member functions. Remove pointer indirection for m_dtuple_vec. spatial_index_info::add(): Duplicate any PRIMARY KEY fields that would point to within ext->buf because that buffer will be allocated in a shorter-lifetime memory heap. --- .../innodb_gis/r/alter_spatial_index.result | 10 ++ .../innodb_gis/t/alter_spatial_index.test | 12 ++ storage/innobase/row/row0merge.cc | 168 +++++++----------- 3 files changed, 90 insertions(+), 100 deletions(-) diff --git a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result index e6ac128bf9f..26c35d0c49f 100644 --- a/mysql-test/suite/innodb_gis/r/alter_spatial_index.result +++ b/mysql-test/suite/innodb_gis/r/alter_spatial_index.result @@ -794,4 +794,14 @@ ENGINE=InnoDB; INSERT INTO t VALUES (REPEAT('MariaDB Corporation Ab ',351),POINT(0,0)); ALTER TABLE t FORCE; DROP TABLE t; +# +# MDEV-29856 heap-use-after-poison in row_merge_spatial_rows() +# with PRIMARY KEY on column prefix +# +CREATE TABLE t (id INT, f TEXT, s POINT NOT NULL, +PRIMARY KEY(id,f(1)), SPATIAL(s)) ENGINE=InnoDB; +INSERT INTO t VALUES +(1,REPEAT('x',8192),@p:=ST_GeomFromText('POINT(0 0)')),(2,'',@p); +ALTER TABLE t FORCE; +DROP TABLE t; # End of 10.3 tests diff --git a/mysql-test/suite/innodb_gis/t/alter_spatial_index.test b/mysql-test/suite/innodb_gis/t/alter_spatial_index.test index 4cfa1daf657..5c110e13fb6 100644 --- a/mysql-test/suite/innodb_gis/t/alter_spatial_index.test +++ b/mysql-test/suite/innodb_gis/t/alter_spatial_index.test @@ -793,4 +793,16 @@ ALTER TABLE t FORCE; # Cleanup DROP TABLE t; +--echo # +--echo # MDEV-29856 heap-use-after-poison in row_merge_spatial_rows() +--echo # with PRIMARY KEY on column prefix +--echo # + +CREATE TABLE t (id INT, f TEXT, s POINT NOT NULL, + PRIMARY KEY(id,f(1)), SPATIAL(s)) ENGINE=InnoDB; +INSERT INTO t VALUES +(1,REPEAT('x',8192),@p:=ST_GeomFromText('POINT(0 0)')),(2,'',@p); +ALTER TABLE t FORCE; +DROP TABLE t; + --echo # End of 10.3 tests diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 3d729b54f7c..7bd15177dad 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -60,63 +60,48 @@ Completed by Sunny Bains and Marko Makela /* Whether to disable file system cache */ char srv_disable_sort_file_cache; -/** Class that caches index row tuples made from a single cluster +/** Class that caches spatial index row tuples made from a single cluster index page scan, and then insert into corresponding index tree */ -class index_tuple_info_t { +class spatial_index_info { public: - /** constructor - @param[in] heap memory heap - @param[in] index index to be created */ - index_tuple_info_t( - mem_heap_t* heap, - dict_index_t* index) UNIV_NOTHROW - { - m_heap = heap; - m_index = index; - m_dtuple_vec = UT_NEW_NOKEY(idx_tuple_vec()); - } + /** constructor + @param index spatial index to be created */ + spatial_index_info(dict_index_t *index) : index(index) + { + ut_ad(index->is_spatial()); + } - /** destructor */ - ~index_tuple_info_t() - { - UT_DELETE(m_dtuple_vec); - } - - /** Get the index object - @return the index object */ - dict_index_t* get_index() UNIV_NOTHROW - { - return(m_index); - } - - /** Caches an index row into index tuple vector - @param[in] row table row - @param[in] ext externally stored column - prefixes, or NULL */ - void add( - const dtuple_t* row, - const row_ext_t* ext) UNIV_NOTHROW - { - dtuple_t* dtuple; - - dtuple = row_build_index_entry(row, ext, m_index, m_heap); - - ut_ad(dtuple); - - m_dtuple_vec->push_back(dtuple); - } + /** Caches an index row into index tuple vector + @param[in] row table row + @param[in] ext externally stored column prefixes, or NULL */ + void add(const dtuple_t *row, const row_ext_t *ext, mem_heap_t *heap) + { + dtuple_t *dtuple= row_build_index_entry(row, ext, index, heap); + ut_ad(dtuple); + ut_ad(dtuple->n_fields == index->n_fields); + if (ext) + { + /* Replace any references to ext, because ext will be allocated + from row_heap. */ + for (ulint i= 1; i < dtuple->n_fields; i++) + { + dfield_t &dfield= dtuple->fields[i]; + if (dfield.data >= ext->buf && + dfield.data <= &ext->buf[ext->n_ext * ext->max_len]) + dfield_dup(&dfield, heap); + } + } + m_dtuple_vec.push_back(dtuple); + } /** Insert spatial index rows cached in vector into spatial index @param[in] trx_id transaction id - @param[in,out] row_heap memory heap @param[in] pcur cluster index scanning cursor + @param[in,out] heap temporary memory heap @param[in,out] scan_mtr mini-transaction for pcur @return DB_SUCCESS if successful, else error number */ - inline dberr_t insert( - trx_id_t trx_id, - mem_heap_t* row_heap, - btr_pcur_t* pcur, - mtr_t* scan_mtr) + inline dberr_t insert(trx_id_t trx_id, btr_pcur_t* pcur, + mem_heap_t* heap, mtr_t* scan_mtr) { big_rec_t* big_rec; rec_t* rec; @@ -130,14 +115,12 @@ public: | BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG | BTR_CREATE_FLAG; - ut_ad(dict_index_is_spatial(m_index)); - DBUG_EXECUTE_IF("row_merge_instrument_log_check_flush", log_sys.check_flush_or_checkpoint = true; ); - for (idx_tuple_vec::iterator it = m_dtuple_vec->begin(); - it != m_dtuple_vec->end(); + for (idx_tuple_vec::iterator it = m_dtuple_vec.begin(); + it != m_dtuple_vec.end(); ++it) { dtuple = *it; ut_ad(dtuple); @@ -153,14 +136,14 @@ public: } mtr.start(); - m_index->set_modified(mtr); + index->set_modified(mtr); - ins_cur.index = m_index; - rtr_init_rtr_info(&rtr_info, false, &ins_cur, m_index, + ins_cur.index = index; + rtr_init_rtr_info(&rtr_info, false, &ins_cur, index, false); rtr_info_update_btr(&ins_cur, &rtr_info); - btr_cur_search_to_nth_level(m_index, 0, dtuple, + btr_cur_search_to_nth_level(index, 0, dtuple, PAGE_CUR_RTREE_INSERT, BTR_MODIFY_LEAF, &ins_cur, __FILE__, __LINE__, @@ -169,44 +152,44 @@ public: /* It need to update MBR in parent entry, so change search mode to BTR_MODIFY_TREE */ if (rtr_info.mbr_adj) { - mtr_commit(&mtr); + mtr.commit(); rtr_clean_rtr_info(&rtr_info, true); rtr_init_rtr_info(&rtr_info, false, &ins_cur, - m_index, false); + index, false); rtr_info_update_btr(&ins_cur, &rtr_info); - mtr_start(&mtr); - m_index->set_modified(mtr); + mtr.start(); + index->set_modified(mtr); btr_cur_search_to_nth_level( - m_index, 0, dtuple, + index, 0, dtuple, PAGE_CUR_RTREE_INSERT, BTR_MODIFY_TREE, &ins_cur, __FILE__, __LINE__, &mtr); } error = btr_cur_optimistic_insert( - flag, &ins_cur, &ins_offsets, &row_heap, + flag, &ins_cur, &ins_offsets, &heap, dtuple, &rec, &big_rec, 0, NULL, &mtr); if (error == DB_FAIL) { ut_ad(!big_rec); mtr.commit(); mtr.start(); - m_index->set_modified(mtr); + index->set_modified(mtr); rtr_clean_rtr_info(&rtr_info, true); rtr_init_rtr_info(&rtr_info, false, - &ins_cur, m_index, false); + &ins_cur, index, false); rtr_info_update_btr(&ins_cur, &rtr_info); btr_cur_search_to_nth_level( - m_index, 0, dtuple, + index, 0, dtuple, PAGE_CUR_RTREE_INSERT, BTR_MODIFY_TREE, &ins_cur, __FILE__, __LINE__, &mtr); error = btr_cur_pessimistic_insert( flag, &ins_cur, &ins_offsets, - &row_heap, dtuple, &rec, + &heap, dtuple, &rec, &big_rec, 0, NULL, &mtr); } @@ -229,30 +212,26 @@ public: } } - mtr_commit(&mtr); + mtr.commit(); rtr_clean_rtr_info(&rtr_info, true); } - m_dtuple_vec->clear(); + m_dtuple_vec.clear(); return(error); } private: - /** Cache index rows made from a cluster index scan. Usually - for rows on single cluster index page */ - typedef std::vector > - idx_tuple_vec; + /** Cache index rows made from a cluster index scan. Usually + for rows on single cluster index page */ + typedef std::vector > idx_tuple_vec; - /** vector used to cache index rows made from cluster index scan */ - idx_tuple_vec* m_dtuple_vec; - - /** the index being built */ - dict_index_t* m_index; - - /** memory heap for creating index tuples */ - mem_heap_t* m_heap; + /** vector used to cache index rows made from cluster index scan */ + idx_tuple_vec m_dtuple_vec; +public: + /** the index being built */ + dict_index_t*const index; }; /* Maximum pending doc memory limit in bytes for a fts tokenization thread */ @@ -1566,7 +1545,6 @@ row_mtuple_cmp( @param[in] trx_id transaction id @param[in] sp_tuples cached spatial rows @param[in] num_spatial number of spatial indexes -@param[in,out] row_heap heap for insert @param[in,out] sp_heap heap for tuples @param[in,out] pcur cluster index cursor @param[in,out] mtr mini transaction @@ -1575,9 +1553,8 @@ static dberr_t row_merge_spatial_rows( trx_id_t trx_id, - index_tuple_info_t** sp_tuples, + spatial_index_info** sp_tuples, ulint num_spatial, - mem_heap_t* row_heap, mem_heap_t* sp_heap, btr_pcur_t* pcur, mtr_t* mtr) @@ -1591,7 +1568,7 @@ row_merge_spatial_rows( ut_ad(sp_heap != NULL); for (ulint j = 0; j < num_spatial; j++) { - err = sp_tuples[j]->insert(trx_id, row_heap, pcur, mtr); + err = sp_tuples[j]->insert(trx_id, pcur, sp_heap, mtr); if (err != DB_SUCCESS) { return(err); @@ -1714,8 +1691,7 @@ row_merge_read_clustered_index( os_event_t fts_parallel_sort_event = NULL; ibool fts_pll_sort = FALSE; int64_t sig_count = 0; - index_tuple_info_t** sp_tuples = NULL; - mem_heap_t* sp_heap = NULL; + spatial_index_info** sp_tuples = NULL; ulint num_spatial = 0; BtrBulk* clust_btr_bulk = NULL; bool clust_temp_file = false; @@ -1805,9 +1781,7 @@ row_merge_read_clustered_index( if (num_spatial > 0) { ulint count = 0; - sp_heap = mem_heap_create(512); - - sp_tuples = static_cast( + sp_tuples = static_cast( ut_malloc_nokey(num_spatial * sizeof(*sp_tuples))); @@ -1815,9 +1789,7 @@ row_merge_read_clustered_index( if (dict_index_is_spatial(index[i])) { sp_tuples[count] = UT_NEW_NOKEY( - index_tuple_info_t( - sp_heap, - index[i])); + spatial_index_info(index[i])); count++; } } @@ -1948,7 +1920,7 @@ row_merge_read_clustered_index( /* Insert the cached spatial index rows. */ err = row_merge_spatial_rows( trx->id, sp_tuples, num_spatial, - row_heap, sp_heap, &pcur, &mtr); + row_heap, &pcur, &mtr); if (err != DB_SUCCESS) { goto func_exit; @@ -2329,7 +2301,7 @@ write_buffers: continue; } - ut_ad(sp_tuples[s_idx_cnt]->get_index() + ut_ad(sp_tuples[s_idx_cnt]->index == buf->index); /* If the geometry field is invalid, report @@ -2339,7 +2311,7 @@ write_buffers: break; } - sp_tuples[s_idx_cnt]->add(row, ext); + sp_tuples[s_idx_cnt]->add(row, ext, buf->heap); s_idx_cnt++; continue; @@ -2469,7 +2441,7 @@ write_buffers: err = row_merge_spatial_rows( trx->id, sp_tuples, num_spatial, - row_heap, sp_heap, + row_heap, &pcur, &mtr); if (err != DB_SUCCESS) { @@ -2847,10 +2819,6 @@ wait_again: UT_DELETE(sp_tuples[i]); } ut_free(sp_tuples); - - if (sp_heap) { - mem_heap_free(sp_heap); - } } /* Update the next Doc ID we used. Table should be locked, so From 12f20c154d24b2d29b29bdd1fbbd03ee3b6f5697 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 16:04:16 +0200 Subject: [PATCH 32/38] Work around MDEV-24813 in main.rowid_filter_innodb_debug Let us avoid excessive allocation of explicit record locks. --- mysql-test/include/rowid_filter_debug_kill.inc | 18 ++++++------------ .../main/rowid_filter_innodb_debug.result | 15 +++++---------- mysql-test/main/rowid_filter_innodb_debug.test | 1 - .../main/rowid_filter_myisam_debug.result | 14 +++++--------- 4 files changed, 16 insertions(+), 32 deletions(-) diff --git a/mysql-test/include/rowid_filter_debug_kill.inc b/mysql-test/include/rowid_filter_debug_kill.inc index c701d206297..513efed8a4c 100644 --- a/mysql-test/include/rowid_filter_debug_kill.inc +++ b/mysql-test/include/rowid_filter_debug_kill.inc @@ -1,17 +1,14 @@ --source include/have_debug.inc --source include/have_debug_sync.inc +--source include/have_sequence.inc --source include/count_sessions.inc --echo # --echo # MDEV-22761 KILL QUERY during rowid_filter, crashes --echo # -create table t0(a int); -insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); - -# 100 rows create table t2(a int); -insert into t2 select A.a + B.a* 10 from t0 A, t0 B; +insert into t2 select * from seq_0_to_99; # 10K rows CREATE TABLE t3 ( @@ -26,11 +23,10 @@ where table_schema=database() and table_name='t3'; insert into t3 select - A.a, - B.a, + A.seq, + B.seq, 'filler-data-filler-data' -from - t2 A, t2 B; +from seq_0_to_99 A, seq_0_to_99 B; analyze table t2,t3; @@ -48,7 +44,6 @@ where t3.key1=t2.a and t3.key2 in (2,3); connect (con1, localhost, root,,); -connection con1; set debug_sync='now WAIT_FOR at_rowid_filter_check'; evalp kill query $target_id; set debug_sync='now SIGNAL go'; @@ -60,6 +55,5 @@ disconnect con1; reap; set debug_sync='RESET'; -drop table t0,t2,t3; +drop table t2,t3; --source include/wait_until_count_sessions.inc - diff --git a/mysql-test/main/rowid_filter_innodb_debug.result b/mysql-test/main/rowid_filter_innodb_debug.result index f989e00919b..7741a949e7d 100644 --- a/mysql-test/main/rowid_filter_innodb_debug.result +++ b/mysql-test/main/rowid_filter_innodb_debug.result @@ -2,10 +2,8 @@ set default_storage_engine=innodb; # # MDEV-22761 KILL QUERY during rowid_filter, crashes # -create table t0(a int); -insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t2(a int); -insert into t2 select A.a + B.a* 10 from t0 A, t0 B; +insert into t2 select * from seq_0_to_99; CREATE TABLE t3 ( key1 int , key2 int, @@ -19,11 +17,10 @@ engine InnoDB insert into t3 select -A.a, -B.a, +A.seq, +B.seq, 'filler-data-filler-data' -from -t2 A, t2 B; +from seq_0_to_99 A, seq_0_to_99 B; analyze table t2,t3; Table Op Msg_type Msg_text test.t2 analyze status Engine-independent statistics collected @@ -42,7 +39,6 @@ select * from t2, t3 where t3.key1=t2.a and t3.key2 in (2,3); connect con1, localhost, root,,; -connection con1; set debug_sync='now WAIT_FOR at_rowid_filter_check'; kill query $target_id; set debug_sync='now SIGNAL go'; @@ -50,7 +46,7 @@ connection default; disconnect con1; ERROR 70100: Query execution was interrupted set debug_sync='RESET'; -drop table t0,t2,t3; +drop table t2,t3; set default_storage_engine=default; set @save_optimizer_switch= @@optimizer_switch; set @save_use_stat_tables= @@use_stat_tables; @@ -77,7 +73,6 @@ test.t1 analyze status OK set debug_sync='handler_rowid_filter_check SIGNAL killme WAIT_FOR go'; SELECT * FROM t1 WHERE a > 0 AND b=0; connect con1, localhost, root,,; -connection con1; set debug_sync='now WAIT_FOR killme'; kill query @id; set debug_sync='now SIGNAL go'; diff --git a/mysql-test/main/rowid_filter_innodb_debug.test b/mysql-test/main/rowid_filter_innodb_debug.test index 74deaa8ccc9..6353ffa335e 100644 --- a/mysql-test/main/rowid_filter_innodb_debug.test +++ b/mysql-test/main/rowid_filter_innodb_debug.test @@ -39,7 +39,6 @@ set debug_sync='handler_rowid_filter_check SIGNAL killme WAIT_FOR go'; send SELECT * FROM t1 WHERE a > 0 AND b=0; connect (con1, localhost, root,,); -connection con1; let $ignore= `SELECT @id := $ID`; set debug_sync='now WAIT_FOR killme'; kill query @id; diff --git a/mysql-test/main/rowid_filter_myisam_debug.result b/mysql-test/main/rowid_filter_myisam_debug.result index 32a989f50da..75a8fad6947 100644 --- a/mysql-test/main/rowid_filter_myisam_debug.result +++ b/mysql-test/main/rowid_filter_myisam_debug.result @@ -1,10 +1,8 @@ # # MDEV-22761 KILL QUERY during rowid_filter, crashes # -create table t0(a int); -insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9); create table t2(a int); -insert into t2 select A.a + B.a* 10 from t0 A, t0 B; +insert into t2 select * from seq_0_to_99; CREATE TABLE t3 ( key1 int , key2 int, @@ -18,11 +16,10 @@ engine MyISAM insert into t3 select -A.a, -B.a, +A.seq, +B.seq, 'filler-data-filler-data' -from -t2 A, t2 B; +from seq_0_to_99 A, seq_0_to_99 B; analyze table t2,t3; Table Op Msg_type Msg_text test.t2 analyze status Engine-independent statistics collected @@ -41,7 +38,6 @@ select * from t2, t3 where t3.key1=t2.a and t3.key2 in (2,3); connect con1, localhost, root,,; -connection con1; set debug_sync='now WAIT_FOR at_rowid_filter_check'; kill query $target_id; set debug_sync='now SIGNAL go'; @@ -49,4 +45,4 @@ connection default; disconnect con1; ERROR 70100: Query execution was interrupted set debug_sync='RESET'; -drop table t0,t2,t3; +drop table t2,t3; From 8fb176c3c1c71516f0562399d055e92686519588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 16:59:36 +0200 Subject: [PATCH 33/38] MDEV-27121 fixup: mariabackup.mdev-14447,full_crc32 --- mysql-test/suite/mariabackup/mdev-14447.combinations | 5 +++++ storage/innobase/buf/buf0buf.cc | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 mysql-test/suite/mariabackup/mdev-14447.combinations diff --git a/mysql-test/suite/mariabackup/mdev-14447.combinations b/mysql-test/suite/mariabackup/mdev-14447.combinations new file mode 100644 index 00000000000..79e5f7836ed --- /dev/null +++ b/mysql-test/suite/mariabackup/mdev-14447.combinations @@ -0,0 +1,5 @@ +[crc32] +--innodb-checksum-algorithm=crc32 + +[full_crc32] +--innodb-checksum-algorithm=full_crc32 diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index d5415d6b249..59d35ddcd5a 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -998,7 +998,7 @@ buf_page_is_corrupted( DBUG_EXECUTE_IF( "page_intermittent_checksum_mismatch", { static int page_counter; - if (page_counter++ == 2) { + if (page_counter++ == 3) { crc32++; } }); From e572c745dc04ac7659a40849abce62f39a0b09d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 17:34:34 +0200 Subject: [PATCH 34/38] MDEV-29504/MDEV-29849 TRUNCATE breaks FOREIGN KEY locking ha_innobase::referenced_by_foreign_key(): Protect the check with dict_sys.freeze(), to prevent races with TRUNCATE TABLE. The test innodb.instant_alter_crash has been adjusted for this additional locking. dict_table_is_referenced_by_foreign_key(): Removed (merged to the only caller). create_table_info_t::create_table(): Ignore missing indexes for FOREIGN KEY constraints if foreign_key_checks=0. create_table_info_t::create_table_update_dict(): Rewritten as a static function. Do not return any error. ha_innobase::create(): When trx!=nullptr and we are operating on a persistent table, do not rollback, commit, or release the data dictionary latch. ha_innobase::truncate(): Protect the entire critical section with an exclusive dict_sys.latch, so that ha_innobase::referenced_by_foreign_key() on referenced tables will return a consistent result. In case of a failure, invoke dict_load_foreigns() to restore also any FOREIGN KEY constraints. ha_innobase::free_foreign_key_create_info(): Define inline. lock_release(): Disregard innodb_evict_tables_on_commit_debug=ON when dict_sys.locked() holds. It would hold when fts_load_stopword() is invoked by create_table_info_t::create_table_update_dict(). dict_sys_t::locked(): Return whether the current thread is holding the exclusive dict_sys.latch. dict_sys_t::frozen_not_locked(): Return whether any thread is holding a shared dict_sys.latch. In the test main.mysql_upgrade, the InnoDB persistent statistics will no longer be recalculated in ha_innobase::open() as part of CHECK TABLE ... FOR UPGRADE. They were deleted earlier in the test. Tested by: Matthias Leich --- mysql-test/main/mysql_upgrade.result | 4 - .../suite/innodb/r/innodb-fkcheck.result | 8 + mysql-test/suite/innodb/r/innodb.result | 12 +- .../suite/innodb/r/instant_alter_crash.result | 16 +- .../suite/innodb/r/truncate_foreign.result | 10 + mysql-test/suite/innodb/t/innodb-fkcheck.test | 13 +- mysql-test/suite/innodb/t/innodb.test | 12 +- .../suite/innodb/t/instant_alter_crash.test | 19 +- .../suite/innodb/t/truncate_foreign.test | 11 + .../suite/innodb_fts/r/misc_debug.result | 1 - mysql-test/suite/innodb_fts/t/misc_debug.test | 1 - storage/innobase/dict/dict0dict.cc | 22 +- storage/innobase/handler/ha_innodb.cc | 702 ++++++++---------- storage/innobase/handler/ha_innodb.h | 22 +- storage/innobase/handler/handler0alter.cc | 5 +- storage/innobase/include/dict0dict.h | 25 +- storage/innobase/include/dict0load.h | 2 +- storage/innobase/lock/lock0lock.cc | 3 +- 18 files changed, 448 insertions(+), 440 deletions(-) diff --git a/mysql-test/main/mysql_upgrade.result b/mysql-test/main/mysql_upgrade.result index 34af8eb6466..b6160bd3525 100644 --- a/mysql-test/main/mysql_upgrade.result +++ b/mysql-test/main/mysql_upgrade.result @@ -1319,10 +1319,6 @@ partition p2008 values less than (2009) ); select length(table_name) from mysql.innodb_table_stats; length(table_name) -79 -79 -79 -79 drop table extralongname_extralongname_extralongname_extralongname_ext; # End of 10.0 tests set sql_mode=default; diff --git a/mysql-test/suite/innodb/r/innodb-fkcheck.result b/mysql-test/suite/innodb/r/innodb-fkcheck.result index 2c2be83a3ff..f86ba50597f 100644 --- a/mysql-test/suite/innodb/r/innodb-fkcheck.result +++ b/mysql-test/suite/innodb/r/innodb-fkcheck.result @@ -33,11 +33,19 @@ b bigint unsigned NOT NULL, d1 date NOT NULL, PRIMARY KEY (b,d1) ) ENGINE=InnoDB; +DROP TABLE b; +set foreign_key_checks = 1; +CREATE TABLE b ( +b bigint unsigned NOT NULL, +d1 date NOT NULL, +PRIMARY KEY (b,d1) +) ENGINE=InnoDB; ERROR HY000: Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed") show warnings; Level Code Message Error 1005 Can't create table `bug_fk`.`b` (errno: 150 "Foreign key constraint is incorrectly formed") Warning 1215 Cannot add foreign key constraint for `b` +set foreign_key_checks = 0; DROP TABLE IF EXISTS d; Warnings: Note 1051 Unknown table 'bug_fk.d' diff --git a/mysql-test/suite/innodb/r/innodb.result b/mysql-test/suite/innodb/r/innodb.result index edbdcd2b28e..47e5f0f5c94 100644 --- a/mysql-test/suite/innodb/r/innodb.result +++ b/mysql-test/suite/innodb/r/innodb.result @@ -2531,9 +2531,19 @@ disconnect b; set foreign_key_checks=0; create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; create table t1(a char(10) primary key, b varchar(20)) engine = innodb; -ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed") set foreign_key_checks=1; +insert into t2 values (1,1); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`)) +set foreign_key_checks=0; +drop table t1; +set foreign_key_checks=1; +insert into t2 values (1,1); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`b`) REFERENCES `t1` (`a`)) +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +ERROR HY000: Can't create table `test`.`t1` (errno: 150 "Foreign key constraint is incorrectly formed") drop table t2; +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +drop table t1; set foreign_key_checks=0; create table t1(a varchar(10) primary key) engine = innodb DEFAULT CHARSET=latin1; create table t2 (a varchar(10), foreign key (a) references t1(a)) engine = innodb DEFAULT CHARSET=utf8; diff --git a/mysql-test/suite/innodb/r/instant_alter_crash.result b/mysql-test/suite/innodb/r/instant_alter_crash.result index 843f33fddd1..f0fedcc7673 100644 --- a/mysql-test/suite/innodb/r/instant_alter_crash.result +++ b/mysql-test/suite/innodb/r/instant_alter_crash.result @@ -34,13 +34,15 @@ ROLLBACK; InnoDB 0 transactions not purged INSERT INTO t2 VALUES (16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt'); +BEGIN; +UPDATE t1 SET c2=c2+1; connect ddl, localhost, root; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; ALTER TABLE t2 DROP COLUMN c3, ADD COLUMN c5 TEXT DEFAULT 'naturam abhorrere'; connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -UPDATE t1 SET c2=c2+1; +COMMIT; # Kill the server disconnect ddl; # restart @@ -61,6 +63,8 @@ DELETE FROM t2; ROLLBACK; InnoDB 0 transactions not purged INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum'); +BEGIN; +DELETE FROM t1; connect ddl, localhost, root; ALTER TABLE t2 DROP COLUMN c3; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; @@ -68,7 +72,7 @@ ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum'); connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -DELETE FROM t1; +COMMIT; # Kill the server disconnect ddl; # restart @@ -138,6 +142,8 @@ InnoDB 0 transactions not purged # # MDEV-24323 Crash on recovery after kill during instant ADD COLUMN # +BEGIN; +INSERT INTO t1 VALUES(0,0); connect ddl, localhost, root; CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2)) ENGINE=InnoDB; @@ -147,7 +153,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi'; connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -INSERT INTO t1 VALUES(0,0); +COMMIT; # Kill the server disconnect ddl; # restart @@ -183,13 +189,15 @@ DROP TABLE t2,t3; # CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6); +BEGIN; +DELETE FROM t1; connect ddl, localhost, root; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST; connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -DELETE FROM t1; +COMMIT; # Kill the server disconnect ddl; # restart diff --git a/mysql-test/suite/innodb/r/truncate_foreign.result b/mysql-test/suite/innodb/r/truncate_foreign.result index 3154674aabf..e587baa5288 100644 --- a/mysql-test/suite/innodb/r/truncate_foreign.result +++ b/mysql-test/suite/innodb/r/truncate_foreign.result @@ -80,9 +80,19 @@ SET FOREIGN_KEY_CHECKS=0; ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY; INSERT INTO t1 VALUES (1,1); LOCK TABLES t1 WRITE; +SET FOREIGN_KEY_CHECKS=1; TRUNCATE t1; ERROR HY000: Cannot add foreign key constraint for `t1` INSERT INTO t1 VALUES (2,2); +ERROR HY000: Table 't1' was not locked with LOCK TABLES +SELECT * FROM t1; +pk a +1 1 +UNLOCK TABLES; +INSERT INTO t1 VALUES (2,2); +ERROR 23000: Cannot add or update a child row: a foreign key constraint fails (`test`.`t1`, CONSTRAINT `t1_ibfk_1` FOREIGN KEY (`a`) REFERENCES `t1` (`a`)) +SET FOREIGN_KEY_CHECKS=0; +INSERT INTO t1 VALUES (2,2); SELECT * FROM t1; pk a 1 1 diff --git a/mysql-test/suite/innodb/t/innodb-fkcheck.test b/mysql-test/suite/innodb/t/innodb-fkcheck.test index 4657edc4d65..5ff3533fce1 100644 --- a/mysql-test/suite/innodb/t/innodb-fkcheck.test +++ b/mysql-test/suite/innodb/t/innodb-fkcheck.test @@ -46,7 +46,15 @@ show create table c; # # Note that column b has different type in parent table # ---error 1005 +CREATE TABLE b ( + b bigint unsigned NOT NULL, + d1 date NOT NULL, + PRIMARY KEY (b,d1) +) ENGINE=InnoDB; +DROP TABLE b; + +set foreign_key_checks = 1; +--error ER_CANT_CREATE_TABLE CREATE TABLE b ( b bigint unsigned NOT NULL, d1 date NOT NULL, @@ -54,6 +62,7 @@ CREATE TABLE b ( ) ENGINE=InnoDB; show warnings; +set foreign_key_checks = 0; DROP TABLE IF EXISTS d; @@ -64,7 +73,7 @@ CREATE TABLE d ( CONSTRAINT bd_fk FOREIGN KEY (b) REFERENCES b (b) ) ENGINE=InnoDB; -show warnings; +show warnings; set foreign_key_checks = 1; diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test index 3a8c12dfbbd..3b3b2770df7 100644 --- a/mysql-test/suite/innodb/t/innodb.test +++ b/mysql-test/suite/innodb/t/innodb.test @@ -1598,12 +1598,22 @@ disconnect b; set foreign_key_checks=0; create table t2 (a int primary key, b int, foreign key (b) references t1(a)) engine = innodb; +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +set foreign_key_checks=1; +--error ER_NO_REFERENCED_ROW_2 +insert into t2 values (1,1); +set foreign_key_checks=0; +drop table t1; +set foreign_key_checks=1; +--error ER_NO_REFERENCED_ROW_2 +insert into t2 values (1,1); # Embedded server doesn't chdir to data directory --replace_result $MYSQLTEST_VARDIR . master-data/ '' --error ER_CANT_CREATE_TABLE create table t1(a char(10) primary key, b varchar(20)) engine = innodb; -set foreign_key_checks=1; drop table t2; +create table t1(a char(10) primary key, b varchar(20)) engine = innodb; +drop table t1; # test that FKs between different charsets are not accepted in CREATE even # when f_k_c is 0 diff --git a/mysql-test/suite/innodb/t/instant_alter_crash.test b/mysql-test/suite/innodb/t/instant_alter_crash.test index 4d211ece106..0bd983a2b4c 100644 --- a/mysql-test/suite/innodb/t/instant_alter_crash.test +++ b/mysql-test/suite/innodb/t/instant_alter_crash.test @@ -47,6 +47,9 @@ ROLLBACK; INSERT INTO t2 VALUES (16,1551,'Omnium enim rerum'),(128,1571,' principia parva sunt'); +BEGIN; +UPDATE t1 SET c2=c2+1; + connect ddl, localhost, root; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; --send @@ -55,7 +58,7 @@ ALTER TABLE t2 DROP COLUMN c3, ADD COLUMN c5 TEXT DEFAULT 'naturam abhorrere'; connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -UPDATE t1 SET c2=c2+1; +COMMIT; --source include/kill_mysqld.inc disconnect ddl; @@ -73,6 +76,8 @@ ROLLBACK; --source include/wait_all_purged.inc INSERT INTO t2 VALUES (64,42,'De finibus bonorum'), (347,33101,' et malorum'); +BEGIN; +DELETE FROM t1; connect ddl, localhost, root; ALTER TABLE t2 DROP COLUMN c3; @@ -83,7 +88,7 @@ ALTER TABLE t2 ADD COLUMN (c4 TEXT NOT NULL DEFAULT ' et malorum'); connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -DELETE FROM t1; +COMMIT; --source include/kill_mysqld.inc disconnect ddl; @@ -177,6 +182,9 @@ DELETE FROM t2; --echo # --echo # MDEV-24323 Crash on recovery after kill during instant ADD COLUMN --echo # +BEGIN; +INSERT INTO t1 VALUES(0,0); + connect ddl, localhost, root; CREATE TABLE t3(id INT PRIMARY KEY, c2 INT, v2 INT AS(c2) VIRTUAL, UNIQUE(v2)) ENGINE=InnoDB; @@ -189,7 +197,7 @@ ALTER TABLE t3 ADD COLUMN c3 TEXT NOT NULL DEFAULT 'sic transit gloria mundi'; connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -INSERT INTO t1 VALUES(0,0); +COMMIT; --source include/kill_mysqld.inc disconnect ddl; @@ -207,6 +215,9 @@ DROP TABLE t2,t3; CREATE TABLE t2(a INT UNSIGNED PRIMARY KEY) ENGINE=InnoDB; INSERT INTO t2 VALUES (1),(2),(3),(4),(5),(6); +BEGIN; +DELETE FROM t1; + connect ddl, localhost, root; SET DEBUG_SYNC='innodb_alter_inplace_before_commit SIGNAL ddl WAIT_FOR ever'; --send @@ -215,7 +226,7 @@ ALTER TABLE t2 ADD COLUMN b TINYINT UNSIGNED NOT NULL DEFAULT 42 FIRST; connection default; SET DEBUG_SYNC='now WAIT_FOR ddl'; SET GLOBAL innodb_flush_log_at_trx_commit=1; -DELETE FROM t1; +COMMIT; --source include/kill_mysqld.inc disconnect ddl; diff --git a/mysql-test/suite/innodb/t/truncate_foreign.test b/mysql-test/suite/innodb/t/truncate_foreign.test index e40029e18be..abbe1b3df87 100644 --- a/mysql-test/suite/innodb/t/truncate_foreign.test +++ b/mysql-test/suite/innodb/t/truncate_foreign.test @@ -92,8 +92,19 @@ SET FOREIGN_KEY_CHECKS=0; ALTER TABLE t1 ADD FOREIGN KEY (a) REFERENCES t1 (a), ALGORITHM=COPY; INSERT INTO t1 VALUES (1,1); LOCK TABLES t1 WRITE; +SET FOREIGN_KEY_CHECKS=1; --error ER_CANNOT_ADD_FOREIGN TRUNCATE t1; +# Whether TRUNCATE succeeds or fails, it will reload FOREIGN KEY constraints. +# As a result, ha_innobase::referenced_by_foreign_key() will retun TRUE +# (for the self-referential key), and the statement will fail. +--error ER_TABLE_NOT_LOCKED +INSERT INTO t1 VALUES (2,2); +SELECT * FROM t1; +UNLOCK TABLES; +--error ER_NO_REFERENCED_ROW_2 +INSERT INTO t1 VALUES (2,2); +SET FOREIGN_KEY_CHECKS=0; INSERT INTO t1 VALUES (2,2); SELECT * FROM t1; DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/r/misc_debug.result b/mysql-test/suite/innodb_fts/r/misc_debug.result index 18f715b9d95..11df7d89f0b 100644 --- a/mysql-test/suite/innodb_fts/r/misc_debug.result +++ b/mysql-test/suite/innodb_fts/r/misc_debug.result @@ -62,7 +62,6 @@ SET @saved_debug_dbug= @@debug_dbug; CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB; SET debug_dbug='+d,ib_create_table_fail_too_many_trx'; TRUNCATE t1; -ERROR HY000: Got error -1 "Internal error < 0 (Not system error)" from storage engine InnoDB SET debug_dbug=@saved_debug_dbug; DROP TABLE t1; # End of 10.3 tests diff --git a/mysql-test/suite/innodb_fts/t/misc_debug.test b/mysql-test/suite/innodb_fts/t/misc_debug.test index c086348b631..9246d27a704 100644 --- a/mysql-test/suite/innodb_fts/t/misc_debug.test +++ b/mysql-test/suite/innodb_fts/t/misc_debug.test @@ -91,7 +91,6 @@ SET @saved_debug_dbug= @@debug_dbug; CREATE TABLE t1 (b CHAR(12), FULLTEXT KEY(b)) engine=InnoDB; SET debug_dbug='+d,ib_create_table_fail_too_many_trx'; ---error ER_GET_ERRNO TRUNCATE t1; SET debug_dbug=@saved_debug_dbug; DROP TABLE t1; diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc index 43ccf8c4d09..362b949e10f 100644 --- a/storage/innobase/dict/dict0dict.cc +++ b/storage/innobase/dict/dict0dict.cc @@ -685,8 +685,7 @@ dict_acquire_mdl_shared(dict_table_t *table, } else { - ut_ad(dict_sys.frozen()); - ut_ad(!dict_sys.locked()); + ut_ad(dict_sys.frozen_not_locked()); db_len= dict_get_db_name_len(table->name.m_name); } @@ -1003,7 +1002,7 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) latch_ex_wait_start.store(0, std::memory_order_relaxed); ut_ad(!latch_readers); ut_ad(!latch_ex); - ut_d(latch_ex= true); + ut_d(latch_ex= pthread_self()); return; } @@ -1021,15 +1020,15 @@ void dict_sys_t::lock_wait(SRW_LOCK_ARGS(const char *file, unsigned line)) latch.wr_lock(SRW_LOCK_ARGS(file, line)); ut_ad(!latch_readers); ut_ad(!latch_ex); - ut_d(latch_ex= true); + ut_d(latch_ex= pthread_self()); } #ifdef UNIV_PFS_RWLOCK ATTRIBUTE_NOINLINE void dict_sys_t::unlock() { - ut_ad(latch_ex); + ut_ad(latch_ex == pthread_self()); ut_ad(!latch_readers); - ut_d(latch_ex= false); + ut_d(latch_ex= 0); latch.wr_unlock(); } @@ -2749,17 +2748,6 @@ dict_index_build_internal_fts( } /*====================== FOREIGN KEY PROCESSING ========================*/ -/*********************************************************************//** -Checks if a table is referenced by foreign keys. -@return TRUE if table is referenced by a foreign key */ -ibool -dict_table_is_referenced_by_foreign_key( -/*====================================*/ - const dict_table_t* table) /*!< in: InnoDB table */ -{ - return(!table->referenced_set.empty()); -} - /**********************************************************************//** Removes a foreign constraint struct from the dictionary cache. */ void diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index d2b6bd62520..b6180f51ebb 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -11473,6 +11473,8 @@ innobase_fts_load_stopword( trx_t* trx, /*!< in: transaction */ THD* thd) /*!< in: current thread */ { + ut_ad(dict_sys.locked()); + const char *stopword_table= THDVAR(thd, ft_user_stopword_table); if (!stopword_table) { @@ -11482,9 +11484,11 @@ innobase_fts_load_stopword( mysql_mutex_unlock(&LOCK_global_system_variables); } - return !high_level_read_only && - fts_load_stopword(table, trx, stopword_table, - THDVAR(thd, ft_enable_stopword), false); + table->fts->dict_locked= true; + bool success= fts_load_stopword(table, trx, stopword_table, + THDVAR(thd, ft_enable_stopword), false); + table->fts->dict_locked= false; + return success; } /** Parse the table name into normal name and remote path if needed. @@ -12820,15 +12824,18 @@ int create_table_info_t::create_table(bool create_fk) dberr_t err = create_fk ? create_foreign_keys() : DB_SUCCESS; if (err == DB_SUCCESS) { + const dict_err_ignore_t ignore_err = m_trx->check_foreigns + ? DICT_ERR_IGNORE_NONE : DICT_ERR_IGNORE_FK_NOKEY; + /* Check that also referencing constraints are ok */ dict_names_t fk_tables; err = dict_load_foreigns(m_table_name, nullptr, m_trx->id, true, - DICT_ERR_IGNORE_NONE, fk_tables); + ignore_err, fk_tables); while (err == DB_SUCCESS && !fk_tables.empty()) { dict_sys.load_table( {fk_tables.front(), strlen(fk_tables.front())}, - DICT_ERR_IGNORE_NONE); + ignore_err); fk_tables.pop_front(); } } @@ -13109,96 +13116,59 @@ bool create_table_info_t::row_size_is_acceptable( return true; } -/** Update a new table in an InnoDB database. -@return error number */ -int -create_table_info_t::create_table_update_dict() +void create_table_info_t::create_table_update_dict(dict_table_t *table, + THD *thd, + const HA_CREATE_INFO &info, + const TABLE &t) { - dict_table_t* innobase_table; + ut_ad(dict_sys.locked()); - DBUG_ENTER("create_table_update_dict"); + DBUG_ASSERT(table->get_ref_count()); + if (table->fts) + { + if (!table->fts_doc_id_index) + table->fts_doc_id_index= + dict_table_get_index_on_name(table, FTS_DOC_ID_INDEX_NAME); + else + DBUG_ASSERT(table->fts_doc_id_index == + dict_table_get_index_on_name(table, FTS_DOC_ID_INDEX_NAME)); + } - innobase_table = dict_table_open_on_name( - m_table_name, false, DICT_ERR_IGNORE_NONE); + DBUG_ASSERT(!table->fts == !table->fts_doc_id_index); - DBUG_ASSERT(innobase_table != 0); - if (innobase_table->fts != NULL) { - if (innobase_table->fts_doc_id_index == NULL) { - innobase_table->fts_doc_id_index - = dict_table_get_index_on_name( - innobase_table, FTS_DOC_ID_INDEX_NAME); - DBUG_ASSERT(innobase_table->fts_doc_id_index != NULL); - } else { - DBUG_ASSERT(innobase_table->fts_doc_id_index - == dict_table_get_index_on_name( - innobase_table, - FTS_DOC_ID_INDEX_NAME)); - } - } + innobase_copy_frm_flags_from_create_info(table, &info); - DBUG_ASSERT((innobase_table->fts == NULL) - == (innobase_table->fts_doc_id_index == NULL)); + /* Load server stopword into FTS cache */ + if (table->flags2 & DICT_TF2_FTS && + innobase_fts_load_stopword(table, nullptr, thd)) + fts_optimize_add_table(table); - innobase_copy_frm_flags_from_create_info(innobase_table, m_create_info); + if (const Field *ai = t.found_next_number_field) + { + ut_ad(ai->stored_in_db()); + ib_uint64_t autoinc= info.auto_increment_value; + if (autoinc == 0) + autoinc= 1; - dict_stats_update(innobase_table, DICT_STATS_EMPTY_TABLE); + table->autoinc_mutex.wr_lock(); + dict_table_autoinc_initialize(table, autoinc); - /* Load server stopword into FTS cache */ - if (m_flags2 & DICT_TF2_FTS) { - if (!innobase_fts_load_stopword(innobase_table, NULL, m_thd)) { - innobase_table->release(); - DBUG_RETURN(-1); - } + if (!table->is_temporary()) + { + const unsigned col_no= innodb_col_no(ai); + table->persistent_autoinc= static_cast + (dict_table_get_nth_col_pos(table, col_no, nullptr) + 1) & + dict_index_t::MAX_N_FIELDS; + /* Persist the "last used" value, which typically is AUTO_INCREMENT - 1. + In btr_create(), the value 0 was already written. */ + if (--autoinc) + btr_write_autoinc(dict_table_get_first_index(table), autoinc); + } - dict_sys.lock(SRW_LOCK_CALL); - fts_optimize_add_table(innobase_table); - dict_sys.unlock(); - } + table->autoinc_mutex.wr_unlock(); + } - if (const Field* ai = m_form->found_next_number_field) { - ut_ad(ai->stored_in_db()); - - ib_uint64_t autoinc = m_create_info->auto_increment_value; - - if (autoinc == 0) { - autoinc = 1; - } - - innobase_table->autoinc_mutex.wr_lock(); - dict_table_autoinc_initialize(innobase_table, autoinc); - - if (innobase_table->is_temporary()) { - /* AUTO_INCREMENT is not persistent for - TEMPORARY TABLE. Temporary tables are never - evicted. Keep the counter in memory only. */ - } else { - const unsigned col_no = innodb_col_no(ai); - - innobase_table->persistent_autoinc - = static_cast( - dict_table_get_nth_col_pos( - innobase_table, col_no, NULL) - + 1) - & dict_index_t::MAX_N_FIELDS; - - /* Persist the "last used" value, which - typically is AUTO_INCREMENT - 1. - In btr_create(), the value 0 was already written. */ - if (--autoinc) { - btr_write_autoinc( - dict_table_get_first_index( - innobase_table), - autoinc); - } - } - - innobase_table->autoinc_mutex.wr_unlock(); - } - - innobase_parse_hint_from_comment(m_thd, innobase_table, m_form->s); - - dict_table_close(innobase_table); - DBUG_RETURN(0); + innobase_parse_hint_from_comment(thd, table, t.s); } /** Allocate a new trx. */ @@ -13215,89 +13185,80 @@ create_table_info_t::allocate_trx() @param[in] create_info Create info (including create statement string). @param[in] file_per_table whether to create .ibd file @param[in,out] trx dictionary transaction, or NULL to create new -@return 0 if success else error number. */ -inline int -ha_innobase::create( - const char* name, - TABLE* form, - HA_CREATE_INFO* create_info, - bool file_per_table, - trx_t* trx) +@return error code +@retval 0 on success */ +int +ha_innobase::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info, + bool file_per_table, trx_t *trx= nullptr) { - char norm_name[FN_REFLEN]; /* {database}/{tablename} */ - char remote_path[FN_REFLEN]; /* Absolute path of table */ + char norm_name[FN_REFLEN]; /* {database}/{tablename} */ + char remote_path[FN_REFLEN]; /* Absolute path of table */ - DBUG_ENTER("ha_innobase::create"); + DBUG_ENTER("ha_innobase::create"); + DBUG_ASSERT(form->s == table_share); + DBUG_ASSERT(table_share->table_type == TABLE_TYPE_SEQUENCE || + table_share->table_type == TABLE_TYPE_NORMAL); - DBUG_ASSERT(form->s == table_share); - DBUG_ASSERT(table_share->table_type == TABLE_TYPE_SEQUENCE - || table_share->table_type == TABLE_TYPE_NORMAL); + create_table_info_t info(ha_thd(), form, create_info, norm_name, + remote_path, file_per_table, trx); - create_table_info_t info(ha_thd(), - form, - create_info, - norm_name, - remote_path, - file_per_table, trx); + int error= info.initialize(); + if (!error) + error= info.prepare_create_table(name, !trx); + if (error) + DBUG_RETURN(error); - { - int error = info.initialize(); - if (!error) { - error = info.prepare_create_table(name, !trx); - } - if (error) { - if (trx) { - trx_rollback_for_mysql(trx); - row_mysql_unlock_data_dictionary(trx); - } - DBUG_RETURN(error); - } - } + const bool own_trx= !trx; + if (own_trx) + { + info.allocate_trx(); + trx= info.trx(); + DBUG_ASSERT(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); - const bool own_trx = !trx; - int error = 0; + if (!(info.flags2() & DICT_TF2_TEMPORARY)) + { + trx_start_for_ddl(trx); + if (dberr_t err= lock_sys_tables(trx)) + error= convert_error_code_to_mysql(err, 0, nullptr); + } + row_mysql_lock_data_dictionary(trx); + } - if (own_trx) { - info.allocate_trx(); - trx = info.trx(); - DBUG_ASSERT(trx_state_eq(trx, TRX_STATE_NOT_STARTED)); - } - if (own_trx && !(info.flags2() & DICT_TF2_TEMPORARY)) { - trx_start_for_ddl(trx); - if (dberr_t err = lock_sys_tables(trx)) { - error = convert_error_code_to_mysql(err, 0, nullptr); - } - } - if (own_trx) { - row_mysql_lock_data_dictionary(trx); - } + if (!error) + error= info.create_table(own_trx); - if (!error) { - error = info.create_table(own_trx); - } + if (own_trx || (info.flags2() & DICT_TF2_TEMPORARY)) + { + if (error) + trx_rollback_for_mysql(trx); + else + { + std::vector deleted; + trx->commit(deleted); + ut_ad(deleted.empty()); + info.table()->acquire(); + info.create_table_update_dict(info.table(), info.thd(), + *create_info, *form); + } - if (error) { - /* Rollback will drop the being-created table. */ - trx_rollback_for_mysql(trx); - row_mysql_unlock_data_dictionary(trx); - } else { - /* When this is invoked as part of ha_innobase::truncate(), - the old copy of the table will be deleted here. */ - std::vector deleted; - trx->commit(deleted); - row_mysql_unlock_data_dictionary(trx); - for (pfs_os_file_t d : deleted) os_file_close(d); - error = info.create_table_update_dict(); - if (!(info.flags2() & DICT_TF2_TEMPORARY)) { - log_write_up_to(trx->commit_lsn, true); - } - } + if (own_trx) + { + row_mysql_unlock_data_dictionary(trx); - if (own_trx) { - trx->free(); - } + if (!error) + { + dict_stats_update(info.table(), DICT_STATS_EMPTY_TABLE); + if (!info.table()->is_temporary()) + log_write_up_to(trx->commit_lsn, true); + info.table()->release(); + } + trx->free(); + } + } + else if (!error && m_prebuilt) + m_prebuilt->table= info.table(); - DBUG_RETURN(error); + DBUG_RETURN(error); } /** Create a new table to an InnoDB database. @@ -13305,13 +13266,10 @@ ha_innobase::create( @param[in] form Table format; columns and index information. @param[in] create_info Create info (including create statement string). @return 0 if success else error number. */ -int -ha_innobase::create( - const char* name, - TABLE* form, - HA_CREATE_INFO* create_info) +int ha_innobase::create(const char *name, TABLE *form, + HA_CREATE_INFO *create_info) { - return create(name, form, create_info, srv_file_per_table); + return create(name, form, create_info, srv_file_per_table); } /*****************************************************************//** @@ -13840,229 +13798,247 @@ static dberr_t innobase_rename_table(trx_t *trx, const char *from, @retval 0 on success */ int ha_innobase::truncate() { - DBUG_ENTER("ha_innobase::truncate"); + DBUG_ENTER("ha_innobase::truncate"); - update_thd(); + update_thd(); - if (is_read_only()) { - DBUG_RETURN(HA_ERR_TABLE_READONLY); - } + if (is_read_only()) + DBUG_RETURN(HA_ERR_TABLE_READONLY); - HA_CREATE_INFO info; - dict_table_t* ib_table = m_prebuilt->table; - info.init(); - update_create_info_from_table(&info, table); - switch (dict_tf_get_rec_format(ib_table->flags)) { - case REC_FORMAT_REDUNDANT: - info.row_type = ROW_TYPE_REDUNDANT; - break; - case REC_FORMAT_COMPACT: - info.row_type = ROW_TYPE_COMPACT; - break; - case REC_FORMAT_COMPRESSED: - info.row_type = ROW_TYPE_COMPRESSED; - break; - case REC_FORMAT_DYNAMIC: - info.row_type = ROW_TYPE_DYNAMIC; - break; - } + HA_CREATE_INFO info; + dict_table_t *ib_table= m_prebuilt->table; + info.init(); + update_create_info_from_table(&info, table); + switch (dict_tf_get_rec_format(ib_table->flags)) { + case REC_FORMAT_REDUNDANT: + info.row_type= ROW_TYPE_REDUNDANT; + break; + case REC_FORMAT_COMPACT: + info.row_type= ROW_TYPE_COMPACT; + break; + case REC_FORMAT_COMPRESSED: + info.row_type= ROW_TYPE_COMPRESSED; + break; + case REC_FORMAT_DYNAMIC: + info.row_type= ROW_TYPE_DYNAMIC; + break; + } - const auto stored_lock = m_prebuilt->stored_select_lock_type; - trx_t* trx = innobase_trx_allocate(m_user_thd); - trx_start_for_ddl(trx); + const auto stored_lock= m_prebuilt->stored_select_lock_type; + trx_t *trx= innobase_trx_allocate(m_user_thd); + trx_start_for_ddl(trx); - if (ib_table->is_temporary()) { - info.options|= HA_LEX_CREATE_TMP_TABLE; - btr_drop_temporary_table(*ib_table); - m_prebuilt->table = nullptr; - row_prebuilt_free(m_prebuilt); - m_prebuilt = nullptr; - my_free(m_upd_buf); - m_upd_buf = nullptr; - m_upd_buf_size = 0; + if (ib_table->is_temporary()) + { + info.options|= HA_LEX_CREATE_TMP_TABLE; + btr_drop_temporary_table(*ib_table); + m_prebuilt->table= nullptr; + row_prebuilt_free(m_prebuilt); + m_prebuilt= nullptr; + my_free(m_upd_buf); + m_upd_buf= nullptr; + m_upd_buf_size= 0; - row_mysql_lock_data_dictionary(trx); - ib_table->release(); - dict_sys.remove(ib_table, false, true); + row_mysql_lock_data_dictionary(trx); + ib_table->release(); + dict_sys.remove(ib_table, false, true); + int err= create(ib_table->name.m_name, table, &info, true, trx); + row_mysql_unlock_data_dictionary(trx); - int err = create(ib_table->name.m_name, table, &info, true, - trx); - ut_ad(!err); - if (!err) { - err = open(ib_table->name.m_name, 0, 0); - m_prebuilt->stored_select_lock_type = stored_lock; - } + ut_ad(!err); + if (!err) + { + err= open(ib_table->name.m_name, 0, 0); + m_prebuilt->table->release(); + m_prebuilt->stored_select_lock_type= stored_lock; + } - trx->free(); + trx->free(); #ifdef BTR_CUR_HASH_ADAPT - if (UT_LIST_GET_LEN(ib_table->freed_indexes)) { - ib_table->vc_templ = nullptr; - ib_table->id = 0; - DBUG_RETURN(err); - } + if (UT_LIST_GET_LEN(ib_table->freed_indexes)) + { + ib_table->vc_templ= nullptr; + ib_table->id= 0; + } + else #endif /* BTR_CUR_HASH_ADAPT */ + dict_mem_table_free(ib_table); - dict_mem_table_free(ib_table); - DBUG_RETURN(err); - } + DBUG_RETURN(err); + } - mem_heap_t* heap = mem_heap_create(1000); + mem_heap_t *heap= mem_heap_create(1000); - dict_get_and_save_data_dir_path(ib_table); - info.data_file_name = ib_table->data_dir_path; - const char* temp_name = dict_mem_create_temporary_tablename( - heap, ib_table->name.m_name, ib_table->id); - const char* name = mem_heap_strdup(heap, ib_table->name.m_name); + dict_get_and_save_data_dir_path(ib_table); + info.data_file_name= ib_table->data_dir_path; + const char *temp_name= + dict_mem_create_temporary_tablename(heap, + ib_table->name.m_name, ib_table->id); + const char *name= mem_heap_strdup(heap, ib_table->name.m_name); - dict_table_t *table_stats = nullptr, *index_stats = nullptr; - MDL_ticket *mdl_table = nullptr, *mdl_index = nullptr; + dict_table_t *table_stats = nullptr, *index_stats = nullptr; + MDL_ticket *mdl_table = nullptr, *mdl_index = nullptr; - dberr_t error = DB_SUCCESS; + dberr_t error= DB_SUCCESS; - dict_sys.freeze(SRW_LOCK_CALL); - for (const dict_foreign_t* f : ib_table->referenced_set) { - if (dict_table_t* child = f->foreign_table) { - error = lock_table_for_trx(child, trx, LOCK_X); - if (error != DB_SUCCESS) { - break; - } - } - } - dict_sys.unfreeze(); + dict_sys.freeze(SRW_LOCK_CALL); + for (const dict_foreign_t *f : ib_table->referenced_set) + if (dict_table_t *child= f->foreign_table) + if ((error= lock_table_for_trx(child, trx, LOCK_X)) != DB_SUCCESS) + break; + dict_sys.unfreeze(); - if (error == DB_SUCCESS) { - error = lock_table_for_trx(ib_table, trx, LOCK_X); - } + if (error == DB_SUCCESS) + error= lock_table_for_trx(ib_table, trx, LOCK_X); - const bool fts = error == DB_SUCCESS - && ib_table->flags2 & (DICT_TF2_FTS_HAS_DOC_ID | DICT_TF2_FTS); + const bool fts= error == DB_SUCCESS && + ib_table->flags2 & (DICT_TF2_FTS_HAS_DOC_ID | DICT_TF2_FTS); - if (fts) { - fts_optimize_remove_table(ib_table); - purge_sys.stop_FTS(*ib_table); - error = fts_lock_tables(trx, *ib_table); - } + if (fts) + { + fts_optimize_remove_table(ib_table); + purge_sys.stop_FTS(*ib_table); + error= fts_lock_tables(trx, *ib_table); + } - /* Wait for purge threads to stop using the table. */ - for (uint n = 15; ib_table->get_ref_count() > 1; ) { - if (!--n) { - error = DB_LOCK_WAIT_TIMEOUT; - break; - } + /* Wait for purge threads to stop using the table. */ + for (uint n = 15; ib_table->get_ref_count() > 1; ) + { + if (!--n) + { + error= DB_LOCK_WAIT_TIMEOUT; + break; + } + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - } + if (error == DB_SUCCESS && dict_stats_is_persistent_enabled(ib_table) && + !ib_table->is_stats_table()) + { + table_stats= dict_table_open_on_name(TABLE_STATS_NAME, false, + DICT_ERR_IGNORE_NONE); + if (table_stats) + { + dict_sys.freeze(SRW_LOCK_CALL); + table_stats= dict_acquire_mdl_shared(table_stats, m_user_thd, + &mdl_table); + dict_sys.unfreeze(); + } + index_stats= dict_table_open_on_name(INDEX_STATS_NAME, false, + DICT_ERR_IGNORE_NONE); + if (index_stats) + { + dict_sys.freeze(SRW_LOCK_CALL); + index_stats= dict_acquire_mdl_shared(index_stats, m_user_thd, + &mdl_index); + dict_sys.unfreeze(); + } - if (error == DB_SUCCESS && dict_stats_is_persistent_enabled(ib_table) - && !ib_table->is_stats_table()) { - table_stats= dict_table_open_on_name(TABLE_STATS_NAME, false, - DICT_ERR_IGNORE_NONE); - if (table_stats) { - dict_sys.freeze(SRW_LOCK_CALL); - table_stats = dict_acquire_mdl_shared( - table_stats, m_user_thd, &mdl_table); - dict_sys.unfreeze(); - } - index_stats = dict_table_open_on_name(INDEX_STATS_NAME, false, - DICT_ERR_IGNORE_NONE); - if (index_stats) { - dict_sys.freeze(SRW_LOCK_CALL); - index_stats = dict_acquire_mdl_shared( - index_stats, m_user_thd, &mdl_index); - dict_sys.unfreeze(); - } + if (table_stats && index_stats && + !strcmp(table_stats->name.m_name, TABLE_STATS_NAME) && + !strcmp(index_stats->name.m_name, INDEX_STATS_NAME) && + !(error= lock_table_for_trx(table_stats, trx, LOCK_X))) + error= lock_table_for_trx(index_stats, trx, LOCK_X); + } - if (table_stats && index_stats - && !strcmp(table_stats->name.m_name, TABLE_STATS_NAME) - && !strcmp(index_stats->name.m_name, INDEX_STATS_NAME) && - !(error = lock_table_for_trx(table_stats, trx, LOCK_X))) { - error = lock_table_for_trx(index_stats, trx, LOCK_X); - } - } + if (error == DB_SUCCESS) + error= lock_sys_tables(trx); - if (error == DB_SUCCESS) { - error = lock_sys_tables(trx); - } + std::vector deleted; - row_mysql_lock_data_dictionary(trx); + row_mysql_lock_data_dictionary(trx); - if (error == DB_SUCCESS) { - error = innobase_rename_table(trx, ib_table->name.m_name, - temp_name, false); + if (error == DB_SUCCESS) + { + error= innobase_rename_table(trx, ib_table->name.m_name, temp_name, false); + if (error == DB_SUCCESS) + error= trx->drop_table(*ib_table); + } - if (error == DB_SUCCESS) { - error = trx->drop_table(*ib_table); - } - } + int err = convert_error_code_to_mysql(error, ib_table->flags, m_user_thd); + const auto update_time = ib_table->update_time; - int err = convert_error_code_to_mysql(error, ib_table->flags, - m_user_thd); - if (err) { - trx_rollback_for_mysql(trx); - if (fts) { - fts_optimize_add_table(ib_table); - purge_sys.resume_FTS(); - } - row_mysql_unlock_data_dictionary(trx); - } else { - const auto update_time = ib_table->update_time; - const auto stored_lock = m_prebuilt->stored_select_lock_type; - const auto def_trx_id = ib_table->def_trx_id; - ib_table->release(); - m_prebuilt->table = nullptr; + if (err) + { + trx_rollback_for_mysql(trx); + if (fts) + fts_optimize_add_table(ib_table); + } + else + { + const auto def_trx_id= ib_table->def_trx_id; + ib_table->release(); + m_prebuilt->table= nullptr; - err = create(name, table, &info, - dict_table_is_file_per_table(ib_table), trx); - /* On success, create() durably committed trx. */ - if (fts) { - purge_sys.resume_FTS(); - } + err= create(name, table, &info, dict_table_is_file_per_table(ib_table), + trx); + if (!err) + { + m_prebuilt->table->acquire(); + create_table_info_t::create_table_update_dict(m_prebuilt->table, + m_user_thd, info, *table); + trx->commit(deleted); + } + else + { + trx_rollback_for_mysql(trx); + m_prebuilt->table= dict_table_open_on_name(name, true, + DICT_ERR_IGNORE_FK_NOKEY); + m_prebuilt->table->def_trx_id= def_trx_id; + } + dict_names_t fk_tables; + dict_load_foreigns(m_prebuilt->table->name.m_name, nullptr, 1, true, + DICT_ERR_IGNORE_FK_NOKEY, fk_tables); + for (const char *f : fk_tables) + dict_sys.load_table({f, strlen(f)}); + } - if (err) { -reload: - m_prebuilt->table = dict_table_open_on_name( - name, false, DICT_ERR_IGNORE_NONE); - m_prebuilt->table->def_trx_id = def_trx_id; - } else { - row_prebuilt_t* prebuilt = m_prebuilt; - uchar* upd_buf = m_upd_buf; - ulint upd_buf_size = m_upd_buf_size; - /* Mimic ha_innobase::close(). */ - m_prebuilt = nullptr; - m_upd_buf = nullptr; - m_upd_buf_size = 0; + if (fts) + purge_sys.resume_FTS(); - err = open(name, 0, 0); + row_mysql_unlock_data_dictionary(trx); + for (pfs_os_file_t d : deleted) os_file_close(d); - if (!err) { - m_prebuilt->stored_select_lock_type - = stored_lock; - m_prebuilt->table->update_time = update_time; - row_prebuilt_free(prebuilt); - my_free(upd_buf); - } else { - /* Revert to the old table. */ - m_prebuilt = prebuilt; - m_upd_buf = upd_buf; - m_upd_buf_size = upd_buf_size; - goto reload; - } - } - } + if (!err) + { + dict_stats_update(m_prebuilt->table, DICT_STATS_EMPTY_TABLE); + log_write_up_to(trx->commit_lsn, true); + row_prebuilt_t *prebuilt= m_prebuilt; + uchar *upd_buf= m_upd_buf; + ulint upd_buf_size= m_upd_buf_size; + /* Mimic ha_innobase::close(). */ + m_prebuilt= nullptr; + m_upd_buf= nullptr; + m_upd_buf_size= 0; - trx->free(); + err= open(name, 0, 0); + if (!err) + { + m_prebuilt->stored_select_lock_type= stored_lock; + m_prebuilt->table->update_time= update_time; + row_prebuilt_free(prebuilt); + my_free(upd_buf); + } + else + { + /* Revert to the old table. */ + m_prebuilt= prebuilt; + m_upd_buf= upd_buf; + m_upd_buf_size= upd_buf_size; + } + } - mem_heap_free(heap); + trx->free(); - if (table_stats) { - dict_table_close(table_stats, false, m_user_thd, mdl_table); - } - if (index_stats) { - dict_table_close(index_stats, false, m_user_thd, mdl_index); - } + mem_heap_free(heap); - DBUG_RETURN(err); + if (table_stats) + dict_table_close(table_stats, false, m_user_thd, mdl_table); + if (index_stats) + dict_table_close(index_stats, false, m_user_thd, mdl_index); + + DBUG_RETURN(err); } /*********************************************************************//** @@ -15656,30 +15632,12 @@ delete is then allowed internally to resolve a duplicate key conflict in REPLACE, not an update. @return > 0 if referenced by a FOREIGN KEY */ -uint -ha_innobase::referenced_by_foreign_key(void) -/*========================================*/ +uint ha_innobase::referenced_by_foreign_key() { - if (dict_table_is_referenced_by_foreign_key(m_prebuilt->table)) { - - return(1); - } - - return(0); -} - -/*******************************************************************//** -Frees the foreign key create info for a table stored in InnoDB, if it is -non-NULL. */ - -void -ha_innobase::free_foreign_key_create_info( -/*======================================*/ - char* str) /*!< in, own: create info string to free */ -{ - if (str != NULL) { - my_free(str); - } + dict_sys.freeze(SRW_LOCK_CALL); + const bool empty= m_prebuilt->table->referenced_set.empty(); + dict_sys.unfreeze(); + return !empty; } /*******************************************************************//** diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h index 01acde3d8e6..3c6452f1966 100644 --- a/storage/innobase/handler/ha_innodb.h +++ b/storage/innobase/handler/ha_innodb.h @@ -190,12 +190,12 @@ public: void update_create_info(HA_CREATE_INFO* create_info) override; - inline int create( + int create( const char* name, TABLE* form, HA_CREATE_INFO* create_info, bool file_per_table, - trx_t* trx = NULL); + trx_t* trx); int create( const char* name, @@ -225,7 +225,7 @@ public: uint referenced_by_foreign_key() override; - void free_foreign_key_create_info(char* str) override; + void free_foreign_key_create_info(char* str) override { my_free(str); } uint lock_count(void) const override; @@ -639,8 +639,9 @@ public: @param create_fk whether to add FOREIGN KEY constraints */ int create_table(bool create_fk = true); - /** Update the internal data dictionary. */ - int create_table_update_dict(); + static void create_table_update_dict(dict_table_t* table, THD* thd, + const HA_CREATE_INFO& info, + const TABLE& t); /** Validates the create options. Checks that the options KEY_BLOCK_SIZE, ROW_FORMAT, DATA DIRECTORY, TEMPORARY & TABLESPACE @@ -700,12 +701,13 @@ public: trx_t* trx() const { return(m_trx); } - /** Return table name. */ - const char* table_name() const - { return(m_table_name); } + /** @return table name */ + const char* table_name() const { return(m_table_name); } - THD* thd() const - { return(m_thd); } + /** @return the created table */ + dict_table_t *table() const { return m_table; } + + THD* thd() const { return(m_thd); } private: /** Parses the table name into normal name and either temp path or diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index fa86a920dd8..8ef58d64167 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -7286,13 +7286,10 @@ error_handling_drop_uncached: goto error_handling; } - ctx->new_table->fts->dict_locked = true; - error = innobase_fts_load_stopword( ctx->new_table, ctx->trx, ctx->prebuilt->trx->mysql_thd) ? DB_SUCCESS : DB_ERROR; - ctx->new_table->fts->dict_locked = false; if (error != DB_SUCCESS) { goto error_handling; @@ -9882,7 +9879,7 @@ innobase_update_foreign_cache( err = dict_load_foreigns(user_table->name.m_name, ctx->col_names, 1, true, - DICT_ERR_IGNORE_NONE, + DICT_ERR_IGNORE_FK_NOKEY, fk_tables); if (err == DB_CANNOT_ADD_CONSTRAINT) { diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h index cfaf4fab83e..e54a138cc02 100644 --- a/storage/innobase/include/dict0dict.h +++ b/storage/innobase/include/dict0dict.h @@ -421,14 +421,6 @@ dict_foreign_add_to_cache( dict_err_ignore_t ignore_err) /*!< in: error to be ignored */ MY_ATTRIBUTE((nonnull(1), warn_unused_result)); -/*********************************************************************//** -Checks if a table is referenced by foreign keys. -@return TRUE if table is referenced by a foreign key */ -ibool -dict_table_is_referenced_by_foreign_key( -/*====================================*/ - const dict_table_t* table) /*!< in: InnoDB table */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); /**********************************************************************//** Replace the index passed in with another equivalent index in the foreign key lists of the table. @@ -1329,7 +1321,7 @@ class dict_sys_t alignas(CPU_LEVEL1_DCACHE_LINESIZE) srw_lock latch; #ifdef UNIV_DEBUG /** whether latch is being held in exclusive mode (by any thread) */ - bool latch_ex; + Atomic_relaxed latch_ex; /** number of S-latch holders */ Atomic_counter latch_readers; #endif @@ -1503,11 +1495,12 @@ public: /** @return whether any thread (not necessarily the current thread) is holding the latch; that is, this check may return false positives */ - bool frozen() const { return latch_readers || locked(); } + bool frozen() const { return latch_readers || latch_ex; } /** @return whether any thread (not necessarily the current thread) - is holding the exclusive latch; that is, this check may return false - positives */ - bool locked() const { return latch_ex; } + is holding a shared latch */ + bool frozen_not_locked() const { return latch_readers; } + /** @return whether the current thread holds the exclusive latch */ + bool locked() const { return latch_ex == pthread_self(); } #endif private: /** Acquire the exclusive latch */ @@ -1526,7 +1519,7 @@ public: { ut_ad(!latch_readers); ut_ad(!latch_ex); - ut_d(latch_ex= true); + ut_d(latch_ex= pthread_self()); } else lock_wait(SRW_LOCK_ARGS(file, line)); @@ -1543,9 +1536,9 @@ public: /** Unlock the data dictionary cache. */ void unlock() { - ut_ad(latch_ex); + ut_ad(latch_ex == pthread_self()); ut_ad(!latch_readers); - ut_d(latch_ex= false); + ut_d(latch_ex= 0); latch.wr_unlock(); } /** Acquire a shared lock on the dictionary cache. */ diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h index a94823b4a86..f7d33d5b43b 100644 --- a/storage/innobase/include/dict0load.h +++ b/storage/innobase/include/dict0load.h @@ -100,7 +100,7 @@ dict_load_foreigns( which must be loaded subsequently to load all the foreign key constraints. */ - MY_ATTRIBUTE((nonnull(1), warn_unused_result)); + MY_ATTRIBUTE((nonnull(1))); /********************************************************************//** This function opens a system table, and return the first record. diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 448021d840a..db4035157b0 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -3934,8 +3934,7 @@ void lock_release(trx_t *trx) #ifdef UNIV_DEBUG std::set to_evict; if (innodb_evict_tables_on_commit_debug && - !trx->is_recovered && !trx->dict_operation && - !trx->dict_operation_lock_mode) + !trx->is_recovered && !dict_sys.locked()) for (const auto& p : trx->mod_tables) if (!p.first->is_temporary()) to_evict.emplace(p.first->id); From fda5846704ec9218b78ed5ed06f58b7391369a1a Mon Sep 17 00:00:00 2001 From: Andrew Hutchings Date: Tue, 8 Nov 2022 15:49:52 +0000 Subject: [PATCH 35/38] MDEV-29397 CONNECT engine: Fix note turning into error (#2325) * MDEV-29397 Fix note turning into error ODBC Rewind triggered an error with no SQL, but this is sometimes a valid condition (as can be seen with other classes). Setting this to a 0 return stops errors firing when they shouldn't. Also fixes ASAN hits from in MDEV-29687 tabext.cpp. --- .../connect/mysql-test/connect/r/odbc_postgresql.result | 9 +++++++++ .../connect/mysql-test/connect/t/odbc_postgresql.test | 9 +++++++++ storage/connect/odbconn.cpp | 2 +- storage/connect/tabext.cpp | 4 ++-- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/storage/connect/mysql-test/connect/r/odbc_postgresql.result b/storage/connect/mysql-test/connect/r/odbc_postgresql.result index 6bd8d75a601..9ecb66307e6 100644 --- a/storage/connect/mysql-test/connect/r/odbc_postgresql.result +++ b/storage/connect/mysql-test/connect/r/odbc_postgresql.result @@ -319,3 +319,12 @@ SELECT * from pg_in_maria; my space column My value DROP TABLE pg_in_maria; +# +# MDEV-29397 UPDATE with WHERE on part of two-part primary key causes +# info to turn into error. +# +CREATE TABLE t1 (a VARCHAR(6), b VARCHAR(6), PRIMARY KEY(a, b)) ENGINE=CONNECT TABNAME='schema1.t3' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr'; +UPDATE t1 SET a='10' WHERE a='20'; +Warnings: +Note 1105 schema1.t3: 0 affected rows +DROP TABLE t1; diff --git a/storage/connect/mysql-test/connect/t/odbc_postgresql.test b/storage/connect/mysql-test/connect/t/odbc_postgresql.test index ec98453d630..187bec55b38 100644 --- a/storage/connect/mysql-test/connect/t/odbc_postgresql.test +++ b/storage/connect/mysql-test/connect/t/odbc_postgresql.test @@ -223,3 +223,12 @@ DROP TABLE t1; CREATE TABLE pg_in_maria ENGINE=CONNECT TABNAME='schema1.space_in_column_name' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr' quoted=1; SELECT * from pg_in_maria; DROP TABLE pg_in_maria; + +--echo # +--echo # MDEV-29397 UPDATE with WHERE on part of two-part primary key causes +--echo # info to turn into error. +--echo # +CREATE TABLE t1 (a VARCHAR(6), b VARCHAR(6), PRIMARY KEY(a, b)) ENGINE=CONNECT TABNAME='schema1.t3' CHARSET=utf8 DATA_CHARSET=utf8 TABLE_TYPE=ODBC CONNECTION='DSN=ConnectEnginePostgresql;UID=mtr;PWD=mtr'; +UPDATE t1 SET a='10' WHERE a='20'; +DROP TABLE t1; + diff --git a/storage/connect/odbconn.cpp b/storage/connect/odbconn.cpp index 33c2b0aaf70..e83f1b5f04c 100644 --- a/storage/connect/odbconn.cpp +++ b/storage/connect/odbconn.cpp @@ -2582,7 +2582,7 @@ int ODBConn::Rewind(char *sql, ODBCCOL *tocols) int rc, rbuf = -1; if (!m_hstmt) - rbuf = -1; + rbuf = 0; else if (m_Full) rbuf = m_Rows; // No need to "rewind" else if (m_Scrollable) { diff --git a/storage/connect/tabext.cpp b/storage/connect/tabext.cpp index 95725dfc44b..d1b94c81c11 100644 --- a/storage/connect/tabext.cpp +++ b/storage/connect/tabext.cpp @@ -473,7 +473,7 @@ bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt) my_len= res - buf + 1; my_schema_table= (char *) malloc(my_len); memcpy(my_schema_table, buf, my_len - 1); - my_schema_table[my_len] = 0; + my_schema_table[my_len - 1] = 0; Query->Append(Quote); Query->Append(my_schema_table); Query->Append(Quote); @@ -481,7 +481,7 @@ bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt) Query->Append("."); // Parse table my_len= strlen(buf) - my_len + 1; - my_schema_table= (char *) malloc(my_len); + my_schema_table= (char *) malloc(my_len + 1); memcpy(my_schema_table, ++res, my_len); my_schema_table[my_len] = 0; Query->Append(Quote); From b955f4eff72e8602ef60cb57bf1420e38802681f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 8 Nov 2022 18:21:39 +0200 Subject: [PATCH 36/38] MDEV-22512: Re-enable the tests on 10.5 --- mysql-test/suite/innodb_gis/disabled.def | 1 - mysql-test/suite/innodb_zip/disabled.def | 1 - 2 files changed, 2 deletions(-) delete mode 100644 mysql-test/suite/innodb_zip/disabled.def diff --git a/mysql-test/suite/innodb_gis/disabled.def b/mysql-test/suite/innodb_gis/disabled.def index ba492f4f033..2d4d3686dd1 100644 --- a/mysql-test/suite/innodb_gis/disabled.def +++ b/mysql-test/suite/innodb_gis/disabled.def @@ -13,4 +13,3 @@ rtree_concurrent_srch : MDEV-15284 COUNT(*) mismatch rtree_recovery : MDEV-15284 COUNT(*) mismatch rtree_compress2 : MDEV-16269 CHECK TABLE reports wrong count -types : MDEV-22512 recovery runs out of memory before 10.5 diff --git a/mysql-test/suite/innodb_zip/disabled.def b/mysql-test/suite/innodb_zip/disabled.def deleted file mode 100644 index fcf7333f843..00000000000 --- a/mysql-test/suite/innodb_zip/disabled.def +++ /dev/null @@ -1 +0,0 @@ -recover : MDEV-22512 recovery runs out of memory before 10.5 From 6b91792a087a4c356584a6f1fa8e7d9809a1d58a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 9 Nov 2022 09:23:18 +0200 Subject: [PATCH 37/38] MDEV-29883 Deadlock between InnoDB statistics update and BLOB insert This is a backport of commit 8b6a308e463f937eb8d2498b04967a222c83af90 from MariaDB Server 10.6.11. No attempt to reproduce the hang in earlier an earlier version of MariaDB Server than 10.6 was made. In each caller of fseg_n_reserved_pages() except ibuf_init_at_db_start() which is a special case for ibuf.index at database startup, we must hold an index latch that prevents concurrent allocation or freeing of index pages. Any operation that allocates or free pages that belong to an index tree must first acquire an index latch in non-shared mode, and while holding that, acquire an index root page latch in non-shared mode. btr_get_size(), btr_get_size_and_reserved(): Assert that a strong enough index latch is being held. dict_stats_update_transient_for_index(), dict_stats_analyze_index(): Acquire a strong enough index latch. These operations had followed the same order of acquiring latches in every InnoDB version since the very beginning (commit c533308a158795f91247e9fe3c7304fa5e7d2b3c). The hang was introduced in commit 2e814d4702d71a04388386a9f591d14a35980bfe which imported mysql/mysql-server@ac74632293bea967b352d1b472abedeeaa921b98 which failed to strengthen the locking requirements of the function btr_get_size(). --- storage/innobase/btr/btr0btr.cc | 4 ++-- storage/innobase/dict/dict0defrag_bg.cc | 4 ++-- storage/innobase/dict/dict0stats.cc | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index f041e35e501..6b575885f81 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -603,7 +603,7 @@ btr_get_size( ut_ad(srv_read_only_mode || mtr_memo_contains(mtr, dict_index_get_lock(index), - MTR_MEMO_S_LOCK)); + MTR_MEMO_SX_LOCK)); if (index->page == FIL_NULL || dict_index_is_online_ddl(index) @@ -657,7 +657,7 @@ btr_get_size_and_reserved( ulint dummy; ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index), - MTR_MEMO_S_LOCK)); + MTR_MEMO_SX_LOCK)); ut_a(flag == BTR_N_LEAF_PAGES || flag == BTR_TOTAL_SIZE); diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc index 7c6f5d75b5d..9cc23a89c1b 100644 --- a/storage/innobase/dict/dict0defrag_bg.cc +++ b/storage/innobase/dict/dict0defrag_bg.cc @@ -1,6 +1,6 @@ /***************************************************************************** -Copyright (c) 2016, 2019, MariaDB Corporation. +Copyright (c) 2016, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -282,7 +282,7 @@ dict_stats_save_defrag_stats( ulint n_leaf_pages; ulint n_leaf_reserved; mtr.start(); - mtr_s_lock_index(index, &mtr); + mtr_sx_lock_index(index, &mtr); n_leaf_reserved = btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES, &n_leaf_pages, &mtr); mtr.commit(); diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index e36e2184e2d..b74edee5669 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2009, 2019, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2015, 2021, MariaDB Corporation. +Copyright (c) 2015, 2022, MariaDB Corporation. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -852,7 +852,7 @@ dict_stats_update_transient_for_index( ulint size; mtr.start(); - mtr_s_lock_index(index, &mtr); + mtr_sx_lock_index(index, &mtr); size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); if (size != ULINT_UNDEFINED) { @@ -1945,7 +1945,7 @@ static index_stats_t dict_stats_analyze_index(dict_index_t* index) DEBUG_PRINTF(" %s(index=%s)\n", __func__, index->name()); mtr.start(); - mtr_s_lock_index(index, &mtr); + mtr_sx_lock_index(index, &mtr); size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr); if (size != ULINT_UNDEFINED) { From e56c12b3cdf57ad29cee0ffe33bd6bc44c963789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 9 Nov 2022 12:02:04 +0200 Subject: [PATCH 38/38] Add an end marker to a test --- mysql-test/suite/innodb/r/insert_into_empty.result | 1 + mysql-test/suite/innodb/t/insert_into_empty.test | 2 ++ 2 files changed, 3 insertions(+) diff --git a/mysql-test/suite/innodb/r/insert_into_empty.result b/mysql-test/suite/innodb/r/insert_into_empty.result index 38378fd687f..bca8e5a31f6 100644 --- a/mysql-test/suite/innodb/r/insert_into_empty.result +++ b/mysql-test/suite/innodb/r/insert_into_empty.result @@ -193,3 +193,4 @@ SELECT n_rows FROM mysql.innodb_table_stats WHERE TABLE_NAME="t1"; n_rows 4096 DROP TABLE t1; +# End of 10.6 tests diff --git a/mysql-test/suite/innodb/t/insert_into_empty.test b/mysql-test/suite/innodb/t/insert_into_empty.test index 4181087472f..1e275a48dda 100644 --- a/mysql-test/suite/innodb/t/insert_into_empty.test +++ b/mysql-test/suite/innodb/t/insert_into_empty.test @@ -206,3 +206,5 @@ where table_name="t1"; source include/wait_condition.inc; SELECT n_rows FROM mysql.innodb_table_stats WHERE TABLE_NAME="t1"; DROP TABLE t1; + +--echo # End of 10.6 tests