From 73b58ac4873eb98057cc1f57b8e6fde53aa9b29d Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Thu, 1 Aug 2024 13:07:12 +0700 Subject: [PATCH 01/45] MDEV-34649: Memory leaks on running DELETE statement in PS mode with positional parameters Re-design of a way for handling the DELETE statement introduced by the task MDEV-28883, added regression caused by missing reset of the data member current_select->first_cond_optimization on handling the DELETE statement that results in a memory leaks on second execution of the same DELETE statement in PS mode. To fix memory leaks, added set of the data member current_select->first_cond_optimization to the value false on finishing execution of DELETE statement. --- mysql-test/main/ps_mem_leaks.result | 14 ++++++++++++++ mysql-test/main/ps_mem_leaks.test | 18 ++++++++++++++++++ sql/sql_delete.cc | 1 + 3 files changed, 33 insertions(+) diff --git a/mysql-test/main/ps_mem_leaks.result b/mysql-test/main/ps_mem_leaks.result index ebbccb71c6b..b915329ff18 100644 --- a/mysql-test/main/ps_mem_leaks.result +++ b/mysql-test/main/ps_mem_leaks.result @@ -148,3 +148,17 @@ CALL p1(2); DROP TABLE t1; DROP PROCEDURE p1; # End of 10.11 tests +# +# MDEV-34649: Memory leaks on running DELETE statement in PS mode with positional parameters +# +CREATE TABLE t1 (a INT, b VARCHAR(30)) CHARSET=utf8mb4; +INSERT INTO t1 VALUES (1, 'one'), (0, NULL), (3, 'three'), (4, 'four'); +PREPARE stmt FROM 'DELETE FROM t1 WHERE b=?' ; +SET @arg00=NULL; +EXECUTE stmt USING @arg00; +SET @arg00='one'; +EXECUTE stmt USING @arg00; +# Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1; +# End of 11.1 diff --git a/mysql-test/main/ps_mem_leaks.test b/mysql-test/main/ps_mem_leaks.test index 75381e13116..e824200d0fb 100644 --- a/mysql-test/main/ps_mem_leaks.test +++ b/mysql-test/main/ps_mem_leaks.test @@ -167,3 +167,21 @@ DROP TABLE t1; DROP PROCEDURE p1; --echo # End of 10.11 tests + +--echo # +--echo # MDEV-34649: Memory leaks on running DELETE statement in PS mode with positional parameters +--echo # +CREATE TABLE t1 (a INT, b VARCHAR(30)) CHARSET=utf8mb4; +INSERT INTO t1 VALUES (1, 'one'), (0, NULL), (3, 'three'), (4, 'four'); +PREPARE stmt FROM 'DELETE FROM t1 WHERE b=?' ; +SET @arg00=NULL; +EXECUTE stmt USING @arg00; +SET @arg00='one'; +# Without the patch, attempt to run the same prepared statement the second time +# would result in memory leaks +EXECUTE stmt USING @arg00; +--echo # Clean up +DEALLOCATE PREPARE stmt; +DROP TABLE t1; + +--echo # End of 11.1 diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b7b3b79bbb6..b1fc89b2a28 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -912,6 +912,7 @@ cleanup: { thd->lex->current_select->save_leaf_tables(thd); thd->lex->current_select->leaf_tables_saved= true; + thd->lex->current_select->first_cond_optimization= false; } delete deltempfile; From d072a29601834cd61252158c95f068aa13eb55fa Mon Sep 17 00:00:00 2001 From: Galina Shalygina Date: Wed, 24 Jul 2024 13:55:55 +0200 Subject: [PATCH 02/45] MDEV-23983: Crash caused by query containing constant having clause Before this patch the crash occured when a single row dataset is used and Item::remove_eq_conds() is called for HAVING. This function is not supposed to be called after the elimination of multiple equalities. To fix this problem instead of Item::remove_eq_conds() Item::val_int() is used. In this case the optimizer tries to evaluate the condition for the single row dataset and discovers impossible HAVING immediately. So, the execution phase is skipped. Approved by Igor Babaev --- mysql-test/main/having.result | 44 ++++++++++++++++++++++++++++++++++ mysql-test/main/having.test | 45 +++++++++++++++++++++++++++++++++++ sql/sql_select.cc | 19 ++++++++------- 3 files changed, 100 insertions(+), 8 deletions(-) diff --git a/mysql-test/main/having.result b/mysql-test/main/having.result index 95497a59c20..9f8a1c6e73c 100644 --- a/mysql-test/main/having.result +++ b/mysql-test/main/having.result @@ -955,3 +955,47 @@ DROP TABLE t; # # End of 10.4 tests # +# +# MDEV-23983: Crash caused by query containing constant having clause +# +CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b TEXT, c INT); +INSERT INTO t1 VALUES (3, 7, 'b', 1), (4, 7, 'b', 1); +SELECT * FROM t1 +WHERE t1.id = 3 +GROUP BY t1.a +HAVING t1.b = 'b' and t1.c = 1; +id a b c +3 7 b 1 +SELECT * FROM t1 +WHERE t1.id = 3 +GROUP BY t1.a +HAVING t1.b = 'b' and t1.c = 2; +id a b c +explain SELECT * FROM t1 +WHERE t1.id = 3 +GROUP BY t1.a +HAVING t1.b = 'b' and t1.c = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING noticed after reading const tables +DROP TABLE t1; +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM; +CREATE TABLE t2 (id INT, b TEXT, c INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3, 'b', 1); +SELECT t2.* FROM t2 LEFT JOIN t1 ON t2.id = t1.a +GROUP BY t2.id +HAVING t2.b = 'b' and t2.c = 1; +id b c +3 b 1 +SELECT t2.* FROM t2 LEFT JOIN t1 ON t2.id = t1.a +GROUP BY t2.id +HAVING t2.b = 'b' and t2.c = 2; +id b c +explain SELECT t2.* FROM t2 LEFT JOIN t1 ON t2.id = t1.a +GROUP BY t2.id +HAVING t2.b = 'b' and t2.c = 2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE NULL NULL NULL NULL NULL NULL NULL Impossible HAVING noticed after reading const tables +DROP TABLE t1,t2; +# +# End of 10.5 tests +# diff --git a/mysql-test/main/having.test b/mysql-test/main/having.test index b114070c60f..812038b2d60 100644 --- a/mysql-test/main/having.test +++ b/mysql-test/main/having.test @@ -1011,3 +1011,48 @@ DROP TABLE t; --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-23983: Crash caused by query containing constant having clause +--echo # + +CREATE TABLE t1 (id INT PRIMARY KEY, a INT, b TEXT, c INT); +INSERT INTO t1 VALUES (3, 7, 'b', 1), (4, 7, 'b', 1); + +SELECT * FROM t1 +WHERE t1.id = 3 +GROUP BY t1.a +HAVING t1.b = 'b' and t1.c = 1; + +let $q= +SELECT * FROM t1 +WHERE t1.id = 3 +GROUP BY t1.a +HAVING t1.b = 'b' and t1.c = 2; + +eval $q; +eval explain $q; + +DROP TABLE t1; + +CREATE TABLE t1 (a INT, b INT) ENGINE=MyISAM; +CREATE TABLE t2 (id INT, b TEXT, c INT) ENGINE=MyISAM; +INSERT INTO t2 VALUES (3, 'b', 1); + +SELECT t2.* FROM t2 LEFT JOIN t1 ON t2.id = t1.a +GROUP BY t2.id +HAVING t2.b = 'b' and t2.c = 1; + +let $q= +SELECT t2.* FROM t2 LEFT JOIN t1 ON t2.id = t1.a +GROUP BY t2.id +HAVING t2.b = 'b' and t2.c = 2; + +eval $q; +eval explain $q; + +DROP TABLE t1,t2; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b86ffed8619..93b53699c9a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2971,19 +2971,22 @@ int JOIN::optimize_stage2() which do not use aggregate functions. In such case temporary table may not be used and const condition elements may be lost during further having - condition transformation in JOIN::exec. + condition transformation. */ if (having && const_table_map && !having->with_sum_func()) { having->update_used_tables(); - having= having->remove_eq_conds(thd, &select_lex->having_value, true); - if (select_lex->having_value == Item::COND_FALSE) + if (having->const_item() && !having->is_expensive()) { - having= new (thd->mem_root) Item_bool(thd, false); - zero_result_cause= "Impossible HAVING noticed after reading const tables"; - error= 0; - select_lex->mark_const_derived(zero_result_cause); - goto setup_subq_exit; + bool having_value= having->val_int(); + having= new (thd->mem_root) Item_bool(thd, having_value); + if (!having_value) + { + zero_result_cause= "Impossible HAVING noticed after reading const tables"; + error= 0; + select_lex->mark_const_derived(zero_result_cause); + goto setup_subq_exit; + } } } From 37119cd2567cdc710e3d0fd097a10b6bb9def3c8 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Thu, 1 Aug 2024 17:44:54 +0530 Subject: [PATCH 03/45] MDEV-29010 Table cannot be loaded after instant ALTER Reason: ====== - InnoDB fails to load the instant alter table metadata from clustered index while loading the table definition. The reason is that InnoDB metadata blob has the column length exceeds maximum fixed length column size. Fix: === - InnoDB should treat the long fixed length column as variable length fields that needs external storage while initializing the field map for instant alter operation --- mysql-test/suite/innodb/r/instant_alter_bugs.result | 9 +++++++++ mysql-test/suite/innodb/t/instant_alter_bugs.test | 11 +++++++++++ storage/innobase/handler/handler0alter.cc | 7 +++++++ 3 files changed, 27 insertions(+) diff --git a/mysql-test/suite/innodb/r/instant_alter_bugs.result b/mysql-test/suite/innodb/r/instant_alter_bugs.result index dc64a041c3c..c74730599d3 100644 --- a/mysql-test/suite/innodb/r/instant_alter_bugs.result +++ b/mysql-test/suite/innodb/r/instant_alter_bugs.result @@ -521,3 +521,12 @@ COUNT(*) 1 DROP TABLE t1; # End of 10.4 tests +# +# MDEV-29010 Table cannot be loaded after instant ALTER +# +CREATE TABLE t1 (a CHAR(255), b INT, +c INT as (b) VIRTUAL)ENGINE=InnoDB CHARACTER SET utf32; +ALTER TABLE t1 DROP COLUMN a; +ALTER TABLE t1 DROP COLUMN c; +DROP TABLE t1; +# End of 10.5 tests diff --git a/mysql-test/suite/innodb/t/instant_alter_bugs.test b/mysql-test/suite/innodb/t/instant_alter_bugs.test index db04ac711b2..c1b999dbc74 100644 --- a/mysql-test/suite/innodb/t/instant_alter_bugs.test +++ b/mysql-test/suite/innodb/t/instant_alter_bugs.test @@ -553,3 +553,14 @@ SELECT COUNT(*) FROM t1; DROP TABLE t1; --echo # End of 10.4 tests + +--echo # +--echo # MDEV-29010 Table cannot be loaded after instant ALTER +--echo # +CREATE TABLE t1 (a CHAR(255), b INT, + c INT as (b) VIRTUAL)ENGINE=InnoDB CHARACTER SET utf32; +ALTER TABLE t1 DROP COLUMN a; +ALTER TABLE t1 DROP COLUMN c; +DROP TABLE t1; + +--echo # End of 10.5 tests diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index b5a76bfcdc2..d3a7e3d3749 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -181,6 +181,13 @@ inline void dict_table_t::init_instant(const dict_table_t& table) auto fixed_len = dict_col_get_fixed_size( f.col, not_redundant()); + + /* Long fixed length can be treated as variable + length fields that needs external storage */ + if (fixed_len > DICT_MAX_FIXED_COL_LEN) { + fixed_len = 0; + } + field_map_it->set_dropped(); if (!f.col->is_nullable()) { field_map_it->set_not_null(); From 00862b688c90057256f3b2fdc2a69e788bcf100d Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 2 Aug 2024 14:34:31 +0700 Subject: [PATCH 04/45] MDEV-14959: Control over memory allocated for SP/PS The final touch to fixing memory leaks for PS/SP. This patch turns on by default the option WITH_PROTECT_STATEMENT_MEMROOT in order to build server with memory leaks detection mechanism switched on. --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cc34e04b98d..c2e98317763 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -192,11 +192,7 @@ ELSE() ENDIF() -IF("${MYSQL_NO_DASH_VERSION}" VERSION_LESS 11.2) - SET(MEMPROTECT_DEFAULT ON) -ELSE() - SET(MEMPROTECT_DEFAULT OFF) -ENDIF() +SET(MEMPROTECT_DEFAULT ON) OPTION(WITH_PROTECT_STATEMENT_MEMROOT "Enable protection of statement's memory root after first SP/PS execution. Turned into account only for debug build" ${MEMPROTECT_DEFAULT}) From e515e8077393cf5cf3dcda8d6cf57e2d3bca8404 Mon Sep 17 00:00:00 2001 From: mariadb-DebarunBanerjee Date: Sat, 3 Aug 2024 13:11:35 +0530 Subject: [PATCH 05/45] MDEV-34689 Redo log corruption at high load Issue: During mtr_t:commit, if there is not enough space available in redo log buffer, we flush the buffer. During flush, the LSN lock is released allowing other concurrent mtr to commit. After flush we reacquire the lock but use the old LSN obtained before check. It could lead to redo log corruption. As the LSN moves backwards with the possibility of data loss and unrecoverable server if the server aborts for any reason or if server is shutdown with innodb_fast_shutdown=2. With normal shutdown, recovery fails to map the checkpoint LSN to correct offset. In debug mode it hits log0log.cc:863: lsn_t log_t::write_buf() Assertion `new_buf_free == ((lsn - first_lsn) & write_size_1)' failed. In release mode, after normal shutdown, restart fails. [ERROR] InnoDB: Missing FILE_CHECKPOINT(8416546) at 8416546 [ERROR] InnoDB: Log scan aborted at LSN 8416546 Backup fails reading the corrupt redo log. [00] 2024-07-31 20:59:10 Retrying read of log at LSN=7334851 [00] FATAL ERROR: 2024-07-31 20:59:11 Was only able to copy log from 7334851 to 7334851, not 8416446; try increasing innodb_log_file_size Unless a backup is tried or the server is shutdown or killed immediately, the corrupt redo part is eventually truncated and there may not be any visible issues seen in release mode. This issue was introduced by the following commit. commit a635c40648519fd6c3729c9657872a16a0a20821 MDEV-27774 Reduce scalability bottlenecks in mtr_t::commit() Fix: If we need to release latch and flush redo before writing mtr logs, make sure to get the latest system LSN after reacquiring the redo system latch. --- storage/innobase/mtr/mtr0mtr.cc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 6f3abb442a3..0bc531855b9 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -1042,13 +1042,19 @@ std::pair log_t::append_prepare(size_t size, bool ex) noexcept size_t b{spin ? lock_lsn() : buf_free.load(std::memory_order_relaxed)}; write_to_buf++; - const lsn_t l{lsn.load(std::memory_order_relaxed)}, end_lsn{l + size}; + lsn_t l{lsn.load(std::memory_order_relaxed)}, end_lsn{l + size}; if (UNIV_UNLIKELY(pmem ? (end_lsn - get_flushed_lsn(std::memory_order_relaxed)) > capacity() : b + size >= buf_size)) + { b= append_prepare_wait(b, ex, l); + /* While flushing log, we had released the lsn lock and LSN could have + progressed in the meantime. */ + l= lsn.load(std::memory_order_relaxed); + end_lsn= l + size; + } size_t new_buf_free= b + size; if (pmem && new_buf_free >= file_size) From cf202decde475933dfa6b0aadfa5e04e667bfab7 Mon Sep 17 00:00:00 2001 From: Oleg Smirnov Date: Fri, 2 Aug 2024 18:48:29 +0700 Subject: [PATCH 06/45] MDEV-34683 Types mismatch when cloning items causes debug assertion New runtime type diagnostic (MDEV-34490) has detected that classes Item_func_eq, Item_default_value and Item_date_literal_for_invalid_dates incorrectly return an instance of its ancestor classes when being cloned. This commit fixes that. Additionally, it fixes a bug at Item_func_case_simple::do_build_clone() which led to an endless loop of cloning functions calls. Reviewer: Oleksandr Byelkin --- mysql-test/main/item_types.result | 14 ++++++++++++++ mysql-test/main/item_types.test | 18 ++++++++++++++++++ sql/item.h | 7 ++++++- sql/item_cmpfunc.cc | 10 ++++++++++ sql/item_cmpfunc.h | 3 ++- 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/item_types.result b/mysql-test/main/item_types.result index 865b4f612ae..40db01f2609 100644 --- a/mysql-test/main/item_types.result +++ b/mysql-test/main/item_types.result @@ -14,3 +14,17 @@ SELECT * FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.c<=>5; c c DROP TABLE t1, t2; SET optimizer_switch=default; +# +# MDEV-34683 Types mismatch when cloning items causes debug assertion +# +CREATE TABLE t1 (a date); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +SELECT a FROM v1 WHERE a IN ('a', 'b', 'c'); +a +CREATE VIEW v2 AS SELECT '' as a; +SELECT * FROM v2 WHERE a='' AND CASE '' WHEN '' THEN '' ELSE a END=''; +a + +DROP TABLE t1; +DROP VIEW v1, v2; +# End of 10.5 tests diff --git a/mysql-test/main/item_types.test b/mysql-test/main/item_types.test index f43bfe1a8ac..6f10d6bf71a 100644 --- a/mysql-test/main/item_types.test +++ b/mysql-test/main/item_types.test @@ -13,3 +13,21 @@ SELECT * FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.c<=>5; DROP TABLE t1, t2; SET optimizer_switch=default; + +--echo # +--echo # MDEV-34683 Types mismatch when cloning items causes debug assertion +--echo # + +CREATE TABLE t1 (a date); +CREATE ALGORITHM=TEMPTABLE VIEW v1 AS SELECT * FROM t1; +--disable_warnings +SELECT a FROM v1 WHERE a IN ('a', 'b', 'c'); +--enable_warnings + +CREATE VIEW v2 AS SELECT '' as a; +SELECT * FROM v2 WHERE a='' AND CASE '' WHEN '' THEN '' ELSE a END=''; + +DROP TABLE t1; +DROP VIEW v1, v2; + +--echo # End of 10.5 tests diff --git a/sql/item.h b/sql/item.h index b531647e8bf..796b2ec9eee 100644 --- a/sql/item.h +++ b/sql/item.h @@ -5225,6 +5225,9 @@ public: cached_time.copy_to_mysql_time(ltime); return (null_value= false); } + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; @@ -6699,7 +6702,9 @@ public: description */ bool associate_with_target_field(THD *thd, Item_field *field) override; - + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item* do_build_clone(THD *thd) const override { return get_copy(thd); } private: bool tie_field(THD *thd); }; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 2f9da57cdba..c4c96f6f7ae 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1814,6 +1814,16 @@ longlong Item_func_eq::val_int() } +Item *Item_func_eq::do_build_clone(THD *thd) const +{ + /* + Clone the parent and cast to the child class since there is nothing + specific for Item_func_eq + */ + return (Item_func_eq*) Item_bool_rowready_func2::do_build_clone(thd); +} + + /** Same as Item_func_eq, but NULL = NULL. */ bool Item_func_equal::fix_length_and_dec() diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index d394d932adf..adbb00147dc 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -765,6 +765,7 @@ public: friend class Arg_comparator; Item *do_get_copy(THD *thd) const override { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override; }; class Item_func_equal final :public Item_bool_rowready_func2 @@ -2324,7 +2325,7 @@ public: Item *do_build_clone(THD *thd) const override { Item_func_case_simple *clone= (Item_func_case_simple *) - Item_func_case::build_clone(thd); + Item_func_case::do_build_clone(thd); uint ncases= when_count(); if (clone && clone->Predicant_to_list_comparator::init_clone(thd, ncases)) return NULL; From 83040474dcb6e9468bb0a7e42f3a31dc6e156d1a Mon Sep 17 00:00:00 2001 From: Andre F de Miranda Date: Fri, 24 May 2024 22:51:01 +1000 Subject: [PATCH 07/45] MDEV-34234: make lsof optional on RPM Signed-off-by: Julius Goryavsky --- cmake/cpack_rpm.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 65a739dc03e..66645a6676d 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -220,8 +220,9 @@ SETA(CPACK_RPM_server_PACKAGE_REQUIRES IF(WITH_WSREP) SETA(CPACK_RPM_server_PACKAGE_REQUIRES - "galera-4" "rsync" "lsof" "grep" "gawk" "iproute" + "galera-4" "rsync" "grep" "gawk" "iproute" "coreutils" "findutils" "tar") + SETA(CPACK_RPM_server_PACKAGE_RECOMMENDS "lsof") ENDIF() SET(CPACK_RPM_server_PRE_INSTALL_SCRIPT_FILE ${CMAKE_SOURCE_DIR}/support-files/rpm/server-prein.sh) From 0ba6068a82bbce0abf2540dfc0c6954cb281250f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 1 Aug 2024 08:28:28 +0300 Subject: [PATCH 08/45] MDEV-32782 : galera_sst_mysqldump_with_key test failed Modified test configuration file to use wsrep_sync_wait to make sure committed transactions are replicated before next operation. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera/disabled.def | 1 - mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf | 5 +++++ mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 4f3f9884997..1fdde67fd3d 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -16,5 +16,4 @@ galera_sequences : MDEV-32561 WSREP FSM failure: no such a transition REPLICATIN galera_concurrent_ctas : MDEV-32779 galera_concurrent_ctas: assertion in the galera::ReplicatorSMM::finish_cert() galera_as_slave_replay : MDEV-32780 galera_as_slave_replay: assertion in the wsrep::transaction::before_rollback() galera_slave_replay : MDEV-32780 galera_as_slave_replay: assertion in the wsrep::transaction::before_rollback() -galera_sst_mysqldump_with_key : MDEV-32782 galera_sst_mysqldump_with_key test failed galera_var_ignore_apply_errors : MENT-1997 galera_var_ignore_apply_errors test freezes diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf index 52ec6af7e74..da04a605291 100644 --- a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf +++ b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.cnf @@ -3,6 +3,11 @@ # We do not set mysqldump-related SST options here because doing so on startup # causes the first MTR connection to be forefully dropped by Galera, which in turn confuses MTR +[mysqld] +wsrep-debug=1 +wsrep-sync_wait=15 +loose-galera_sst_mysqldump_with_key=1 + [mysqld.1] wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true' diff --git a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test index 3e0e944b0df..31a88777150 100644 --- a/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test +++ b/mysql-test/suite/galera/t/galera_sst_mysqldump_with_key.test @@ -6,6 +6,7 @@ --source include/galera_cluster.inc --source include/have_innodb.inc --source include/have_ssl_communication.inc +--source include/force_restart.inc --source suite/galera/include/galera_sst_set_mysqldump.inc --let $node_1=node_1 From cb80ef93a9b0a7b4f80fde519629f3ad93fcea15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Wed, 31 Jul 2024 14:45:32 +0300 Subject: [PATCH 09/45] MDEV-32778 : galera_ssl_reload failed with warning message Fixed used configuration and added suppression for warning message. Test case changes only. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera_3nodes/disabled.def | 1 - .../galera_3nodes/r/galera_ssl_reload.result | 6 ++++++ .../galera_3nodes/t/galera_ssl_reload.cnf | 10 +++++++--- .../galera_3nodes/t/galera_ssl_reload.test | 20 +++++++++++++------ 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index bcd0fb03478..cbadf6dd5c1 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -11,7 +11,6 @@ ############################################################################## galera_2_cluster : MDEV-32631 galera_2_cluster: before_rollback(): Assertion `0' failed -galera_ssl_reload : MDEV-32778 galera_ssl_reload failed with warning message galera_pc_bootstrap : temporarily disabled at the request of Codership galera_ipv6_mariabackup_section : temporarily disabled at the request of Codership GCF-354 : MDEV-25614 Galera test failure on GCF-354 diff --git a/mysql-test/suite/galera_3nodes/r/galera_ssl_reload.result b/mysql-test/suite/galera_3nodes/r/galera_ssl_reload.result index 1daf3bedf4f..fffc4f3f5b5 100644 --- a/mysql-test/suite/galera_3nodes/r/galera_ssl_reload.result +++ b/mysql-test/suite/galera_3nodes/r/galera_ssl_reload.result @@ -14,3 +14,9 @@ connection node_3; # restart: with restart_parameters connection node_2; FLUSH SSL; +connection node_3; +call mtr.add_suppression("WSREP: Handshake failed: unexpected eof while reading"); +connection node_2; +call mtr.add_suppression("WSREP: Handshake failed: unexpected eof while reading"); +connection node_1; +call mtr.add_suppression("WSREP: Handshake failed: unexpected eof while reading"); diff --git a/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.cnf b/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.cnf index 65d1599268d..d4c654e2bf8 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.cnf +++ b/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.cnf @@ -1,10 +1,14 @@ !include ../galera_3nodes.cnf +[mysqld] +wsrep-debug=1 +loose-galera-ssl-reload=1 + [mysqld.1] -wsrep_provider_options='base_port=@mysqld.1.#galera_port;socket.ssl=yes;socket.ssl_ca=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.root.crt;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.1.crt;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.1.key' +wsrep_provider_options='base_port=@mysqld.1.#galera_port;socket.ssl=yes;socket.ssl_ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/client-cert.pem;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/client-key.pem' [mysqld.2] -wsrep_provider_options='base_port=@mysqld.2.#galera_port;socket.ssl=yes;socket.ssl_ca=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.root.crt;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.1.crt;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.1.key' +wsrep_provider_options='base_port=@mysqld.2.#galera_port;socket.ssl=yes;socket.ssl_ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/client-cert.pem;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/client-key.pem' [mysqld.3] -wsrep_provider_options='base_port=@mysqld.3.#galera_port;socket.ssl=yes;socket.ssl_ca=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.root.crt;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.1.crt;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/galera_certs/galera.1.key' +wsrep_provider_options='base_port=@mysqld.3.#galera_port;socket.ssl=yes;socket.ssl_ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem;socket.ssl_cert=@ENV.MYSQL_TEST_DIR/std_data/client-cert.pem;socket.ssl_key=@ENV.MYSQL_TEST_DIR/std_data/client-key.pem' diff --git a/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.test b/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.test index 714d4b3f75c..f7bed23294d 100644 --- a/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.test +++ b/mysql-test/suite/galera_3nodes/t/galera_ssl_reload.test @@ -5,6 +5,7 @@ --source include/galera_cluster.inc --source include/have_openssl.inc --source include/have_ssl_communication.inc +--source include/force_restart.inc --let $galera_version=26.4.8 source ../../wsrep/include/check_galera_version.inc; @@ -31,22 +32,22 @@ let $ssl_cert = $MYSQLTEST_VARDIR/tmp/ssl_cert.pem; let $ssl_key = $MYSQLTEST_VARDIR/tmp/ssl_key.pem; let $ssl_ca = $MYSQLTEST_VARDIR/tmp/ssl_ca.pem; -copy_file std_data/galera_certs/galera.root.crt $ssl_ca; -copy_file std_data/galera_certs/galera.1.crt $ssl_cert; -copy_file std_data/galera_certs/galera.1.key $ssl_key; +copy_file std_data/cacert.pem $ssl_ca; +copy_file std_data/client-cert.pem $ssl_cert; +copy_file std_data/client-key.pem $ssl_key; --connection node_2 --source include/shutdown_mysqld.inc --let $restart_noprint=1 ---let $restart_parameters = --wsrep_cluster_address=gcomm://127.0.0.1:$NODE_GALERAPORT_1 --wsrep_provider_options=base_port=$NODE_GALERAPORT_2;socket.ssl=yes;socket.ssl_ca=$MYSQL_TEST_DIR/std_data/galera_certs/galera.root.crt;socket.ssl_cert=$MYSQLTEST_VARDIR/tmp/ssl_cert.pem;socket.ssl_key=$MYSQLTEST_VARDIR/tmp/ssl_key.pem +--let $restart_parameters = --wsrep_cluster_address=gcomm://127.0.0.1:$NODE_GALERAPORT_1 --wsrep_provider_options=base_port=$NODE_GALERAPORT_2;socket.ssl=yes;socket.ssl_ca=$MYSQL_TEST_DIR/std_data/cacert.pem;socket.ssl_cert=$MYSQLTEST_VARDIR/tmp/ssl_cert.pem;socket.ssl_key=$MYSQLTEST_VARDIR/tmp/ssl_key.pem --source include/start_mysqld.inc --source include/galera_wait_ready.inc # Set certificate and key and reload by setting directly `wsrep_provider_options` remove_file $ssl_cert; remove_file $ssl_key; -copy_file std_data/galera_certs/galera.2.crt $ssl_cert; -copy_file std_data/galera_certs/galera.2.key $ssl_key; +copy_file std_data/client-cert.pem $ssl_cert; +copy_file std_data/client-key.pem $ssl_key; SET GLOBAL wsrep_provider_options = 'socket.ssl_reload=1'; --connection node_3 @@ -67,5 +68,12 @@ remove_file $ssl_ca; remove_file $ssl_cert; remove_file $ssl_key; +--connection node_3 +call mtr.add_suppression("WSREP: Handshake failed: unexpected eof while reading"); +--connection node_2 +call mtr.add_suppression("WSREP: Handshake failed: unexpected eof while reading"); +--connection node_1 +call mtr.add_suppression("WSREP: Handshake failed: unexpected eof while reading"); + # Restore original auto_increment_offset values. --source ../galera/include/auto_increment_offset_restore.inc From eb30a9d63391359e686cfffb36b4c0e4a7e2f5a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 26 Jul 2024 09:04:30 +0300 Subject: [PATCH 10/45] MDEV-34647 : 'INSERT...SELECT' on MyISAM table suddenly replicated by Galera Replication of MyISAM and Aria DML is experimental and best effort only. Earlier change make INSERT SELECT on both MyISAM and Aria to replicate using TOI and STATEMENT replication. Replication should happen only if user has set needed wsrep_mode setting. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera/r/MDEV-34647.result | 100 ++++++++++++++++++++ mysql-test/suite/galera/r/mdev-22063.result | 16 ++-- mysql-test/suite/galera/t/MDEV-34647.test | 53 +++++++++++ mysql-test/suite/galera/t/mdev-22063.test | 8 +- sql/sql_parse.cc | 8 +- 5 files changed, 172 insertions(+), 13 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-34647.result create mode 100644 mysql-test/suite/galera/t/MDEV-34647.test diff --git a/mysql-test/suite/galera/r/MDEV-34647.result b/mysql-test/suite/galera/r/MDEV-34647.result new file mode 100644 index 00000000000..5a1d4530e52 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-34647.result @@ -0,0 +1,100 @@ +connection node_2; +connection node_1; +create table t1(id serial, val varchar(100)) engine=myisam; +insert into t1 values(null, 'a'); +insert into t1 values(null, 'b'); +insert into t1 select null, 'c'; +insert into t1 select null, 'd' from t1; +select * from t1; +id val +1 a +3 b +5 c +7 d +9 d +11 d +create table t2(id serial, val varchar(100)) engine=aria; +insert into t2 values(null, 'a'); +insert into t2 values(null, 'b'); +insert into t2 select null, 'c'; +insert into t2 select null, 'd' from t2; +select * from t2; +id val +1 a +3 b +5 c +7 d +9 d +11 d +create table t3(id serial, val varchar(100)) engine=innodb; +insert into t3 values(null, 'a'); +insert into t3 values(null, 'b'); +insert into t3 select null, 'c'; +insert into t3 select null, 'd' from t3; +select * from t3; +id val +1 a +3 b +5 c +7 d +9 d +11 d +set global wsrep_replicate_myisam=ON; +create table t4(id serial, val varchar(100)) engine=myisam; +insert into t4 values(null, 'a'); +insert into t4 values(null, 'b'); +insert into t4 select null, 'c'; +insert into t4 select null, 'd' from t4; +select * from t4; +id val +1 a +2 b +3 c +4 d +5 d +6 d +create table t5(id serial, val varchar(100)) engine=myisam; +insert into t5 values(null, 'a'); +insert into t5 values(null, 'b'); +insert into t5 select null, 'c'; +insert into t5 select null, 'd' from t5; +select * from t2; +id val +1 a +3 b +5 c +7 d +9 d +11 d +connection node_2; +select * from t1; +id val +select * from t2; +id val +select * from t3; +id val +1 a +3 b +5 c +7 d +9 d +11 d +select * from t4; +id val +1 a +2 b +3 c +4 d +5 d +6 d +select * from t5; +id val +1 a +2 b +3 c +4 d +5 d +6 d +connection node_1; +drop table t1,t2,t3,t4,t5; +set global wsrep_replicate_myisam=default; diff --git a/mysql-test/suite/galera/r/mdev-22063.result b/mysql-test/suite/galera/r/mdev-22063.result index 5773e70cc9d..f5007b2656c 100644 --- a/mysql-test/suite/galera/r/mdev-22063.result +++ b/mysql-test/suite/galera/r/mdev-22063.result @@ -114,7 +114,7 @@ EXPECT_1000 1000 SELECT COUNT(*) AS EXPECT_1000 FROM t3; EXPECT_1000 -1000 +0 SELECT COUNT(*) AS EXPECT_1000 FROM t4; EXPECT_1000 1000 @@ -127,9 +127,9 @@ EXPECT_1000 SELECT COUNT(*) AS EXPECT_1000 FROM t7; EXPECT_1000 1000 -SELECT COUNT(*) AS EXPECT_1000 FROM t8; -EXPECT_1000 -1000 +SELECT COUNT(*) AS EXPECT_0 FROM t8; +EXPECT_0 +0 connection node_1; DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8; # Bigger INSERT INTO ... SELECT test @@ -182,7 +182,7 @@ EXPECT_1000 1000 SELECT COUNT(*) AS EXPECT_1000 FROM t3; EXPECT_1000 -1000 +0 SELECT COUNT(*) AS EXPECT_1000 FROM t4; EXPECT_1000 1000 @@ -195,9 +195,9 @@ EXPECT_1000 SELECT COUNT(*) AS EXPECT_1000 FROM t7; EXPECT_1000 1000 -SELECT COUNT(*) AS EXPECT_1000 FROM t8; -EXPECT_1000 -1000 +SELECT COUNT(*) AS EXPECT_0 FROM t8; +EXPECT_0 +0 connection node_1; DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8; CREATE TABLE t1(pk int not null primary key) engine=innodb; diff --git a/mysql-test/suite/galera/t/MDEV-34647.test b/mysql-test/suite/galera/t/MDEV-34647.test new file mode 100644 index 00000000000..1697bf05f28 --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-34647.test @@ -0,0 +1,53 @@ +--source include/galera_cluster.inc +--source include/have_aria.inc + +create table t1(id serial, val varchar(100)) engine=myisam; +insert into t1 values(null, 'a'); +insert into t1 values(null, 'b'); +insert into t1 select null, 'c'; +insert into t1 select null, 'd' from t1; +select * from t1; + +create table t2(id serial, val varchar(100)) engine=aria; +insert into t2 values(null, 'a'); +insert into t2 values(null, 'b'); +insert into t2 select null, 'c'; +insert into t2 select null, 'd' from t2; +select * from t2; + +create table t3(id serial, val varchar(100)) engine=innodb; +insert into t3 values(null, 'a'); +insert into t3 values(null, 'b'); +insert into t3 select null, 'c'; +insert into t3 select null, 'd' from t3; +select * from t3; + +set global wsrep_replicate_myisam=ON; + +create table t4(id serial, val varchar(100)) engine=myisam; +insert into t4 values(null, 'a'); +insert into t4 values(null, 'b'); +insert into t4 select null, 'c'; +insert into t4 select null, 'd' from t4; +select * from t4; + +create table t5(id serial, val varchar(100)) engine=myisam; +insert into t5 values(null, 'a'); +insert into t5 values(null, 'b'); +insert into t5 select null, 'c'; +insert into t5 select null, 'd' from t5; +select * from t2; + + +--connection node_2 +select * from t1; +select * from t2; +select * from t3; +select * from t4; +select * from t5; + + +--connection node_1 +drop table t1,t2,t3,t4,t5; +set global wsrep_replicate_myisam=default; + diff --git a/mysql-test/suite/galera/t/mdev-22063.test b/mysql-test/suite/galera/t/mdev-22063.test index ef16c0c8716..c3a7af7e0bb 100644 --- a/mysql-test/suite/galera/t/mdev-22063.test +++ b/mysql-test/suite/galera/t/mdev-22063.test @@ -97,7 +97,7 @@ SELECT COUNT(*) AS EXPECT_1000 FROM t8; --connection node_2 --let $wait_condition = SELECT COUNT(*) = 8 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME LIKE 't_' --source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 1000 FROM test.t8; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM test.t7; --source include/wait_condition.inc SELECT COUNT(*) AS EXPECT_1000 FROM t1; @@ -107,7 +107,7 @@ SELECT COUNT(*) AS EXPECT_1000 FROM t4; SELECT COUNT(*) AS EXPECT_1000 FROM t5; SELECT COUNT(*) AS EXPECT_1000 FROM t6; SELECT COUNT(*) AS EXPECT_1000 FROM t7; -SELECT COUNT(*) AS EXPECT_1000 FROM t8; +SELECT COUNT(*) AS EXPECT_0 FROM t8; --connection node_1 DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8; @@ -145,7 +145,7 @@ SELECT COUNT(*) AS EXPECT_1000 FROM t8; --connection node_2 --let $wait_condition = SELECT COUNT(*) = 8 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'test' AND TABLE_NAME LIKE 't_' --source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 1000 FROM test.t8; +--let $wait_condition = SELECT COUNT(*) = 1000 FROM test.t7; --source include/wait_condition.inc SELECT COUNT(*) AS EXPECT_1000 FROM t1; @@ -155,7 +155,7 @@ SELECT COUNT(*) AS EXPECT_1000 FROM t4; SELECT COUNT(*) AS EXPECT_1000 FROM t5; SELECT COUNT(*) AS EXPECT_1000 FROM t6; SELECT COUNT(*) AS EXPECT_1000 FROM t7; -SELECT COUNT(*) AS EXPECT_1000 FROM t8; +SELECT COUNT(*) AS EXPECT_0 FROM t8; --connection node_1 DROP TABLE t1,t2,t3,t4,t5,t6,t7,t8; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 8a218290114..2d6c7621f7b 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4761,7 +4761,13 @@ mysql_execute_command(THD *thd) // For !InnoDB we start TOI if it is not yet started and hope for the best if (!is_innodb && !wsrep_toi) - WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); + { + const legacy_db_type db_type= first_table->table->file->partition_ht()->db_type; + + /* Currently we support TOI for MyISAM only. */ + if (db_type == DB_TYPE_MYISAM && wsrep_replicate_myisam) + WSREP_TO_ISOLATION_BEGIN(first_table->db.str, first_table->table_name.str, NULL); + } } #endif /* WITH_WSREP */ /* From 71f289e5d1691a060148d7063c663730f580f26d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 30 Jul 2024 12:30:39 +0300 Subject: [PATCH 11/45] MDEV-25614 : Galera test failure on GCF-354 Modified node config with longer timeouts for suspect, inactive, install and wait_prim timeout. Increased node_1 weight to keep it primary component when other nodes are voted out. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera_3nodes/disabled.def | 1 - mysql-test/suite/galera_3nodes/r/GCF-354.result | 9 ++++++--- mysql-test/suite/galera_3nodes/t/GCF-354.cnf | 11 +++++++++++ mysql-test/suite/galera_3nodes/t/GCF-354.test | 10 ++++------ 4 files changed, 21 insertions(+), 10 deletions(-) diff --git a/mysql-test/suite/galera_3nodes/disabled.def b/mysql-test/suite/galera_3nodes/disabled.def index cbadf6dd5c1..b7f0d8da8c1 100644 --- a/mysql-test/suite/galera_3nodes/disabled.def +++ b/mysql-test/suite/galera_3nodes/disabled.def @@ -13,4 +13,3 @@ galera_2_cluster : MDEV-32631 galera_2_cluster: before_rollback(): Assertion `0' failed galera_pc_bootstrap : temporarily disabled at the request of Codership galera_ipv6_mariabackup_section : temporarily disabled at the request of Codership -GCF-354 : MDEV-25614 Galera test failure on GCF-354 diff --git a/mysql-test/suite/galera_3nodes/r/GCF-354.result b/mysql-test/suite/galera_3nodes/r/GCF-354.result index 3fdd44fe9d3..c69de54747f 100644 --- a/mysql-test/suite/galera_3nodes/r/GCF-354.result +++ b/mysql-test/suite/galera_3nodes/r/GCF-354.result @@ -1,17 +1,20 @@ connection node_2; connection node_1; +connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3; connection node_1; connection node_2; connection node_3; connection node_2; -SET SESSION wsrep_on=OFF; +SET wsrep_on=OFF; DROP SCHEMA test; connection node_3; -SET SESSION wsrep_on=OFF; +SET wsrep_on=OFF; CREATE TABLE test.t1 (f1 INTEGER NOT NULL PRIMARY KEY) engine=innodb; connection node_1; CREATE TABLE test.t1 (f1 INTEGER NOT NULL PRIMARY KEY) engine=innodb; -INSERT INTO test.t1 values (1); +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; +VARIABLE_VALUE +1 SHOW STATUS LIKE 'wsrep_cluster_status'; Variable_name Value wsrep_cluster_status Primary diff --git a/mysql-test/suite/galera_3nodes/t/GCF-354.cnf b/mysql-test/suite/galera_3nodes/t/GCF-354.cnf index 4c5e4854606..e87e65ca58c 100644 --- a/mysql-test/suite/galera_3nodes/t/GCF-354.cnf +++ b/mysql-test/suite/galera_3nodes/t/GCF-354.cnf @@ -3,3 +3,14 @@ [mysqld] wsrep-ignore-apply-errors=0 wsrep_sync_wait=0 +loose-gcf-354=0 +wsrep-debug=1 + +[mysqld.1] +wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.1.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;pc.wait_prim_timeout=PT60S;gcache.size=1G;pc.weight=4' + +[mysqld.2] +wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.2.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;pc.wait_prim_timeout=PT60S;gcache.size=1G' + +[mysqld.3] +wsrep_provider_options='repl.causal_read_timeout=PT90S;base_port=@mysqld.3.#galera_port;evs.suspect_timeout=PT10S;evs.inactive_timeout=PT30S;evs.install_timeout=PT15S;pc.wait_prim_timeout=PT60S;gcache.size=1G' diff --git a/mysql-test/suite/galera_3nodes/t/GCF-354.test b/mysql-test/suite/galera_3nodes/t/GCF-354.test index 44dfa3deeb7..372f6329e8e 100644 --- a/mysql-test/suite/galera_3nodes/t/GCF-354.test +++ b/mysql-test/suite/galera_3nodes/t/GCF-354.test @@ -2,9 +2,7 @@ --source include/have_innodb.inc --source include/force_restart.inc ---let $galera_connection_name = node_3 ---let $galera_server_number = 3 ---source include/galera_connect.inc +--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3 # Save original auto_increment_offset values. --let $node_1=node_1 @@ -16,11 +14,11 @@ # 1. Create different inconsistencies on nodes 2 and 3 # --connection node_2 -SET SESSION wsrep_on=OFF; +SET wsrep_on=OFF; DROP SCHEMA test; --connection node_3 -SET SESSION wsrep_on=OFF; +SET wsrep_on=OFF; CREATE TABLE test.t1 (f1 INTEGER NOT NULL PRIMARY KEY) engine=innodb; # # 2. The following should generate different errors on nodes 2 and 3 and @@ -29,10 +27,10 @@ CREATE TABLE test.t1 (f1 INTEGER NOT NULL PRIMARY KEY) engine=innodb; # --connection node_1 CREATE TABLE test.t1 (f1 INTEGER NOT NULL PRIMARY KEY) engine=innodb; -INSERT INTO test.t1 values (1); --let $wait_condition = SELECT VARIABLE_VALUE = 1 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' --source include/wait_condition.inc +SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status' --source include/wait_condition.inc SHOW STATUS LIKE 'wsrep_cluster_status'; From 8b51d34462370b96af420587fdc07934abcea8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 23 Jul 2024 11:57:01 +0300 Subject: [PATCH 12/45] MDEV-34640 : galera_var_ignore_apply_errors test freezes Test improvements only to make test more robust. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera/disabled.def | 1 - .../r/galera_var_ignore_apply_errors.result | 83 +++++++++---- .../t/galera_var_ignore_apply_errors.cnf | 7 +- .../t/galera_var_ignore_apply_errors.test | 116 +++++++----------- 4 files changed, 104 insertions(+), 103 deletions(-) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 1fdde67fd3d..e00bdbf85c0 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -16,4 +16,3 @@ galera_sequences : MDEV-32561 WSREP FSM failure: no such a transition REPLICATIN galera_concurrent_ctas : MDEV-32779 galera_concurrent_ctas: assertion in the galera::ReplicatorSMM::finish_cert() galera_as_slave_replay : MDEV-32780 galera_as_slave_replay: assertion in the wsrep::transaction::before_rollback() galera_slave_replay : MDEV-32780 galera_as_slave_replay: assertion in the wsrep::transaction::before_rollback() -galera_var_ignore_apply_errors : MENT-1997 galera_var_ignore_apply_errors test freezes diff --git a/mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result b/mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result index 0b32f43704f..ea8510581bb 100644 --- a/mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result +++ b/mysql-test/suite/galera/r/galera_var_ignore_apply_errors.result @@ -7,27 +7,60 @@ SET GLOBAL wsrep_on = OFF; CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = ON; DROP TABLE t1; +connection node_2; +SHOW TABLES; +Tables_in_test +connection node_1; SET GLOBAL wsrep_on = OFF; CREATE SCHEMA s1; SET GLOBAL wsrep_on = ON; DROP SCHEMA s1; +connection node_2; +SHOW SCHEMAS; +Database +information_schema +mtr +mysql +performance_schema +test +connection node_1; CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = OFF; CREATE INDEX idx1 ON t1 (f1); SET GLOBAL wsrep_on = ON; DROP INDEX idx1 ON t1; +connection node_2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; +connection node_1; CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = OFF; CREATE INDEX idx1 ON t1 (f1); SET GLOBAL wsrep_on = ON; ALTER TABLE t1 DROP INDEX idx1; +connection node_2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; +connection node_1; CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = OFF; ALTER TABLE t1 ADD COLUMN f2 INTEGER; SET GLOBAL wsrep_on = ON; ALTER TABLE t1 DROP COLUMN f2; +connection node_2; +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `f1` int(11) DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci DROP TABLE t1; connection node_2; SET GLOBAL wsrep_ignore_apply_errors = 2; @@ -37,12 +70,11 @@ SET GLOBAL wsrep_on = OFF; INSERT INTO t1 VALUES (1); SET GLOBAL wsrep_on = ON; DELETE FROM t1 WHERE f1 = 1; -connection node_1; -SELECT COUNT(*) as expect_0 FROM t1; +SELECT COUNT(*) AS expect_0 FROM t1; expect_0 0 connection node_2; -SELECT COUNT(*) as expect_0 FROM t1; +SELECT COUNT(*) AS expect_0 FROM t1; expect_0 0 DROP TABLE t1; @@ -57,12 +89,11 @@ INSERT INTO t1 VALUES (3); DELETE FROM t1 WHERE f1 = 1; DELETE FROM t1 WHERE f1 = 2; COMMIT; -connection node_1; -SELECT COUNT(*) as expect_1 FROM t1; +SELECT COUNT(*) AS expect_1 FROM t1; expect_1 1 connection node_2; -SELECT COUNT(*) as expect_1 FROM t1; +SELECT COUNT(*) AS expect_1 FROM t1; expect_1 1 DROP TABLE t1; @@ -75,14 +106,14 @@ DELETE FROM t1 WHERE f1 = 3; SET SESSION wsrep_on = ON; connection node_1; DELETE FROM t1; -SELECT COUNT(*) as expect_0 FROM t1; +SELECT COUNT(*) AS expect_0 FROM t1; expect_0 0 connection node_2; -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; -VARIABLE_VALUE = 'Primary' -1 -SELECT COUNT(*) as expect_0 FROM t1; +SELECT VARIABLE_VALUE expect_Primary FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +expect_Primary +Primary +SELECT COUNT(*) AS expect_0 FROM t1; expect_0 0 DROP TABLE t1; @@ -103,14 +134,14 @@ DELETE FROM t1 WHERE f1 = 4; DELETE FROM t1 WHERE f1 = 5; COMMIT; SET AUTOCOMMIT=ON; -SELECT COUNT(*) as expect_0 FROM t1; +SELECT COUNT(*) AS expect_0 FROM t1; expect_0 0 connection node_2; -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; -VARIABLE_VALUE = 'Primary' -1 -SELECT COUNT(*) as expect_0 FROM t1; +SELECT VARIABLE_VALUE expect_Primary FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +expect_Primary +Primary +SELECT COUNT(*) AS expect_0 FROM t1; expect_0 0 DROP TABLE t1; @@ -126,14 +157,14 @@ DELETE FROM t1 WHERE f1 = 3; SET SESSION wsrep_on = ON; connection node_1; DELETE t1, t2 FROM t1 JOIN t2 WHERE t1.f1 = t2.f1; -SELECT COUNT(*) as expect_0 FROM t1; +SELECT COUNT(*) expect_0 FROM t1; expect_0 0 connection node_2; -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +SELECT VARIABLE_VALUE = 'Primary' FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; VARIABLE_VALUE = 'Primary' 1 -SELECT COUNT(*) as expect_0 FROM t1; +SELECT COUNT(*) expect_0 FROM t1; expect_0 0 DROP TABLE t1,t2; @@ -148,20 +179,20 @@ DELETE FROM child WHERE parent_id = 2; SET SESSION wsrep_on = ON; connection node_1; DELETE FROM parent; -SELECT COUNT(*) as expect_0 FROM parent; +SELECT COUNT(*) AS expect_0 FROM parent; expect_0 0 -SELECT COUNT(*) as expect_0 FROM child; +SELECT COUNT(*) AS expect_0 FROM child; expect_0 0 connection node_2; -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +SELECT VARIABLE_VALUE = 'Primary' FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; VARIABLE_VALUE = 'Primary' 1 -SELECT COUNT(*) as expect_0 FROM parent; +SELECT COUNT(*) AS expect_0 FROM parent; expect_0 0 -SELECT COUNT(*) as expect_0 FROM child; +SELECT COUNT(*) AS expect_0 FROM child; expect_0 0 DROP TABLE child, parent; @@ -175,8 +206,10 @@ connection node_1; CREATE TABLE t1 (f1 INTEGER, f2 INTEGER); DROP TABLE t1; connection node_2; +SELECT * FROM t1; +ERROR 42S02: Table 'test.t1' doesn't exist SET GLOBAL wsrep_ignore_apply_errors = 7; -CALL mtr.add_suppression("Can't find record in 't.*'"); +CALL mtr.add_suppression("Can't find record in "); CALL mtr.add_suppression("Slave SQL: Could not execute Delete_rows event"); CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test\\.t1'' on query\\. Default database: 'test'\\. Query: 'DROP TABLE t1', Error_code: 1051"); CALL mtr.add_suppression("Slave SQL: Error 'Can't drop database 's1'; database doesn't exist' on query\\. Default database: 'test'\\. Query: 'DROP SCHEMA s1', Error_code: 1008"); diff --git a/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.cnf b/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.cnf index 545cc8147e0..1d02401decc 100644 --- a/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.cnf +++ b/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.cnf @@ -1,7 +1,6 @@ !include ../galera_2nodes.cnf -[mysqld.1] -wsrep_debug=1 - -[mysqld.2] +[mysqld] wsrep_debug=1 +wsrep_sync_wait=15 +loose-galera-var-ignore-apply-errors=1 diff --git a/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test b/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test index e5bff5d8dc4..d5c6521add4 100644 --- a/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test +++ b/mysql-test/suite/galera/t/galera_var_ignore_apply_errors.test @@ -3,7 +3,7 @@ # --source include/galera_cluster.inc - +--source include/force_restart.inc # # Ignore reconciling DDL errors on node_2 @@ -17,41 +17,55 @@ SET GLOBAL wsrep_ignore_apply_errors = 1; SET GLOBAL wsrep_on = OFF; CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc DROP TABLE t1; +--connection node_2 +SHOW TABLES; + # Drop schema that does not exist +--connection node_1 SET GLOBAL wsrep_on = OFF; CREATE SCHEMA s1; SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc DROP SCHEMA s1; +--connection node_2 +SHOW SCHEMAS; + # Drop index that does not exist using DROP INDEX +--connection node_1 CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = OFF; CREATE INDEX idx1 ON t1 (f1); SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc DROP INDEX idx1 ON t1; + +--connection node_2 +SHOW CREATE TABLE t1; DROP TABLE t1; # Drop index that does not exist using ALTER TABLE +--connection node_1 CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = OFF; CREATE INDEX idx1 ON t1 (f1); SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc ALTER TABLE t1 DROP INDEX idx1; + +--connection node_2 +SHOW CREATE TABLE t1; DROP TABLE t1; # Drop column that does not exist +--connection node_1 CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = OFF; ALTER TABLE t1 ADD COLUMN f2 INTEGER; SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc ALTER TABLE t1 DROP COLUMN f2; + +--connection node_2 +SHOW CREATE TABLE t1; DROP TABLE t1; @@ -68,21 +82,11 @@ CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = OFF; INSERT INTO t1 VALUES (1); SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc DELETE FROM t1 WHERE f1 = 1; +SELECT COUNT(*) AS expect_0 FROM t1; ---connection node_1 ---let $wait_condition = SELECT COUNT(*) = 0 FROM t1; ---source include/wait_condition.inc -SELECT COUNT(*) as expect_0 FROM t1; --connection node_2 ---source include/galera_wait_ready.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; ---source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 0 FROM t1; ---source include/wait_condition.inc -SELECT COUNT(*) as expect_0 FROM t1; - +SELECT COUNT(*) AS expect_0 FROM t1; DROP TABLE t1; # Delete row that does not exist in a multi statement transaction @@ -92,25 +96,15 @@ INSERT INTO t1 VALUES (2); SET GLOBAL wsrep_on = OFF; INSERT INTO t1 VALUES (1); SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc START TRANSACTION; INSERT INTO t1 VALUES (3); DELETE FROM t1 WHERE f1 = 1; DELETE FROM t1 WHERE f1 = 2; COMMIT; +SELECT COUNT(*) AS expect_1 FROM t1; ---connection node_1 ---let $wait_condition = SELECT COUNT(*) = 1 FROM t1; ---source include/wait_condition.inc -SELECT COUNT(*) as expect_1 FROM t1; --connection node_2 ---source include/galera_wait_ready.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; ---source include/wait_condition.inc ---let $wait_condition = SELECT COUNT(*) = 1 FROM t1; ---source include/wait_condition.inc -SELECT COUNT(*) as expect_1 FROM t1; - +SELECT COUNT(*) AS expect_1 FROM t1; DROP TABLE t1; # @@ -127,21 +121,16 @@ INSERT INTO t1 VALUES (1),(2),(3),(4),(5); SET SESSION wsrep_on = OFF; DELETE FROM t1 WHERE f1 = 3; SET SESSION wsrep_on = ON; ---source include/galera_wait_ready.inc + --connection node_1 DELETE FROM t1; +SELECT COUNT(*) AS expect_0 FROM t1; -SELECT COUNT(*) as expect_0 FROM t1; --connection node_2 ---source include/galera_wait_ready.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; ---source include/wait_condition.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; ---source include/wait_condition.inc -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --let $wait_condition = SELECT COUNT(*) = 0 FROM t1; --source include/wait_condition.inc -SELECT COUNT(*) as expect_0 FROM t1; +SELECT VARIABLE_VALUE expect_Primary FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +SELECT COUNT(*) AS expect_0 FROM t1; DROP TABLE t1; # @@ -158,10 +147,8 @@ INSERT INTO t1 VALUES (1),(2),(3),(4),(5); SET SESSION wsrep_on = OFF; DELETE FROM t1 WHERE f1 = 3; SET SESSION wsrep_on = ON; ---source include/galera_wait_ready.inc --connection node_1 - SET AUTOCOMMIT=OFF; START TRANSACTION; DELETE FROM t1 WHERE f1 = 1; @@ -171,18 +158,13 @@ DELETE FROM t1 WHERE f1 = 4; DELETE FROM t1 WHERE f1 = 5; COMMIT; SET AUTOCOMMIT=ON; +SELECT COUNT(*) AS expect_0 FROM t1; -SELECT COUNT(*) as expect_0 FROM t1; --connection node_2 ---source include/galera_wait_ready.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; ---source include/wait_condition.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; ---source include/wait_condition.inc -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --let $wait_condition = SELECT COUNT(*) = 0 FROM t1; --source include/wait_condition.inc -SELECT COUNT(*) as expect_0 FROM t1; +SELECT VARIABLE_VALUE expect_Primary FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +SELECT COUNT(*) AS expect_0 FROM t1; DROP TABLE t1; # @@ -203,22 +185,16 @@ SET SESSION wsrep_on = OFF; DELETE FROM t2 WHERE f1 = 2; DELETE FROM t1 WHERE f1 = 3; SET SESSION wsrep_on = ON; ---source include/galera_wait_ready.inc --connection node_1 DELETE t1, t2 FROM t1 JOIN t2 WHERE t1.f1 = t2.f1; -SELECT COUNT(*) as expect_0 FROM t1; +SELECT COUNT(*) expect_0 FROM t1; --connection node_2 ---source include/galera_wait_ready.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; ---source include/wait_condition.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; ---source include/wait_condition.inc -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; --let $wait_condition = SELECT COUNT(*) = 0 FROM t1; --source include/wait_condition.inc -SELECT COUNT(*) as expect_0 FROM t1; +SELECT VARIABLE_VALUE = 'Primary' FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +SELECT COUNT(*) expect_0 FROM t1; DROP TABLE t1,t2; # @@ -238,26 +214,18 @@ INSERT INTO child VALUES (1,1),(2,2),(3,3); SET SESSION wsrep_on = OFF; DELETE FROM child WHERE parent_id = 2; SET SESSION wsrep_on = ON; ---source include/galera_wait_ready.inc --connection node_1 DELETE FROM parent; -SELECT COUNT(*) as expect_0 FROM parent; -SELECT COUNT(*) as expect_0 FROM child; +SELECT COUNT(*) AS expect_0 FROM parent; +SELECT COUNT(*) AS expect_0 FROM child; --connection node_2 ---source include/galera_wait_ready.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; ---source include/wait_condition.inc ---let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; ---source include/wait_condition.inc -SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_status'; ---let $wait_condition = SELECT COUNT(*) = 0 FROM parent; ---source include/wait_condition.inc --let $wait_condition = SELECT COUNT(*) = 0 FROM child; --source include/wait_condition.inc -SELECT COUNT(*) as expect_0 FROM parent; -SELECT COUNT(*) as expect_0 FROM child; +SELECT VARIABLE_VALUE = 'Primary' FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status'; +SELECT COUNT(*) AS expect_0 FROM parent; +SELECT COUNT(*) AS expect_0 FROM child; DROP TABLE child, parent; # @@ -272,15 +240,17 @@ SET GLOBAL wsrep_ignore_apply_errors = 4; SET GLOBAL wsrep_on = OFF; CREATE TABLE t1 (f1 INTEGER); SET GLOBAL wsrep_on = ON; ---source include/galera_wait_ready.inc + --connection node_1 CREATE TABLE t1 (f1 INTEGER, f2 INTEGER); DROP TABLE t1; --connection node_2 +--error ER_NO_SUCH_TABLE +SELECT * FROM t1; SET GLOBAL wsrep_ignore_apply_errors = 7; -CALL mtr.add_suppression("Can't find record in 't.*'"); +CALL mtr.add_suppression("Can't find record in "); CALL mtr.add_suppression("Slave SQL: Could not execute Delete_rows event"); CALL mtr.add_suppression("Slave SQL: Error 'Unknown table 'test\\.t1'' on query\\. Default database: 'test'\\. Query: 'DROP TABLE t1', Error_code: 1051"); CALL mtr.add_suppression("Slave SQL: Error 'Can't drop database 's1'; database doesn't exist' on query\\. Default database: 'test'\\. Query: 'DROP SCHEMA s1', Error_code: 1008"); From bce3f3f6287f706e90e067b16f9a8203f64a30a7 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Fri, 2 Aug 2024 10:29:08 +1000 Subject: [PATCH 13/45] MDEV-34682 Reset spider_hton_ptr in error mode of spider_db_init() --- .../spider/bugfix/r/mdev_34682.result | 19 +++++++++++++++++++ .../spider/bugfix/t/mdev_34682.test | 14 ++++++++++++++ .../spider/include/clean_up_spider.inc | 10 +++++----- storage/spider/spd_table.cc | 1 + 4 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 storage/spider/mysql-test/spider/bugfix/r/mdev_34682.result create mode 100644 storage/spider/mysql-test/spider/bugfix/t/mdev_34682.test diff --git a/storage/spider/mysql-test/spider/bugfix/r/mdev_34682.result b/storage/spider/mysql-test/spider/bugfix/r/mdev_34682.result new file mode 100644 index 00000000000..7253e136488 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/r/mdev_34682.result @@ -0,0 +1,19 @@ +set @old_aria_encrypt_tables=@@global.aria_encrypt_tables; +set global aria_encrypt_tables=ON; +CREATE FUNCTION spider_direct_sql RETURNS INT SONAME 'ha_spider.so'; +call mtr.add_suppression(".*\\[ERROR\\] SPIDER plugin initialization failed at.* by 'Initialization of encryption failed for"); +call mtr.add_suppression(".*\\[ERROR\\] Plugin 'SPIDER' registration as a STORAGE ENGINE failed."); +INSTALL PLUGIN spider SONAME 'ha_spider.so'; +ERROR HY000: Can't initialize function 'spider'; Plugin initialization function failed. +SELECT spider_direct_sql ('SELECT * FROM s','a','srv "b"'); +ERROR HY000: Can't initialize function 'spider_direct_sql'; Plugin 'SPIDER' is not loaded +Warnings: +Note 1305 FUNCTION test.spider_flush_table_mon_cache does not exist +Warnings: +Note 1305 FUNCTION test.spider_copy_tables does not exist +Warnings: +Note 1305 FUNCTION test.spider_ping_table does not exist +Warnings: +Note 1305 FUNCTION test.spider_bg_direct_sql does not exist +Warnings: +Note 1305 SONAME ha_spider.so does not exist diff --git a/storage/spider/mysql-test/spider/bugfix/t/mdev_34682.test b/storage/spider/mysql-test/spider/bugfix/t/mdev_34682.test new file mode 100644 index 00000000000..d61f7db4330 --- /dev/null +++ b/storage/spider/mysql-test/spider/bugfix/t/mdev_34682.test @@ -0,0 +1,14 @@ +set @old_aria_encrypt_tables=@@global.aria_encrypt_tables; +set global aria_encrypt_tables=ON; + +CREATE FUNCTION spider_direct_sql RETURNS INT SONAME 'ha_spider.so'; +call mtr.add_suppression(".*\\[ERROR\\] SPIDER plugin initialization failed at.* by 'Initialization of encryption failed for"); +call mtr.add_suppression(".*\\[ERROR\\] Plugin 'SPIDER' registration as a STORAGE ENGINE failed."); +--error ER_CANT_INITIALIZE_UDF +INSTALL PLUGIN spider SONAME 'ha_spider.so'; +--error ER_CANT_INITIALIZE_UDF +SELECT spider_direct_sql ('SELECT * FROM s','a','srv "b"'); + +--disable_query_log +--source ../../include/clean_up_spider.inc +set global aria_encrypt_tables=@old_aria_encrypt_tables; diff --git a/storage/spider/mysql-test/spider/include/clean_up_spider.inc b/storage/spider/mysql-test/spider/include/clean_up_spider.inc index 249606ec774..5b016e731d9 100644 --- a/storage/spider/mysql-test/spider/include/clean_up_spider.inc +++ b/storage/spider/mysql-test/spider/include/clean_up_spider.inc @@ -1,8 +1,8 @@ -DROP FUNCTION spider_flush_table_mon_cache; -DROP FUNCTION spider_copy_tables; -DROP FUNCTION spider_ping_table; -DROP FUNCTION spider_bg_direct_sql; -DROP FUNCTION spider_direct_sql; +DROP FUNCTION IF EXISTS spider_flush_table_mon_cache; +DROP FUNCTION IF EXISTS spider_copy_tables; +DROP FUNCTION IF EXISTS spider_ping_table; +DROP FUNCTION IF EXISTS spider_bg_direct_sql; +DROP FUNCTION IF EXISTS spider_direct_sql; UNINSTALL SONAME IF EXISTS 'ha_spider'; DROP TABLE IF EXISTS mysql.spider_xa; DROP TABLE IF EXISTS mysql.spider_xa_member; diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index 461e47dd012..c1166c4e7d5 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -6805,6 +6805,7 @@ error_pt_attr_setstate: pthread_attr_destroy(&spider_pt_attr); error_pt_attr_init: #endif + spider_hton_ptr= NULL; DBUG_RETURN(error_num); } From fa8ce92cc004f8db65ebb208aa1c212c1e64397d Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Fri, 2 Aug 2024 10:31:08 +1000 Subject: [PATCH 14/45] MDEV-34682 Return the return value of ddl recovery done in ha_initialize_handlerton Otherwise it could cause false negative when ddl recovery done is part of the plugin initialization --- sql/handler.cc | 2 +- storage/spider/spd_table.cc | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/sql/handler.cc b/sql/handler.cc index 8239e44b841..a21556d8181 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -782,7 +782,7 @@ int ha_initialize_handlerton(st_plugin_int *plugin) update_discovery_counters(hton, 1); if (ddl_recovery_done && hton->signal_ddl_recovery_done) - hton->signal_ddl_recovery_done(hton); + ret= hton->signal_ddl_recovery_done(hton); DBUG_RETURN(ret); diff --git a/storage/spider/spd_table.cc b/storage/spider/spd_table.cc index a138fd21598..0a38e8056af 100644 --- a/storage/spider/spd_table.cc +++ b/storage/spider/spd_table.cc @@ -6511,8 +6511,10 @@ bool spider_init_system_tables() /* - Spider is typically loaded before ddl_recovery, but DDL statements - cannot be executed before ddl_recovery, so we delay system table creation. + Spider may be loaded before ddl_recovery (e.g. with + --plugin-load-add), but DDL statements in spider init queries cannot + be executed before ddl_recovery, so we execute these queries only + after ddl recovery. */ static int spider_after_ddl_recovery(handlerton *) { From 25e2d0a6bbd64e9b509f4a2d00a9d8736367965e Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Tue, 6 Aug 2024 15:26:55 +0200 Subject: [PATCH 15/45] MDEV-34632 Assertion failed in handler::assert_icp_limitations Assertion `table->field[0]->ptr >= table->record[0] && table->field[0]->ptr <= table->record[0] + table->s->reclength' failed in handler::assert_icp_limitations. table->move_fields has some limitations: 1. It cannot be used in cascade 2. It should always have a restoring pair. Rule 1 is covered by assertions in handler::assert_icp_limitations and handler::ptr_in_record (commit 30894fe9a9). Rule 2 should be manually maintained with care. Hopefully, the rule 1 assertions may sometimes help as well. In ha_myisam::repair, both rules are broken. table->move_fields is used asymmetrically there: it is set on every param->fix_record call (i.e. in compute_vcols) but is restored only once, in the end of repair. The reason to updating field ptr's for every call is that compute_vcols can (supposedly) be called in parallel, that is, with the same table, but different records. The condition to "unmove" the pointers in ha_myisam::restore_vcos_after_repair is incorrect, when stored vcols are available, and myisam stores a VIRTUAL field if it's the only field in the table (the record cannot be of zero length). This patch solves the problem by "unmoving" the pointers symmetrically, in compute_vcols. That is, both rules will be preserved maintained. --- mysql-test/suite/vcol/inc/vcol_keys.inc | 17 +++++++ .../suite/vcol/r/vcol_keys_innodb.result | 19 ++++++++ .../suite/vcol/r/vcol_keys_myisam.result | 19 ++++++++ storage/myisam/ha_myisam.cc | 47 ++++++------------- storage/myisam/ha_myisam.h | 1 - 5 files changed, 70 insertions(+), 33 deletions(-) diff --git a/mysql-test/suite/vcol/inc/vcol_keys.inc b/mysql-test/suite/vcol/inc/vcol_keys.inc index 8ec89daff0b..d209e24811b 100644 --- a/mysql-test/suite/vcol/inc/vcol_keys.inc +++ b/mysql-test/suite/vcol/inc/vcol_keys.inc @@ -15,6 +15,8 @@ ################################################################################ +--source include/have_sequence.inc + --echo # - UNIQUE KEY --echo # - INDEX --echo # - FULLTEXT INDEX @@ -231,3 +233,18 @@ CREATE TABLE t1 ( DELETE FROM t1 WHERE vc IS NULL ORDER BY pk; DROP TABLE t1; +# +# MDEV-34632 Assertion `table->field[0]->ptr >= table->record[0] && +# table->field[0]->ptr <= table->record[0] + table->s->reclength' failed in +# void handler::assert_icp_limitations(uchar*) +# +SET sql_mode=''; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL,KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 SELECT 1 FROM seq_1_to_2 ; +SELECT * FROM t1; +DROP TABLE t1; + +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL,KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 SELECT 1 UNION SELECT 1; +SELECT * FROM t1; +DROP TABLE t1; diff --git a/mysql-test/suite/vcol/r/vcol_keys_innodb.result b/mysql-test/suite/vcol/r/vcol_keys_innodb.result index c07e00a5e20..51e97864a25 100644 --- a/mysql-test/suite/vcol/r/vcol_keys_innodb.result +++ b/mysql-test/suite/vcol/r/vcol_keys_innodb.result @@ -215,6 +215,25 @@ INDEX(vc(32)) ); DELETE FROM t1 WHERE vc IS NULL ORDER BY pk; DROP TABLE t1; +SET sql_mode=''; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL,KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 SELECT 1 FROM seq_1_to_2 ; +Warnings: +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +SELECT * FROM t1; +a +1 +1 +DROP TABLE t1; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL,KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 SELECT 1 UNION SELECT 1; +Warnings: +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +SELECT * FROM t1; +a +1 +DROP TABLE t1; # # MDEV-11737 Failing assertion: block->magic_n == MEM_BLOCK_MAGIC_N # diff --git a/mysql-test/suite/vcol/r/vcol_keys_myisam.result b/mysql-test/suite/vcol/r/vcol_keys_myisam.result index 0112c3986e8..2a05464846a 100644 --- a/mysql-test/suite/vcol/r/vcol_keys_myisam.result +++ b/mysql-test/suite/vcol/r/vcol_keys_myisam.result @@ -209,6 +209,25 @@ INDEX(vc(32)) ); DELETE FROM t1 WHERE vc IS NULL ORDER BY pk; DROP TABLE t1; +SET sql_mode=''; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL,KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 SELECT 1 FROM seq_1_to_2 ; +Warnings: +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +SELECT * FROM t1; +a +1 +1 +DROP TABLE t1; +CREATE TABLE t1 (a INT GENERATED ALWAYS AS (1) VIRTUAL,KEY(a)) ENGINE=MyISAM; +INSERT INTO t1 SELECT 1 UNION SELECT 1; +Warnings: +Warning 1906 The value specified for generated column 'a' in table 't1' has been ignored +SELECT * FROM t1; +a +1 +DROP TABLE t1; # # Original test # diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 022a7bb6819..c5d13273b23 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -721,29 +721,32 @@ static void init_compute_vcols(void *table) static int compute_vcols(MI_INFO *info, uchar *record, int keynum) { + int error= 0; /* This mutex is needed for parallel repair */ mysql_mutex_lock(&info->s->intern_lock); TABLE *table= (TABLE*)(info->external_ref); - table->move_fields(table->field, record, table->field[0]->record_ptr()); + table->move_fields(table->field, record, table->record[0]); if (keynum == -1) // update all vcols { - int error= table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_READ); + error= table->update_virtual_fields(table->file, VCOL_UPDATE_FOR_READ); if (table->update_virtual_fields(table->file, VCOL_UPDATE_INDEXED)) error= 1; - mysql_mutex_unlock(&info->s->intern_lock); - return error; } - // update only one key - KEY *key= table->key_info + keynum; - KEY_PART_INFO *kp= key->key_part, *end= kp + key->ext_key_parts; - for (; kp < end; kp++) + else { - Field *f= table->field[kp->fieldnr - 1]; - if (f->vcol_info && !f->vcol_info->stored_in_db) - table->update_virtual_field(f, false); + // update only one key + KEY *key= table->key_info + keynum; + KEY_PART_INFO *kp= key->key_part, *end= kp + key->ext_key_parts; + for (; kp < end; kp++) + { + Field *f= table->field[kp->fieldnr - 1]; + if (f->vcol_info && !f->vcol_info->stored_in_db) + table->update_virtual_field(f, false); + } } + table->move_fields(table->field, table->record[0], record); mysql_mutex_unlock(&info->s->intern_lock); - return 0; + return error; } } @@ -1025,16 +1028,6 @@ void ha_myisam::setup_vcols_for_repair(HA_CHECK *param) table->use_all_columns(); } -void ha_myisam::restore_vcos_after_repair() -{ - if (file->s->base.reclength < file->s->vreclength) - { - table->move_fields(table->field, table->record[0], - table->field[0]->record_ptr()); - table->default_column_bitmaps(); - } -} - int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) { if (!file) return HA_ADMIN_INTERNAL_ERROR; @@ -1131,8 +1124,6 @@ int ha_myisam::check(THD* thd, HA_CHECK_OPT* check_opt) file->update |= HA_STATE_CHANGED | HA_STATE_ROW_CHANGED; } - restore_vcos_after_repair(); - thd_proc_info(thd, old_proc_info); return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; } @@ -1178,8 +1169,6 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt) else if (!mi_is_crashed(file) && !thd->killed) mi_mark_crashed(file); - restore_vcos_after_repair(); - return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; } @@ -1229,8 +1218,6 @@ int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt) break; } - restore_vcos_after_repair(); - if (!error && start_records != file->state->records && !(check_opt->flags & T_VERY_SILENT)) { @@ -1268,8 +1255,6 @@ int ha_myisam::optimize(THD* thd, HA_CHECK_OPT *check_opt) error= repair(thd,*param,1); } - restore_vcos_after_repair(); - return error; } @@ -1707,8 +1692,6 @@ int ha_myisam::enable_indexes(key_map map, bool persist) } info(HA_STATUS_CONST); thd_proc_info(thd, save_proc_info); - - restore_vcos_after_repair(); } DBUG_RETURN(error); } diff --git a/storage/myisam/ha_myisam.h b/storage/myisam/ha_myisam.h index 46202468475..e72636e9e22 100644 --- a/storage/myisam/ha_myisam.h +++ b/storage/myisam/ha_myisam.h @@ -49,7 +49,6 @@ class ha_myisam final : public handler bool can_enable_indexes; int repair(THD *thd, HA_CHECK ¶m, bool optimize); void setup_vcols_for_repair(HA_CHECK *param); - void restore_vcos_after_repair(); public: ha_myisam(handlerton *hton, TABLE_SHARE *table_arg); From 56fb04aa7c78c11649805df0a8ad9d7de08f374d Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Thu, 8 Aug 2024 17:56:56 -0400 Subject: [PATCH 16/45] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 05e6832c930..da85fbe02b8 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=5 -MYSQL_VERSION_PATCH=26 +MYSQL_VERSION_PATCH=27 SERVER_MATURITY=stable From f15de4258583fdd4213b46d1ab1ecf5375a1a790 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Thu, 8 Aug 2024 17:58:51 -0400 Subject: [PATCH 17/45] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index a4214274a42..2933d080d5b 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=6 -MYSQL_VERSION_PATCH=19 +MYSQL_VERSION_PATCH=20 SERVER_MATURITY=stable From 8da477414b3ec7ca37cdd0eec095f1a6e6ef01bd Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Thu, 8 Aug 2024 18:00:06 -0400 Subject: [PATCH 18/45] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 68bc4383131..2e9a9392854 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=11 -MYSQL_VERSION_PATCH=9 +MYSQL_VERSION_PATCH=10 SERVER_MATURITY=stable From fdaa44a416fd9d02acc86060d59d9bcc378521e4 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Thu, 8 Aug 2024 18:01:18 -0400 Subject: [PATCH 19/45] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 23aa5974ee6..4737ed40f35 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=11 MYSQL_VERSION_MINOR=1 -MYSQL_VERSION_PATCH=6 +MYSQL_VERSION_PATCH=7 SERVER_MATURITY=stable From 9a56a315610710a56948563161fad837861aa740 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Thu, 8 Aug 2024 18:02:30 -0400 Subject: [PATCH 20/45] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 58e713313cb..d1f7bb29b4c 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=11 MYSQL_VERSION_MINOR=2 -MYSQL_VERSION_PATCH=5 +MYSQL_VERSION_PATCH=6 SERVER_MATURITY=stable From d1713666b06ae5525f85afe5a5c3e46ab2c26a0a Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Fri, 19 Jul 2024 21:44:34 +0200 Subject: [PATCH 21/45] Fix incorrect setting of opt_local_file in mysqlimport, for named pipe For named pipe, server and client are on the same machine, and opt_local_infile just adds unnecessary copying via "load data local infile" --- client/mysqlimport.c | 1 - 1 file changed, 1 deletion(-) diff --git a/client/mysqlimport.c b/client/mysqlimport.c index 3a9f9005cb6..405eda8cc10 100644 --- a/client/mysqlimport.c +++ b/client/mysqlimport.c @@ -249,7 +249,6 @@ get_one_option(const struct my_option *opt, const char *argument, #ifdef __WIN__ case 'W': opt_protocol = MYSQL_PROTOCOL_PIPE; - opt_local_file=1; break; #endif case OPT_MYSQL_PROTOCOL: From b619be35693b531bf34cdb00cf41318975cbf87b Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 29 Jul 2024 01:03:17 +0200 Subject: [PATCH 22/45] Support -DCONC_WITH_SSL parameter passed to CMake Usually it is not needed, but sometimes we need to testing interoperability, e.g OpenSSL server / SCHANNEL client, or WolfSSL server / OpenSSL client. --- cmake/mariadb_connector_c.cmake | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cmake/mariadb_connector_c.cmake b/cmake/mariadb_connector_c.cmake index b4f56597775..9b4f25498fd 100644 --- a/cmake/mariadb_connector_c.cmake +++ b/cmake/mariadb_connector_c.cmake @@ -8,15 +8,17 @@ SET(CONC_WITH_SIGNCODE ${SIGNCODE}) SET(SIGN_OPTIONS ${SIGNTOOL_PARAMETERS}) SET(CONC_WITH_EXTERNAL_ZLIB ON) -IF(SSL_DEFINES MATCHES "WOLFSSL") - IF(WIN32) - SET(CONC_WITH_SSL "SCHANNEL") +IF(NOT CONC_WITH_SSL) + IF(SSL_DEFINES MATCHES "WOLFSSL") + IF(WIN32) + SET(CONC_WITH_SSL "SCHANNEL") + ELSE() + SET(CONC_WITH_SSL "GNUTLS") # that's what debian wants, right? + ENDIF() ELSE() - SET(CONC_WITH_SSL "GNUTLS") # that's what debian wants, right? + SET(CONC_WITH_SSL "OPENSSL") + SET(OPENSSL_FOUND TRUE) ENDIF() -ELSE() - SET(CONC_WITH_SSL "OPENSSL") - SET(OPENSSL_FOUND TRUE) ENDIF() SET(CONC_WITH_CURL OFF) From 62fd7b4cd2cd0a8527c30e3661fc917b7e07522b Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 29 Jul 2024 01:10:32 +0200 Subject: [PATCH 23/45] OpenSSL - set all heap functions in CRYPTO_set_mem_functions. The reason is that on Windows, OpenSSL can be built with different C runtime than the server (e.g Debug runtime in debug vcpkg build). Overwriting only malloc(), with CRT that server is using can cause mixup of incompatible malloc() and free() inside openssl. To fix, overwrite all memory functions. --- mysys_ssl/openssl.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/mysys_ssl/openssl.c b/mysys_ssl/openssl.c index 8adaeae4069..e0271817309 100644 --- a/mysys_ssl/openssl.c +++ b/mysys_ssl/openssl.c @@ -47,12 +47,25 @@ static void *coc_malloc(size_t size, const char *f __attribute__((unused)), return malloc(size); } +static void *coc_realloc(void *addr, size_t num, + const char *file __attribute__((unused)), + int line __attribute__((unused))) +{ + return realloc(addr, num); +} + +static void coc_free(void *addr, const char *file __attribute__((unused)), + int line __attribute__((unused))) +{ + free(addr); +} + int check_openssl_compatibility() { EVP_CIPHER_CTX *evp_ctx; EVP_MD_CTX *md5_ctx; - if (!CRYPTO_set_mem_functions(coc_malloc, NULL, NULL)) + if (!CRYPTO_set_mem_functions(coc_malloc, coc_realloc, coc_free)) return 0; testing= 1; From 4a67bd5105188d10de45521ef19ea11772eed1dc Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 8 Aug 2024 11:13:41 +0200 Subject: [PATCH 24/45] Fix server on windows, so it does not write to error log byte-by-byte fprintf() on Windows, when used on unbuffered FILE*, writes bytewise. This can make crash handler messages harder to read, if they are mixed up with other error log output. Fixed , on Windows, by using a small buffer for formatting, and fwrite instead of fprintf, if buffer is large enough for message. --- sql/log.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/sql/log.cc b/sql/log.cc index 01700cc048d..4f74900e59a 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -9215,6 +9215,25 @@ static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff, #ifndef EMBEDDED_LIBRARY +#ifndef _WIN32 +#define fprintf_stderr(format, ...) fprintf(stderr, format, __VA_ARGS__) +#else +/* + On Windows, if FILE* is unbuffered, fprintf() writes output byte by byte. + This is suboptimal for printing to error log, we want full message at once. +*/ +#define fprintf_stderr(format, ...) \ + do \ + { \ + char buf[256]; \ + size_t len= snprintf(buf, sizeof(buf), format, __VA_ARGS__); \ + if (len >= sizeof(buf)) \ + fprintf(stderr, format, __VA_ARGS__); \ + else \ + fwrite(buf, len, 1, stderr); \ + } while (0) +#endif + static void print_buffer_to_file(enum loglevel level, const char *buffer, size_t length) { @@ -9248,7 +9267,7 @@ static void print_buffer_to_file(enum loglevel level, const char *buffer, localtime_r(&skr, &tm_tmp); start=&tm_tmp; - fprintf(stderr, "%d-%02d-%02d %2d:%02d:%02d %lu [%s] %.*s%.*s\n", + fprintf_stderr( "%d-%02d-%02d %2d:%02d:%02d %lu [%s] %.*s%.*s\n", start->tm_year + 1900, start->tm_mon+1, start->tm_mday, From e997bf58fbefa06d47403001482ab81502f764dd Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 6 Aug 2024 14:35:39 +0200 Subject: [PATCH 25/45] MDEV-34714 perror-win test failure on localized Windows Let perror produce OS error messages in English --- extra/perror.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extra/perror.c b/extra/perror.c index d678d46d1be..4710b28035a 100644 --- a/extra/perror.c +++ b/extra/perror.c @@ -206,7 +206,8 @@ static my_bool print_win_error_msg(DWORD error, my_bool verbose) char *s; if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, error, 0, (char *)&s, 0, + NULL, error, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (char *) &s, 0, NULL)) { char* end = s + strlen(s) - 1; From c83ba513da0e3d38f8001fdf4fa55e8a812e6103 Mon Sep 17 00:00:00 2001 From: Ian Gilfillan Date: Tue, 6 Aug 2024 20:34:33 +0200 Subject: [PATCH 26/45] Update sponsors --- CREDITS | 63 ++++++++++++++++++++--------- mysql-test/main/contributors.result | 46 ++++++++++++++++----- sql/contributors.h | 48 ++++++++++++++++------ 3 files changed, 115 insertions(+), 42 deletions(-) diff --git a/CREDITS b/CREDITS index 35604064980..42f1697f992 100644 --- a/CREDITS +++ b/CREDITS @@ -1,20 +1,48 @@ MariaDB is brought to you by the MariaDB Foundation, a non profit organization registered in the USA. -The current main sponsors of the MariaDB Foundation are: +As of August 2024, the main sponsors of the MariaDB Foundation are: -Alibaba Cloud https://www.alibabacloud.com/ (2017) -Intel https://www.intel.com (2022) -MariaDB Corporation https://www.mariadb.com (2013) -Microsoft https://microsoft.com/ (2017) -ServiceNow https://servicenow.com (2019) -SIT https://sit.org (2022) -Tencent Cloud https://cloud.tencent.com (2017) -Development Bank of Singapore https://dbs.com (2016) -IBM https://www.ibm.com (2017) -Automattic https://automattic.com (2019) -Galera Cluster https://galeracluster.com (2020) -Percona https://www.percona.com (2018) +Amazon https://amazon.com +Acronis https://www.acronis.com +Alibaba Cloud https://www.alibabacloud.com +C>onstructor https://constructor.org +Development Bank of Singapore https://www.dbs.com +Intel https://www.intel.com +MariaDB plc https://www.mariadb.com +ServiceNow https://servicenow.com +WebPros https://webpros.com +IBM https://www.ibm.com +IONOS https://www.ionos.com +Automattic https://automattic.com +SkySQL https://skysql.com +team.blue https://team.blue +Tencent Cloud https://cloud.tencent.com +Wikimedia Foundation https://www.wikimediafoundation.org +Cyber Leo https://cyberleo.com +Hetzner https://www.hetzner.com +Rumahweb https://www.rumahweb.com +Tasjeel.ae https://www.tasjeel.ae +Galera Cluster https://galeracluster.com +Percona https://www.percona.com +Vettabase https://vettabase.com + +Previous sponsors include: + +Booking.com +Jelastic.com +Microsoft +Nexedi +Open Query +Planeetta Web Hosting +SpringbokSQL +Tencent Games +Tencent Game DBA +Tencent TDSQL +Verkkokauppa +Virtuozzo +Visma +Webyog For a full list of sponsors, see https://mariadb.org/about/#sponsors @@ -27,7 +55,7 @@ For all corporate sponsorships please contact the MariaDB Foundation Board via foundation@mariadb.org. The MariaDB Foundation is responsible for the MariaDB source -repository, the official MariaDB binaries and http://mariadb.org. +repository, the official MariaDB binaries and https://mariadb.org. The MariaDB Foundation also provides, among other things, the following services to the MariaDB community: @@ -37,8 +65,8 @@ following services to the MariaDB community: - Merging MySQL patches into MariaDB - Bug fixing in MariaDB (for bugs that affects a large part of the community) - Building the official MariaDB binaries -- Maintaining http://mariadb.org -- Documenting MariaDB in the MariaDB Knowledge Base http://mariadb.com/kb +- Maintaining https://mariadb.org +- Documenting MariaDB in the MariaDB Knowledge Base https://mariadb.com/kb To be able to do the above we need help from corporations and individuals! @@ -49,8 +77,5 @@ go to https://mariadb.org/donate/ You can get a list of all the main authors of MariaDB / MySQL by running SHOW AUTHORS; -You can get a list sponsors and contributors by running -SHOW CONTRIBUTORS; - You can read more about the MariaDB Foundation at: https://mariadb.org/about/ diff --git a/mysql-test/main/contributors.result b/mysql-test/main/contributors.result index 8d72373696c..9126385faa0 100644 --- a/mysql-test/main/contributors.result +++ b/mysql-test/main/contributors.result @@ -1,18 +1,42 @@ SHOW CONTRIBUTORS; Name Location Comment +Amazon https://www.amazon.com/ Diamond Sponsor of the MariaDB Foundation +Acronis https://www.acronis.com/ Platinum Sponsor of the MariaDB Foundation Alibaba Cloud https://www.alibabacloud.com/ Platinum Sponsor of the MariaDB Foundation -Tencent Cloud https://cloud.tencent.com Platinum Sponsor of the MariaDB Foundation -Microsoft https://microsoft.com/ Platinum Sponsor of the MariaDB Foundation -MariaDB Corporation https://mariadb.com Founding member, Platinum Sponsor of the MariaDB Foundation -ServiceNow https://servicenow.com Platinum Sponsor of the MariaDB Foundation -Intel https://www.intel.com Platinum Sponsor of the MariaDB Foundation -SIT https://sit.org Platinum Sponsor of the MariaDB Foundation -Visma https://visma.com Gold Sponsor of the MariaDB Foundation -DBS https://dbs.com Gold Sponsor of the MariaDB Foundation -IBM https://www.ibm.com Gold Sponsor of the MariaDB Foundation -Automattic https://automattic.com Silver Sponsor of the MariaDB Foundation +C Date: Wed, 12 Jun 2024 16:53:15 +0400 Subject: [PATCH 27/45] MDEV-34376 Wrong data types when mixing an utf8 *TEXT column and a short binary A mixture of a multi-byte *TEXT column and a short binary column produced a too large column. For example, COALESCE(tinytext_utf8mb4, short_varbinary) produced a BLOB column instead of an expected TINYBLOB. - Adding a virtual method Type_all_attributes::character_octet_length(), returning max_length by default. - Overriding Item_field::character_octet_length() to extract the octet length from the underlying Field. - Overriding Item_ref::character_octet_length() to extract the octet length from the references Item (e.g. as VIEW fields). - Fixing Type_numeric_attributes::find_max_octet_length() to take the octet length using the new method character_octet_length() instead of accessing max_length directly. --- mysql-test/main/ctype_utf8mb4.result | 121 +++++++++++++++++++++++++++ mysql-test/main/ctype_utf8mb4.test | 93 ++++++++++++++++++++ sql/item.h | 12 +++ sql/sql_type.cc | 2 +- sql/sql_type.h | 1 + 5 files changed, 228 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/ctype_utf8mb4.result b/mysql-test/main/ctype_utf8mb4.result index 64f28bd4bf3..bc370b2a694 100644 --- a/mysql-test/main/ctype_utf8mb4.result +++ b/mysql-test/main/ctype_utf8mb4.result @@ -4165,5 +4165,126 @@ SELECT 1 COLLATE utf8mb4_bin; SELECT 1 COLLATE latin1_swedish_ci; ERROR 42000: COLLATION 'latin1_swedish_ci' is not valid for CHARACTER SET 'utf8mb4' # +# MDEV-34376 Wrong data types when mixing an utf8 *TEXT column and a short binary +# +CREATE TABLE t1 ( +c_tinytext tinytext, +c_text text, +c_mediumtext mediumtext, +c_longtext longtext +) CHARACTER SET utf8mb4; +CREATE VIEW v1 AS SELECT * FROM t1; +CREATE VIEW v2 AS SELECT * FROM v1; +# Using table fields +CREATE TABLE t2 AS SELECT +COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary, +COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary, +COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary, +COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary +FROM t1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `mix_tinytext_binary` tinyblob DEFAULT NULL, + `mix_text_binary` blob DEFAULT NULL, + `mix_mediumtext_binary` mediumblob DEFAULT NULL, + `mix_longtext_binary` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +c_tinytext AS mix_tinytext_binary, +c_text AS mix_text_binary, +c_mediumtext AS mix_mediumtext_binary, +c_longtext AS mix_longtext_binary +FROM t1 +UNION SELECT +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `mix_tinytext_binary` tinyblob DEFAULT NULL, + `mix_text_binary` blob DEFAULT NULL, + `mix_mediumtext_binary` mediumblob DEFAULT NULL, + `mix_longtext_binary` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t2; +# Using view fields +CREATE TABLE t2 AS SELECT +COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary, +COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary, +COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary, +COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary +FROM v1; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `mix_tinytext_binary` tinyblob DEFAULT NULL, + `mix_text_binary` blob DEFAULT NULL, + `mix_mediumtext_binary` mediumblob DEFAULT NULL, + `mix_longtext_binary` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +c_tinytext AS mix_tinytext_binary, +c_text AS mix_text_binary, +c_mediumtext AS mix_mediumtext_binary, +c_longtext AS mix_longtext_binary +FROM v1 +UNION SELECT +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `mix_tinytext_binary` tinyblob DEFAULT NULL, + `mix_text_binary` blob DEFAULT NULL, + `mix_mediumtext_binary` mediumblob DEFAULT NULL, + `mix_longtext_binary` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t2; +# Using view on view fields +CREATE TABLE t2 AS SELECT +COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary, +COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary, +COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary, +COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary +FROM v2; +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `mix_tinytext_binary` tinyblob DEFAULT NULL, + `mix_text_binary` blob DEFAULT NULL, + `mix_mediumtext_binary` mediumblob DEFAULT NULL, + `mix_longtext_binary` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t2; +CREATE TABLE t2 AS SELECT +c_tinytext AS mix_tinytext_binary, +c_text AS mix_text_binary, +c_mediumtext AS mix_mediumtext_binary, +c_longtext AS mix_longtext_binary +FROM v2 +UNION SELECT +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY), +CAST('binary data' AS BINARY); +SHOW CREATE TABLE t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `mix_tinytext_binary` tinyblob DEFAULT NULL, + `mix_text_binary` blob DEFAULT NULL, + `mix_mediumtext_binary` mediumblob DEFAULT NULL, + `mix_longtext_binary` longblob DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +DROP TABLE t2; +DROP VIEW v2, v1; +DROP TABLE t1; +# # End of 10.5 tests # diff --git a/mysql-test/main/ctype_utf8mb4.test b/mysql-test/main/ctype_utf8mb4.test index c0c5568b3bd..6361252ab80 100644 --- a/mysql-test/main/ctype_utf8mb4.test +++ b/mysql-test/main/ctype_utf8mb4.test @@ -2062,6 +2062,99 @@ SELECT 1 COLLATE utf8mb4_bin; --error ER_COLLATION_CHARSET_MISMATCH SELECT 1 COLLATE latin1_swedish_ci; +--echo # +--echo # MDEV-34376 Wrong data types when mixing an utf8 *TEXT column and a short binary +--echo # + +CREATE TABLE t1 ( + c_tinytext tinytext, + c_text text, + c_mediumtext mediumtext, + c_longtext longtext +) CHARACTER SET utf8mb4; +CREATE VIEW v1 AS SELECT * FROM t1; +CREATE VIEW v2 AS SELECT * FROM v1; + +--echo # Using table fields + +CREATE TABLE t2 AS SELECT + COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary, + COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary, + COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary, + COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary +FROM t1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + c_tinytext AS mix_tinytext_binary, + c_text AS mix_text_binary, + c_mediumtext AS mix_mediumtext_binary, + c_longtext AS mix_longtext_binary +FROM t1 +UNION SELECT + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY); +SHOW CREATE TABLE t2; +DROP TABLE t2; + + +--echo # Using view fields + +CREATE TABLE t2 AS SELECT + COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary, + COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary, + COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary, + COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary +FROM v1; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + c_tinytext AS mix_tinytext_binary, + c_text AS mix_text_binary, + c_mediumtext AS mix_mediumtext_binary, + c_longtext AS mix_longtext_binary +FROM v1 +UNION SELECT + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY); +SHOW CREATE TABLE t2; +DROP TABLE t2; + + +--echo # Using view on view fields + +CREATE TABLE t2 AS SELECT + COALESCE(c_tinytext, CAST('binary data' AS BINARY)) AS mix_tinytext_binary, + COALESCE(c_text, CAST('binary data' AS BINARY)) AS mix_text_binary, + COALESCE(c_mediumtext, CAST('binary data' AS BINARY)) AS mix_mediumtext_binary, + COALESCE(c_longtext, CAST('binary data' AS BINARY)) AS mix_longtext_binary +FROM v2; +SHOW CREATE TABLE t2; +DROP TABLE t2; + +CREATE TABLE t2 AS SELECT + c_tinytext AS mix_tinytext_binary, + c_text AS mix_text_binary, + c_mediumtext AS mix_mediumtext_binary, + c_longtext AS mix_longtext_binary +FROM v2 +UNION SELECT + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY), + CAST('binary data' AS BINARY); +SHOW CREATE TABLE t2; +DROP TABLE t2; + +DROP VIEW v2, v1; +DROP TABLE t1; + --echo # --echo # End of 10.5 tests --echo # diff --git a/sql/item.h b/sql/item.h index 796b2ec9eee..9af0a077f75 100644 --- a/sql/item.h +++ b/sql/item.h @@ -3576,6 +3576,10 @@ public: return &type_handler_null; return field->type_handler(); } + uint32 character_octet_length() const override + { + return field->character_octet_length(); + } Field *create_tmp_field_from_item_field(MEM_ROOT *root, TABLE *new_table, Item_ref *orig_item, const Tmp_field_param *param); @@ -5578,6 +5582,10 @@ public: { return (*ref)->type_handler(); } const Type_handler *real_type_handler() const override { return (*ref)->real_type_handler(); } + uint32 character_octet_length() const override + { + return Item_ref::real_item()->character_octet_length(); + } Field *get_tmp_table_field() override { return result_field ? result_field : (*ref)->get_tmp_table_field(); } Item *get_tmp_table_item(THD *thd) override; @@ -5616,6 +5624,10 @@ public: (*ref)->save_in_field(result_field, no_conversions); } Item *real_item() override { return ref ? (*ref)->real_item() : this; } + const Item *real_item() const + { + return const_cast(this)->Item_ref::real_item(); + } const TYPELIB *get_typelib() const override { return ref ? (*ref)->get_typelib() : NULL; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index 9ede9e2582d..44475e29bcc 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -1221,7 +1221,7 @@ uint32 Type_numeric_attributes::find_max_octet_length(Item **item, uint nitems) { uint32 octet_length= 0; for (uint i= 0; i < nitems ; i++) - set_if_bigger(octet_length, item[i]->max_length); + set_if_bigger(octet_length, item[i]->character_octet_length()); return octet_length; } diff --git a/sql/sql_type.h b/sql/sql_type.h index 874623e4316..859b63b5ad1 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3345,6 +3345,7 @@ public: { } virtual ~Type_all_attributes() = default; virtual void set_maybe_null(bool maybe_null_arg)= 0; + virtual uint32 character_octet_length() const { return max_length; } // Returns total number of decimal digits virtual uint decimal_precision() const= 0; virtual const TYPELIB *get_typelib() const= 0; From cd8b8bb964c1f1faffecb124ed3030144e658f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Thu, 18 Jul 2024 10:10:26 +0300 Subject: [PATCH 28/45] MDEV-34594 : Assertion `client_state.transaction().active()' failed in int wsrep_thd_append_key(THD*, const wsrep_key*, int, Wsrep_service_key_type) CREATE TABLE [SELECT|REPLACE SELECT] is CTAS and idea was that we force ROW format. However, it was not correctly enforced and keys were appended before wsrep transaction was started. At THD::decide_logging_format we should force used stmt binlog format to ROW in CTAS case and produce a warning if used binlog format was not ROW. At ha_innodb::update_row we should not append keys similarly as in ha_innodb::write_row if sql_command is SQLCOM_CREATE_TABLE. Improved error logging on ::write_row, ::update_row and ::delete_row if wsrep key append fails. Signed-off-by: Julius Goryavsky --- mysql-test/suite/galera/r/MDEV-34594.result | 88 +++++++++++++++++++ mysql-test/suite/galera/t/MDEV-34594.test | 68 ++++++++++++++ mysql-test/suite/wsrep/r/binlog_format.result | 8 ++ sql/sql_class.cc | 18 ++++ storage/innobase/handler/ha_innodb.cc | 24 +++-- 5 files changed, 199 insertions(+), 7 deletions(-) create mode 100644 mysql-test/suite/galera/r/MDEV-34594.result create mode 100644 mysql-test/suite/galera/t/MDEV-34594.test diff --git a/mysql-test/suite/galera/r/MDEV-34594.result b/mysql-test/suite/galera/r/MDEV-34594.result new file mode 100644 index 00000000000..f9caeba8e59 --- /dev/null +++ b/mysql-test/suite/galera/r/MDEV-34594.result @@ -0,0 +1,88 @@ +connection node_2; +connection node_1; +# +# Case 1: test with binlog_format ROW +# +connection node_1; +SET @@binlog_format=ROW; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +connection node_2; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +DROP TABLE t1,t2; +# +# Case 2: test with binlog_format MIXED +# +connection node_1; +SET @@binlog_format=MIXED; +Warnings: +Warning 1105 MariaDB Galera and flashback do not support binlog format: MIXED +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +connection node_2; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +DROP TABLE t1,t2; +# +# Case 3: test with binlog_format STATEMENT +# +connection node_1; +SET @@binlog_format=STATEMENT; +Warnings: +Warning 1105 MariaDB Galera and flashback do not support binlog format: STATEMENT +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +connection node_2; +SELECT * FROM t1; +a b +1 2 +2 3 +SELECT * FROM t2; +a b +1 3 +DROP TABLE t1,t2; +connection node_1; diff --git a/mysql-test/suite/galera/t/MDEV-34594.test b/mysql-test/suite/galera/t/MDEV-34594.test new file mode 100644 index 00000000000..256070cf40d --- /dev/null +++ b/mysql-test/suite/galera/t/MDEV-34594.test @@ -0,0 +1,68 @@ +--source include/galera_cluster.inc +--source include/log_bin.inc + +--echo # +--echo # Case 1: test with binlog_format ROW +--echo # +--connection node_1 +SET @@binlog_format=ROW; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +# +# Note that this has two rows (1,2) and (1,3) where (1,3) contains duplicate key +# but we requested REPLACE --> ::update_row() is called to update (1,2) --> (1,3) +# +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc + +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1,t2; + +--echo # +--echo # Case 2: test with binlog_format MIXED +--echo # +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc +SET @@binlog_format=MIXED; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc + +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1,t2; + +--echo # +--echo # Case 3: test with binlog_format STATEMENT +--echo # +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc +SET @@binlog_format=STATEMENT; +CREATE TABLE t1 (a INT UNIQUE) SELECT 1 AS a,2 AS b UNION SELECT 2 AS a,3 AS c; +CREATE TABLE t2 (a INT UNIQUE) REPLACE SELECT 1 AS a,2 AS b UNION SELECT 1 AS a,3 AS c; +SELECT * FROM t1; +SELECT * FROM t2; + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 2 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' OR TABLE_NAME = 't1' +--source include/wait_condition.inc + +SELECT * FROM t1; +SELECT * FROM t2; +DROP TABLE t1,t2; + +--connection node_1 +--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't2' +--source include/wait_condition.inc diff --git a/mysql-test/suite/wsrep/r/binlog_format.result b/mysql-test/suite/wsrep/r/binlog_format.result index 079ceb975dd..ce4b45319bc 100644 --- a/mysql-test/suite/wsrep/r/binlog_format.result +++ b/mysql-test/suite/wsrep/r/binlog_format.result @@ -16,6 +16,9 @@ SHOW VARIABLES LIKE 'binlog_format'; Variable_name Value binlog_format STATEMENT CREATE TABLE IF NOT EXISTS test.t1 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW SET binlog_format=MIXED; Warnings: Warning 1105 MariaDB Galera and flashback do not support binlog format: MIXED @@ -26,9 +29,14 @@ SHOW VARIABLES LIKE 'binlog_format'; Variable_name Value binlog_format MIXED CREATE TABLE IF NOT EXISTS test.t2 AS SELECT * FROM information_schema.routines WHERE 1 = 0; +Warnings: +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW SET binlog_format=ROW; SHOW WARNINGS; Level Code Message +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW +Warning 1105 Galera does not support binlog_format = MIXED in CREATE TABLE [SELECT|REPLACE] forcing ROW SHOW VARIABLES LIKE 'binlog_format'; Variable_name Value binlog_format ROW diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 124ed6e051d..fc04f5436f3 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -6372,6 +6372,24 @@ int THD::decide_logging_format(TABLE_LIST *tables) } set_current_stmt_binlog_format_row(); } + + /* If user has requested binlog_format STMT OR MIXED + in CREATE TABLE [SELECT|REPLACE] we will fall back + to ROW. + + Note that we can't use local binlog_format variable + here because wsrep_binlog_format sets it to ROW. + */ + if (wsrep_ctas && variables.binlog_format != BINLOG_FORMAT_ROW) + { + push_warning_printf(this, Sql_condition::WARN_LEVEL_WARN, + ER_UNKNOWN_ERROR, + "Galera does not support binlog_format = %s " + "in CREATE TABLE [SELECT|REPLACE] forcing ROW", + binlog_format == BINLOG_FORMAT_STMT ? + "STMT" : "MIXED"); + set_current_stmt_binlog_format_row(); + } #endif /* WITH_WSREP */ if (WSREP_EMULATE_BINLOG_NNULL(this) || diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 08229b21839..d249cb205f4 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -7858,7 +7858,10 @@ set_max_autoinc: if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE, record, NULL)) { - DBUG_PRINT("wsrep", ("row key failed")); + WSREP_DEBUG("::write_rows::wsrep_append_keys failed THD %ld for %s.%s", + thd_get_thread_id(m_user_thd), + table->s->db.str, + table->s->table_name.str); error_result = HA_ERR_INTERNAL_ERROR; goto func_exit; } @@ -8558,16 +8561,20 @@ func_exit: #ifdef WITH_WSREP if (error == DB_SUCCESS && trx->is_wsrep() && wsrep_thd_is_local(m_user_thd) - && !wsrep_thd_ignore_table(m_user_thd)) { - DBUG_PRINT("wsrep", ("update row key")); + && !wsrep_thd_ignore_table(m_user_thd) + && (thd_sql_command(m_user_thd) != SQLCOM_CREATE_TABLE) + && (thd_sql_command(m_user_thd) != SQLCOM_LOAD || + thd_binlog_format(m_user_thd) == BINLOG_FORMAT_ROW)) { if (wsrep_append_keys(m_user_thd, wsrep_protocol_version >= 4 ? WSREP_SERVICE_KEY_UPDATE : WSREP_SERVICE_KEY_EXCLUSIVE, - old_row, new_row)){ - WSREP_DEBUG("WSREP: UPDATE_ROW_KEY FAILED"); - DBUG_PRINT("wsrep", ("row key failed")); + old_row, new_row)) { + WSREP_DEBUG("::update_rows::wsrep_append_keys failed THD %ld for %s.%s", + thd_get_thread_id(m_user_thd), + table->s->db.str, + table->s->table_name.str); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } } @@ -8620,7 +8627,10 @@ ha_innobase::delete_row( if (wsrep_append_keys(m_user_thd, WSREP_SERVICE_KEY_EXCLUSIVE, record, NULL)) { - DBUG_PRINT("wsrep", ("delete fail")); + WSREP_DEBUG("::delete_rows::wsrep_append_keys failed THD %ld for %s.%s", + thd_get_thread_id(m_user_thd), + table->s->db.str, + table->s->table_name.str); DBUG_RETURN(HA_ERR_INTERNAL_ERROR); } } From 2c5d8376cdfd25d7510c85b3896b506715f96590 Mon Sep 17 00:00:00 2001 From: Julius Goryavsky Date: Wed, 7 Aug 2024 16:40:35 +0200 Subject: [PATCH 29/45] MDEV-30686: Endless loop when trying to establish connection With wsrep_sst_rsync, node goes into endless loop when trying to establish connection to donor for IST/SST if the database is bind on specific IP address, not the "*". This commit fixes this problem. Separate tests are not required - the problem can occur in normal configurations on a number of systems when selecting a bing address other than "*", especially on FreeBSD and with the IPv6 addresses. --- scripts/wsrep_sst_rsync.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/scripts/wsrep_sst_rsync.sh b/scripts/wsrep_sst_rsync.sh index e386930c5b7..b05f4bc2efd 100644 --- a/scripts/wsrep_sst_rsync.sh +++ b/scripts/wsrep_sst_rsync.sh @@ -100,10 +100,9 @@ check_pid_and_port() local busy=0 if [ $lsof_available -ne 0 ]; then - port_info=$(lsof -Pnl -i ":$port" 2>/dev/null | \ - grep -F '(LISTEN)') + port_info=$(lsof -Pnl -i ":$port" 2>/dev/null | grep -F '(LISTEN)') echo "$port_info" | \ - grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port[[:space:]]" && busy=1 + grep -q -E "[[:space:]]\\[?(\\*|[[:xdigit:]]*(:[[:xdigit:]]*)+)(\\](%[^:]+)?)?:$port[[:space:]]" && busy=1 else local filter='([^[:space:]]+[[:space:]]+){4}[^[:space:]]+' if [ $sockstat_available -ne 0 ]; then @@ -122,7 +121,7 @@ check_pid_and_port() grep -F 'users:(' | grep -o -E "$filter") fi echo "$port_info" | \ - grep -q -E "[[:space:]](\\*|\\[?::\\]?):$port\$" && busy=1 + grep -q -E "[[:space:]]\\[?(\\*|[[:xdigit:]]*(:[[:xdigit:]]*)+)(\\](%[^:]+)?)?:$port\$" && busy=1 fi if [ $busy -eq 0 ]; then From 12b01d740be82ab1fa583f8a54026b97123e5fe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 13 Aug 2024 08:20:18 +0300 Subject: [PATCH 30/45] MDEV-34707: BUF_GET_RECOVER assertion failure on upgrade buf_page_get_gen(): Relax the assertion once more. The LSN may grow by invoking ibuf_upgrade(), that is, when upgrading files where innodb_change_buffering!=none was used. The LSN may also have been recovered from a log that needs to be upgraded to the current format. --- storage/innobase/buf/buf0buf.cc | 3 +++ storage/innobase/srv/srv0start.cc | 3 +++ 2 files changed, 6 insertions(+) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 0832aefe364..0112ce8f53d 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -2606,8 +2606,11 @@ buf_page_get_gen( would typically be around 60000 with the default innodb_undo_tablespaces=3, and less than 110000 with the maximum innodb_undo_tablespaces=127. */ + ut_d(extern bool ibuf_upgrade_was_needed;) ut_ad(mode == BUF_GET_RECOVER ? recv_recovery_is_on() || log_sys.get_lsn() < 120000 + || log_sys.get_lsn() == recv_sys.lsn + SIZE_OF_FILE_CHECKPOINT + || ibuf_upgrade_was_needed : !recv_recovery_is_on() || recv_sys.after_apply); ut_ad(!mtr || mtr->is_active()); ut_ad(mtr || mode == BUF_PEEK_IF_IN_POOL); diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index 11b8349887f..280f616163f 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -1163,8 +1163,11 @@ static dberr_t srv_log_rebuild_if_needed() return srv_log_rebuild(); } +ut_d(bool ibuf_upgrade_was_needed;) + ATTRIBUTE_COLD static dberr_t ibuf_log_rebuild_if_needed() { + ut_d(ibuf_upgrade_was_needed= true;) mysql_mutex_lock(&recv_sys.mutex); recv_sys.apply(true); mysql_mutex_unlock(&recv_sys.mutex); From b304ec30308a86d87f29e509b988d3120b940f58 Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Tue, 13 Aug 2024 15:22:09 +0530 Subject: [PATCH 31/45] MDEV-14231 MATCH() AGAINST( IN BOOLEAN MODE), results mismatch - Added plugin_debug.test, multiple_index.test to innodb_fts suite from mysql-5.7. - commit c5b28e55f6ff2a77bf67a2052cc4f4ddd73bc151 removes the warning for InnoDB rebuilding table to add FTS_DOC_ID - multiple_index test case has MATCH(a) values are smaller than in MySQL because ROLLBACK updates the stat_n_rows. - st_mysql_ftparser_boolean_info structure conveys boolean metadata to mysql search engine for every word in the query. This structure misses the position value to store the correct offset of every word. So phrase search queries in plugin_debug test case with boolean mode for simple parser throws wrong result. --- .../suite/innodb_fts/r/multiple_index.result | 210 ++++++++++++ .../suite/innodb_fts/r/plugin_debug.result | 318 ++++++++++++++++++ .../suite/innodb_fts/t/multiple_index.test | 169 ++++++++++ .../suite/innodb_fts/t/plugin_debug.test | 308 +++++++++++++++++ 4 files changed, 1005 insertions(+) create mode 100644 mysql-test/suite/innodb_fts/r/multiple_index.result create mode 100644 mysql-test/suite/innodb_fts/r/plugin_debug.result create mode 100644 mysql-test/suite/innodb_fts/t/multiple_index.test create mode 100644 mysql-test/suite/innodb_fts/t/plugin_debug.test diff --git a/mysql-test/suite/innodb_fts/r/multiple_index.result b/mysql-test/suite/innodb_fts/r/multiple_index.result new file mode 100644 index 00000000000..5608ce4bf4a --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/multiple_index.result @@ -0,0 +1,210 @@ +CREATE TABLE t1 ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +a VARCHAR(200), +b TEXT +) ENGINE = InnoDB STATS_PERSISTENT=0; +INSERT INTO t1 (a,b) VALUES +('MySQL Tutorial','DBMS stands for DataBase ...') , +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'); +ALTER TABLE t1 ADD FULLTEXT INDEX idx_1 (a); +ALTER TABLE t1 ADD FULLTEXT INDEX idx_2 (b); +SHOW CREATE TABLE t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `a` varchar(200) DEFAULT NULL, + `b` text DEFAULT NULL, + PRIMARY KEY (`id`), + FULLTEXT KEY `idx_1` (`a`), + FULLTEXT KEY `idx_2` (`b`) +) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci STATS_PERSISTENT=0 +START TRANSACTION; +INSERT INTO t1 (a,b) VALUES +('1001 MySQL Tricks','1. Never run mysqld as root. 2. ...'), +('MySQL vs. YourSQL','In the following database comparison ...'), +('MySQL Security','When configured properly, MySQL ...'); +ROLLBACK; +SELECT * FROM t1 WHERE MATCH (a) +AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(a) AGAINST("+mysql +Tutorial" IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(b) AGAINST("+Tutorial" IN BOOLEAN MODE); +id a b +3 Optimizing MySQL In this tutorial we will show ... +select * from t1 where MATCH(b) AGAINST("+stands +(DataBase)" IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(b) AGAINST("+DataBase -(comparison)" IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select *, MATCH(a) AGAINST("Optimizing MySQL" IN BOOLEAN MODE) as x from t1; +id a b x +1 MySQL Tutorial DBMS stands for DataBase ... 0.000000001885928302414186 +2 How To Use MySQL Well After you went through a ... 0.000000001885928302414186 +3 Optimizing MySQL In this tutorial we will show ... 0.22764469683170319 +select *, MATCH(b) AGAINST("collections support" IN BOOLEAN MODE) as x from t1; +id a b x +1 MySQL Tutorial DBMS stands for DataBase ... 0 +2 How To Use MySQL Well After you went through a ... 0 +3 Optimizing MySQL In this tutorial we will show ... 0 +select * from t1 where MATCH a AGAINST ("+Optimiz* +Optimiz*" IN BOOLEAN MODE); +id a b +3 Optimizing MySQL In this tutorial we will show ... +select * from t1 where MATCH b AGAINST ('"DBMS stands"' IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH b AGAINST ('"DBMS STANDS"' IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(b) AGAINST ("DataBase" WITH QUERY EXPANSION); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(a) AGAINST ("Security" WITH QUERY EXPANSION); +id a b +ALTER TABLE t1 DROP INDEX idx_1; +ALTER TABLE t1 DROP INDEX idx_2; +ALTER TABLE t1 ADD FULLTEXT INDEX idx_1 (a); +ALTER TABLE t1 ADD FULLTEXT INDEX idx_2 (b); +SELECT * FROM t1 WHERE MATCH (a) +AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(a) AGAINST("+mysql +Tutorial" IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(b) AGAINST("+Tutorial" IN BOOLEAN MODE); +id a b +3 Optimizing MySQL In this tutorial we will show ... +select * from t1 where MATCH(b) AGAINST("+stands +(DataBase)" IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(b) AGAINST("+DataBase -(comparison)" IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select *, MATCH(a) AGAINST("Optimizing MySQL" IN BOOLEAN MODE) as x from t1; +id a b x +1 MySQL Tutorial DBMS stands for DataBase ... 0.000000001885928302414186 +2 How To Use MySQL Well After you went through a ... 0.000000001885928302414186 +3 Optimizing MySQL In this tutorial we will show ... 0.22764469683170319 +select *, MATCH(b) AGAINST("collections support" IN BOOLEAN MODE) as x from t1; +id a b x +1 MySQL Tutorial DBMS stands for DataBase ... 0 +2 How To Use MySQL Well After you went through a ... 0 +3 Optimizing MySQL In this tutorial we will show ... 0 +select * from t1 where MATCH a AGAINST ("+Optimiz* +Optimiz*" IN BOOLEAN MODE); +id a b +3 Optimizing MySQL In this tutorial we will show ... +select * from t1 where MATCH b AGAINST ('"DBMS stands"' IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH b AGAINST ('"DBMS STANDS"' IN BOOLEAN MODE); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(b) AGAINST ("DataBase" WITH QUERY EXPANSION); +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +select * from t1 where MATCH(a) AGAINST ("Security" WITH QUERY EXPANSION); +id a b +INSERT INTO t1 (a,b) VALUES ('test query expansion','for database ...'); +INSERT INTO t1 (a,b) VALUES +('test proximity search, test, proximity and phrase', +'search, with proximity innodb'); +INSERT INTO t1 (a,b) VALUES +('test proximity fts search, test, proximity and phrase', +'search, with proximity innodb'); +INSERT INTO t1 (a,b) VALUES +('test more of proximity for fts search, test, more proximity and phrase', +'search, with proximity innodb'); +SELECT * FROM t1 +WHERE MATCH (a) +AGAINST ('"proximity search"@3' IN BOOLEAN MODE); +id a b +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test proximity fts search, test, proximity and phrase search, with proximity innodb +SELECT * FROM t1 +WHERE MATCH (a) +AGAINST ('"proximity search"@2' IN BOOLEAN MODE); +id a b +8 test proximity search, test, proximity and phrase search, with proximity innodb +SELECT * FROM t1 +WHERE MATCH (b) +AGAINST ('"proximity innodb"@4' IN BOOLEAN MODE); +id a b +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test proximity fts search, test, proximity and phrase search, with proximity innodb +10 test more of proximity for fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM t1 +WHERE MATCH (a) +AGAINST ('"test proximity"@3' IN BOOLEAN MODE); +id a b +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test proximity fts search, test, proximity and phrase search, with proximity innodb +10 test more of proximity for fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM t1 +WHERE MATCH (a) +AGAINST ('"more test proximity"@3' IN BOOLEAN MODE); +id a b +10 test more of proximity for fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM t1 +WHERE MATCH (a) +AGAINST ('"more test proximity"@2' IN BOOLEAN MODE); +id a b +SELECT * FROM t1 +WHERE MATCH (a) +AGAINST ('"more fts proximity"@02' IN BOOLEAN MODE); +id a b +SELECT * FROM t1 WHERE CONCAT(t1.a,t1.b) IN ( +SELECT CONCAT(a,b) FROM t1 AS t2 WHERE +MATCH (t2.a) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) +) OR t1.id = 3 ; +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM t1 WHERE CONCAT(t1.a,t1.b) IN ( +SELECT CONCAT(a,b) FROM t1 AS t2 +WHERE MATCH (t2.a) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) +AND t2.id != 3) ; +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +SELECT * FROM t1 WHERE id IN (SELECT MIN(id) FROM t1 WHERE +MATCH (b) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE)) OR id = 3 ; +id a b +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM t1 WHERE id NOT IN (SELECT MIN(id) FROM t1 +WHERE MATCH (b) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE)) ; +id a b +1 MySQL Tutorial DBMS stands for DataBase ... +2 How To Use MySQL Well After you went through a ... +7 test query expansion for database ... +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test proximity fts search, test, proximity and phrase search, with proximity innodb +10 test more of proximity for fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM t1 WHERE EXISTS (SELECT t2.id FROM t1 AS t2 WHERE +MATCH (t2.b) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) +AND t1.id = t2.id) ; +id a b +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM t1 WHERE NOT EXISTS (SELECT t2.id FROM t1 AS t2 WHERE +MATCH (t2.a) AGAINST ('Tutorial' IN NATURAL LANGUAGE MODE) +AND t1.id = t2.id) ; +id a b +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +7 test query expansion for database ... +8 test proximity search, test, proximity and phrase search, with proximity innodb +9 test proximity fts search, test, proximity and phrase search, with proximity innodb +10 test more of proximity for fts search, test, more proximity and phrase search, with proximity innodb +SELECT * FROM t1 WHERE t1.id = (SELECT MAX(t2.id) FROM t1 AS t2 WHERE +MATCH(t2.a) AGAINST ('"proximity search"@3' IN BOOLEAN MODE)); +id a b +9 test proximity fts search, test, proximity and phrase search, with proximity innodb +SELECT * FROM t1 WHERE t1.id > (SELECT MIN(t2.id) FROM t1 AS t2 WHERE +MATCH(t2.b) AGAINST ('"proximity innodb"@3' IN BOOLEAN MODE)); +id a b +9 test proximity fts search, test, proximity and phrase search, with proximity innodb +10 test more of proximity for fts search, test, more proximity and phrase search, with proximity innodb +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/r/plugin_debug.result b/mysql-test/suite/innodb_fts/r/plugin_debug.result new file mode 100644 index 00000000000..6f12e2b0809 --- /dev/null +++ b/mysql-test/suite/innodb_fts/r/plugin_debug.result @@ -0,0 +1,318 @@ +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; +# Test Part 2: Create Index Test(CREATE TABLE WITH FULLTEXT INDEX) +CREATE TABLE articles ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT, +FULLTEXT (title, body) WITH PARSER simple_parser +) ENGINE=InnoDB; +INSERT INTO articles (title, body) VALUES +('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'), +('1001 MySQL Tricks','How to use full-text search engine'), +('Go MySQL Tricks','How to use full text search engine'); +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('mysql'); +id title body +1 MySQL Tutorial DBMS stands for MySQL DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('will go'); +id title body +# Test plugin parser tokenizer difference +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full-text'); +id title body +4 1001 MySQL Tricks How to use full-text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full text'); +id title body +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); +id title body +DROP TABLE articles; +# Test Part 3: Row Merge Create Index Test(ALTER TABLE ADD FULLTEXT INDEX) +CREATE TABLE articles ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT +) ENGINE=InnoDB; +INSERT INTO articles (title, body) VALUES +('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'), +('1001 MySQL Tricks','How to use full-text search engine'), +('Go MySQL Tricks','How to use full text search engine'); +ALTER TABLE articles ADD FULLTEXT INDEX (title, body) WITH PARSER simple_parser; +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('mysql'); +id title body +1 MySQL Tutorial DBMS stands for MySQL DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('will go'); +id title body +# Test plugin parser tokenizer difference +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full-text'); +id title body +4 1001 MySQL Tricks How to use full-text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full text'); +id title body +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full-text' WITH QUERY EXPANSION); +id title body +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +2 How To Use MySQL Well After you went through a ... +1 MySQL Tutorial DBMS stands for MySQL DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full text' WITH QUERY EXPANSION); +id title body +5 Go MySQL Tricks How to use full text search engine +4 1001 MySQL Tricks How to use full-text search engine +2 How To Use MySQL Well After you went through a ... +1 MySQL Tutorial DBMS stands for MySQL DataBase ... +3 Optimizing MySQL In this tutorial we will show ... +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); +id title body +DROP TABLE articles; +# Test Part 3 END +SET SESSION debug="+d,fts_instrument_use_default_parser"; +# Test Part 4: Create Index Test with Default/Internal Parser +CREATE TABLE articles ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT, +FULLTEXT (title, body) WITH PARSER simple_parser +) ENGINE=InnoDB; +INSERT INTO articles (title, body) VALUES +('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'), +('1001 MySQL Tricks','How to use full-text search engine'), +('Go MySQL Tricks','How to use full text search engine'); +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('mysql'); +id title body +1 MySQL Tutorial DBMS stands for MySQL DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('will go'); +id title body +# Test plugin parser tokenizer difference +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full-text'); +id title body +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full text'); +id title body +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +# simple parser st_mysql_ftparser_boolean_info doesn't +# store position of every word in boolean metadata. +# This leads to empty result +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); +id title body +DROP TABLE articles; +# Test Part 5: Row Merge Create Index Test with Default/Internal Parser +CREATE TABLE articles ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT +) ENGINE=InnoDB; +INSERT INTO articles (title, body) VALUES +('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'), +('1001 MySQL Tricks','How to use full-text search engine'), +('Go MySQL Tricks','How to use full text search engine'); +ALTER TABLE articles ADD FULLTEXT INDEX (title, body) WITH PARSER simple_parser; +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('mysql'); +id title body +1 MySQL Tutorial DBMS stands for MySQL DataBase ... +2 How To Use MySQL Well After you went through a ... +3 Optimizing MySQL In this tutorial we will show ... +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('will go'); +id title body +# Test plugin parser tokenizer difference +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full-text'); +id title body +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('full text'); +id title body +4 1001 MySQL Tricks How to use full-text search engine +5 Go MySQL Tricks How to use full text search engine +# simple parser st_mysql_ftparser_boolean_info doesn't +# store position of every word in boolean metadata. +# This leads to empty result +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); +id title body +DROP TABLE articles; +# Test Part 6: Test Query Parser with Default/Internal Parser +SET GLOBAL innodb_ft_enable_diag_print = 1; +CREATE TABLE articles ( +id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, +title VARCHAR(200), +body TEXT, +FULLTEXT (title, body) WITH PARSER simple_parser +) ENGINE=InnoDB; +INSERT INTO articles (title, body) VALUES +('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), +('MySQL Tutorial','DBMS stands for MySQL good one DataBase ...'), +('How To Use MySQL Well','After you went through a ...'), +('Optimizing MySQL','In this tutorial we will show ...'), +('1001 MySQL Tricks','How to use full-text search engine'); +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('+mysql -database' IN BOOLEAN MODE); +id title body +3 How To Use MySQL Well After you went through a ... +4 Optimizing MySQL In this tutorial we will show ... +5 1001 MySQL Tricks How to use full-text search engine +SELECT * FROM articles WHERE +MATCH(title, body) AGAINST('>mysql (SELECT MIN(t2.id) FROM t1 AS t2 WHERE +MATCH(t2.b) AGAINST ('"proximity innodb"@3' IN BOOLEAN MODE)); + +DROP TABLE t1; diff --git a/mysql-test/suite/innodb_fts/t/plugin_debug.test b/mysql-test/suite/innodb_fts/t/plugin_debug.test new file mode 100644 index 00000000000..4bf6d98d883 --- /dev/null +++ b/mysql-test/suite/innodb_fts/t/plugin_debug.test @@ -0,0 +1,308 @@ +--source include/have_innodb.inc +--source include/have_debug.inc +--source include/have_simple_parser.inc + +# Install fts parser plugin +INSTALL PLUGIN simple_parser SONAME 'mypluglib'; + +-- echo # Test Part 2: Create Index Test(CREATE TABLE WITH FULLTEXT INDEX) +CREATE TABLE articles ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT, + FULLTEXT (title, body) WITH PARSER simple_parser + ) ENGINE=InnoDB; + +INSERT INTO articles (title, body) VALUES + ('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), + ('How To Use MySQL Well','After you went through a ...'), + ('Optimizing MySQL','In this tutorial we will show ...'), + ('1001 MySQL Tricks','How to use full-text search engine'), + ('Go MySQL Tricks','How to use full text search engine'); + +# Simple term search +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('mysql'); + +# Test stopword and word len less than fts_min_token_size +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('will go'); + +-- echo # Test plugin parser tokenizer difference +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full-text'); + +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full text'); + +# No result here, we get '"mysql' 'database"' by simple parser +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); + +DROP TABLE articles; + +-- echo # Test Part 3: Row Merge Create Index Test(ALTER TABLE ADD FULLTEXT INDEX) +CREATE TABLE articles ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT + ) ENGINE=InnoDB; + +INSERT INTO articles (title, body) VALUES + ('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), + ('How To Use MySQL Well','After you went through a ...'), + ('Optimizing MySQL','In this tutorial we will show ...'), + ('1001 MySQL Tricks','How to use full-text search engine'), + ('Go MySQL Tricks','How to use full text search engine'); + +# Create fulltext index +ALTER TABLE articles ADD FULLTEXT INDEX (title, body) WITH PARSER simple_parser; + +# Simple term search +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('mysql'); + +# Test stopword and word len less than fts_min_token_size +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('will go'); + +-- echo # Test plugin parser tokenizer difference +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full-text'); + +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full text'); + +# Test query expansion +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full-text' WITH QUERY EXPANSION); + +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full text' WITH QUERY EXPANSION); + +# No result here, we get '"mysql' 'database"' by simple parser +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); + +DROP TABLE articles; +-- echo # Test Part 3 END + +# Use default parser +SET SESSION debug="+d,fts_instrument_use_default_parser"; + +-- echo # Test Part 4: Create Index Test with Default/Internal Parser +CREATE TABLE articles ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT, + FULLTEXT (title, body) WITH PARSER simple_parser + ) ENGINE=InnoDB; + +INSERT INTO articles (title, body) VALUES + ('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), + ('How To Use MySQL Well','After you went through a ...'), + ('Optimizing MySQL','In this tutorial we will show ...'), + ('1001 MySQL Tricks','How to use full-text search engine'), + ('Go MySQL Tricks','How to use full text search engine'); + +# Simple term search +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('mysql'); + +# Test stopword and word len less than fts_min_token_size +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('will go'); + +-- echo # Test plugin parser tokenizer difference +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full-text'); + +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full text'); + +# Phrase search +--echo # simple parser st_mysql_ftparser_boolean_info doesn't +--echo # store position of every word in boolean metadata. +--echo # This leads to empty result +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); + +DROP TABLE articles; + +# Disable query parse using plugin parser +-- echo # Test Part 5: Row Merge Create Index Test with Default/Internal Parser +CREATE TABLE articles ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT + ) ENGINE=InnoDB; + +INSERT INTO articles (title, body) VALUES + ('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), + ('How To Use MySQL Well','After you went through a ...'), + ('Optimizing MySQL','In this tutorial we will show ...'), + ('1001 MySQL Tricks','How to use full-text search engine'), + ('Go MySQL Tricks','How to use full text search engine'); + +# Create fulltext index +ALTER TABLE articles ADD FULLTEXT INDEX (title, body) WITH PARSER simple_parser; + +# Simple term search +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('mysql'); + +# Test stopword and word len less than fts_min_token_size +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('will go'); + +-- echo # Test plugin parser tokenizer difference +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full-text'); + +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('full text'); + +# Phrase search +--echo # simple parser st_mysql_ftparser_boolean_info doesn't +--echo # store position of every word in boolean metadata. +--echo # This leads to empty result +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('"mysql database"' IN BOOLEAN MODE); + +DROP TABLE articles; + +-- echo # Test Part 6: Test Query Parser with Default/Internal Parser +let $innodb_ft_enable_diag_print_orig = `SELECT @@innodb_ft_enable_diag_print`; +# Enable diag print to print query parse tree +SET GLOBAL innodb_ft_enable_diag_print = 1; + +CREATE TABLE articles ( + id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY, + title VARCHAR(200), + body TEXT, + FULLTEXT (title, body) WITH PARSER simple_parser + ) ENGINE=InnoDB; + +INSERT INTO articles (title, body) VALUES + ('MySQL Tutorial','DBMS stands for MySQL DataBase ...'), + ('MySQL Tutorial','DBMS stands for MySQL good one DataBase ...'), + ('How To Use MySQL Well','After you went through a ...'), + ('Optimizing MySQL','In this tutorial we will show ...'), + ('1001 MySQL Tricks','How to use full-text search engine'); + +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('+mysql -database' IN BOOLEAN MODE); + +SELECT * FROM articles WHERE + MATCH(title, body) AGAINST('>mysql Date: Wed, 14 Aug 2024 07:54:15 +0300 Subject: [PATCH 32/45] MDEV-34678 pthread_mutex_init() without pthread_mutex_destroy() When SUX_LOCK_GENERIC is defined, the srw_mutex, srw_lock, sux_lock are implemented based on pthread_mutex_t and pthread_cond_t. This is the only option for systems that lack a futex-like system call. In the SUX_LOCK_GENERIC mode, if pthread_mutex_init() is allocating some resources that need to be freed by pthread_mutex_destroy(), a memory leak could occur when we are repeatedly invoking pthread_mutex_init() without a pthread_mutex_destroy() in between. pthread_mutex_wrapper::initialized: A debug field to track whether pthread_mutex_init() has been invoked. This also helps find bugs like the one that was fixed by commit 1c8af2ae53a3a48d64b4167d21b20ff5e1caef36 (MDEV-34422); one simply needs to add -DSUX_LOCK_GENERIC to the CMAKE_CXX_FLAGS to catch that particular bug on the initial server bootstrap. buf_block_init(), buf_page_init_for_read(): Invoke block_lock::init() because buf_page_t::init() will no longer do that. buf_page_t::init(): Instead of invoking lock.init(), assert that it has already been invoked (the lock is vacant). add_fts_index(), build_fts_hidden_table(): Explicitly invoke index_lock::init() in order to avoid a pthread_mutex_destroy() invocation on an uninitialized object. srw_lock_debug::destroy(): Invoke readers_lock.destroy(). trx_sys_t::create(): Invoke trx_rseg_t::init() on all rollback segments in order to guarantee a deterministic state for shutdown, even if InnoDB fails to start up. trx_rseg_array_init(), trx_temp_rseg_create(), trx_rseg_create(): Invoke trx_rseg_t::destroy() before trx_rseg_t::init() in order to balance pthread_mutex_init() and pthread_mutex_destroy() calls. --- storage/innobase/buf/buf0buf.cc | 1 + storage/innobase/buf/buf0rea.cc | 1 + storage/innobase/include/buf0buf.h | 2 +- storage/innobase/include/srw_lock.h | 23 ++++++++++++++++++----- storage/innobase/row/row0import.cc | 2 ++ storage/innobase/sync/srw_lock.cc | 1 + storage/innobase/trx/trx0rseg.cc | 2 ++ storage/innobase/trx/trx0sys.cc | 14 +++++++------- 8 files changed, 33 insertions(+), 13 deletions(-) diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 61941592fab..44b093e93ed 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -842,6 +842,7 @@ buf_block_init(buf_block_t* block, byte* frame) MEM_MAKE_DEFINED(&block->modify_clock, sizeof block->modify_clock); ut_ad(!block->modify_clock); MEM_MAKE_DEFINED(&block->page.lock, sizeof block->page.lock); + block->page.lock.init(); block->page.init(buf_page_t::NOT_USED, page_id_t(~0ULL)); #ifdef BTR_CUR_HASH_ADAPT MEM_MAKE_DEFINED(&block->index, sizeof block->index); diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index 7279497e14c..ee6bffd4031 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -212,6 +212,7 @@ static buf_page_t* buf_page_init_for_read(ulint mode, const page_id_t page_id, page_zip_set_size(&bpage->zip, zip_size); bpage->zip.data = (page_zip_t*) data; + bpage->lock.init(); bpage->init(buf_page_t::READ_FIX, page_id); bpage->lock.x_lock(true); diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index be614ce2fa2..0996046cda0 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -648,10 +648,10 @@ public: void init(uint32_t state, page_id_t id) { ut_ad(state < REMOVE_HASH || state >= UNFIXED); + ut_ad(!lock.is_locked_or_waiting()); id_= id; zip.fix= state; oldest_modification_= 0; - lock.init(); ut_d(in_zip_hash= false); ut_d(in_free_list= false); ut_d(in_LRU_list= false); diff --git a/storage/innobase/include/srw_lock.h b/storage/innobase/include/srw_lock.h index 40bf9f8b0c2..72b78df146c 100644 --- a/storage/innobase/include/srw_lock.h +++ b/storage/innobase/include/srw_lock.h @@ -40,32 +40,45 @@ template class pthread_mutex_wrapper final { pthread_mutex_t lock; +#ifdef UNIV_DEBUG + /** whether the mutex is usable; set by init(); cleared by destroy() */ + bool initialized{false}; +public: + ~pthread_mutex_wrapper() { ut_ad(!initialized); } +#endif public: void init() { + ut_ad(!initialized); + ut_d(initialized= true); if (spinloop) pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); else pthread_mutex_init(&lock, nullptr); } - void destroy() { pthread_mutex_destroy(&lock); } + void destroy() + { + ut_ad(initialized); ut_d(initialized=false); + pthread_mutex_destroy(&lock); + } # ifdef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP - void wr_lock() { pthread_mutex_lock(&lock); } + void wr_lock() { ut_ad(initialized); pthread_mutex_lock(&lock); } # else private: void wr_wait(); public: inline void wr_lock(); # endif - void wr_unlock() { pthread_mutex_unlock(&lock); } - bool wr_lock_try() { return !pthread_mutex_trylock(&lock); } + void wr_unlock() { ut_ad(initialized); pthread_mutex_unlock(&lock); } + bool wr_lock_try() + { ut_ad(initialized); return !pthread_mutex_trylock(&lock); } }; # ifndef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP template<> void pthread_mutex_wrapper::wr_wait(); template<> inline void pthread_mutex_wrapper::wr_lock() -{ pthread_mutex_lock(&lock); } +{ ut_ad(initialized); pthread_mutex_lock(&lock); } template<> inline void pthread_mutex_wrapper::wr_lock() { if (!wr_lock_try()) wr_wait(); } diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index eecfac18017..b130675da15 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -3212,6 +3212,7 @@ static void add_fts_index(dict_table_t *table) { dict_index_t *fts_index= dict_mem_index_create( table, FTS_DOC_ID_INDEX_NAME, DICT_UNIQUE, 2); + fts_index->lock.SRW_LOCK_INIT(index_tree_rw_lock_key); fts_index->page= FIL_NULL; fts_index->cached= 1; fts_index->n_uniq= 1; @@ -3293,6 +3294,7 @@ static dict_table_t *build_fts_hidden_table( new_table, old_index->name, old_index->type, old_index->n_fields + is_clustered); + new_index->lock.SRW_LOCK_INIT(index_tree_rw_lock_key); new_index->id= old_index->id; new_index->n_uniq= old_index->n_uniq; new_index->type= old_index->type; diff --git a/storage/innobase/sync/srw_lock.cc b/storage/innobase/sync/srw_lock.cc index c1e32f26d51..eac3db19152 100644 --- a/storage/innobase/sync/srw_lock.cc +++ b/storage/innobase/sync/srw_lock.cc @@ -661,6 +661,7 @@ void srw_lock_debug::destroy() ut_ad(r->empty()); delete r; } + readers_lock.destroy(); srw_lock::destroy(); } diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc index 86f5b064b7f..e3173e1eff2 100644 --- a/storage/innobase/trx/trx0rseg.cc +++ b/storage/innobase/trx/trx0rseg.cc @@ -631,6 +631,7 @@ dberr_t trx_rseg_array_init() sys, rseg_id); if (page_no != FIL_NULL) { trx_rseg_t& rseg = trx_sys.rseg_array[rseg_id]; + rseg.destroy(); rseg.init(fil_space_get( trx_sysf_rseg_get_space( sys, rseg_id)), @@ -715,6 +716,7 @@ dberr_t trx_temp_rseg_create(mtr_t *mtr) mtr->commit(); return err; } + trx_sys.temp_rsegs[i].destroy(); trx_sys.temp_rsegs[i].init(fil_system.temp_space, rblock->page.id().page_no()); mtr->commit(); diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc index 33c408707cc..76f3ba79baf 100644 --- a/storage/innobase/trx/trx0sys.cc +++ b/storage/innobase/trx/trx0sys.cc @@ -152,6 +152,10 @@ void trx_sys_t::create() m_initialised= true; trx_list.create(); rw_trx_hash.init(); + for (auto &rseg : temp_rsegs) + rseg.init(nullptr, FIL_NULL); + for (auto &rseg : rseg_array) + rseg.init(nullptr, FIL_NULL); } size_t trx_sys_t::history_size() @@ -230,6 +234,7 @@ static trx_rseg_t *trx_rseg_create(ulint space_id) ? nullptr : trx_rseg_header_create(space, rseg_id, 0, &mtr, &err)) { rseg= &trx_sys.rseg_array[rseg_id]; + rseg->destroy(); rseg->init(space, rblock->page.id().page_no()); ut_ad(rseg->is_persistent()); mtr.write<4,mtr_t::MAYBE_NOP> @@ -329,13 +334,8 @@ trx_sys_t::close() rw_trx_hash.destroy(); /* There can't be any active transactions. */ - - for (ulint i = 0; i < array_elements(temp_rsegs); ++i) { - temp_rsegs[i].destroy(); - } - for (ulint i = 0; i < array_elements(rseg_array); ++i) { - rseg_array[i].destroy(); - } + for (auto& rseg : temp_rsegs) rseg.destroy(); + for (auto& rseg : rseg_array) rseg.destroy(); ut_a(trx_list.empty()); trx_list.close(); From ecd910ae3a2c0b29d49602aa71f400be3794184f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 14 Aug 2024 08:43:08 +0300 Subject: [PATCH 33/45] MDEV-34755 g++- -Wstringop-truncation due to safe_strcpy() The #pragma that was removed in commit e255837eaf90e72eaf122d88b30011db17f7ecf2 (MDEV-34266) turns out to be necessary for silencing all cases of -Wstringop-truncation. --- include/m_string.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/m_string.h b/include/m_string.h index 3da252b0912..ddfaf84b2d0 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -255,9 +255,20 @@ static inline void safe_strcpy(char *dst, size_t dst_size, const char *src) * * 2) IF there is no 0 byte in the first dst_size bytes of src, strncpy will * copy dst_size bytes, and the final byte won't be 0. + * + * In GCC 8+, the `-Wstringop-truncation` warning may object to strncpy() + * being used in this way, so we need to disable this warning for this + * single statement. */ +#if defined __GNUC__ && __GNUC__ >= 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstringop-truncation" +#endif strncpy(dst, src, dst_size); +#if defined __GNUC__ && __GNUC__ >= 8 +#pragma GCC diagnostic pop +#endif dst[dst_size - 1]= 0; } From e40dfcdd89e23b3d3f4cb544e61e6d7ab411b96e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Thu, 15 Aug 2024 10:13:49 +0300 Subject: [PATCH 34/45] Fix clang++-19 -Wunused-but-set-variable --- storage/innobase/buf/buf0lru.cc | 2 +- storage/innobase/include/page0page.h | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index 34d737b3103..5ec55ef2179 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -837,7 +837,7 @@ bool buf_LRU_free_page(buf_page_t *bpage, bool zip) break; case 1: mysql_mutex_lock(&buf_pool.flush_list_mutex); - if (const lsn_t om = bpage->oldest_modification()) { + if (ut_d(const lsn_t om =) bpage->oldest_modification()) { ut_ad(om == 1); buf_pool.delete_from_flush_list(bpage); } diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h index eb6bf56e8dd..ec94354f78e 100644 --- a/storage/innobase/include/page0page.h +++ b/storage/innobase/include/page0page.h @@ -421,8 +421,7 @@ inline void page_rec_set_n_owned(buf_block_t *block, rec_t *rec, ulint n_owned, ut_ad(block->frame == page_align(rec)); ut_ad(comp == (page_is_comp(block->frame) != 0)); - if (page_zip_des_t *page_zip= compressed - ? buf_block_get_page_zip(block) : nullptr) + if (compressed && is_buf_block_get_page_zip(block)) { ut_ad(comp); rec_set_bit_field_1(rec, n_owned, REC_NEW_N_OWNED, From f41a120298aa17ca80eecaa68614a6addf91ebc6 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Tue, 13 Aug 2024 18:28:23 +0200 Subject: [PATCH 35/45] Fix typo in xtrabackup --help output --- extra/mariabackup/xtrabackup.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index c126d0b5b7c..4a6a4ad9afc 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -1704,7 +1704,7 @@ struct my_option xb_server_options[] = 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, {"check-privileges", OPT_XTRA_CHECK_PRIVILEGES, "Check database user " - "privileges fro the backup user", + "privileges for the backup user", &opt_check_privileges, &opt_check_privileges, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 }, From 5dc2fe4815ddfb19c406f225576040882fe62b02 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Fri, 16 Aug 2024 22:27:01 +0200 Subject: [PATCH 36/45] Fix sporadic failure in test rpl.rpl_rotate_logs The test started failing after push of MDEV-31404. Signed-off-by: Kristian Nielsen --- mysql-test/suite/rpl/r/rpl_rotate_logs.result | 2 -- mysql-test/suite/rpl/t/rpl_rotate_logs.test | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/r/rpl_rotate_logs.result b/mysql-test/suite/rpl/r/rpl_rotate_logs.result index 8e8f0026c93..4b7c1642a11 100644 --- a/mysql-test/suite/rpl/r/rpl_rotate_logs.result +++ b/mysql-test/suite/rpl/r/rpl_rotate_logs.result @@ -70,8 +70,6 @@ master-bin.000002 # master-bin.000003 # SELECT @time_for_purge:=DATE_ADD('tmpval', INTERVAL 1 SECOND); purge master logs before (@time_for_purge); -Warnings: -Note 1375 Binary log 'master-bin.000003' is not purged because it is the current active binlog show binary logs; Log_name File_size master-bin.000003 # diff --git a/mysql-test/suite/rpl/t/rpl_rotate_logs.test b/mysql-test/suite/rpl/t/rpl_rotate_logs.test index 483ebe43ed7..6de85b7ca89 100644 --- a/mysql-test/suite/rpl/t/rpl_rotate_logs.test +++ b/mysql-test/suite/rpl/t/rpl_rotate_logs.test @@ -134,7 +134,12 @@ remove_file $MYSQLTEST_VARDIR/tmp/rpl_rotate_logs.tmp; --eval SELECT @time_for_purge:=DATE_ADD('$tmpval', INTERVAL 1 SECOND) --enable_result_log +# Disable the warning "is not purged because it is the current active binlog". +# (If the purge is delayed, this warning will not occur, causing .result +# difference). +--disable_warnings purge master logs before (@time_for_purge); +--enable_warnings source include/show_binary_logs.inc; insert into t2 values (65); sync_slave_with_master; From 260345343658188d968295a005e1d83a4afacb06 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Fri, 9 Aug 2024 15:39:59 +1000 Subject: [PATCH 37/45] MDEV-33836 Fix version markers in tests relating to MDEV-28152 MDEV-28152 was pushed to 11.5, not 11.4 --- mysql-test/suite/sql_sequence/auto_increment.result | 2 +- mysql-test/suite/sql_sequence/auto_increment.test | 2 +- mysql-test/suite/sql_sequence/concurrent_create.result | 2 +- mysql-test/suite/sql_sequence/concurrent_create.test | 2 +- mysql-test/suite/sql_sequence/create.result | 2 +- mysql-test/suite/sql_sequence/create.test | 2 +- mysql-test/suite/sql_sequence/mysqldump.result | 2 +- mysql-test/suite/sql_sequence/mysqldump.test | 2 +- mysql-test/suite/sql_sequence/next.result | 2 +- mysql-test/suite/sql_sequence/next.test | 2 +- mysql-test/suite/sql_sequence/setval.result | 2 +- mysql-test/suite/sql_sequence/setval.test | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/mysql-test/suite/sql_sequence/auto_increment.result b/mysql-test/suite/sql_sequence/auto_increment.result index eab2d0dccea..9327cedbd44 100644 --- a/mysql-test/suite/sql_sequence/auto_increment.result +++ b/mysql-test/suite/sql_sequence/auto_increment.result @@ -47,5 +47,5 @@ create sequence s as bigint start with -9223372036854775805 minvalue -9223372036 drop sequence s; set global auto_increment_increment= default, auto_increment_offset= default; # -# End of 11.4 tests +# End of 11.5 tests # diff --git a/mysql-test/suite/sql_sequence/auto_increment.test b/mysql-test/suite/sql_sequence/auto_increment.test index 0d23eba759a..8119d7fee08 100644 --- a/mysql-test/suite/sql_sequence/auto_increment.test +++ b/mysql-test/suite/sql_sequence/auto_increment.test @@ -51,5 +51,5 @@ set global auto_increment_increment= default, auto_increment_offset= default; --enable_ps2_protocol --echo # ---echo # End of 11.4 tests +--echo # End of 11.5 tests --echo # diff --git a/mysql-test/suite/sql_sequence/concurrent_create.result b/mysql-test/suite/sql_sequence/concurrent_create.result index 02d243c5964..1099e983cc3 100644 --- a/mysql-test/suite/sql_sequence/concurrent_create.result +++ b/mysql-test/suite/sql_sequence/concurrent_create.result @@ -62,5 +62,5 @@ next_not_cached_value minimum_value maximum_value start_value increment cache_si 1 1 16777214 1 1 1000 0 0 DROP SEQUENCE s1, s2; # -# End of 11.4 tests +# End of 11.5 tests # diff --git a/mysql-test/suite/sql_sequence/concurrent_create.test b/mysql-test/suite/sql_sequence/concurrent_create.test index f66e7732093..b6d010e348f 100644 --- a/mysql-test/suite/sql_sequence/concurrent_create.test +++ b/mysql-test/suite/sql_sequence/concurrent_create.test @@ -94,5 +94,5 @@ select * from s2; DROP SEQUENCE s1, s2; --echo # ---echo # End of 11.4 tests +--echo # End of 11.5 tests --echo # diff --git a/mysql-test/suite/sql_sequence/create.result b/mysql-test/suite/sql_sequence/create.result index 903280e25be..936e2769534 100644 --- a/mysql-test/suite/sql_sequence/create.result +++ b/mysql-test/suite/sql_sequence/create.result @@ -1342,5 +1342,5 @@ def test s8 bigint 64 2 0 1 1 9223372036854775806 1 0 def test s9 tinyint unsigned 8 2 0 1 1 254 1 0 drop sequence s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13; # -# End of 11.4 tests +# End of 11.5 tests # diff --git a/mysql-test/suite/sql_sequence/create.test b/mysql-test/suite/sql_sequence/create.test index b401fd6c1bb..e3d01ce1a35 100644 --- a/mysql-test/suite/sql_sequence/create.test +++ b/mysql-test/suite/sql_sequence/create.test @@ -767,5 +767,5 @@ select * from information_schema.sequences order by sequence_name; drop sequence s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13; --echo # ---echo # End of 11.4 tests +--echo # End of 11.5 tests --echo # diff --git a/mysql-test/suite/sql_sequence/mysqldump.result b/mysql-test/suite/sql_sequence/mysqldump.result index a5489479c69..0485bf3dec8 100644 --- a/mysql-test/suite/sql_sequence/mysqldump.result +++ b/mysql-test/suite/sql_sequence/mysqldump.result @@ -181,5 +181,5 @@ DROP DATABASE test1; DROP DATABASE test2; set sql_mode=default; # -# End of 11.4 tests +# End of 11.5 tests # diff --git a/mysql-test/suite/sql_sequence/mysqldump.test b/mysql-test/suite/sql_sequence/mysqldump.test index 64de0233e57..b6f7aa3de77 100644 --- a/mysql-test/suite/sql_sequence/mysqldump.test +++ b/mysql-test/suite/sql_sequence/mysqldump.test @@ -117,5 +117,5 @@ DROP DATABASE test2; set sql_mode=default; --echo # ---echo # End of 11.4 tests +--echo # End of 11.5 tests --echo # diff --git a/mysql-test/suite/sql_sequence/next.result b/mysql-test/suite/sql_sequence/next.result index 7b715b8ce6a..fbc3ac8243d 100644 --- a/mysql-test/suite/sql_sequence/next.result +++ b/mysql-test/suite/sql_sequence/next.result @@ -848,5 +848,5 @@ next value for t1 18446744073709551614 drop sequence t1; # -# End of 11.4 tests +# End of 11.5 tests # diff --git a/mysql-test/suite/sql_sequence/next.test b/mysql-test/suite/sql_sequence/next.test index fab35dd3e7c..c364ba01021 100644 --- a/mysql-test/suite/sql_sequence/next.test +++ b/mysql-test/suite/sql_sequence/next.test @@ -480,5 +480,5 @@ select next value for t1; drop sequence t1; --echo # ---echo # End of 11.4 tests +--echo # End of 11.5 tests --echo # diff --git a/mysql-test/suite/sql_sequence/setval.result b/mysql-test/suite/sql_sequence/setval.result index 3bbeea50f92..f78766070b5 100644 --- a/mysql-test/suite/sql_sequence/setval.result +++ b/mysql-test/suite/sql_sequence/setval.result @@ -418,4 +418,4 @@ setval(s, 32767) select nextval(s); ERROR HY000: Sequence 'test.s' has run out drop sequence s; -# End of 11.4 tests +# End of 11.5 tests diff --git a/mysql-test/suite/sql_sequence/setval.test b/mysql-test/suite/sql_sequence/setval.test index 84f62066e65..37b60b6d6e7 100644 --- a/mysql-test/suite/sql_sequence/setval.test +++ b/mysql-test/suite/sql_sequence/setval.test @@ -253,4 +253,4 @@ select nextval(s); drop sequence s; --enable_ps2_protocol ---echo # End of 11.4 tests +--echo # End of 11.5 tests From 8b8c8fcb864f4f9753211ad911337201cfe21d23 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Mon, 12 Aug 2024 10:33:12 +1000 Subject: [PATCH 38/45] MDEV-33836 Compute modulus correctly in sequence When the sequence is unsigned bigint, it needs to be cast to unsigned for correct computation of the modulus. --- .../suite/sql_sequence/auto_increment.result | 15 +++++++++++++++ .../suite/sql_sequence/auto_increment.test | 17 +++++++++++++++++ mysql-test/suite/sql_sequence/setval.result | 11 +++++++++++ mysql-test/suite/sql_sequence/setval.test | 11 +++++++++++ sql/sql_sequence.cc | 5 ++++- 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/mysql-test/suite/sql_sequence/auto_increment.result b/mysql-test/suite/sql_sequence/auto_increment.result index 9327cedbd44..a65b045ec9a 100644 --- a/mysql-test/suite/sql_sequence/auto_increment.result +++ b/mysql-test/suite/sql_sequence/auto_increment.result @@ -47,5 +47,20 @@ create sequence s as bigint start with -9223372036854775805 minvalue -9223372036 drop sequence s; set global auto_increment_increment= default, auto_increment_offset= default; # +# MDEV-33836 Assertion `(ulonglong) next_free_value % real_increment == (ulonglong) offset' failed in void sequence_definition::adjust_values(longlong) +# +CREATE SEQUENCE s AS BIGINT UNSIGNED START WITH 9223372036854775800 INCREMENT 0; +set @old_AUTO_INCREMENT_INCREMENT=@@global.AUTO_INCREMENT_INCREMENT; +set global AUTO_INCREMENT_INCREMENT=10; +SELECT NEXTVAL (s); +NEXTVAL (s) +9223372036854775800 +FLUSH TABLES WITH READ LOCK; +UPDATE s SET a=1; +Got one of the listed errors +unlock tables; +set global AUTO_INCREMENT_INCREMENT=@old_AUTO_INCREMENT_INCREMENT; +drop sequence s; +# # End of 11.5 tests # diff --git a/mysql-test/suite/sql_sequence/auto_increment.test b/mysql-test/suite/sql_sequence/auto_increment.test index 8119d7fee08..47f2fcaecfe 100644 --- a/mysql-test/suite/sql_sequence/auto_increment.test +++ b/mysql-test/suite/sql_sequence/auto_increment.test @@ -48,6 +48,23 @@ create sequence s as bigint start with -9223372036854775805 minvalue -9223372036 drop sequence s; set global auto_increment_increment= default, auto_increment_offset= default; + +--echo # +--echo # MDEV-33836 Assertion `(ulonglong) next_free_value % real_increment == (ulonglong) offset' failed in void sequence_definition::adjust_values(longlong) +--echo # + +CREATE SEQUENCE s AS BIGINT UNSIGNED START WITH 9223372036854775800 INCREMENT 0; +set @old_AUTO_INCREMENT_INCREMENT=@@global.AUTO_INCREMENT_INCREMENT; +set global AUTO_INCREMENT_INCREMENT=10; +SELECT NEXTVAL (s); +FLUSH TABLES WITH READ LOCK; +# ER_CANT_UPDATE_WITH_READLOCK when executed normally +# ER_BAD_FIELD_ERROR when executed as a prepared statement +--error ER_CANT_UPDATE_WITH_READLOCK,ER_BAD_FIELD_ERROR +UPDATE s SET a=1; +unlock tables; +set global AUTO_INCREMENT_INCREMENT=@old_AUTO_INCREMENT_INCREMENT; +drop sequence s; --enable_ps2_protocol --echo # diff --git a/mysql-test/suite/sql_sequence/setval.result b/mysql-test/suite/sql_sequence/setval.result index f78766070b5..1152f6b59de 100644 --- a/mysql-test/suite/sql_sequence/setval.result +++ b/mysql-test/suite/sql_sequence/setval.result @@ -418,4 +418,15 @@ setval(s, 32767) select nextval(s); ERROR HY000: Sequence 'test.s' has run out drop sequence s; +# +# MDEV-33836 Assertion `(ulonglong) next_free_value % real_increment == (ulonglong) offset' failed in void sequence_definition::adjust_values(longlong) +# +CREATE SEQUENCE s AS BIGINT UNSIGNED START WITH 9223372036854775800 INCREMENT 0; +set @old_AUTO_INCREMENT_INCREMENT=@@global.AUTO_INCREMENT_INCREMENT; +set global AUTO_INCREMENT_INCREMENT=100; +SELECT SETVAL (s,12345678901234567890); +SETVAL (s,12345678901234567890) +12345678901234567890 +drop sequence s; +set global AUTO_INCREMENT_INCREMENT=@old_AUTO_INCREMENT_INCREMENT; # End of 11.5 tests diff --git a/mysql-test/suite/sql_sequence/setval.test b/mysql-test/suite/sql_sequence/setval.test index 37b60b6d6e7..8a40aade541 100644 --- a/mysql-test/suite/sql_sequence/setval.test +++ b/mysql-test/suite/sql_sequence/setval.test @@ -253,4 +253,15 @@ select nextval(s); drop sequence s; --enable_ps2_protocol +--echo # +--echo # MDEV-33836 Assertion `(ulonglong) next_free_value % real_increment == (ulonglong) offset' failed in void sequence_definition::adjust_values(longlong) +--echo # + +CREATE SEQUENCE s AS BIGINT UNSIGNED START WITH 9223372036854775800 INCREMENT 0; +set @old_AUTO_INCREMENT_INCREMENT=@@global.AUTO_INCREMENT_INCREMENT; +set global AUTO_INCREMENT_INCREMENT=100; +SELECT SETVAL (s,12345678901234567890); +drop sequence s; +set global AUTO_INCREMENT_INCREMENT=@old_AUTO_INCREMENT_INCREMENT; + --echo # End of 11.5 tests diff --git a/sql/sql_sequence.cc b/sql/sql_sequence.cc index 7ecc9adbe07..4d6d06defe4 100644 --- a/sql/sql_sequence.cc +++ b/sql/sql_sequence.cc @@ -751,7 +751,10 @@ void sequence_definition::adjust_values(longlong next_value) next_free_value % real_increment == offset */ - off= next_free_value % real_increment; + if (is_unsigned) + off= (ulonglong) next_free_value % real_increment; + else + off= next_free_value % real_increment; if (off < 0) off+= real_increment; to_add= (real_increment + offset - off) % real_increment; From ba5482ffc293f162382a7f4296fd296b59cf0acb Mon Sep 17 00:00:00 2001 From: Dmitry Shulga Date: Fri, 16 Aug 2024 12:43:35 +0700 Subject: [PATCH 39/45] MDEV-34718: Trigger doesn't work correctly with bulk update Running an UPDATE statement in PS mode and having positional parameter(s) bound with an array of actual values (that is prepared to be run in bulk mode) results in incorrect behaviour in presence of on update trigger that also executes an UPDATE statement. The same is true for handling a DELETE statement in presence of on delete trigger. Typically, the visible effect of such incorrect behaviour is expressed in a wrong number of updated/deleted rows of a target table. Additionally, in case UPDATE statement, a number of modified rows and a state message returned by a statement contains wrong information about a number of modified rows. The reason for incorrect number of updated/deleted rows is that a data structure used for binding positional argument with its actual values is stored in THD (this is thd->bulk_param) and reused on processing every INSERT/UPDATE/DELETE statement. It leads to consuming actual values bound with top-level UPDATE/DELETE statement by other DML statements used by triggers' body. To fix the issue, reset the thd->bulk_param temporary to the value nullptr before invoking triggers and restore its value on finishing its execution. The second part of the problem relating with wrong value of affected rows reported by Connector/C API is caused by the fact that diagnostics area is reused by an original DML statement and a statement invoked by a trigger. This fact should be take into account on finalizing a state of diagnostics area on completion running of a statement. Important remark: in case the macros DBUG_OFF is on, call of the method Diagnostics_area::reset_diagnostics_area() results in reset of the data members m_affected_rows, m_statement_warn_count. Values of these data members of the class Diagnostics_area are used on sending OK and EOF messages. In case DML statement is executed in PS bulk mode such resetting results in sending wrong result values to a client for affected rows in case the DML statement fires a triggers. So, reset these data members only in case the current statement being processed is not run in bulk mode. --- sql/sql_base.cc | 12 + sql/sql_delete.cc | 7 + sql/sql_error.cc | 19 +- sql/sql_error.h | 5 + sql/sql_insert.cc | 35 ++- sql/sql_update.cc | 20 ++ tests/mysql_client_test.c | 450 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 534 insertions(+), 14 deletions(-) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 8738f181d77..29daca40acb 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8784,10 +8784,22 @@ fill_record_n_invoke_before_triggers(THD *thd, TABLE *table, if (!result && triggers) { + void *save_bulk_param= thd->bulk_param; + /* + Reset the sentinel thd->bulk_param in order not to consume the next + values of a bound array in case one of statement executed by + the trigger's body is INSERT statement. + */ + thd->bulk_param= nullptr; + if (triggers->process_triggers(thd, event, TRG_ACTION_BEFORE, TRUE) || not_null_fields_have_null_values(table)) + { + thd->bulk_param= save_bulk_param; return TRUE; + } + thd->bulk_param= save_bulk_param; /* Re-calculate virtual fields to cater for cases when base columns are diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 945385e114d..99da79c599b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -796,13 +796,17 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, delete_history); if (delete_record) { + void *save_bulk_param= thd->bulk_param; + thd->bulk_param= nullptr; if (!delete_history && table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_BEFORE, FALSE)) { error= 1; + thd->bulk_param= save_bulk_param; break; } + thd->bulk_param= save_bulk_param; // no LIMIT / OFFSET if (returning && result->send_data(returning->item_list) < 0) @@ -833,13 +837,16 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (likely(!error)) { deleted++; + thd->bulk_param= nullptr; if (!delete_history && table->triggers && table->triggers->process_triggers(thd, TRG_EVENT_DELETE, TRG_ACTION_AFTER, FALSE)) { error= 1; + thd->bulk_param= save_bulk_param; break; } + thd->bulk_param= save_bulk_param; if (!--limit && using_limit) { error= -1; diff --git a/sql/sql_error.cc b/sql/sql_error.cc index 2b4ae7149c5..6a3730ed3df 100644 --- a/sql/sql_error.cc +++ b/sql/sql_error.cc @@ -309,14 +309,27 @@ Diagnostics_area::reset_diagnostics_area() m_message[0]= '\0'; Sql_state_errno::clear(); Sql_user_condition_identity::clear(); - m_affected_rows= 0; m_last_insert_id= 0; - m_statement_warn_count= 0; + if (!is_bulk_op()) + { + m_affected_rows= 0; + m_statement_warn_count= 0; + } #endif get_warning_info()->clear_error_condition(); set_is_sent(false); /** Tiny reset in debug mode to see garbage right away */ - m_status= DA_EMPTY; + if (!is_bulk_op()) + /* + For BULK DML operations (e.g. UPDATE) the data member m_status + has the value DA_OK_BULK. Keep this value in order to handle + m_affected_rows, m_statement_warn_count in correct way. Else, + the number of rows and the number of warnings affected by + the last statement executed as part of a trigger fired by the dml + (e.g. UPDATE statement fires a trigger on AFTER UPDATE) would counts + rows modified by trigger's statement. + */ + m_status= DA_EMPTY; DBUG_VOID_RETURN; } diff --git a/sql/sql_error.h b/sql/sql_error.h index 92bc0b821a9..78c29fc4a2d 100644 --- a/sql/sql_error.h +++ b/sql/sql_error.h @@ -1066,6 +1066,11 @@ public: return m_affected_rows; } + void set_message(const char *msg) + { + strmake_buf(m_message, msg); + } + ulonglong last_insert_id() const { DBUG_ASSERT(m_status == DA_OK || m_status == DA_OK_BULK); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 35eec93f540..cf3ec929d09 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1021,19 +1021,11 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, */ restore_record(table,s->default_values); // Get empty record table->reset_default_fields(); - /* - Reset the sentinel thd->bulk_param in order not to consume the next - values of a bound array in case one of statement executed by - the trigger's body is INSERT statement. - */ - void *save_bulk_param= thd->bulk_param; - thd->bulk_param= nullptr; if (unlikely(fill_record_n_invoke_before_triggers(thd, table, fields, *values, 0, TRG_EVENT_INSERT))) { - thd->bulk_param= save_bulk_param; if (values_list.elements != 1 && ! thd->is_error()) { info.records++; @@ -1047,7 +1039,6 @@ bool mysql_insert(THD *thd, TABLE_LIST *table_list, error=1; break; } - thd->bulk_param= save_bulk_param; } else { @@ -1334,7 +1325,18 @@ values_loop_end: */ if (returning) result->send_eof(); - else + else if (!(thd->in_sub_stmt & SUB_STMT_TRIGGER)) + /* + Set the status and the number of affected rows in Diagnostics_area + only in case the INSERT statement is not processed as part of a trigger + invoked by some other DML statement. Else we would result in incorrect + number of affected rows for bulk DML operations, e.g. the UPDATE + statement (called via PS protocol). It would happen since the data + member Diagnostics_area::m_affected_rows modified twice per DML + statement - first time at the end of handling the INSERT statement + invoking by a trigger fired on handling the original DML statement, + and the second time at the end of handling the original DML statement. + */ my_ok(thd, info.copied + info.deleted + ((thd->client_capabilities & CLIENT_FOUND_ROWS) ? info.touched : info.updated), id); @@ -1356,7 +1358,18 @@ values_loop_end: (long) thd->get_stmt_da()->current_statement_warn_count()); if (returning) result->send_eof(); - else + else if (!(thd->in_sub_stmt & SUB_STMT_TRIGGER)) + /* + Set the status and the number of affected rows in Diagnostics_area + only in case the INSERT statement is not processed as part of a trigger + invoked by some other DML statement. Else we would result in incorrect + number of affected rows for bulk DML operations, e.g. the UPDATE + statement (called via PS protocol). It would happen since the data + member Diagnostics_area::m_affected_rows modified twice per DML + statement - first time at the end of handling the INSERT statement + invoking by a trigger fired on handling the original DML statement, + and the second time at the end of handling the original DML statement. + */ ::my_ok(thd, info.copied + info.deleted + updated, id, buff); } thd->abort_on_warning= 0; diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 92cb4191fc6..adb209b7b56 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -1146,13 +1146,19 @@ error: rows_inserted++; } + void *save_bulk_param= thd->bulk_param; + thd->bulk_param= nullptr; + if (table->triggers && unlikely(table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER, TRUE))) { error= 1; + thd->bulk_param= save_bulk_param; + break; } + thd->bulk_param= save_bulk_param; if (!--limit && using_limit) { @@ -1342,6 +1348,20 @@ update_end: (ulong) thd->get_stmt_da()->current_statement_warn_count()); my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, id, buff); + if (thd->get_stmt_da()->is_bulk_op()) + { + /* + Update the diagnostics message sent to a client with number of actual + rows update by the statement. For bulk UPDATE operation it should be + done after returning from my_ok() since the final number of updated + rows be knows on finishing the entire bulk update statement. + */ + my_snprintf(buff, sizeof(buff), ER_THD(thd, ER_UPDATE_INFO), + (ulong) thd->get_stmt_da()->affected_rows(), + (ulong) thd->get_stmt_da()->affected_rows(), + (ulong) thd->get_stmt_da()->current_statement_warn_count()); + thd->get_stmt_da()->set_message(buff); + } DBUG_PRINT("info",("%ld records updated", (long) updated)); } thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 66281641b08..138eae10ab1 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -22059,6 +22059,452 @@ static void test_mdev_30159() myquery(rc); } + +#ifndef EMBEDDED_LIBRARY +/** + Test case for bulk UPDATE against a table with an active AFTER UPDATE + trigger. +*/ + +static void test_mdev_34718_au() +{ + int rc; + MYSQL_STMT *stmt_update; + MYSQL_BIND bind[2]; + unsigned int vals[]= { 1, 2, 3}; + unsigned int new_vals[]= { 5, 6, 7}; + unsigned int vals_array_len= 3; + my_ulonglong row_count; + MYSQL_RES *result; + MYSQL_ROW row; + const char *update_stmt= "UPDATE t1 SET a = ? WHERE a = ?"; + const char *update_stmt_state_info; + + myheader("test_mdev_34718_au"); + + /* Set up test's environment */ + rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2), (3)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TRIGGER t1_au AFTER UPDATE ON t1 " + "FOR EACH ROW BEGIN INSERT INTO t2 (a) VALUES (NEW.a); END;"); + + stmt_update= mysql_stmt_init(mysql); + check_stmt(stmt_update); + + rc= mysql_stmt_prepare(stmt_update, update_stmt, strlen(update_stmt)); + check_execute(stmt_update, rc); + + memset(&bind[0], 0, sizeof(MYSQL_BIND)); + memset(&bind[1], 0, sizeof(MYSQL_BIND)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= new_vals; + + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= vals; + + /* + Every input positional parameter is bound with array of 3 elements + containing actual values for positional parameters + */ + rc= mysql_stmt_attr_set(stmt_update, STMT_ATTR_ARRAY_SIZE, &vals_array_len); + check_execute(stmt_update, rc); + + rc= mysql_stmt_bind_param(stmt_update, bind); + check_execute(stmt_update, rc); + + /* + Execution of this prepared statement replaces the table rows (1), (2), (3) + with values (5), (6), (7) + */ + rc= mysql_stmt_execute(stmt_update); + check_execute(stmt_update, rc); + + /* + Check that the BULK UPDATE statement affects exactly 3 rows + */ + row_count = mysql_stmt_affected_rows(stmt_update); + DIE_UNLESS(row_count == 3); + + update_stmt_state_info= mysql_info(mysql); + + /* + Check that information about executed operation is matched with + the expected result + */ + DIE_UNLESS(!strcmp("Rows matched: 3 Changed: 3 Warnings: 0", + update_stmt_state_info)); + + /* + * Check that the AFTER UPDATE trigger of the table t1 does work correctly + * and inserts the rows (5), (6), (7) into the table t2. + */ + rc= mysql_query(mysql, "SELECT 't1' tname, a FROM t1 " + "UNION SELECT 't2' tname, a FROM t2 ORDER BY tname, a"); + myquery(rc); + + result= mysql_store_result(mysql); + + row = mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t1") == 0 && atoi(row[1]) == 5); + + row = mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t1") == 0 && atoi(row[1]) == 6); + + row = mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t1") == 0 && atoi(row[1]) == 7); + + row = mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 5); + + row = mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 6); + + row = mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 7); + + row= mysql_fetch_row(result); + DIE_UNLESS(row == NULL); + + mysql_free_result(result); + + mysql_stmt_close(stmt_update); + + /* Clean up */ + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + + +/** + Test case for bulk UPDATE against a table with an active BEFORE UPDATE + trigger. +*/ + +static void test_mdev_34718_bu() +{ + int rc; + MYSQL_STMT *stmt_update; + MYSQL_BIND bind[2]; + unsigned int vals[]= { 1, 2, 3}; + unsigned int new_vals[]= { 5, 6, 7}; + unsigned int vals_array_len= 3; + my_ulonglong row_count; + MYSQL_RES *result; + MYSQL_ROW row; + const char *update_stmt= "UPDATE t1 SET a = ? WHERE a = ?"; + const char *update_stmt_state_info; + + myheader("test_mdev_34718_bu"); + + /* Set up test's environment */ + rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2), (3)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TRIGGER t1_au BEFORE UPDATE ON t1 " + "FOR EACH ROW BEGIN INSERT INTO t2 (a) VALUES (NEW.a); END;"); + + /* Initialize the prepared statement and set it up for bulk operations */ + stmt_update= mysql_stmt_init(mysql); + check_stmt(stmt_update); + + rc= mysql_stmt_prepare(stmt_update, update_stmt, strlen(update_stmt)); + check_execute(stmt_update, rc); + + memset(&bind[0], 0, sizeof(MYSQL_BIND)); + memset(&bind[1], 0, sizeof(MYSQL_BIND)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= new_vals; + + bind[1].buffer_type= MYSQL_TYPE_LONG; + bind[1].buffer= vals; + + /* + Every input positional parameter is bound with array of 3 elements + containing actual values for positional parameters + */ + rc= mysql_stmt_attr_set(stmt_update, STMT_ATTR_ARRAY_SIZE, &vals_array_len); + check_execute(stmt_update, rc); + + rc= mysql_stmt_bind_param(stmt_update, bind); + check_execute(stmt_update, rc); + + /* + Execution of this prepared statement replaces the table rows (1), (2), (3) + with values (5), (6), (7) + */ + rc= mysql_stmt_execute(stmt_update); + check_execute(stmt_update, rc); + + /* + Check that the BULK UPDATE statement affects exactly 3 rows + */ + row_count= mysql_stmt_affected_rows(stmt_update); + DIE_UNLESS(row_count == 3); + + update_stmt_state_info= mysql_info(mysql); + + /* + Check that information about executed operation is matched with + the expected result + */ + DIE_UNLESS(!strcmp("Rows matched: 3 Changed: 3 Warnings: 0", + update_stmt_state_info)); + + /* + * Check that the BEFORE UPDATE trigger of the table t1 does work correctly + * and inserts the rows (5), (6), (7) into the table t2. + */ + rc= mysql_query(mysql, "SELECT 't1' tname, a FROM t1 " + "UNION SELECT 't2' tname, a FROM t2 ORDER BY tname, a"); + myquery(rc); + + result= mysql_store_result(mysql); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t1") == 0 && atoi(row[1]) == 5); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t1") == 0 && atoi(row[1]) == 6); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t1") == 0 && atoi(row[1]) == 7); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 5); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 6); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 7); + + row= mysql_fetch_row(result); + DIE_UNLESS(row == NULL); + + mysql_free_result(result); + + mysql_stmt_close(stmt_update); + + /* Clean up */ + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + + +/** + Test case for bulk DELETE against a table with an active BEFORE DELETE + trigger. +*/ + +static void test_mdev_34718_bd() +{ + int rc; + MYSQL_STMT *stmt_delete; + MYSQL_BIND bind[1]; + unsigned int vals[]= { 1, 2, 3}; + unsigned int vals_array_len= 3; + my_ulonglong row_count; + MYSQL_RES *result; + MYSQL_ROW row; + const char *delete_stmt= "DELETE FROM t1 WHERE a = ?"; + + myheader("test_mdev_34718_bd"); + + /* Set up test's environment */ + rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2), (3)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TRIGGER t1_bd BEFORE DELETE ON t1 " + "FOR EACH ROW BEGIN INSERT INTO t2 (a) VALUES (OLD.a); END;"); + + /* Initialize the prepared statement and set it up for bulk operations */ + stmt_delete= mysql_stmt_init(mysql); + check_stmt(stmt_delete); + + rc= mysql_stmt_prepare(stmt_delete, delete_stmt, strlen(delete_stmt)); + check_execute(stmt_delete, rc); + + memset(&bind[0], 0, sizeof(MYSQL_BIND)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= vals; + + /* + Input positional parameter is bound with array of 3 elements + containing actual values for the positional parameter + */ + rc= mysql_stmt_attr_set(stmt_delete, STMT_ATTR_ARRAY_SIZE, &vals_array_len); + check_execute(stmt_delete, rc); + + rc= mysql_stmt_bind_param(stmt_delete, bind); + check_execute(stmt_delete, rc); + + /* + Execution of this prepared statement deletes the rows (1), (2), (3) + from the table t1 and inserts the rows (1), (2), (3) into the table t2 + in result of firing the BEFORE DELETE trigger + */ + rc= mysql_stmt_execute(stmt_delete); + check_execute(stmt_delete, rc); + + /* + Check that the BULK DELETE statement affects exactly 3 rows + */ + row_count= mysql_stmt_affected_rows(stmt_delete); + DIE_UNLESS(row_count == 3); + + /* + * Check that the BEFORE DELETE trigger of the table t1 does work correctly + * and inserts the rows (1), (2), (3) into the table t2. + */ + rc= mysql_query(mysql, "SELECT 't1' tname, a FROM t1 " + "UNION SELECT 't2' tname, a FROM t2 ORDER BY tname, a"); + myquery(rc); + + result= mysql_store_result(mysql); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 1); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 2); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 3); + + row= mysql_fetch_row(result); + DIE_UNLESS(row == NULL); + + mysql_free_result(result); + + mysql_stmt_close(stmt_delete); + + /* Clean up */ + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} + + +/** + Test case for bulk DELETE against a table with an active AFTER DELETE + trigger. +*/ +static void test_mdev_34718_ad() +{ + int rc; + MYSQL_STMT *stmt_delete; + MYSQL_BIND bind[1]; + unsigned int vals[]= { 1, 2, 3}; + unsigned int vals_array_len= 3; + my_ulonglong row_count; + MYSQL_RES *result; + MYSQL_ROW row; + const char *delete_stmt= "DELETE FROM t1 WHERE a = ?"; + + myheader("test_mdev_34718_bd"); + + /* Set up test's environment */ + rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TABLE t2 (a INT)"); + myquery(rc); + + rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1), (2), (3)"); + myquery(rc); + + rc= mysql_query(mysql, "CREATE TRIGGER t1_bd AFTER DELETE ON t1 " + "FOR EACH ROW BEGIN INSERT INTO t2 (a) VALUES (OLD.a); END;"); + + /* Initialize the prepared statement and set it up for bulk operations */ + stmt_delete= mysql_stmt_init(mysql); + check_stmt(stmt_delete); + + rc= mysql_stmt_prepare(stmt_delete, delete_stmt, strlen(delete_stmt)); + check_execute(stmt_delete, rc); + + memset(&bind[0], 0, sizeof(MYSQL_BIND)); + + bind[0].buffer_type= MYSQL_TYPE_LONG; + bind[0].buffer= vals; + + /* + Input positional parameter is bound with array of 3 elements + containing actual values for the positional parameter + */ + rc= mysql_stmt_attr_set(stmt_delete, STMT_ATTR_ARRAY_SIZE, &vals_array_len); + check_execute(stmt_delete, rc); + + rc= mysql_stmt_bind_param(stmt_delete, bind); + check_execute(stmt_delete, rc); + + /* + Execution of this prepared statement deletes the rows (1), (2), (3) + from the table t1 and inserts the rows (1), (2), (3) into the table t2 + in result of firing the BEFORE DELETE trigger + */ + rc= mysql_stmt_execute(stmt_delete); + check_execute(stmt_delete, rc); + + /* + Check that the BULK DELETE statement affects exactly 3 rows + */ + row_count= mysql_stmt_affected_rows(stmt_delete); + DIE_UNLESS(row_count == 3); + + /* + * Check that the AFTER DELETE trigger of the table t1 does work correctly + * and inserts the rows (1), (2), (3) into the table t2. + */ + rc= mysql_query(mysql, "SELECT 't1' tname, a FROM t1 " + "UNION SELECT 't2' tname, a FROM t2 ORDER BY tname, a"); + myquery(rc); + + result= mysql_store_result(mysql); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 1); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 2); + + row= mysql_fetch_row(result); + DIE_UNLESS(strcmp(row[0], "t2") == 0 && atoi(row[1]) == 3); + + row= mysql_fetch_row(result); + DIE_UNLESS(row == NULL); + + mysql_free_result(result); + + mysql_stmt_close(stmt_delete); + + /* Clean up */ + rc= mysql_query(mysql, "DROP TABLE t1, t2"); + myquery(rc); +} +#endif // EMBEDDED_LIBRARY + /* Check that server_status returned after connecting to server is consistent with the value of autocommit variable. @@ -22406,6 +22852,10 @@ static struct my_tests_st my_tests[]= { { "test_connect_autocommit", test_connect_autocommit}, #ifndef EMBEDDED_LIBRARY { "test_mdev_24411", test_mdev_24411}, + { "test_mdev_34718_bu", test_mdev_34718_bu }, + { "test_mdev_34718_au", test_mdev_34718_au }, + { "test_mdev_34718_bd", test_mdev_34718_bd }, + { "test_mdev_34718_ad", test_mdev_34718_ad }, #endif { 0, 0 } }; From e51d55a63ff98bdb3b44681434d619c51adb3863 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 19 Aug 2024 10:59:57 +0300 Subject: [PATCH 40/45] Revert "mtr: remove not_valgrind_build" The original code is correct. valgrind and asan binaries should be built with a specialiced version of mem_root that makes it easier to find memory overwrites. This is what the BUILD scripts is doing. The specialiced mem_root code allocates a new block for every allocation which is visiable for any test that depenmds on the default original malloc size and usage. --- mysql-test/include/not_valgrind_build.inc | 4 ++++ mysql-test/main/sp-no-valgrind.test | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 mysql-test/include/not_valgrind_build.inc diff --git a/mysql-test/include/not_valgrind_build.inc b/mysql-test/include/not_valgrind_build.inc new file mode 100644 index 00000000000..b62a1bc953b --- /dev/null +++ b/mysql-test/include/not_valgrind_build.inc @@ -0,0 +1,4 @@ +if (`select version() like '%valgrind%' || version() like '%asan%'`) +{ + skip Does not run with binaries built with valgrind or asan; +} diff --git a/mysql-test/main/sp-no-valgrind.test b/mysql-test/main/sp-no-valgrind.test index 1b4a0f84f1e..6bacc7b150c 100644 --- a/mysql-test/main/sp-no-valgrind.test +++ b/mysql-test/main/sp-no-valgrind.test @@ -1,5 +1,5 @@ --source include/not_msan.inc ---source include/not_valgrind.inc +--source include/not_valgrind_build.inc --echo # MDEV-20699 do not cache SP in SHOW CREATE --echo # Warmup round, this might allocate some memory for session variable From db8ab4aca27de0c02b9e4b4f367d23c2d6c27c03 Mon Sep 17 00:00:00 2001 From: Monty Date: Mon, 19 Aug 2024 11:14:11 +0300 Subject: [PATCH 41/45] Sort result from table_statistics and index_statistics This is needed as the order of rows are not deterministic, especially in future versions of table statistics. --- mysql-test/main/subselect.test | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mysql-test/main/subselect.test b/mysql-test/main/subselect.test index d010f01be56..3f01e984125 100644 --- a/mysql-test/main/subselect.test +++ b/mysql-test/main/subselect.test @@ -5932,7 +5932,9 @@ WHERE SLEEP(0.1) OR c < 'p' OR b = ( SELECT MIN(b) FROM t2 ); --enable_ps2_protocol --echo # The following shows that t2 was indeed scanned with a full scan. +--sorted_result show table_statistics; +--sorted_result show index_statistics; set global userstat=@tmp_mdev410; From fccfdc28b8b3aa42378d7433febbf31d6af7a732 Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 19 Aug 2024 17:15:46 +0200 Subject: [PATCH 42/45] MDEV-34771 Types mismatch when cloning items causes debug assertion Missing methods added to Item_bin_string --- mysql-test/main/item_types.result | 9 +++++++++ mysql-test/main/item_types.test | 10 ++++++++++ sql/item.h | 3 +++ 3 files changed, 22 insertions(+) diff --git a/mysql-test/main/item_types.result b/mysql-test/main/item_types.result index 40db01f2609..6a73549a886 100644 --- a/mysql-test/main/item_types.result +++ b/mysql-test/main/item_types.result @@ -27,4 +27,13 @@ a DROP TABLE t1; DROP VIEW v1, v2; +# +# MDEV-34771: Types mismatch when cloning items causes debug assertion +# +CREATE VIEW t AS SELECT 1 AS a; +SELECT * FROM t WHERE a=b''; +a +drop view t; +# # End of 10.5 tests +# diff --git a/mysql-test/main/item_types.test b/mysql-test/main/item_types.test index 6f10d6bf71a..56af975df9d 100644 --- a/mysql-test/main/item_types.test +++ b/mysql-test/main/item_types.test @@ -30,4 +30,14 @@ SELECT * FROM v2 WHERE a='' AND CASE '' WHEN '' THEN '' ELSE a END=''; DROP TABLE t1; DROP VIEW v1, v2; +--echo # +--echo # MDEV-34771: Types mismatch when cloning items causes debug assertion +--echo # + +CREATE VIEW t AS SELECT 1 AS a; +SELECT * FROM t WHERE a=b''; +drop view t; + +--echo # --echo # End of 10.5 tests +--echo # diff --git a/sql/item.h b/sql/item.h index 9af0a077f75..f5ef54382cb 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4946,6 +4946,9 @@ class Item_bin_string: public Item_hex_hybrid public: Item_bin_string(THD *thd, const char *str, size_t str_length); void print(String *str, enum_query_type query_type) override; + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; From ae02999cdbea0ebb57cafc8c6b09878b8ea8a3be Mon Sep 17 00:00:00 2001 From: Oleksandr Byelkin Date: Mon, 19 Aug 2024 18:49:04 +0200 Subject: [PATCH 43/45] MDEV-34776 Assertion failure in Item_string::do_build_clone Added missed methods to Item_string child. --- mysql-test/main/item_types.result | 7 +++++++ mysql-test/main/item_types.test | 8 ++++++++ sql/item.h | 12 ++++++++++++ 3 files changed, 27 insertions(+) diff --git a/mysql-test/main/item_types.result b/mysql-test/main/item_types.result index 6a73549a886..0193d33be6d 100644 --- a/mysql-test/main/item_types.result +++ b/mysql-test/main/item_types.result @@ -35,5 +35,12 @@ SELECT * FROM t WHERE a=b''; a drop view t; # +# MDEV-34776: Assertion failure in Item_string::do_build_clone +# +CREATE VIEW v AS SELECT version() AS f; +SELECT * FROM v WHERE f = '10.5.20'; +f +drop view v; +# # End of 10.5 tests # diff --git a/mysql-test/main/item_types.test b/mysql-test/main/item_types.test index 56af975df9d..2818ae582af 100644 --- a/mysql-test/main/item_types.test +++ b/mysql-test/main/item_types.test @@ -38,6 +38,14 @@ CREATE VIEW t AS SELECT 1 AS a; SELECT * FROM t WHERE a=b''; drop view t; +--echo # +--echo # MDEV-34776: Assertion failure in Item_string::do_build_clone +--echo # + +CREATE VIEW v AS SELECT version() AS f; +SELECT * FROM v WHERE f = '10.5.20'; +drop view v; + --echo # --echo # End of 10.5 tests --echo # diff --git a/sql/item.h b/sql/item.h index f5ef54382cb..cddef65f4fd 100644 --- a/sql/item.h +++ b/sql/item.h @@ -4719,6 +4719,9 @@ public: Item_string_sys(THD *thd, const char *str): Item_string(thd, str, (uint) strlen(str), system_charset_info) { } + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; @@ -4733,6 +4736,9 @@ public: Item_string(thd, str, (uint) strlen(str), &my_charset_latin1, DERIVATION_COERCIBLE, MY_REPERTOIRE_ASCII) { } + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; @@ -4769,6 +4775,9 @@ public: // require fix_fields() to be re-run for every statement. return mark_unsupported_function(func_name.str, arg, VCOL_TIME_FUNC); } + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; @@ -4786,6 +4795,9 @@ public: { return mark_unsupported_function("safe_string", arg, VCOL_IMPOSSIBLE); } + Item *do_get_copy(THD *thd) const override + { return get_item_copy(thd, this); } + Item *do_build_clone(THD *thd) const override { return get_copy(thd); } }; From 78fcb9474c90f89a7065ea01d9b00d2c546e36b6 Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Mon, 19 Aug 2024 20:49:28 +0200 Subject: [PATCH 44/45] Fix sporadic failure in test rpl.rpl_rotate_logs Clarify confusing comments in the previous commit, and note that the failure started after push of MDEV-34504. Signed-off-by: Kristian Nielsen --- mysql-test/suite/rpl/t/rpl_rotate_logs.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mysql-test/suite/rpl/t/rpl_rotate_logs.test b/mysql-test/suite/rpl/t/rpl_rotate_logs.test index 6de85b7ca89..3ea78dbc174 100644 --- a/mysql-test/suite/rpl/t/rpl_rotate_logs.test +++ b/mysql-test/suite/rpl/t/rpl_rotate_logs.test @@ -135,8 +135,8 @@ remove_file $MYSQLTEST_VARDIR/tmp/rpl_rotate_logs.tmp; --enable_result_log # Disable the warning "is not purged because it is the current active binlog". -# (If the purge is delayed, this warning will not occur, causing .result -# difference). +# This warning will appear or not, depending on whether the timestamp of +# master-bin.000003 ends up earlier than @time_for_purge or not in the test run. --disable_warnings purge master logs before (@time_for_purge); --enable_warnings From 7318fa180d7c607f11efad45eaa95a170f6b0b7c Mon Sep 17 00:00:00 2001 From: Kristian Nielsen Date: Sat, 17 Aug 2024 12:29:00 +0200 Subject: [PATCH 45/45] Fix sporadic test failure of mariabackup.slave_provision_nolock The test requires a larger innodb log file size; this was lost as a side-effect of d7699c51ebfc2921678d1e20a0b4490ccc1954e9. Signed-off-by: Kristian Nielsen --- mysql-test/suite/mariabackup/slave_provision_nolock.cnf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/suite/mariabackup/slave_provision_nolock.cnf b/mysql-test/suite/mariabackup/slave_provision_nolock.cnf index d8326a5ccb8..bba1d2a73c6 100644 --- a/mysql-test/suite/mariabackup/slave_provision_nolock.cnf +++ b/mysql-test/suite/mariabackup/slave_provision_nolock.cnf @@ -3,6 +3,9 @@ [mysqld.1] log-slave-updates loose-innodb +# Test does a lot of DML during the backup, larger than 10M log is needed for +# mariabackup to always be able to copy all that it needs. +loose-innodb_log_file_size= 96M [mysqld.2] log-slave-updates