From ccb9f673b48ffa17103e628f34804ee1f2748b37 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 3 Aug 2020 13:23:38 +0200 Subject: [PATCH 01/20] MDEV-23348 vio_shutdown does not prevent later ReadFile on named pipe Introduce st_vio::shutdown_flag to be checked prior to Read/WriteFile and during wait for async.io to finish. --- include/violite.h | 1 + vio/vio.c | 1 + vio/viopipe.c | 17 +++++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/violite.h b/include/violite.h index 5bc6359b153..bb3fd8f6b6c 100644 --- a/include/violite.h +++ b/include/violite.h @@ -281,6 +281,7 @@ struct st_vio OVERLAPPED overlapped; DWORD read_timeout_ms; DWORD write_timeout_ms; + int shutdown_flag; #endif }; #endif /* vio_violite_h_ */ diff --git a/vio/vio.c b/vio/vio.c index 52a5387a852..694d2f7b7ff 100644 --- a/vio/vio.c +++ b/vio/vio.c @@ -68,6 +68,7 @@ int vio_shared_memory_shutdown(Vio *vio, int how) int vio_pipe_shutdown(Vio *vio, int how) { + vio->shutdown_flag= how; return CancelIoEx(vio->hPipe, NULL); } #endif diff --git a/vio/viopipe.c b/vio/viopipe.c index 5007599aa17..aeaad311b7e 100644 --- a/vio/viopipe.c +++ b/vio/viopipe.c @@ -75,6 +75,9 @@ size_t vio_read_pipe(Vio *vio, uchar *buf, size_t count) size_t ret= (size_t) -1; DBUG_ENTER("vio_read_pipe"); + if (vio->shutdown_flag) + return ret; + disable_iocp_notification(&vio->overlapped); /* Attempt to read from the pipe (overlapped I/O). */ @@ -85,8 +88,11 @@ size_t vio_read_pipe(Vio *vio, uchar *buf, size_t count) } /* Read operation is pending completion asynchronously? */ else if (GetLastError() == ERROR_IO_PENDING) + { + if (vio->shutdown_flag) + CancelIo(vio->hPipe); ret= wait_overlapped_result(vio, vio->read_timeout); - + } enable_iocp_notification(&vio->overlapped); DBUG_RETURN(ret); @@ -99,6 +105,8 @@ size_t vio_write_pipe(Vio *vio, const uchar *buf, size_t count) size_t ret= (size_t) -1; DBUG_ENTER("vio_write_pipe"); + if (vio->shutdown_flag == SHUT_RDWR) + return ret; disable_iocp_notification(&vio->overlapped); /* Attempt to write to the pipe (overlapped I/O). */ if (WriteFile(vio->hPipe, buf, (DWORD)count, &transferred, &vio->overlapped)) @@ -108,8 +116,11 @@ size_t vio_write_pipe(Vio *vio, const uchar *buf, size_t count) } /* Write operation is pending completion asynchronously? */ else if (GetLastError() == ERROR_IO_PENDING) + { + if (vio->shutdown_flag == SHUT_RDWR) + CancelIo(vio->hPipe); ret= wait_overlapped_result(vio, vio->write_timeout); - + } enable_iocp_notification(&vio->overlapped); DBUG_RETURN(ret); } @@ -129,9 +140,7 @@ int vio_close_pipe(Vio *vio) BOOL ret; DBUG_ENTER("vio_close_pipe"); - CancelIo(vio->hPipe); CloseHandle(vio->overlapped.hEvent); - DisconnectNamedPipe(vio->hPipe); ret= CloseHandle(vio->hPipe); vio->type= VIO_CLOSED; From b3e9798ff3fe4dcdda841dc72bd5d9a26db9eaa1 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 3 Aug 2020 13:35:53 +0200 Subject: [PATCH 02/20] Fix named_pipe test so it can be used with --repeat Remove the error log of the mysqld instance that was attempted to start in the test. --- mysql-test/main/named_pipe.test | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/main/named_pipe.test b/mysql-test/main/named_pipe.test index 8503907b808..2fe6f1cc5c0 100644 --- a/mysql-test/main/named_pipe.test +++ b/mysql-test/main/named_pipe.test @@ -30,3 +30,4 @@ let $MYSQLD_DATADIR= `select @@datadir`; let SEARCH_FILE=$MYSQLD_DATADIR/second-mysqld.err; let SEARCH_PATTERN=\[ERROR\] Create named pipe failed; source include/search_pattern_in_file.inc; +remove_file $SEARCH_FILE; From a8ec45863b958757da61af3b2ce0a38b0a79d92c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Mon, 3 Aug 2020 15:15:40 +0300 Subject: [PATCH 03/20] MDEV-23101: SIGSEGV in lock_rec_unlock() when Galera is enabled lock_rec_has_to_wait wsrep_kill_victim lock_rec_create_low lock_rec_add_to_queue DeadlockChecker::select_victim() THD can't change from normal transaction to BF (brute force) transaction here, thus there is no need to syncronize access in wsrep_thd_is_BF function. lock_rec_has_to_wait_in_queue Add condition that lock is not NULL and add assertions if we are in strong state. --- storage/innobase/lock/lock0lock.cc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index c4c045ffba3..1e7d9b031d7 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -754,7 +754,7 @@ lock_rec_has_to_wait( /* if BF thread is locking and has conflict with another BF thread, we need to look at trx ordering and lock types */ if (wsrep_thd_is_BF(trx->mysql_thd, FALSE) && - wsrep_thd_is_BF(lock2->trx->mysql_thd, TRUE)) { + wsrep_thd_is_BF(lock2->trx->mysql_thd, FALSE)) { mtr_t mtr; if (UNIV_UNLIKELY(wsrep_debug)) { @@ -1104,7 +1104,7 @@ wsrep_kill_victim( if (!trx->is_wsrep()) return; my_bool bf_this = wsrep_thd_is_BF(trx->mysql_thd, FALSE); - my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE); + my_bool bf_other = wsrep_thd_is_BF(lock->trx->mysql_thd, FALSE); mtr_t mtr; if ((bf_this && !bf_other) || @@ -1483,7 +1483,7 @@ lock_rec_create_low( lock_t *hash = (lock_t *)c_lock->hash; lock_t *prev = NULL; - while (hash && wsrep_thd_is_BF(hash->trx->mysql_thd, TRUE) + while (hash && wsrep_thd_is_BF(hash->trx->mysql_thd, FALSE) && wsrep_trx_order_before(hash->trx->mysql_thd, trx->mysql_thd)) { prev = hash; @@ -1877,11 +1877,9 @@ lock_rec_add_to_queue( = lock_rec_other_has_expl_req( mode, block, false, heap_no, trx); #ifdef WITH_WSREP - //ut_a(!other_lock || (wsrep_thd_is_BF(trx->mysql_thd, FALSE) && - // wsrep_thd_is_BF(other_lock->trx->mysql_thd, TRUE))); if (other_lock && trx->is_wsrep() && !wsrep_thd_is_BF(trx->mysql_thd, FALSE) && - !wsrep_thd_is_BF(other_lock->trx->mysql_thd, TRUE)) { + !wsrep_thd_is_BF(other_lock->trx->mysql_thd, FALSE)) { ib::info() << "WSREP BF lock conflict for my lock:\n BF:" << ((wsrep_thd_is_BF(trx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " << @@ -2190,6 +2188,7 @@ lock_rec_has_to_wait_in_queue( ulint bit_offset; hash_table_t* hash; + ut_ad(wait_lock); ut_ad(lock_mutex_own()); ut_ad(lock_get_wait(wait_lock)); ut_ad(lock_get_type_low(wait_lock) == LOCK_REC); @@ -2204,9 +2203,10 @@ lock_rec_has_to_wait_in_queue( hash = lock_hash_get(wait_lock->type_mode); for (lock = lock_rec_get_first_on_page_addr(hash, space, page_no); - lock != wait_lock; + lock && lock != wait_lock; lock = lock_rec_get_next_on_page_const(lock)) { + ut_ad(lock); const byte* p = (const byte*) &lock[1]; if (heap_no < lock_rec_get_n_bits(lock) @@ -2214,7 +2214,8 @@ lock_rec_has_to_wait_in_queue( && lock_has_to_wait(wait_lock, lock)) { #ifdef WITH_WSREP if (wsrep_thd_is_BF(wait_lock->trx->mysql_thd, FALSE) && - wsrep_thd_is_BF(lock->trx->mysql_thd, TRUE)) { + wsrep_thd_is_BF(lock->trx->mysql_thd, FALSE)) { + if (UNIV_UNLIKELY(wsrep_debug)) { mtr_t mtr; ib::info() << "WSREP: waiting BF trx: " << ib::hex(wait_lock->trx->id) @@ -7038,7 +7039,7 @@ DeadlockChecker::select_victim() const /* The joining transaction is 'smaller', choose it as the victim and roll it back. */ #ifdef WITH_WSREP - if (wsrep_thd_is_BF(m_start->mysql_thd, TRUE)) { + if (wsrep_thd_is_BF(m_start->mysql_thd, FALSE)) { return(m_wait_lock->trx); } #endif /* WITH_WSREP */ @@ -7046,7 +7047,7 @@ DeadlockChecker::select_victim() const } #ifdef WITH_WSREP - if (wsrep_thd_is_BF(m_wait_lock->trx->mysql_thd, TRUE)) { + if (wsrep_thd_is_BF(m_wait_lock->trx->mysql_thd, FALSE)) { return(m_start); } #endif /* WITH_WSREP */ From 87b1625b5ccb3e0e7f15a32e15892227463c7796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Tue, 4 Aug 2020 07:53:13 +0300 Subject: [PATCH 04/20] Test case MW-328A still fails, thus disable it until it is really fixed. --- mysql-test/suite/galera/disabled.def | 1 + 1 file changed, 1 insertion(+) diff --git a/mysql-test/suite/galera/disabled.def b/mysql-test/suite/galera/disabled.def index 453bbb139f5..02f1bb5eb1f 100644 --- a/mysql-test/suite/galera/disabled.def +++ b/mysql-test/suite/galera/disabled.def @@ -11,6 +11,7 @@ ############################################################################## MW-286 : MDEV-18464 Killing thread can cause mutex deadlock if done concurrently with Galera/replication victim kill +MW-328A : MDEV-22666 galera.MW-328A MTR failed: "Semaphore wait has lasted > 600 seconds" and do not release port 16002 MW-329 : MDEV-19962 Galera test failure on MW-329 galera.galera_defaults : MDEV-21494 Galera test sporadic failure on galera.galera_defaults galera_as_slave_replication_bundle : MDEV-15785 OPTION_GTID_BEGIN is set in Gtid_log_event::do_apply_event() From 745fa255ba73ab8b703481c4c420bfec7d11f6b3 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Thu, 16 Jul 2020 22:15:55 +0530 Subject: [PATCH 05/20] MDEV-14836: Assertion `m_status == DA_ERROR' failed in Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED open_normal_and_derived_table() fails because the query was already killed as rows examined by the query are more than the limit. However, this isn't a real error. Fix: Check if there is actually an error before calling thd->sql_errno() and later send a warning in handle_select() if no real error. --- mysql-test/r/information_schema.result | 13 +++++++++++++ mysql-test/t/information_schema.test | 13 +++++++++++++ sql/sql_show.cc | 18 ++++++++++++------ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 2d404aff6bc..7644ff4e7a2 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -2184,3 +2184,16 @@ SCHEMA_NAME # # End of 10.1 tests # +# +# Start of 10.2 Test +# +# MDEV-14836: Assertion `m_status == DA_ERROR' failed in +# Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED +# +SELECT * FROM INFORMATION_SCHEMA.`COLUMNS` LIMIT ROWS EXAMINED 10; +TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_SCALE DATETIME_PRECISION CHARACTER_SET_NAME COLLATION_NAME COLUMN_TYPE COLUMN_KEY EXTRA PRIVILEGES COLUMN_COMMENT IS_GENERATED GENERATION_EXPRESSION +Warnings: +Warning 1931 Query execution was interrupted. The query examined at least 666 rows, which exceeds LIMIT ROWS EXAMINED (10). The query result may be incomplete +# +# End of 10.2 Test +# diff --git a/mysql-test/t/information_schema.test b/mysql-test/t/information_schema.test index 2df105d4653..df00ff26908 100644 --- a/mysql-test/t/information_schema.test +++ b/mysql-test/t/information_schema.test @@ -1906,3 +1906,16 @@ SELECT SCHEMA_NAME from information_schema.schemata where schema_name=REPEAT('a' --echo # --echo # End of 10.1 tests --echo # + +--echo # +--echo # Start of 10.2 Test +--echo # +--echo # MDEV-14836: Assertion `m_status == DA_ERROR' failed in +--echo # Diagnostics_area::sql_errno upon query from I_S with LIMIT ROWS EXAMINED +--echo # + +SELECT * FROM INFORMATION_SCHEMA.`COLUMNS` LIMIT ROWS EXAMINED 10; + +--echo # +--echo # End of 10.2 Test +--echo # diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 18b7e92bca5..5544c765775 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4430,7 +4430,7 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys, Again we don't do this for SHOW COLUMNS/KEYS because of backward compatibility. */ - if (!is_show_fields_or_keys && result && + if (!is_show_fields_or_keys && result && thd->is_error() && (thd->get_stmt_da()->sql_errno() == ER_NO_SUCH_TABLE || thd->get_stmt_da()->sql_errno() == ER_WRONG_OBJECT)) { @@ -5614,15 +5614,21 @@ static int get_schema_column_record(THD *thd, TABLE_LIST *tables, I.e. we are in SELECT FROM INFORMATION_SCHEMA.COLUMS rather than in SHOW COLUMNS */ - push_warning(thd, Sql_condition::WARN_LEVEL_WARN, - thd->get_stmt_da()->sql_errno(), - thd->get_stmt_da()->message()); - thd->clear_error(); + if (thd->is_error()) + { + /* + The the query was aborted because examined rows exceeded limit. + Don't send the warning here. It is done later, in handle_select(). + */ + push_warning(thd, Sql_condition::WARN_LEVEL_WARN, + thd->get_stmt_da()->sql_errno(), + thd->get_stmt_da()->message()); + thd->clear_error(); + } res= 0; } DBUG_RETURN(res); } - show_table= tables->table; count= 0; ptr= show_table->field; From 5fb07d22f175f9c343d0299340eb3bebcaf6c838 Mon Sep 17 00:00:00 2001 From: Rucha Deodhar Date: Mon, 27 Jul 2020 19:07:08 +0530 Subject: [PATCH 06/20] MDEV-23082: ER_TABLEACCESS_DENIED_ERROR error message is truncated, and inaccurately Analysis: The list of all privileges is 118 characters wide. However, the format of error message was: "%-.32s command denied to user...". get_length() sets the maximum width to 32 characters. As a result, only first 32 characters of list of privilege are stored. Fix: Changing the format to "%-.100T..." so that get_length() sets width to 100. Hence, first 100 characters of the list of privilege are stored and the type specifier 'T' appends '...' so that truncation can be seen. --- mysql-test/r/grant.result | 18 ++++++++++++++++++ mysql-test/t/grant.test | 25 +++++++++++++++++++++++++ sql/share/errmsg-utf8.txt | 38 +++++++++++++++++++------------------- 3 files changed, 62 insertions(+), 19 deletions(-) diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result index e7edaacdc9b..bd24c5bf380 100644 --- a/mysql-test/r/grant.result +++ b/mysql-test/r/grant.result @@ -2767,5 +2767,23 @@ root@localhost DROP TABLE t1; DROP USER dummy@localhost; # +# MDEV-23082: ER_TABLEACCESS_DENIED_ERROR error message is truncated, and +# inaccurately +# +CREATE USER foo; +CREATE DATABASE db; +CREATE TABLE db.t (a INT); +connect con1,localhost,foo,,; +GRANT ALL ON db.t TO foo; +ERROR 42000: SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW ... command denied to user 'foo'@'localhost' for table 't' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT OPTION, REFERENCES, +INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON db.t TO foo; +ERROR 42000: SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW ... command denied to user 'foo'@'localhost' for table 't' +connection default; +disconnect con1; +DROP USER foo; +DROP TABLE db.t; +DROP DATABASE db; +# # End of 10.2 tests # diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test index 11281811f02..fa3a690a2ee 100644 --- a/mysql-test/t/grant.test +++ b/mysql-test/t/grant.test @@ -2267,6 +2267,31 @@ SELECT * FROM t1; DROP TABLE t1; DROP USER dummy@localhost; +--echo # +--echo # MDEV-23082: ER_TABLEACCESS_DENIED_ERROR error message is truncated, and +--echo # inaccurately +--echo # + +CREATE USER foo; +CREATE DATABASE db; +CREATE TABLE db.t (a INT); + +--connect (con1,localhost,foo,,) + +--error ER_TABLEACCESS_DENIED_ERROR +GRANT ALL ON db.t TO foo; + +--error ER_TABLEACCESS_DENIED_ERROR +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, GRANT OPTION, REFERENCES, +INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER ON db.t TO foo; + +--connection default +--disconnect con1 + +DROP USER foo; +DROP TABLE db.t; +DROP DATABASE db; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt index 8db992c7501..a4465ae0083 100644 --- a/sql/share/errmsg-utf8.txt +++ b/sql/share/errmsg-utf8.txt @@ -3244,25 +3244,25 @@ ER_NONEXISTING_GRANT 42000 swe "Det finns inget privilegium definierat för användare '%-.48s' på '%-.64s'" ukr "Повноважень не визначено для користувача '%-.48s' з хосту '%-.64s'" ER_TABLEACCESS_DENIED_ERROR 42000 - cze "%-.32s příkaz nepřístupný pro uživatele: '%s'@'%s' pro tabulku '%-.192s'" - dan "%-.32s-kommandoen er ikke tilladt for brugeren '%s'@'%s' for tabellen '%-.192s'" - nla "%-.32s commando geweigerd voor gebruiker: '%s'@'%s' voor tabel '%-.192s'" - eng "%-.32s command denied to user '%s'@'%s' for table '%-.192s'" - jps "コマンド %-.32s は ユーザー '%s'@'%s' ,テーブル '%-.192s' に対して許可されていません", - est "%-.32s käsk ei ole lubatud kasutajale '%s'@'%s' tabelis '%-.192s'" - fre "La commande '%-.32s' est interdite à l'utilisateur: '%s'@'%s' sur la table '%-.192s'" - ger "%-.32s Befehl nicht erlaubt für Benutzer '%s'@'%s' auf Tabelle '%-.192s'" - hun "%-.32s parancs a '%s'@'%s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban" - ita "Comando %-.32s negato per l'utente: '%s'@'%s' sulla tabella '%-.192s'" - jpn "コマンド %-.32s は ユーザー '%s'@'%s' ,テーブル '%-.192s' に対して許可されていません" - kor "'%-.32s' 명령은 다음 사용자에게 거부되었습니다. : '%s'@'%s' for 테이블 '%-.192s'" - por "Comando '%-.32s' negado para o usuário '%s'@'%s' na tabela '%-.192s'" - rum "Comanda %-.32s interzisa utilizatorului: '%s'@'%s' pentru tabela '%-.192s'" - rus "Команда %-.32s запрещена пользователю '%s'@'%s' для таблицы '%-.192s'" - serbian "%-.32s komanda zabranjena za korisnika '%s'@'%s' za tabelu '%-.192s'" - spa "%-.32s comando negado para usuario: '%s'@'%s' para tabla '%-.192s'" - swe "%-.32s ej tillåtet för '%s'@'%s' för tabell '%-.192s'" - ukr "%-.32s команда заборонена користувачу: '%s'@'%s' у таблиці '%-.192s'" + cze "%-.100T příkaz nepřístupný pro uživatele: '%s'@'%s' pro tabulku '%-.192s'" + dan "%-.100T-kommandoen er ikke tilladt for brugeren '%s'@'%s' for tabellen '%-.192s'" + nla "%-.100T commando geweigerd voor gebruiker: '%s'@'%s' voor tabel '%-.192s'" + eng "%-.100T command denied to user '%s'@'%s' for table '%-.192s'" + jps "コマンド %-.100T は ユーザー '%s'@'%s' ,テーブル '%-.192s' に対して許可されていません", + est "%-.100T käsk ei ole lubatud kasutajale '%s'@'%s' tabelis '%-.192s'" + fre "La commande '%-.100T' est interdite à l'utilisateur: '%s'@'%s' sur la table '%-.192s'" + ger "%-.100T Befehl nicht erlaubt für Benutzer '%s'@'%s' auf Tabelle '%-.192s'" + hun "%-.100T parancs a '%s'@'%s' felhasznalo szamara nem engedelyezett a '%-.192s' tablaban" + ita "Comando %-.100T negato per l'utente: '%s'@'%s' sulla tabella '%-.192s'" + jpn "コマンド %-.100T は ユーザー '%s'@'%s' ,テーブル '%-.192s' に対して許可されていません" + kor "'%-.100T' 명령은 다음 사용자에게 거부되었습니다. : '%s'@'%s' for 테이블 '%-.192s'" + por "Comando '%-.100T' negado para o usuário '%s'@'%s' na tabela '%-.192s'" + rum "Comanda %-.100T interzisa utilizatorului: '%s'@'%s' pentru tabela '%-.192s'" + rus "Команда %-.100T запрещена пользователю '%s'@'%s' для таблицы '%-.192s'" + serbian "%-.100T komanda zabranjena za korisnika '%s'@'%s' za tabelu '%-.192s'" + spa "%-.100T comando negado para usuario: '%s'@'%s' para tabla '%-.192s'" + swe "%-.100T ej tillåtet för '%s'@'%s' för tabell '%-.192s'" + ukr "%-.100T команда заборонена користувачу: '%s'@'%s' у таблиці '%-.192s'" ER_COLUMNACCESS_DENIED_ERROR 42000 cze "%-.32s příkaz nepřístupný pro uživatele: '%s'@'%s' pro sloupec '%-.192s' v tabulce '%-.192s'" dan "%-.32s-kommandoen er ikke tilladt for brugeren '%s'@'%s' for kolonne '%-.192s' in tabellen '%-.192s'" From d4967659032b18a5504198b41dd3d0a1813d79ef Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 4 Aug 2020 09:49:44 +0400 Subject: [PATCH 07/20] MDEV-22022 Various mangled SQL statements will crash 10.3 to 10.5 debug builds Lex_input_stream::scan_ident_delimited() could go beyond the end of the input when a starting backtick (`) delimiter did not have a corresponding ending backtick. Fix: catch the case when yyGet() returns 0, which means either eof-of-query or straight 0x00 byte inside backticks, and make the parser fail on syntax error, displaying the left backtick as the syntax error place. In case of filename in a script like this: SET CHARACTER_SET_CLIENT=17; -- 17 is 'filename' SELECT doc.`Children`.0 FROM t1; the ending backtick was not recognized as such because my_charlen() returns 0 for a straight backtick (backticks must normally be encoded as @0060 in filename). The same fix works for 'filename': the execution skips the backtick and reaches the end of the query, then yyGet() returns 0. This fix is OK for now. But eventually 'filename' should either be disallowed as a parser character set, or fixed to handle encoded punctuation properly. --- mysql-test/main/ctype_filename.result | 7 +++++++ mysql-test/main/ctype_filename.test | 10 ++++++++++ mysql-test/main/parser.result | 7 +++++++ mysql-test/main/parser.test | 9 +++++++++ sql/sql_lex.cc | 11 ++++++++++- 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/ctype_filename.result b/mysql-test/main/ctype_filename.result index c6d7d1e39b9..7536ea97fb1 100644 --- a/mysql-test/main/ctype_filename.result +++ b/mysql-test/main/ctype_filename.result @@ -21,3 +21,10 @@ SET NAMES utf8; SELECT @a:=CONVERT('aя' USING filename) AS `@a`, BINARY @a, REVERSE(@a), HEX(@a), HEX(REVERSE(@a)); @a BINARY @a REVERSE(@a) HEX(@a) HEX(REVERSE(@a)) aя a@r1 яa 61407231 40723161 +# +# MDEV-22022 Various mangled SQL statements will crash 10.3 to 10.5 debug builds +# +SET CHARACTER_SET_CLIENT=17; +SELECT doc.`Children`.0 FROM t1; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '?Children??0?FROM?t1' at line 1 +SET NAMES latin1; diff --git a/mysql-test/main/ctype_filename.test b/mysql-test/main/ctype_filename.test index 7ec07293a2b..6f77a6c5a3a 100644 --- a/mysql-test/main/ctype_filename.test +++ b/mysql-test/main/ctype_filename.test @@ -27,3 +27,13 @@ select convert(convert(',' using filename) using binary); --echo # SET NAMES utf8; SELECT @a:=CONVERT('aя' USING filename) AS `@a`, BINARY @a, REVERSE(@a), HEX(@a), HEX(REVERSE(@a)); + + +--echo # +--echo # MDEV-22022 Various mangled SQL statements will crash 10.3 to 10.5 debug builds +--echo # + +SET CHARACTER_SET_CLIENT=17; +--error ER_PARSE_ERROR +SELECT doc.`Children`.0 FROM t1; +SET NAMES latin1; diff --git a/mysql-test/main/parser.result b/mysql-test/main/parser.result index 002993eb128..f66fa7c457f 100644 --- a/mysql-test/main/parser.result +++ b/mysql-test/main/parser.result @@ -1760,4 +1760,11 @@ SELECT @@GLOBAL.password; ERROR HY000: Unknown system variable 'password' SELECT @@GLOBAL.role; ERROR HY000: Unknown system variable 'role' +# +# MDEV-22022 Various mangled SQL statements will crash 10.3 to 10.5 debug builds +# +EXECUTE IMMEDIATE 'if(`systeminfo /FO LIST'; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '`systeminfo /FO LIST' at line 1 +EXECUTE IMMEDIATE 'if(`systeminfo'; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '`systeminfo' at line 1 End of 10.3 tests diff --git a/mysql-test/main/parser.test b/mysql-test/main/parser.test index 4ee335dbbb4..5a2d0294171 100644 --- a/mysql-test/main/parser.test +++ b/mysql-test/main/parser.test @@ -1538,4 +1538,13 @@ SELECT @@GLOBAL.password; --error ER_UNKNOWN_SYSTEM_VARIABLE SELECT @@GLOBAL.role; +--echo # +--echo # MDEV-22022 Various mangled SQL statements will crash 10.3 to 10.5 debug builds +--echo # + +--error ER_PARSE_ERROR +EXECUTE IMMEDIATE 'if(`systeminfo /FO LIST'; +--error ER_PARSE_ERROR +EXECUTE IMMEDIATE 'if(`systeminfo'; + --echo End of 10.3 tests diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 89f74b6537b..1ef917f6964 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -2206,8 +2206,17 @@ int Lex_input_stream::scan_ident_delimited(THD *thd, uchar c, quote_char= m_tok_start[0]; DBUG_ASSERT(m_ptr == m_tok_start + 1); - while ((c= yyGet())) + for ( ; ; ) { + if (!(c= yyGet())) + { + /* + End-of-query or straight 0x00 inside a delimited identifier. + Return the quote character, to have the parser fail on syntax error. + */ + m_ptr= (char *) m_tok_start + 1; + return quote_char; + } int var_length= my_charlen(cs, get_ptr() - 1, get_end_of_query()); if (var_length == 1) { From 91caf130b71ac7532b5f1a387b7cf506ea2b09e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 4 Aug 2020 09:56:09 +0300 Subject: [PATCH 08/20] MDEV-23101 fixup: Remove redundant code lock_rec_has_to_wait_in_queue(): Remove an obviously redundant assertion that was added in commit a8ec45863b958757da61af3b2ce0a38b0a79d92c and also enclose a Galera-specific condition in #ifdef WITH_WSREP. --- storage/innobase/lock/lock0lock.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 1e7d9b031d7..4730ae53133 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -2203,10 +2203,11 @@ lock_rec_has_to_wait_in_queue( hash = lock_hash_get(wait_lock->type_mode); for (lock = lock_rec_get_first_on_page_addr(hash, space, page_no); - lock && lock != wait_lock; +#ifdef WITH_WSREP + lock && +#endif + lock != wait_lock; lock = lock_rec_get_next_on_page_const(lock)) { - - ut_ad(lock); const byte* p = (const byte*) &lock[1]; if (heap_no < lock_rec_get_n_bits(lock) From 0e80f5a6934692dd7a47b6d31104fa194bbf18ec Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Wed, 5 Aug 2020 08:14:49 +0400 Subject: [PATCH 09/20] MDEV-23105 Cast number string with many leading zeros to decimal gives unexpected result Skip leading zeros when converting a string to decimal_t. --- mysql-test/r/type_newdecimal.result | 44 +++++++++++++++++++++++++++++ mysql-test/t/type_newdecimal.test | 22 +++++++++++++++ strings/decimal.c | 18 ++++++++++++ 3 files changed, 84 insertions(+) diff --git a/mysql-test/r/type_newdecimal.result b/mysql-test/r/type_newdecimal.result index 7b6629bc7b2..0c8f4f55442 100644 --- a/mysql-test/r/type_newdecimal.result +++ b/mysql-test/r/type_newdecimal.result @@ -2342,6 +2342,50 @@ t1 CREATE TABLE `t1` ( ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE t1; # +# MDEV-23105 Cast number string with many leading zeros to decimal gives unexpected result +# +SELECT CAST(0000000000000000000000000000000000000000000000000000000000000000000000000000000020.01 AS DECIMAL(15,2)) as val; +val +20.01 +SET sql_mode=''; +CREATE TABLE t1 (a TEXT); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1)); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.0')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.9')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.99')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.994')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.995')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.999')); +CREATE TABLE t2 (a TEXT, d DECIMAL(15,2)); +INSERT IGNORE INTO t2 (a,d) SELECT a, a FROM t1; +Warnings: +Note 1265 Data truncated for column 'd' at row 5 +Note 1265 Data truncated for column 'd' at row 6 +Note 1265 Data truncated for column 'd' at row 7 +INSERT IGNORE INTO t2 (a,d) SELECT CONCAT('-',a), CONCAT('-',a) FROM t1; +Warnings: +Note 1265 Data truncated for column 'd' at row 5 +Note 1265 Data truncated for column 'd' at row 6 +Note 1265 Data truncated for column 'd' at row 7 +SELECT d, a FROM t2 ORDER BY d,a; +d a +-2.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.995 +-2.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.999 +-1.99 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.99 +-1.99 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.994 +-1.90 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.9 +-1.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +-1.00 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.0 +1.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 +1.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.0 +1.90 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.9 +1.99 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.99 +1.99 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.994 +2.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.995 +2.00 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.999 +DROP TABLE t1, t2; +SET sql_mode=DEFAULT; +# # End of 10.1 tests # # diff --git a/mysql-test/t/type_newdecimal.test b/mysql-test/t/type_newdecimal.test index 9b1beeb3f51..7338780c616 100644 --- a/mysql-test/t/type_newdecimal.test +++ b/mysql-test/t/type_newdecimal.test @@ -1821,6 +1821,28 @@ CREATE TABLE t1 (a DECIMAL(2,1) DEFAULT 0.10001e0); SHOW CREATE TABLE t1; DROP TABLE t1; +--echo # +--echo # MDEV-23105 Cast number string with many leading zeros to decimal gives unexpected result +--echo # + +SELECT CAST(0000000000000000000000000000000000000000000000000000000000000000000000000000000020.01 AS DECIMAL(15,2)) as val; + +SET sql_mode=''; +CREATE TABLE t1 (a TEXT); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1)); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.0')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.9')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.99')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.994')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.995')); +INSERT INTO t1 VALUES (CONCAT(REPEAT('0',100),1,'.999')); +CREATE TABLE t2 (a TEXT, d DECIMAL(15,2)); +INSERT IGNORE INTO t2 (a,d) SELECT a, a FROM t1; +INSERT IGNORE INTO t2 (a,d) SELECT CONCAT('-',a), CONCAT('-',a) FROM t1; +SELECT d, a FROM t2 ORDER BY d,a; +DROP TABLE t1, t2; +SET sql_mode=DEFAULT; + --echo # --echo # End of 10.1 tests --echo # diff --git a/strings/decimal.c b/strings/decimal.c index 56d09e8f303..dd2e1236489 100644 --- a/strings/decimal.c +++ b/strings/decimal.c @@ -812,6 +812,24 @@ internal_str2dec(const char *from, decimal_t *to, char **end, my_bool fixed) while (s < end_of_string && my_isdigit(&my_charset_latin1, *s)) s++; intg= (int) (s-s1); + /* + If the integer part is long enough and it has multiple leading zeros, + let's trim them, so this expression can return 1 without overflowing: + CAST(CONCAT(REPEAT('0',90),'1') AS DECIMAL(10)) + */ + if (intg > DIG_PER_DEC1 && s1[0] == '0' && s1[1] == '0') + { + /* + Keep at least one digit, to avoid an empty string. + So we trim '0000' to '0' rather than to ''. + Otherwise the below code (converting digits to to->buf) + would fail on a fatal error. + */ + const char *iend= s - 1; + for ( ; s1 < iend && *s1 == '0'; s1++) + { } + intg= (int) (s-s1); + } if (s < end_of_string && *s=='.') { endp= s+1; From 1e31d74833d56609f8711022394c1eb2eb25a19a Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Thu, 23 Jul 2020 14:17:05 +0530 Subject: [PATCH 10/20] MDEV-17066: Bytes lost or Assertion `status_var.local_memory_used == 0 after DELETE with subquery with ROLLUP The issue here is when records are read from the temporary file (filesort result in this case) via a cache(rr_from_cache). The cache is initialized with init_rr_cache. For correlated subquery the cache allocation is happening at each execution of the subquery but the deallocation happens only once and that was when the query execution was done. So generally for subqueries we do two types of cleanup 1) Full cleanup: we should free all resources of the query(like temp tables). This is done generally when the query execution is complete or the subquery re-execution is not needed (case with uncorrelated subquery) 2) Partial cleanup: Minor cleanup that is required if the subquery needs recalculation. This is done for all the structures that need to be allocated for each execution (example SORT_INFO for filesort is allocated for each execution of the correlated subquery). The fix here would be free the cache used by rr_from_cache in the partial cleanup phase. --- mysql-test/r/subselect4.result | 25 ++++++++++++++++ mysql-test/t/subselect4.test | 23 +++++++++++++++ sql/records.cc | 20 +++++++++---- sql/records.h | 1 + sql/sql_select.cc | 53 ++++++++++++++++++++++------------ sql/sql_select.h | 2 +- 6 files changed, 99 insertions(+), 25 deletions(-) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index a21b4174aae..ad8df9f9836 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2620,4 +2620,29 @@ SELECT (SELECT DISTINCT t1i.b FROM t1 t1i GROUP BY t1i.a ORDER BY MAX(t1o.b)) FR 0 SET @@optimizer_switch= @save_optimizer_switch; DROP TABLE t1; +# +# MDEV-17066: Bytes lost or Assertion `status_var.local_memory_used == 0 after DELETE +# with subquery with ROLLUP +# +CREATE TABLE t1 (i INT DEFAULT 0, c VARCHAR(2048)); +INSERT INTO t1 SELECT 0, seq FROM seq_1_to_6000; +CREATE TABLE t2 (f VARCHAR(2048) DEFAULT ''); +INSERT INTO t2 VALUES ('1'),('bar'); +EXPLAIN +SELECT * FROM t2 WHERE f IN ( SELECT MAX(c) FROM t1 GROUP BY c WITH ROLLUP); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY t1 ALL NULL NULL NULL NULL 6000 Using filesort +SELECT * FROM t2 WHERE f IN ( SELECT MAX(c) FROM t1 GROUP BY c WITH ROLLUP); +f +1 +SELECT * FROM t2; +f +1 +bar +DELETE FROM t2 WHERE f IN ( SELECT MAX(c) FROM t1 GROUP BY c WITH ROLLUP ); +SELECT * FROM t2; +f +bar +DROP TABLE t1, t2; # End of 10.2 tests diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index c33fe15bdcc..f35df5b6967 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -7,6 +7,8 @@ drop table if exists t0,t1,t2,t3,t4,t5,t6; drop view if exists v1, v2; --enable_warnings +--source include/have_sequence.inc + set @subselect4_tmp= @@optimizer_switch; set optimizer_switch='semijoin=on,firstmatch=on,loosescan=on'; set optimizer_switch='semijoin_with_cache=on'; @@ -2153,4 +2155,25 @@ SELECT (SELECT DISTINCT t1i.b FROM t1 t1i GROUP BY t1i.a ORDER BY MAX(t1o.b)) FR SET @@optimizer_switch= @save_optimizer_switch; DROP TABLE t1; +--echo # +--echo # MDEV-17066: Bytes lost or Assertion `status_var.local_memory_used == 0 after DELETE +--echo # with subquery with ROLLUP +--echo # + +CREATE TABLE t1 (i INT DEFAULT 0, c VARCHAR(2048)); +INSERT INTO t1 SELECT 0, seq FROM seq_1_to_6000; + +CREATE TABLE t2 (f VARCHAR(2048) DEFAULT ''); +INSERT INTO t2 VALUES ('1'),('bar'); + +EXPLAIN +SELECT * FROM t2 WHERE f IN ( SELECT MAX(c) FROM t1 GROUP BY c WITH ROLLUP); +SELECT * FROM t2 WHERE f IN ( SELECT MAX(c) FROM t1 GROUP BY c WITH ROLLUP); + +SELECT * FROM t2; +DELETE FROM t2 WHERE f IN ( SELECT MAX(c) FROM t1 GROUP BY c WITH ROLLUP ); +SELECT * FROM t2; + +DROP TABLE t1, t2; + --echo # End of 10.2 tests diff --git a/sql/records.cc b/sql/records.cc index 6a611d46ca4..8a152cda4c2 100644 --- a/sql/records.cc +++ b/sql/records.cc @@ -320,12 +320,9 @@ bool init_read_record(READ_RECORD *info,THD *thd, TABLE *table, void end_read_record(READ_RECORD *info) -{ /* free cache if used */ - if (info->cache) - { - my_free_lock(info->cache); - info->cache=0; - } +{ + /* free cache if used */ + free_cache(info); if (info->table) { if (info->table->is_created()) @@ -336,6 +333,17 @@ void end_read_record(READ_RECORD *info) } } + +void free_cache(READ_RECORD *info) +{ + if (info->cache) + { + my_free_lock(info->cache); + info->cache=0; + } +} + + static int rr_handle_error(READ_RECORD *info, int error) { if (info->thd->killed) diff --git a/sql/records.h b/sql/records.h index b5f04dbd161..dd63d3608bb 100644 --- a/sql/records.h +++ b/sql/records.h @@ -30,6 +30,7 @@ class SORT_INFO; struct READ_RECORD; void end_read_record(READ_RECORD *info); +void free_cache(READ_RECORD *info); /** A context for reading through a single table using a chosen access method: diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 379a109c57c..96e9602d77d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -12391,24 +12391,7 @@ void JOIN::cleanup(bool full) for (tab= first_linear_tab(this, WITH_BUSH_ROOTS, WITH_CONST_TABLES); tab; tab= next_linear_tab(this, tab, WITH_BUSH_ROOTS)) { - if (!tab->table) - continue; - DBUG_PRINT("info", ("close index: %s.%s alias: %s", - tab->table->s->db.str, - tab->table->s->table_name.str, - tab->table->alias.c_ptr())); - if (tab->table->is_created()) - { - tab->table->file->ha_index_or_rnd_end(); - if (tab->aggr) - { - int tmp= 0; - if ((tmp= tab->table->file->extra(HA_EXTRA_NO_CACHE))) - tab->table->file->print_error(tmp, MYF(0)); - } - } - delete tab->filesort_result; - tab->filesort_result= NULL; + tab->partial_cleanup(); } } } @@ -26982,6 +26965,40 @@ void JOIN::handle_implicit_grouping_with_window_funcs() } } + +/* + @brief + Perform a partial cleanup for the JOIN_TAB structure + + @note + this is used to cleanup resources for the re-execution of correlated + subqueries. +*/ +void JOIN_TAB::partial_cleanup() +{ + if (!table) + return; + + if (table->is_created()) + { + table->file->ha_index_or_rnd_end(); + DBUG_PRINT("info", ("close index: %s.%s alias: %s", + table->s->db.str, + table->s->table_name.str, + table->alias.c_ptr())); + if (aggr) + { + int tmp= 0; + if ((tmp= table->file->extra(HA_EXTRA_NO_CACHE))) + table->file->print_error(tmp, MYF(0)); + } + } + delete filesort_result; + filesort_result= NULL; + free_cache(&read_record); +} + + /** @} (end of group Query_Optimizer) */ diff --git a/sql/sql_select.h b/sql/sql_select.h index 92da1355be0..4584460ca3f 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -613,7 +613,7 @@ typedef struct st_join_table { bool use_order() const; ///< Use ordering provided by chosen index? bool sort_table(); bool remove_duplicates(); - + void partial_cleanup(); } JOIN_TAB; From ab578bdf453c3cb0e9ca561cf373f64c96b22fda Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 4 Aug 2020 14:36:01 +0530 Subject: [PATCH 11/20] MDEV-9513: Assertion `join->group_list || !join->is_in_subquery()' failed in create_sort_index Removing the ORDER BY clause from the UNION when UNION is inside an IN/ALL/ANY/EXISTS subquery. The rewrites are done for subqueries but this rewrite is not done for the fake_select of the UNION. --- mysql-test/r/subselect4.result | 41 ++++++++++++++++++++++++++++++++++ mysql-test/t/subselect4.test | 25 +++++++++++++++++++++ sql/item_subselect.h | 4 ++++ sql/sql_union.cc | 19 ++++++++++++++++ 4 files changed, 89 insertions(+) diff --git a/mysql-test/r/subselect4.result b/mysql-test/r/subselect4.result index 606ab847028..e7655131fcf 100644 --- a/mysql-test/r/subselect4.result +++ b/mysql-test/r/subselect4.result @@ -2608,3 +2608,44 @@ region area population Central America and the Caribbean 442 66422 SET @@optimizer_switch= @save_optimizer_switch; DROP TABLE t1; +# +# MDEV-9513: Assertion `join->group_list || !join->is_in_subquery()' failed in create_sort_index +# +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (2),(3); +EXPLAIN +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY A ALL NULL NULL NULL NULL 2 Using where +3 DEPENDENT UNION B ALL NULL NULL NULL NULL 2 Using where +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); +a +1 +2 +EXPLAIN +SELECT t1.a FROM t1 WHERE EXISTS (SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 +2 SUBQUERY A ALL NULL NULL NULL NULL 2 +3 UNION B ALL NULL NULL NULL NULL 2 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL +SELECT t1.a FROM t1 WHERE EXISTS (SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); +a +1 +2 +EXPLAIN +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION ALL SELECT B.a FROM t2 B ORDER BY 1); +id select_type table type possible_keys key key_len ref rows Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where +2 DEPENDENT SUBQUERY A ALL NULL NULL NULL NULL 2 Using where +3 DEPENDENT UNION B ALL NULL NULL NULL NULL 2 Using where +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION ALL SELECT B.a FROM t2 B ORDER BY 1); +a +1 +2 +DROP TABLE t1,t2; +# end of 10.1 tests diff --git a/mysql-test/t/subselect4.test b/mysql-test/t/subselect4.test index 21ec28b1c03..8f1ad51ca50 100644 --- a/mysql-test/t/subselect4.test +++ b/mysql-test/t/subselect4.test @@ -2138,3 +2138,28 @@ WHERE population/area = (SELECT MAX(population/area) from t1 B where A.region = SET @@optimizer_switch= @save_optimizer_switch; DROP TABLE t1; + +--echo # +--echo # MDEV-9513: Assertion `join->group_list || !join->is_in_subquery()' failed in create_sort_index +--echo # + +CREATE TABLE t1 (a INT); +INSERT INTO t1 VALUES (1),(2); + +CREATE TABLE t2 (a INT); +INSERT INTO t2 VALUES (2),(3); +EXPLAIN +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); + +EXPLAIN +SELECT t1.a FROM t1 WHERE EXISTS (SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); +SELECT t1.a FROM t1 WHERE EXISTS (SELECT A.a FROM t1 A UNION SELECT B.a FROM t2 B ORDER BY 1); + +EXPLAIN +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION ALL SELECT B.a FROM t2 B ORDER BY 1); +SELECT t1.a FROM t1 WHERE t1.a IN ( SELECT A.a FROM t1 A UNION ALL SELECT B.a FROM t2 B ORDER BY 1); + +DROP TABLE t1,t2; + +--echo # end of 10.1 tests diff --git a/sql/item_subselect.h b/sql/item_subselect.h index ee8b31f4f17..9771b067ac4 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -131,6 +131,10 @@ public: Item_subselect(THD *thd); virtual subs_type substype() { return UNKNOWN_SUBS; } + bool is_exists_predicate() + { + return substype() == Item_subselect::EXISTS_SUBS; + } bool is_in_predicate() { return (substype() == Item_subselect::IN_SUBS || diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 38de2d592ed..0e623777ef0 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -388,6 +388,25 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, found_rows_for_union= first_sl->options & OPTION_FOUND_ROWS; is_union_select= is_union() || fake_select_lex; + /* + If we are reading UNION output and the UNION is in the + IN/ANY/ALL/EXISTS subquery, then ORDER BY is redundant and hence should + be removed. + Example: + select ... col IN (select col2 FROM t1 union select col3 from t2 ORDER BY 1) + + (as for ORDER BY ... LIMIT, it currently not supported inside + IN/ALL/ANY subqueries) + (For non-UNION this removal of ORDER BY clause is done in + check_and_do_in_subquery_rewrites()) + */ + if (is_union() && item && + (item->is_in_predicate() || item->is_exists_predicate())) + { + global_parameters()->order_list.first= NULL; + global_parameters()->order_list.elements= 0; + } + /* Global option */ if (is_union_select) From 85bd5314c56c150d756066806d4a6cb5b682383f Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 6 Aug 2020 13:39:10 +0300 Subject: [PATCH 12/20] Better comment about TABLE::maybe_null --- sql/table.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/sql/table.h b/sql/table.h index 93795113fab..2ea9b514df4 100644 --- a/sql/table.h +++ b/sql/table.h @@ -1291,9 +1291,16 @@ public: /* number of select if it is derived table */ uint derived_select_number; /* - 0 or JOIN_TYPE_{LEFT|RIGHT}. Currently this is only compared to 0. - If maybe_null !=0, this table is inner w.r.t. some outer join operation, - and null_row may be true. + Possible values: + - 0 by default + - JOIN_TYPE_{LEFT|RIGHT} if the table is inner w.r.t an outer join + operation + - 1 if the SELECT has mixed_implicit_grouping=1. example: + select max(col1), col2 from t1. In this case, the query produces + one row with all columns having NULL values. + + Interpetation: If maybe_null!=0, all fields of the table are considered + NULLable (and have NULL values when null_row=true) */ uint maybe_null; int current_lock; /* Type of lock on table */ From caa474f8e3139b1d8d00be7bedf337af7fd304a3 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Thu, 6 Aug 2020 17:50:20 +0530 Subject: [PATCH 13/20] MDEV-15180: server crashed with NTH_VALUE() fix_fields for the arguments of the NTH_VALUE function was updating the same reference, so for the second argument (or after the first argument) the items were not resolved to their corresponding field from the view as they were updating the reference to the first argument. --- mysql-test/r/win.result | 16 ++++++++++++++++ mysql-test/t/win.test | 16 ++++++++++++++++ sql/item_windowfunc.cc | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/win.result b/mysql-test/r/win.result index 081aaedd323..3023a86eaad 100644 --- a/mysql-test/r/win.result +++ b/mysql-test/r/win.result @@ -3850,5 +3850,21 @@ ERROR 42000: Too big scale 56 specified for 'rank() over w1'. Maximum is 38 SELECT cast((rank() over w1) as decimal (53,30)); ERROR HY000: Window specification with name 'w1' is not defined # +# MDEV-15180: server crashed with NTH_VALUE() +# +CREATE TABLE t1 (i1 int, a int); +INSERT INTO t1 VALUES (1, 1), (2, 2),(3, 3); +CREATE TABLE t2 (i2 int); +INSERT INTO t2 VALUES (1),(2),(5),(1),(7),(4),(3); +CREATE VIEW v1 AS (SELECT * FROM t1,t2 WHERE t1.i1=t2.i2) ; +SELECT NTH_VALUE(i1, i1) OVER (PARTITION BY i1) FROM v1; +NTH_VALUE(i1, i1) OVER (PARTITION BY i1) +1 +1 +NULL +NULL +DROP VIEW v1; +DROP TABLE t1,t2; +# # End of 10.2 tests # diff --git a/mysql-test/t/win.test b/mysql-test/t/win.test index b749b235082..c7e3dac598b 100644 --- a/mysql-test/t/win.test +++ b/mysql-test/t/win.test @@ -2506,6 +2506,22 @@ SELECT cast((rank() over w1) as decimal (53,56)); --error ER_WRONG_WINDOW_SPEC_NAME SELECT cast((rank() over w1) as decimal (53,30)); +--echo # +--echo # MDEV-15180: server crashed with NTH_VALUE() +--echo # + +CREATE TABLE t1 (i1 int, a int); +INSERT INTO t1 VALUES (1, 1), (2, 2),(3, 3); + +CREATE TABLE t2 (i2 int); +INSERT INTO t2 VALUES (1),(2),(5),(1),(7),(4),(3); + +CREATE VIEW v1 AS (SELECT * FROM t1,t2 WHERE t1.i1=t2.i2) ; +SELECT NTH_VALUE(i1, i1) OVER (PARTITION BY i1) FROM v1; + +DROP VIEW v1; +DROP TABLE t1,t2; + --echo # --echo # End of 10.2 tests --echo # diff --git a/sql/item_windowfunc.cc b/sql/item_windowfunc.cc index 87dddbfb439..bb4a8a9f3af 100644 --- a/sql/item_windowfunc.cc +++ b/sql/item_windowfunc.cc @@ -234,7 +234,7 @@ bool Item_sum_hybrid_simple::fix_fields(THD *thd, Item **ref) { Item *item= args[i]; // 'item' can be changed during fix_fields - if ((!item->fixed && item->fix_fields(thd, args)) || + if ((!item->fixed && item->fix_fields(thd, args + i)) || (item= args[i])->check_cols(1)) return TRUE; with_window_func|= item->with_window_func; From 1dec60c79508f338572a69ef5e21b0535a13d064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 7 Aug 2020 09:06:13 +0300 Subject: [PATCH 14/20] MDEV-22626: mysql_tzinfo_to_sql not replicates timezone to galeranodes if only 1 timezone will be loaded. Move alter to InnoDB earlier to more correct place to handle also if only a one timezone file is loaded. --- .../r/mysql_tzinfo_to_sql_symlink.result | 18 ++++++++++++++++++ .../r/mysql_tzinfo_to_sql_symlink.result | 18 ++++++++++++++++++ sql/tztime.cc | 19 ++++++++++--------- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result index fc9ddce08b1..06e21beace1 100644 --- a/mysql-test/r/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/r/mysql_tzinfo_to_sql_symlink.result @@ -85,6 +85,15 @@ END IF| # # Testing with explicit timezonefile # +\d | +IF (select count(*) from information_schema.global_variables where +variable_name='wsrep_on' and variable_value='ON') = 1 THEN +ALTER TABLE time_zone ENGINE=InnoDB; +ALTER TABLE time_zone_name ENGINE=InnoDB; +ALTER TABLE time_zone_transition ENGINE=InnoDB; +ALTER TABLE time_zone_transition_type ENGINE=InnoDB; +END IF| +\d ; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('XXX', @time_zone_id); @@ -106,6 +115,15 @@ END IF| \d | IF (select count(*) from information_schema.global_variables where variable_name='wsrep_on' and variable_value='ON') = 1 THEN +ALTER TABLE time_zone ENGINE=InnoDB; +ALTER TABLE time_zone_name ENGINE=InnoDB; +ALTER TABLE time_zone_transition ENGINE=InnoDB; +ALTER TABLE time_zone_transition_type ENGINE=InnoDB; +END IF| +\d ; +\d | +IF (select count(*) from information_schema.global_variables where +variable_name='wsrep_on' and variable_value='ON') = 1 THEN ALTER TABLE time_zone_leap_second ENGINE=InnoDB; END IF| \d ; diff --git a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result index 1e6ebbbd34d..51c2e204b78 100644 --- a/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result +++ b/mysql-test/suite/wsrep/r/mysql_tzinfo_to_sql_symlink.result @@ -85,6 +85,15 @@ END IF| # # Testing with explicit timezonefile # +\d | +IF (select count(*) from information_schema.global_variables where +variable_name='wsrep_on' and variable_value='ON') = 1 THEN +ALTER TABLE time_zone ENGINE=InnoDB; +ALTER TABLE time_zone_name ENGINE=InnoDB; +ALTER TABLE time_zone_transition ENGINE=InnoDB; +ALTER TABLE time_zone_transition_type ENGINE=InnoDB; +END IF| +\d ; INSERT INTO time_zone (Use_leap_seconds) VALUES ('N'); SET @time_zone_id= LAST_INSERT_ID(); INSERT INTO time_zone_name (Name, Time_zone_id) VALUES ('XXX', @time_zone_id); @@ -106,6 +115,15 @@ END IF| \d | IF (select count(*) from information_schema.global_variables where variable_name='wsrep_on' and variable_value='ON') = 1 THEN +ALTER TABLE time_zone ENGINE=InnoDB; +ALTER TABLE time_zone_name ENGINE=InnoDB; +ALTER TABLE time_zone_transition ENGINE=InnoDB; +ALTER TABLE time_zone_transition_type ENGINE=InnoDB; +END IF| +\d ; +\d | +IF (select count(*) from information_schema.global_variables where +variable_name='wsrep_on' and variable_value='ON') = 1 THEN ALTER TABLE time_zone_leap_second ENGINE=InnoDB; END IF| \d ; diff --git a/sql/tztime.cc b/sql/tztime.cc index f58801bf4b7..35e18f47629 100644 --- a/sql/tztime.cc +++ b/sql/tztime.cc @@ -2713,6 +2713,7 @@ main(int argc, char **argv) } if (opt_skip_write_binlog) + { /* If skip_write_binlog is set and wsrep is compiled in we disable sql_log_bin and wsrep_on to avoid Galera replicating below truncate table clauses. This will allow user to set different @@ -2720,15 +2721,9 @@ main(int argc, char **argv) printf("set @prep1=if((select count(*) from information_schema.global_variables where variable_name='wsrep_on' and variable_value='ON'), 'SET SESSION SQL_LOG_BIN=?, WSREP_ON=OFF;', 'do ?');\n" "prepare set_wsrep_write_binlog from @prep1;\n" "set @toggle=0; execute set_wsrep_write_binlog using @toggle;\n"); - - if (argc == 1 && !opt_leap) + } + else { - /* Argument is timezonedir */ - - root_name_end= strmake_buf(fullname, argv[0]); - - if(!opt_skip_write_binlog) - { // Alter time zone tables to InnoDB if wsrep_on is enabled // to allow changes to them to replicate with Galera printf("\\d |\n" @@ -2740,7 +2735,13 @@ main(int argc, char **argv) "ALTER TABLE time_zone_transition_type ENGINE=InnoDB;\n" "END IF|\n" "\\d ;\n"); - } + } + + if (argc == 1 && !opt_leap) + { + /* Argument is timezonedir */ + + root_name_end= strmake_buf(fullname, argv[0]); printf("TRUNCATE TABLE time_zone;\n"); printf("TRUNCATE TABLE time_zone_name;\n"); From 845e3c9801d17905bf2392f27cda66669c00f75f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Lindstr=C3=B6m?= Date: Fri, 7 Aug 2020 10:22:38 +0300 Subject: [PATCH 15/20] Replaced infinite loop in procedure with limited loop to avoid hang. --- .../suite/galera/r/galera_bf_lock_wait.result | 32 +++++++++--- .../suite/galera/t/galera_bf_lock_wait.test | 52 +++++++++++++++---- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/mysql-test/suite/galera/r/galera_bf_lock_wait.result b/mysql-test/suite/galera/r/galera_bf_lock_wait.result index 7ec524da888..0b22f963b29 100644 --- a/mysql-test/suite/galera/r/galera_bf_lock_wait.result +++ b/mysql-test/suite/galera/r/galera_bf_lock_wait.result @@ -1,23 +1,41 @@ +connection node_1; CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2; ALTER TABLE t1 add primary key(a); -CREATE PROCEDURE p1() +CREATE PROCEDURE p1(repeat_count INT) BEGIN +DECLARE current_num int; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION rollback; -WHILE 1 DO +SET current_num = 0; +WHILE current_num < repeat_count DO start transaction; update t1 set b=connection_id() where a=1; commit; +SET current_num = current_num + 1; END WHILE; END| +connection node_2; connect node_1_p1, 127.0.0.1, root, , test, $NODE_MYPORT_1; -call p1; +SET SESSION wsrep_sync_wait=0; +call p1(1000); connect node_1_p2, 127.0.0.1, root, , test, $NODE_MYPORT_1; -call p1; +SET SESSION wsrep_sync_wait=0; +call p1(1000); connect node_2_p1, 127.0.0.1, root, , test, $NODE_MYPORT_2; -call p1; +SET SESSION wsrep_sync_wait=0; +call p1(1000); connect node_2_p2, 127.0.0.1, root, , test, $NODE_MYPORT_2; -call p1; -connection default; +SET SESSION wsrep_sync_wait=0; +call p1(1000); +connection node_1; checking error log for 'BF lock wait long' message for 10 times every 10 seconds ... +connection node_1_p1; +connection node_1_p2; +connection node_2_p1; +connection node_2_p2; +connection node_1; drop table t1; drop procedure p1; +disconnect node_1_p1; +disconnect node_1_p2; +disconnect node_2_p1; +disconnect node_2_p2; diff --git a/mysql-test/suite/galera/t/galera_bf_lock_wait.test b/mysql-test/suite/galera/t/galera_bf_lock_wait.test index e3a9077a888..c8a31506ffa 100644 --- a/mysql-test/suite/galera/t/galera_bf_lock_wait.test +++ b/mysql-test/suite/galera/t/galera_bf_lock_wait.test @@ -1,34 +1,47 @@ --source include/galera_cluster.inc --source include/big_test.inc - + +--connection node_1 CREATE TABLE t1 ENGINE=InnoDB select 1 as a, 1 as b union select 2, 2; ALTER TABLE t1 add primary key(a); DELIMITER |; -CREATE PROCEDURE p1() +CREATE PROCEDURE p1(repeat_count INT) BEGIN + DECLARE current_num int; DECLARE CONTINUE HANDLER FOR SQLEXCEPTION rollback; - WHILE 1 DO + SET current_num = 0; + + WHILE current_num < repeat_count DO start transaction; update t1 set b=connection_id() where a=1; commit; + SET current_num = current_num + 1; END WHILE; END| DELIMITER ;| - + +--connection node_2 +--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE' AND ROUTINE_NAME = 'p1' +--source include/wait_condition.inc + --connect node_1_p1, 127.0.0.1, root, , test, $NODE_MYPORT_1 -send call p1; +SET SESSION wsrep_sync_wait=0; +send call p1(1000); --connect node_1_p2, 127.0.0.1, root, , test, $NODE_MYPORT_1 -send call p1; +SET SESSION wsrep_sync_wait=0; +send call p1(1000); --connect node_2_p1, 127.0.0.1, root, , test, $NODE_MYPORT_2 -send call p1; +SET SESSION wsrep_sync_wait=0; +send call p1(1000); --connect node_2_p2, 127.0.0.1, root, , test, $NODE_MYPORT_2 -send call p1; +SET SESSION wsrep_sync_wait=0; +send call p1(1000); -connection default; +connection node_1; let $counter=10; let $sleep_period=10; @@ -46,7 +59,26 @@ while($counter > 0) exec grep 'BF lock wait long' $MYSQLTEST_VARDIR/log/mysqld.*.err; dec $counter; } - + +--connection node_1_p1 +--error 0,1213 +--reap +--connection node_1_p2 +--error 0,1213 +--reap +--connection node_2_p1 +--error 0,1213 +--reap +--connection node_2_p2 +--error 0,1213 +--reap + +--connection node_1 drop table t1; drop procedure p1; +--disconnect node_1_p1 +--disconnect node_1_p2 +--disconnect node_2_p1 +--disconnect node_2_p2 + From deb365581b96527c5c96b3f5ed1235e10543f5f1 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 5 May 2020 19:23:29 +1000 Subject: [PATCH 16/20] MDEV-23386: mtr: main.mysqld--help autosized table{-open,}-cach and max-connections Example of the failure: http://buildbot.askmonty.org/buildbot/builders/bld-p9-rhel7/builds/4417/steps/mtr/logs/stdio ``` main.mysqld--help 'unix' w17 [ fail ] Test ended at 2020-06-20 18:51:45 CURRENT_TEST: main.mysqld--help --- /opt/buildbot-slave/bld-p9-rhel7/build/mysql-test/main/mysqld--help.result 2020-06-20 16:06:49.903604179 +0300 +++ /opt/buildbot-slave/bld-p9-rhel7/build/mysql-test/main/mysqld--help.reject 2020-06-20 18:51:44.886766820 +0300 @@ -1797,10 +1797,10 @@ sync-relay-log-info 10000 sysdate-is-now FALSE system-versioning-alter-history ERROR -table-cache 421 +table-cache 2000 table-definition-cache 400 -table-open-cache 421 -table-open-cache-instances 1 +table-open-cache 2000 +table-open-cache-instances 8 tc-heuristic-recover OFF tcp-keepalive-interval 0 tcp-keepalive-probes 0 mysqltest: Result length mismatch ``` mtr: table_open_cache_basic autosized: Lets assume that >400 are available and that we can set the result back to the start value. All of these system variables are autosized and can generate MTR output differences. Closes #1527 --- mysql-test/r/mysqld--help,win.rdiff | 31 +++++++------------ mysql-test/r/mysqld--help.result | 3 -- .../sys_vars/r/table_open_cache_basic.result | 12 +++---- .../sys_vars/t/table_open_cache_basic.test | 4 +-- mysql-test/t/mysqld--help.test | 3 +- 5 files changed, 22 insertions(+), 31 deletions(-) diff --git a/mysql-test/r/mysqld--help,win.rdiff b/mysql-test/r/mysqld--help,win.rdiff index 128155870b8..b71401bf461 100644 --- a/mysql-test/r/mysqld--help,win.rdiff +++ b/mysql-test/r/mysqld--help,win.rdiff @@ -1,6 +1,6 @@ --- mysqld--help.result +++ mysqld--help,win.reject -@@ -333,7 +333,6 @@ +@@ -337,7 +337,6 @@ The following specify which files/extra groups are read (specified before remain The number of segments in a key cache -L, --language=name Client error messages in given language. May be given as a full path. Deprecated. Use --lc-messages-dir instead. @@ -8,7 +8,7 @@ --lc-messages=name Set the language used for the error messages. -L, --lc-messages-dir=name Directory where error messages are -@@ -533,6 +532,7 @@ +@@ -537,6 +536,7 @@ The following specify which files/extra groups are read (specified before remain Use MySQL-5.6 (instead of MariaDB-5.3) format for TIME, DATETIME, TIMESTAMP columns. (Defaults to on; use --skip-mysql56-temporal-format to disable.) @@ -16,7 +16,7 @@ --net-buffer-length=# Buffer length for TCP/IP and socket communication --net-read-timeout=# -@@ -924,6 +924,9 @@ +@@ -928,6 +928,9 @@ The following specify which files/extra groups are read (specified before remain files within specified directory --server-id=# Uniquely identifies the server instance in the community of replication partners @@ -26,7 +26,7 @@ --show-slave-auth-info Show user and password in SHOW SLAVE HOSTS on this master. -@@ -1034,6 +1037,10 @@ +@@ -1038,6 +1041,10 @@ The following specify which files/extra groups are read (specified before remain Log slow queries to given log file. Defaults logging to 'hostname'-slow.log. Must be enabled to activate other slow log options @@ -37,7 +37,7 @@ --socket=name Socket file to use for connection --sort-buffer-size=# Each thread that needs to do a sort allocates a buffer of -@@ -1052,6 +1059,7 @@ +@@ -1056,6 +1063,7 @@ The following specify which files/extra groups are read (specified before remain NO_ENGINE_SUBSTITUTION, PAD_CHAR_TO_FULL_LENGTH --stack-trace Print a symbolic stack trace on failure (Defaults to on; use --skip-stack-trace to disable.) @@ -45,7 +45,7 @@ --stored-program-cache=# The soft upper limit for number of cached stored routines for one connection. -@@ -1088,25 +1096,11 @@ +@@ -1092,25 +1100,11 @@ The following specify which files/extra groups are read (specified before remain COMMIT, ROLLBACK --thread-cache-size=# How many threads we should keep in a cache for reuse @@ -73,7 +73,7 @@ --thread-stack=# The stack size for each thread --time-format=name The TIME format (ignored) --timed-mutexes Specify whether to time mutexes. Deprecated, has no -@@ -1115,8 +1109,8 @@ +@@ -1119,8 +1113,8 @@ The following specify which files/extra groups are read (specified before remain size, MariaDB will automatically convert it to an on-disk MyISAM or Aria table. -t, --tmpdir=name Path for temporary files. Several paths may be specified, @@ -84,7 +84,7 @@ --transaction-alloc-block-size=# Allocation block size for transactions to be stored in binary log -@@ -1240,7 +1234,6 @@ +@@ -1244,7 +1238,6 @@ key-cache-block-size 1024 key-cache-division-limit 100 key-cache-file-hash-size 512 key-cache-segments 0 @@ -92,7 +92,7 @@ lc-messages en_US lc-messages-dir MYSQL_SHAREDIR/ lc-time-names en_US -@@ -1307,6 +1300,7 @@ +@@ -1310,6 +1303,7 @@ myisam-sort-buffer-size 134216704 myisam-stats-method NULLS_UNEQUAL myisam-use-mmap FALSE mysql56-temporal-format TRUE @@ -100,7 +100,7 @@ net-buffer-length 16384 net-read-timeout 30 net-retry-count 10 -@@ -1403,6 +1397,8 @@ +@@ -1406,6 +1400,8 @@ safe-user-create FALSE secure-auth TRUE secure-file-priv (No default value) server-id 0 @@ -109,7 +109,7 @@ show-slave-auth-info FALSE silent-startup FALSE skip-grant-tables TRUE -@@ -1426,6 +1422,7 @@ +@@ -1429,6 +1425,7 @@ slave-transaction-retries 10 slave-type-conversions slow-launch-time 2 slow-query-log FALSE @@ -117,15 +117,8 @@ sort-buffer-size 2097152 sql-mode NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION stack-trace TRUE -@@ -1438,15 +1435,13 @@ - sync-relay-log 10000 - sync-relay-log-info 10000 - sysdate-is-now FALSE --table-cache 421 -+table-cache 2000 +@@ -1444,10 +1441,8 @@ sysdate-is-now FALSE table-definition-cache 400 --table-open-cache 421 -+table-open-cache 2000 tc-heuristic-recover OFF thread-cache-size 0 -thread-pool-idle-timeout 60 diff --git a/mysql-test/r/mysqld--help.result b/mysql-test/r/mysqld--help.result index c7fb52eeeb6..dce1578adee 100644 --- a/mysql-test/r/mysqld--help.result +++ b/mysql-test/r/mysqld--help.result @@ -1277,7 +1277,6 @@ max-binlog-cache-size 18446744073709547520 max-binlog-size 1073741824 max-binlog-stmt-cache-size 18446744073709547520 max-connect-errors 100 -max-connections 151 max-delayed-threads 20 max-digest-length 1024 max-error-count 64 @@ -1442,9 +1441,7 @@ sync-master-info 10000 sync-relay-log 10000 sync-relay-log-info 10000 sysdate-is-now FALSE -table-cache 421 table-definition-cache 400 -table-open-cache 421 tc-heuristic-recover OFF thread-cache-size 0 thread-pool-idle-timeout 60 diff --git a/mysql-test/suite/sys_vars/r/table_open_cache_basic.result b/mysql-test/suite/sys_vars/r/table_open_cache_basic.result index bc373003e1d..b805eb8f742 100644 --- a/mysql-test/suite/sys_vars/r/table_open_cache_basic.result +++ b/mysql-test/suite/sys_vars/r/table_open_cache_basic.result @@ -1,7 +1,7 @@ SET @start_value = @@global.table_open_cache ; -SELECT @start_value; -@start_value -421 +SELECT @start_value > 400; +@start_value > 400 +1 '#--------------------FN_DYNVARS_001_01------------------------#' SET @@global.table_open_cache = 99; SET @@global.table_open_cache = DeFAULT; @@ -108,6 +108,6 @@ ERROR 42S02: Unknown table 'global' in field list SELECT table_open_cache = @@session.table_open_cache ; ERROR 42S22: Unknown column 'table_open_cache' in 'field list' SET @@global.table_open_cache = @start_value; -SELECT @@global.table_open_cache ; -@@global.table_open_cache -421 +SELECT @@global.table_open_cache = @start_value ; +@@global.table_open_cache = @start_value +1 diff --git a/mysql-test/suite/sys_vars/t/table_open_cache_basic.test b/mysql-test/suite/sys_vars/t/table_open_cache_basic.test index 7d2549cd87f..1b7fbe5cbc5 100644 --- a/mysql-test/suite/sys_vars/t/table_open_cache_basic.test +++ b/mysql-test/suite/sys_vars/t/table_open_cache_basic.test @@ -35,7 +35,7 @@ ########################################################################## SET @start_value = @@global.table_open_cache ; -SELECT @start_value; +SELECT @start_value > 400; --echo '#--------------------FN_DYNVARS_001_01------------------------#' @@ -165,7 +165,7 @@ SELECT table_open_cache = @@session.table_open_cache ; ############################## SET @@global.table_open_cache = @start_value; -SELECT @@global.table_open_cache ; +SELECT @@global.table_open_cache = @start_value ; ################################################################## diff --git a/mysql-test/t/mysqld--help.test b/mysql-test/t/mysqld--help.test index 8924d2c45da..ec6e0f01189 100644 --- a/mysql-test/t/mysqld--help.test +++ b/mysql-test/t/mysqld--help.test @@ -23,7 +23,8 @@ perl; log-slow-queries pid-file slow-query-log-file log-basename datadir slave-load-tmpdir tmpdir socket thread-pool-size large-files-support lower-case-file-system system-time-zone - collation-server character-set-server log-tc-size version.*/; + collation-server character-set-server log-tc-size table-cache + table-open-cache max-connections version.*/; # Plugins which may or may not be there: @plugins=qw/innodb archive blackhole federated partition From 3e3da1642d6d02df00862f69ba64c2c6a8dd9b15 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 10 Aug 2020 10:16:31 -0400 Subject: [PATCH 17/20] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 42407f29a37..453e11b3aae 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=1 -MYSQL_VERSION_PATCH=46 +MYSQL_VERSION_PATCH=47 From 7f67ef14852afebf90aaafdfc7295acbf0ad340f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 10 Aug 2020 15:18:53 +0300 Subject: [PATCH 18/20] MDEV-16115 Hang after reducing innodb_encryption_threads The test encryption.create_or_replace would occasionally fail, because some fil_space_t::n_pending_ops would never be decremented. fil_crypt_find_space_to_rotate(): If rotate_thread_t::should_shutdown() holds due to innodb_encryption_threads having been reduced, do release the reference. fil_space_remove_from_keyrotation(), fil_space_next(): Declare the functions static, simplify a little, and define in the same compilation unit with the only caller, fil_crypt_find_space_to_rotate(). fil_crypt_key_mutex: Remove (unused). --- storage/innobase/fil/fil0crypt.cc | 136 +++++++++++++++++++++++------ storage/innobase/fil/fil0fil.cc | 134 ---------------------------- storage/innobase/include/fil0fil.h | 28 ------ storage/xtradb/fil/fil0crypt.cc | 136 +++++++++++++++++++++++------ storage/xtradb/fil/fil0fil.cc | 134 ---------------------------- storage/xtradb/include/fil0fil.h | 28 ------ 6 files changed, 222 insertions(+), 374 deletions(-) diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 901b28c8c62..fc7ef41786e 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -44,15 +44,8 @@ Modified Jan Lindström jan.lindstrom@mariadb.com #include "ha_prototypes.h" // IB_LOG_ #include -/** Mutex for keys */ -static ib_mutex_t fil_crypt_key_mutex; - static bool fil_crypt_threads_inited = false; -#ifdef UNIV_PFS_MUTEX -static mysql_pfs_key_t fil_crypt_key_mutex_key; -#endif - /** Is encryption enabled/disabled */ UNIV_INTERN ulong srv_encrypt_tables = 0; @@ -133,9 +126,6 @@ UNIV_INTERN void fil_space_crypt_init() { - mutex_create(fil_crypt_key_mutex_key, - &fil_crypt_key_mutex, SYNC_NO_ORDER_CHECK); - fil_crypt_throttle_sleep_event = os_event_create(); mutex_create(fil_crypt_stat_mutex_key, @@ -152,7 +142,6 @@ fil_space_crypt_cleanup() { os_event_free(fil_crypt_throttle_sleep_event); fil_crypt_throttle_sleep_event = NULL; - mutex_free(&fil_crypt_key_mutex); mutex_free(&crypt_stat_mutex); } @@ -1451,6 +1440,109 @@ fil_crypt_return_iops( fil_crypt_update_total_stat(state); } +/** Remove space from key rotation list if there are no pending operations. */ +static void fil_space_remove_from_keyrotation(fil_space_t *space) +{ + ut_ad(mutex_own(&fil_system->mutex)); + + if (space->n_pending_ops == 0 && space->is_in_rotation_list) + { + space->is_in_rotation_list= false; + ut_a(UT_LIST_GET_LEN(fil_system->rotation_list) > 0); + UT_LIST_REMOVE(rotation_list, fil_system->rotation_list, space); + } +} + +/** Return the next tablespace from key rotation list. +@param space previous tablespace (NULL to start from the beginning) +@return pointer to the next tablespace (with n_pending_ops incremented) +@retval NULL if this was the last */ +static fil_space_t *fil_space_keyrotate_next(fil_space_t *space) +{ + ut_ad(mutex_own(&fil_system->mutex)); + + if (UT_LIST_GET_LEN(fil_system->rotation_list) == 0) + { + if (space) + { + space->n_pending_ops--; + fil_space_remove_from_keyrotation(space); + } + + return NULL; + } + + if (!space) + { + space= UT_LIST_GET_FIRST(fil_system->rotation_list); + /* We can trust that space is not NULL because we + checked list length above */ + } + else + { + space->n_pending_ops--; + fil_space_t *old = space; + space= UT_LIST_GET_NEXT(rotation_list, space); + fil_space_remove_from_keyrotation(old); + } + + /* Skip spaces that are being created by fil_ibd_create(), + or dropped. Note that rotation_list contains only + space->purpose == FIL_TABLESPACE. */ + while (space && (!UT_LIST_GET_LEN(space->chain) || space->is_stopping())) + { + fil_space_t *old = space; + space= UT_LIST_GET_NEXT(rotation_list, space); + fil_space_remove_from_keyrotation(old); + } + + if (space) + space->n_pending_ops++; + + return space; +} + +/** Return the next tablespace. +@param space previous tablespace (NULL to start from the beginning) +@return pointer to the next tablespace (with n_pending_ops incremented) +@retval NULL if this was the last */ +static fil_space_t *fil_space_next(fil_space_t *space) +{ + mutex_enter(&fil_system->mutex); + ut_ad(!space || space->n_pending_ops); + + if (!srv_fil_crypt_rotate_key_age) + space= fil_space_keyrotate_next(space); + else if (!space) + { + space= UT_LIST_GET_FIRST(fil_system->space_list); + /* We can trust that space is not NULL because at least the + system tablespace is always present and loaded first. */ + space->n_pending_ops++; + } + else + { + ut_ad(space->n_pending_ops > 0); + /* Move on to the next fil_space_t */ + space->n_pending_ops--; + space= UT_LIST_GET_NEXT(space_list, space); + + /* Skip abnormal tablespaces or those that are being created by + fil_ibd_create(), or being dropped. */ + while (space && + (UT_LIST_GET_LEN(space->chain) == 0 || + space->is_stopping() || space->purpose != FIL_TABLESPACE)) + space= UT_LIST_GET_NEXT(space_list, space); + + if (space) + space->n_pending_ops++; + } + + mutex_exit(&fil_system->mutex); + + return space; +} + /*********************************************************************** Search for a space needing rotation @param[in,out] key_state Key state @@ -1485,14 +1577,7 @@ fil_crypt_find_space_to_rotate( state->space = NULL; } - /* If key rotation is enabled (default) we iterate all tablespaces. - If key rotation is not enabled we iterate only the tablespaces - added to keyrotation list. */ - if (srv_fil_crypt_rotate_key_age) { - state->space = fil_space_next(state->space); - } else { - state->space = fil_space_keyrotate_next(state->space); - } + state->space = fil_space_next(state->space); while (!state->should_shutdown() && state->space) { fil_crypt_read_crypt_data(state->space); @@ -1505,14 +1590,15 @@ fil_crypt_find_space_to_rotate( return true; } - if (srv_fil_crypt_rotate_key_age) { - state->space = fil_space_next(state->space); - } else { - state->space = fil_space_keyrotate_next(state->space); - } + state->space = fil_space_next(state->space); } - /* if we didn't find any space return iops */ + if (state->space) { + fil_space_release(state->space); + state->space = NULL; + } + + /* no work to do; release our allocation of I/O capacity */ fil_crypt_return_iops(state); return false; diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 62fb8deaf72..e3ba8dc7dac 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -6476,137 +6476,3 @@ fil_space_release_for_io(fil_space_t* space) space->n_pending_ios--; mutex_exit(&fil_system->mutex); } - -/** Return the next fil_space_t. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last*/ -UNIV_INTERN -fil_space_t* -fil_space_next(fil_space_t* prev_space) -{ - fil_space_t* space=prev_space; - - mutex_enter(&fil_system->mutex); - - if (prev_space == NULL) { - space = UT_LIST_GET_FIRST(fil_system->space_list); - - /* We can trust that space is not NULL because at least the - system tablespace is always present and loaded first. */ - space->n_pending_ops++; - } else { - ut_ad(space->n_pending_ops > 0); - - /* Move on to the next fil_space_t */ - space->n_pending_ops--; - space = UT_LIST_GET_NEXT(space_list, space); - - /* Skip spaces that are being created by - fil_ibd_create(), or dropped, or !tablespace. */ - while (space != NULL - && (UT_LIST_GET_LEN(space->chain) == 0 - || space->is_stopping() - || space->purpose != FIL_TABLESPACE)) { - space = UT_LIST_GET_NEXT(space_list, space); - } - - if (space != NULL) { - space->n_pending_ops++; - } - } - - mutex_exit(&fil_system->mutex); - - return(space); -} - -/** -Remove space from key rotation list if there are no more -pending operations. -@param[in] space Tablespace */ -static -void -fil_space_remove_from_keyrotation( - fil_space_t* space) -{ - ut_ad(mutex_own(&fil_system->mutex)); - ut_ad(space); - - if (space->n_pending_ops == 0 && space->is_in_rotation_list) { - space->is_in_rotation_list = false; - ut_a(UT_LIST_GET_LEN(fil_system->rotation_list) > 0); - UT_LIST_REMOVE(rotation_list, fil_system->rotation_list, space); - } -} - - -/** Return the next fil_space_t from key rotation list. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last*/ -UNIV_INTERN -fil_space_t* -fil_space_keyrotate_next( - fil_space_t* prev_space) -{ - fil_space_t* space = prev_space; - fil_space_t* old = NULL; - - mutex_enter(&fil_system->mutex); - - if (UT_LIST_GET_LEN(fil_system->rotation_list) == 0) { - if (space) { - ut_ad(space->n_pending_ops > 0); - space->n_pending_ops--; - fil_space_remove_from_keyrotation(space); - } - mutex_exit(&fil_system->mutex); - return(NULL); - } - - if (prev_space == NULL) { - space = UT_LIST_GET_FIRST(fil_system->rotation_list); - - /* We can trust that space is not NULL because we - checked list length above */ - } else { - ut_ad(space->n_pending_ops > 0); - - /* Move on to the next fil_space_t */ - space->n_pending_ops--; - - old = space; - space = UT_LIST_GET_NEXT(rotation_list, space); - - fil_space_remove_from_keyrotation(old); - } - - /* Skip spaces that are being created by fil_ibd_create(), - or dropped. Note that rotation_list contains only - space->purpose == FIL_TABLESPACE. */ - while (space != NULL - && (UT_LIST_GET_LEN(space->chain) == 0 - || space->is_stopping())) { - - old = space; - space = UT_LIST_GET_NEXT(rotation_list, space); - fil_space_remove_from_keyrotation(old); - } - - if (space != NULL) { - space->n_pending_ops++; - } - - mutex_exit(&fil_system->mutex); - - return(space); -} diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 5b11a026cf9..74d0673ccfc 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -699,34 +699,6 @@ UNIV_INTERN void fil_space_release_for_io(fil_space_t* space); -/** Return the next fil_space_t. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in,out] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last */ -UNIV_INTERN -fil_space_t* -fil_space_next( - fil_space_t* prev_space) - MY_ATTRIBUTE((warn_unused_result)); - -/** Return the next fil_space_t from key rotation list. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in,out] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last*/ -UNIV_INTERN -fil_space_t* -fil_space_keyrotate_next( - fil_space_t* prev_space) - MY_ATTRIBUTE((warn_unused_result)); - /** Wrapper with reference-counting for a fil_space_t. */ class FilSpace { diff --git a/storage/xtradb/fil/fil0crypt.cc b/storage/xtradb/fil/fil0crypt.cc index 901b28c8c62..fc7ef41786e 100644 --- a/storage/xtradb/fil/fil0crypt.cc +++ b/storage/xtradb/fil/fil0crypt.cc @@ -44,15 +44,8 @@ Modified Jan Lindström jan.lindstrom@mariadb.com #include "ha_prototypes.h" // IB_LOG_ #include -/** Mutex for keys */ -static ib_mutex_t fil_crypt_key_mutex; - static bool fil_crypt_threads_inited = false; -#ifdef UNIV_PFS_MUTEX -static mysql_pfs_key_t fil_crypt_key_mutex_key; -#endif - /** Is encryption enabled/disabled */ UNIV_INTERN ulong srv_encrypt_tables = 0; @@ -133,9 +126,6 @@ UNIV_INTERN void fil_space_crypt_init() { - mutex_create(fil_crypt_key_mutex_key, - &fil_crypt_key_mutex, SYNC_NO_ORDER_CHECK); - fil_crypt_throttle_sleep_event = os_event_create(); mutex_create(fil_crypt_stat_mutex_key, @@ -152,7 +142,6 @@ fil_space_crypt_cleanup() { os_event_free(fil_crypt_throttle_sleep_event); fil_crypt_throttle_sleep_event = NULL; - mutex_free(&fil_crypt_key_mutex); mutex_free(&crypt_stat_mutex); } @@ -1451,6 +1440,109 @@ fil_crypt_return_iops( fil_crypt_update_total_stat(state); } +/** Remove space from key rotation list if there are no pending operations. */ +static void fil_space_remove_from_keyrotation(fil_space_t *space) +{ + ut_ad(mutex_own(&fil_system->mutex)); + + if (space->n_pending_ops == 0 && space->is_in_rotation_list) + { + space->is_in_rotation_list= false; + ut_a(UT_LIST_GET_LEN(fil_system->rotation_list) > 0); + UT_LIST_REMOVE(rotation_list, fil_system->rotation_list, space); + } +} + +/** Return the next tablespace from key rotation list. +@param space previous tablespace (NULL to start from the beginning) +@return pointer to the next tablespace (with n_pending_ops incremented) +@retval NULL if this was the last */ +static fil_space_t *fil_space_keyrotate_next(fil_space_t *space) +{ + ut_ad(mutex_own(&fil_system->mutex)); + + if (UT_LIST_GET_LEN(fil_system->rotation_list) == 0) + { + if (space) + { + space->n_pending_ops--; + fil_space_remove_from_keyrotation(space); + } + + return NULL; + } + + if (!space) + { + space= UT_LIST_GET_FIRST(fil_system->rotation_list); + /* We can trust that space is not NULL because we + checked list length above */ + } + else + { + space->n_pending_ops--; + fil_space_t *old = space; + space= UT_LIST_GET_NEXT(rotation_list, space); + fil_space_remove_from_keyrotation(old); + } + + /* Skip spaces that are being created by fil_ibd_create(), + or dropped. Note that rotation_list contains only + space->purpose == FIL_TABLESPACE. */ + while (space && (!UT_LIST_GET_LEN(space->chain) || space->is_stopping())) + { + fil_space_t *old = space; + space= UT_LIST_GET_NEXT(rotation_list, space); + fil_space_remove_from_keyrotation(old); + } + + if (space) + space->n_pending_ops++; + + return space; +} + +/** Return the next tablespace. +@param space previous tablespace (NULL to start from the beginning) +@return pointer to the next tablespace (with n_pending_ops incremented) +@retval NULL if this was the last */ +static fil_space_t *fil_space_next(fil_space_t *space) +{ + mutex_enter(&fil_system->mutex); + ut_ad(!space || space->n_pending_ops); + + if (!srv_fil_crypt_rotate_key_age) + space= fil_space_keyrotate_next(space); + else if (!space) + { + space= UT_LIST_GET_FIRST(fil_system->space_list); + /* We can trust that space is not NULL because at least the + system tablespace is always present and loaded first. */ + space->n_pending_ops++; + } + else + { + ut_ad(space->n_pending_ops > 0); + /* Move on to the next fil_space_t */ + space->n_pending_ops--; + space= UT_LIST_GET_NEXT(space_list, space); + + /* Skip abnormal tablespaces or those that are being created by + fil_ibd_create(), or being dropped. */ + while (space && + (UT_LIST_GET_LEN(space->chain) == 0 || + space->is_stopping() || space->purpose != FIL_TABLESPACE)) + space= UT_LIST_GET_NEXT(space_list, space); + + if (space) + space->n_pending_ops++; + } + + mutex_exit(&fil_system->mutex); + + return space; +} + /*********************************************************************** Search for a space needing rotation @param[in,out] key_state Key state @@ -1485,14 +1577,7 @@ fil_crypt_find_space_to_rotate( state->space = NULL; } - /* If key rotation is enabled (default) we iterate all tablespaces. - If key rotation is not enabled we iterate only the tablespaces - added to keyrotation list. */ - if (srv_fil_crypt_rotate_key_age) { - state->space = fil_space_next(state->space); - } else { - state->space = fil_space_keyrotate_next(state->space); - } + state->space = fil_space_next(state->space); while (!state->should_shutdown() && state->space) { fil_crypt_read_crypt_data(state->space); @@ -1505,14 +1590,15 @@ fil_crypt_find_space_to_rotate( return true; } - if (srv_fil_crypt_rotate_key_age) { - state->space = fil_space_next(state->space); - } else { - state->space = fil_space_keyrotate_next(state->space); - } + state->space = fil_space_next(state->space); } - /* if we didn't find any space return iops */ + if (state->space) { + fil_space_release(state->space); + state->space = NULL; + } + + /* no work to do; release our allocation of I/O capacity */ fil_crypt_return_iops(state); return false; diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc index b5ccb533af8..41bc4cca8a6 100644 --- a/storage/xtradb/fil/fil0fil.cc +++ b/storage/xtradb/fil/fil0fil.cc @@ -6863,137 +6863,3 @@ fil_space_release(fil_space_t* space) space->n_pending_ops--; mutex_exit(&fil_system->mutex); } - -/** Return the next fil_space_t. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last*/ -UNIV_INTERN -fil_space_t* -fil_space_next(fil_space_t* prev_space) -{ - fil_space_t* space=prev_space; - - mutex_enter(&fil_system->mutex); - - if (prev_space == NULL) { - space = UT_LIST_GET_FIRST(fil_system->space_list); - - /* We can trust that space is not NULL because at least the - system tablespace is always present and loaded first. */ - space->n_pending_ops++; - } else { - ut_ad(space->n_pending_ops > 0); - - /* Move on to the next fil_space_t */ - space->n_pending_ops--; - space = UT_LIST_GET_NEXT(space_list, space); - - /* Skip spaces that are being created by - fil_ibd_create(), or dropped, or !tablespace. */ - while (space != NULL - && (UT_LIST_GET_LEN(space->chain) == 0 - || space->is_stopping() - || space->purpose != FIL_TABLESPACE)) { - space = UT_LIST_GET_NEXT(space_list, space); - } - - if (space != NULL) { - space->n_pending_ops++; - } - } - - mutex_exit(&fil_system->mutex); - - return(space); -} - -/** -Remove space from key rotation list if there are no more -pending operations. -@param[in] space Tablespace */ -static -void -fil_space_remove_from_keyrotation( - fil_space_t* space) -{ - ut_ad(mutex_own(&fil_system->mutex)); - ut_ad(space); - - if (space->n_pending_ops == 0 && space->is_in_rotation_list) { - space->is_in_rotation_list = false; - ut_a(UT_LIST_GET_LEN(fil_system->rotation_list) > 0); - UT_LIST_REMOVE(rotation_list, fil_system->rotation_list, space); - } -} - - -/** Return the next fil_space_t from key rotation list. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last*/ -UNIV_INTERN -fil_space_t* -fil_space_keyrotate_next( - fil_space_t* prev_space) -{ - fil_space_t* space = prev_space; - fil_space_t* old = NULL; - - mutex_enter(&fil_system->mutex); - - if (UT_LIST_GET_LEN(fil_system->rotation_list) == 0) { - if (space) { - ut_ad(space->n_pending_ops > 0); - space->n_pending_ops--; - fil_space_remove_from_keyrotation(space); - } - mutex_exit(&fil_system->mutex); - return(NULL); - } - - if (prev_space == NULL) { - space = UT_LIST_GET_FIRST(fil_system->rotation_list); - - /* We can trust that space is not NULL because we - checked list length above */ - } else { - ut_ad(space->n_pending_ops > 0); - - /* Move on to the next fil_space_t */ - space->n_pending_ops--; - - old = space; - space = UT_LIST_GET_NEXT(rotation_list, space); - - fil_space_remove_from_keyrotation(old); - } - - /* Skip spaces that are being created by fil_ibd_create(), - or dropped. Note that rotation_list contains only - space->purpose == FIL_TABLESPACE. */ - while (space != NULL - && (UT_LIST_GET_LEN(space->chain) == 0 - || space->is_stopping())) { - - old = space; - space = UT_LIST_GET_NEXT(rotation_list, space); - fil_space_remove_from_keyrotation(old); - } - - if (space != NULL) { - space->n_pending_ops++; - } - - mutex_exit(&fil_system->mutex); - - return(space); -} diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h index 6a823e131ac..78878fa75fc 100644 --- a/storage/xtradb/include/fil0fil.h +++ b/storage/xtradb/include/fil0fil.h @@ -705,34 +705,6 @@ UNIV_INTERN void fil_space_release_for_io(fil_space_t* space); -/** Return the next fil_space_t. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in,out] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last */ -UNIV_INTERN -fil_space_t* -fil_space_next( - fil_space_t* prev_space) - MY_ATTRIBUTE((warn_unused_result)); - -/** Return the next fil_space_t from key rotation list. -Once started, the caller must keep calling this until it returns NULL. -fil_space_acquire() and fil_space_release() are invoked here which -blocks a concurrent operation from dropping the tablespace. -@param[in,out] prev_space Pointer to the previous fil_space_t. -If NULL, use the first fil_space_t on fil_system->space_list. -@return pointer to the next fil_space_t. -@retval NULL if this was the last*/ -UNIV_INTERN -fil_space_t* -fil_space_keyrotate_next( - fil_space_t* prev_space) - MY_ATTRIBUTE((warn_unused_result)); - /** Wrapper with reference-counting for a fil_space_t. */ class FilSpace { From debd36c880bf088363350a31c580ee0c7ee92e42 Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 10 Aug 2020 10:23:10 -0400 Subject: [PATCH 19/20] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index ed8554d24d9..d010acbf85d 100644 --- a/VERSION +++ b/VERSION @@ -1,3 +1,3 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=2 -MYSQL_VERSION_PATCH=33 +MYSQL_VERSION_PATCH=34 From c19335ea5359923c918b07ef9892c14408414b4d Mon Sep 17 00:00:00 2001 From: Daniel Bartholomew Date: Mon, 10 Aug 2020 10:26:37 -0400 Subject: [PATCH 20/20] bump the VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 19a3d95ed2d..5f8bdaf364f 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ MYSQL_VERSION_MAJOR=10 MYSQL_VERSION_MINOR=3 -MYSQL_VERSION_PATCH=24 +MYSQL_VERSION_PATCH=25 SERVER_MATURITY=stable