From 24faa5de16c980fa5575cfc4a89618e48e9a3305 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Wed, 28 Jun 2023 12:22:56 +1000 Subject: [PATCH 01/40] MDEV-30542 Fixing spider/bugfix.self_reference_multi The server needs to have a unique name --- .../spider/bugfix/r/self_reference_multi.result | 8 ++++---- .../spider/bugfix/t/self_reference_multi.test | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/storage/spider/mysql-test/spider/bugfix/r/self_reference_multi.result b/storage/spider/mysql-test/spider/bugfix/r/self_reference_multi.result index c4399ddf9d2..50db034c8cd 100644 --- a/storage/spider/mysql-test/spider/bugfix/r/self_reference_multi.result +++ b/storage/spider/mysql-test/spider/bugfix/r/self_reference_multi.result @@ -4,11 +4,11 @@ for child3 MDEV-6268 SPIDER table with no COMMENT clause causes queries to wait forever -CREATE SERVER srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); +CREATE SERVER $srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); create table t2 (c int); -create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t2"'; -create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"'; -alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t0"'; +create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv_self_reference_multi",TABLE "t2"'; +create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv_self_reference_multi",TABLE "t1"'; +alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv_self_reference_multi",TABLE "t0"'; select * from t0; ERROR HY000: An infinite loop is detected when opening table test.t0 select * from t1; diff --git a/storage/spider/mysql-test/spider/bugfix/t/self_reference_multi.test b/storage/spider/mysql-test/spider/bugfix/t/self_reference_multi.test index 8b6f070d167..a3d561f3fae 100644 --- a/storage/spider/mysql-test/spider/bugfix/t/self_reference_multi.test +++ b/storage/spider/mysql-test/spider/bugfix/t/self_reference_multi.test @@ -8,12 +8,12 @@ --echo MDEV-6268 SPIDER table with no COMMENT clause causes queries to wait forever --echo ---replace_regex /SOCKET ".*"/SOCKET "$MASTER_1_MYSOCK"/ -eval CREATE SERVER srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); +--let $srv=srv_self_reference_multi +evalp CREATE SERVER $srv FOREIGN DATA WRAPPER MYSQL OPTIONS (SOCKET "$MASTER_1_MYSOCK", DATABASE 'test',user 'root'); create table t2 (c int); -create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t2"'; -create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t1"'; -alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "srv",TABLE "t0"'; +eval create table t1 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "$srv",TABLE "t2"'; +eval create table t0 (c int) ENGINE=Spider COMMENT='WRAPPER "mysql", srv "$srv",TABLE "t1"'; +eval alter table t2 ENGINE=Spider COMMENT='WRAPPER "mysql", srv "$srv",TABLE "t0"'; --error 12719 select * from t0; --error 12719 From 33877cfeae6e36ac177e3102dd98ac19f520ef74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 28 Jun 2023 17:07:00 +0300 Subject: [PATCH 02/40] Fix WITH_UBSAN GCC -Wconversion --- storage/innobase/rem/rem0rec.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index d202afa9e20..0adea369037 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -242,9 +242,11 @@ enum rec_leaf_format { REC_LEAF_INSTANT }; -#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 12 +#if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wconversion" /* GCC 5 to 11 need this */ +# if __GNUC__ < 12 || defined WITH_UBSAN +# pragma GCC diagnostic ignored "-Wconversion" +# endif #endif /** Determine the offset to each field in a leaf-page record in ROW_FORMAT=COMPACT,DYNAMIC,COMPRESSED. @@ -1707,7 +1709,7 @@ rec_convert_dtuple_to_rec_new( REC_INFO_BITS_MASK, REC_INFO_BITS_SHIFT); return buf; } -#if defined __GNUC__ && !defined __clang__ && __GNUC__ < 11 +#if defined __GNUC__ && !defined __clang__ # pragma GCC diagnostic pop /* ignored "-Wconversion" */ #endif From 0d3720c12a6ff0a2bb104c852e6c204c887b3dd6 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 15 May 2023 12:41:31 +0400 Subject: [PATCH 03/40] MDEV-30680 Warning: Memory not freed: 280 on mangled query, LeakSanitizer: detected memory leaks The parser works as follows: The rule expr_lex returns a pointer to a newly created sp_expr_lex instance which is not linked to any MariaDB structures yet - it is pointed only from a Bison stack variable. The sp_expr_lex instance gets linked to other structures (such as sp_instr_jump_if_not) later, after scanning some following grammar. Problem before the fix: If a parse error happened immediately after expr_lex (before it got linked), the created sp_expr_lex value got lost causing a memory leak. Fix: - Using Bison's "destructor" directive to free the results of expr_lex on parse/oom errors. - Moving the call for LEX::cleanup_lex_after_parse_error() from MYSQL_YYABORT and yyerror inside parse_sql(). This is needed because Bison calls destructors after yyerror(), while it's important to delete the sp_expr_lex instance before LEX::cleanup_lex_after_parse_error(). The latter frees the memory root containing the sp_expr_lex instance. After this change the code block are executed in the following order: - yyerror() -- now only raises the error to DA (no cleanup done any more) - %destructor { delete $$; } -- destructs the sp_expr_lex instance - LEX::cleanup_lex_after_parse_error() -- frees the memory root containing the sp_expr_lex instance - Removing the "delete sublex" related code from restore_lex(): - restore_lex() is called in most cases on success, when delete is not needed. - There is one place when restore_lex() is called on error: In sp_create_assignment_instr(). But in this case LEX::sp_lex_in_use is true anyway. The patch adds a new DBUG_ASSERT(lex->sp_lex_in_use) to guard this. --- mysql-test/main/sp-memory-leak.result | 21 +++++++++++++++++++ mysql-test/main/sp-memory-leak.test | 29 +++++++++++++++++++++++++++ sql/sp_head.h | 24 +++++++++++++--------- sql/sql_lex.cc | 11 ++++++---- sql/sql_parse.cc | 11 ++++++++++ sql/sql_yacc.yy | 24 ++++++++++++---------- 6 files changed, 95 insertions(+), 25 deletions(-) create mode 100644 mysql-test/main/sp-memory-leak.result create mode 100644 mysql-test/main/sp-memory-leak.test diff --git a/mysql-test/main/sp-memory-leak.result b/mysql-test/main/sp-memory-leak.result new file mode 100644 index 00000000000..aea278801d8 --- /dev/null +++ b/mysql-test/main/sp-memory-leak.result @@ -0,0 +1,21 @@ +# +# MDEV-30680 Warning: Memory not freed: 280 on mangled query, LeakSanitizer: detected memory leaks +# +BEGIN NOT ATOMIC +IF SCALAR() expected_THEN_here; +END +$$ +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 'expected_THEN_here; +END' at line 2 +BEGIN NOT ATOMIC +WHILE SCALAR() expected_DO_here; +END +$$ +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 'expected_DO_here; +END' at line 2 +BEGIN NOT ATOMIC +REPEAT SELECT 1; UNTIL SCALAR() expected_END_here; +END +$$ +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 'expected_END_here; +END' at line 2 diff --git a/mysql-test/main/sp-memory-leak.test b/mysql-test/main/sp-memory-leak.test new file mode 100644 index 00000000000..5b346aa8b10 --- /dev/null +++ b/mysql-test/main/sp-memory-leak.test @@ -0,0 +1,29 @@ +--echo # +--echo # MDEV-30680 Warning: Memory not freed: 280 on mangled query, LeakSanitizer: detected memory leaks +--echo # + +DELIMITER $$; +--error ER_PARSE_ERROR +BEGIN NOT ATOMIC + IF SCALAR() expected_THEN_here; +END +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_PARSE_ERROR +BEGIN NOT ATOMIC + WHILE SCALAR() expected_DO_here; +END +$$ +DELIMITER ;$$ + + +DELIMITER $$; +--error ER_PARSE_ERROR +BEGIN NOT ATOMIC + REPEAT SELECT 1; UNTIL SCALAR() expected_END_here; +END +$$ +DELIMITER ;$$ diff --git a/sql/sp_head.h b/sql/sp_head.h index 12db9c485cf..700485ffd21 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -608,20 +608,24 @@ public: restore_lex(THD *thd) { DBUG_ENTER("sp_head::restore_lex"); + /* + There is no a need to free the current thd->lex here. + - In the majority of the cases restore_lex() is called + on success and thd->lex does not need to be deleted. + - In cases when restore_lex() is called on error, + e.g. from sp_create_assignment_instr(), thd->lex is + already linked to some sp_instr_xxx (using sp_lex_keeper). + + Note, we don't get to here in case of a syntax error + when the current thd->lex is not yet completely + initialized and linked. It gets automatically deleted + by the Bison %destructor in sql_yacc.yy. + */ LEX *oldlex= (LEX *) m_lex.pop(); if (!oldlex) DBUG_RETURN(false); // Nothing to restore - LEX *sublex= thd->lex; // This restores thd->lex and thd->stmt_lex - if (thd->restore_from_local_lex_to_old_lex(oldlex)) - DBUG_RETURN(true); - if (!sublex->sp_lex_in_use) - { - sublex->sphead= NULL; - lex_end(sublex); - delete sublex; - } - DBUG_RETURN(false); + DBUG_RETURN(thd->restore_from_local_lex_to_old_lex(oldlex)); } /** diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 257acebe9e0..7e0ca6d868d 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -485,11 +485,15 @@ bool sp_create_assignment_instr(THD *thd, bool no_lookahead, be deleted by the destructor ~sp_instr_xxx(). So we should remove "lex" from the stack sp_head::m_lex, to avoid double free. - Note, in case "lex" is not owned by any sp_instr_xxx, - it's also safe to remove it from the stack right now. - So we can remove it unconditionally, without testing lex->sp_lex_in_use. */ lex->sphead->restore_lex(thd); + /* + No needs for "delete lex" here: "lex" is already linked + to the sp_instr_stmt (using sp_lex_keeper) instance created by + the call for new_sp_instr_stmt() above. It will be freed + by ~sp_head/~sp_instr/~sp_lex_keeper during THD::end_statement(). + */ + DBUG_ASSERT(lex->sp_lex_in_use); // used by sp_instr_stmt return true; } enum_var_type inner_option_type= lex->option_type; @@ -6773,7 +6777,6 @@ bool LEX::sp_for_loop_implicit_cursor_statement(THD *thd, if (unlikely(!(bounds->m_index= new (thd->mem_root) sp_assignment_lex(thd, this)))) return true; - bounds->m_index->sp_lex_in_use= true; sphead->reset_lex(thd, bounds->m_index); DBUG_ASSERT(thd->lex != this); /* diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 59f21247445..1e8ea5c5c80 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -10454,6 +10454,17 @@ bool parse_sql(THD *thd, Parser_state *parser_state, ((thd->variables.sql_mode & MODE_ORACLE) ? ORAparse(thd) : MYSQLparse(thd)) != 0; + + if (mysql_parse_status) + { + /* + Restore the original LEX if it was replaced when parsing + a stored procedure. We must ensure that a parsing error + does not leave any side effects in the THD. + */ + LEX::cleanup_lex_after_parse_error(thd); + } + DBUG_ASSERT(opt_bootstrap || mysql_parse_status || thd->lex->select_stack_top == 0); thd->lex->current_select= thd->lex->first_select_lex(); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a5a39228776..601ff119fc3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -98,7 +98,6 @@ int yylex(void *yylval, void *yythd); #define MYSQL_YYABORT \ do \ { \ - LEX::cleanup_lex_after_parse_error(thd); \ YYABORT; \ } while (0) @@ -149,13 +148,6 @@ static Item* escape(THD *thd) static void yyerror(THD *thd, const char *s) { - /* - Restore the original LEX if it was replaced when parsing - a stored procedure. We must ensure that a parsing error - does not leave any side effects in the THD. - */ - LEX::cleanup_lex_after_parse_error(thd); - /* "parse error" changed into "syntax error" between bison 1.75 and 1.875 */ if (strcmp(s,"parse error") == 0 || strcmp(s,"syntax error") == 0) s= ER_THD(thd, ER_SYNTAX_ERROR); @@ -1521,6 +1513,19 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); %type expr_lex +%destructor +{ + /* + In case of a syntax/oom error let's free the sp_expr_lex + instance, but only if it has not been linked to any structures + such as sp_instr_jump_if_not::m_lex_keeper yet, e.g.: + IF f1() THEN1 + i.e. THEN1 came instead of the expected THEN causing a syntax error. + */ + if (!$$->sp_lex_in_use) + delete $$; +} + %type assignment_source_lex assignment_source_expr @@ -3806,7 +3811,6 @@ expr_lex: expr { $$= $1; - $$->sp_lex_in_use= true; $$->set_item($2); Lex->pop_select(); //min select if (Lex->check_cte_dependencies_and_resolve_references()) @@ -3838,7 +3842,6 @@ assignment_source_expr: { DBUG_ASSERT($1 == thd->lex); $$= $1; - $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, thd->free_list); thd->free_list= NULL; Lex->pop_select(); //min select @@ -3859,7 +3862,6 @@ for_loop_bound_expr: { DBUG_ASSERT($1 == thd->lex); $$= $1; - $$->sp_lex_in_use= true; $$->set_item_and_free_list($3, NULL); Lex->pop_select(); //main select if (unlikely($$->sphead->restore_lex(thd))) From fdab2c4c648cd3f2db524ef7534843a9d29c4f4f Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 29 Jun 2023 17:30:02 +0400 Subject: [PATCH 04/40] MDEV-31578 DECLARE CURSOR: "Memory not freed: 280 bytes lost" on syntax error When CURSOR parameters get parsed, their sp_assignment_lex instances (one instance per parameter) get collected to List. These instances get linked to sphead only in the end of the list. If a syntax error happened in the middle of the parameter list, these instances were not deleted, which caused memory leaks. Fix: using a Bison %destructor to free rules of the type (on syntax errors). Afte the fix these sp_assignment_lex instances from CURSOR parameters deleted as follows: - If the CURSOR statement was fully parsed, then these instances get properly linked to sp_head structures, so they are deleted during ~sp_head (this did not change) - If the CURSOR statement failed on a syntax error, then by Bison's %destructor (this is being added in the current patch). --- mysql-test/main/sp-memory-leak.result | 21 +++++++++++++++++++++ mysql-test/main/sp-memory-leak.test | 25 +++++++++++++++++++++++++ sql/sql_lex.h | 6 +++++- sql/sql_yacc.yy | 15 +++++++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/sp-memory-leak.result b/mysql-test/main/sp-memory-leak.result index aea278801d8..37a0f119341 100644 --- a/mysql-test/main/sp-memory-leak.result +++ b/mysql-test/main/sp-memory-leak.result @@ -19,3 +19,24 @@ END $$ 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 'expected_END_here; END' at line 2 +# +# MDEV-31578 DECLARE CURSOR: "Memory not freed: 280 bytes lost" on syntax error +# +BEGIN NOT ATOMIC +DECLARE cur CURSOR (a INT) FOR SELECT a+1; +OPEN cur(sp_followed_by_syntax_error(); +CLOSE cur; +END; +$$ +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 '; +CLOSE cur; +END' at line 3 +BEGIN NOT ATOMIC +DECLARE cur CURSOR (a INT) FOR SELECT a+1; +OPEN cur(1,sp_followed_by_syntax_error(); +CLOSE cur; +END; +$$ +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 '; +CLOSE cur; +END' at line 3 diff --git a/mysql-test/main/sp-memory-leak.test b/mysql-test/main/sp-memory-leak.test index 5b346aa8b10..0035044209a 100644 --- a/mysql-test/main/sp-memory-leak.test +++ b/mysql-test/main/sp-memory-leak.test @@ -27,3 +27,28 @@ BEGIN NOT ATOMIC END $$ DELIMITER ;$$ + + +--echo # +--echo # MDEV-31578 DECLARE CURSOR: "Memory not freed: 280 bytes lost" on syntax error +--echo # + +DELIMITER $$; +--error ER_PARSE_ERROR +BEGIN NOT ATOMIC + DECLARE cur CURSOR (a INT) FOR SELECT a+1; + OPEN cur(sp_followed_by_syntax_error(); + CLOSE cur; +END; +$$ +DELIMITER ;$$ + +DELIMITER $$; +--error ER_PARSE_ERROR +BEGIN NOT ATOMIC + DECLARE cur CURSOR (a INT) FOR SELECT a+1; + OPEN cur(1,sp_followed_by_syntax_error(); + CLOSE cur; +END; +$$ +DELIMITER ;$$ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 2e3ce7d7503..5538fdd04e6 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3429,7 +3429,11 @@ public: sp_head *sphead; sp_name *spname; bool sp_lex_in_use; // Keep track on lex usage in SPs for error handling - + void delete_if_not_sp_lex_in_use() + { + if (!sp_lex_in_use) + delete this; + } sp_pcontext *spcont; st_sp_chistics sp_chistics; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 601ff119fc3..524da7be4c3 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1535,6 +1535,21 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); cursor_actual_parameters opt_parenthesized_cursor_actual_parameters +%destructor +{ + if ($$) + { + sp_assignment_lex *elem; + List_iterator li(*$$); + while ((elem= li++)) + { + if (!elem->sp_lex_in_use) + delete elem; + } + } +} + + %type option_type opt_var_type opt_var_ident_type From 5f2a77cef1cced322d3a6e6a48f4f4e5480283dc Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Sat, 10 Jun 2023 08:35:58 +1000 Subject: [PATCH 05/40] MDEV-31268 Fedora MariaDB-shared replaces mariadb-connector-c file /usr/lib64/libmariadb.so.3 from install of MariaDB-shared-10.11.3-1.fc38.x86_64 conflicts with file from package mariadb-connector-c-3.3.5-1.fc38.x86_64 --- cmake/cpack_rpm.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/cpack_rpm.cmake b/cmake/cpack_rpm.cmake index 7b1f0b0ff87..3cc24375c06 100644 --- a/cmake/cpack_rpm.cmake +++ b/cmake/cpack_rpm.cmake @@ -291,6 +291,7 @@ ENDIF() # MDEV-24629, we need it outside of ELSIFs IF(RPM MATCHES "fedora") ALTERNATIVE_NAME("common" "mariadb-connector-c-config" ${MARIADB_CONNECTOR_C_VERSION}-1) + ALTERNATIVE_NAME("shared" "mariadb-connector-c" ${MARIADB_CONNECTOR_C_VERSION}-1) ENDIF() SET(PYTHON_SHEBANG "/usr/bin/python3" CACHE STRING "python shebang") From cb364a78d6be7938a77ff8774a95035b8f703c65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 4 Jul 2023 15:24:57 +0300 Subject: [PATCH 06/40] MDEV-31619 dict_stats_persistent_storage_check() may show garbage during --bootstrap dict_stats_persistent_storage_check(): Do not output errmsg if opt_bootstrap holds, because the message buffer would likely be uninitialized. --- storage/innobase/dict/dict0stats.cc | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc index b5291ccbd87..e8dd976f8d2 100644 --- a/storage/innobase/dict/dict0stats.cc +++ b/storage/innobase/dict/dict0stats.cc @@ -514,15 +514,17 @@ static bool dict_stats_persistent_storage_check(bool dict_already_locked) dict_sys.unlock(); } - if (ret != DB_SUCCESS && ret != DB_STATS_DO_NOT_EXIST) { - ib::error() << errstr; - return(false); - } else if (ret == DB_STATS_DO_NOT_EXIST) { + switch (ret) { + case DB_SUCCESS: + return true; + default: + if (!opt_bootstrap) { + ib::error() << errstr; + } + /* fall through */ + case DB_STATS_DO_NOT_EXIST: return false; } - /* else */ - - return(true); } /** Executes a given SQL statement using the InnoDB internal SQL parser. From f6e488cc6dde2b7dd890fb2ecad753678ec1da76 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 17 Jan 2023 10:58:00 +0100 Subject: [PATCH 07/40] MDEV-26506 Over-quoted JSON when combining JSON_ARRAYAGG with JSON_OBJECT add the test case --- mysql-test/main/type_json.result | 18 ++++++++++++++++++ mysql-test/main/type_json.test | 14 ++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/mysql-test/main/type_json.result b/mysql-test/main/type_json.result index 681bd42c4e3..431a7f138f6 100644 --- a/mysql-test/main/type_json.result +++ b/mysql-test/main/type_json.result @@ -159,5 +159,23 @@ def j 250 (format=json) 9437283 16 Y 0 39 33 j {"a": {"b":"c"}} # +# MDEV-26506 Over-quoted JSON when combining JSON_ARRAYAGG with JSON_OBJECT +# +# maintain JSON property through internal temporary tables +create table t1 (a varchar(30)); +insert into t1 values ('root'); +select json_object('attr2',o) from (select a, json_arrayagg(json_object('attr1', a)) as o from t1) u; +json_object('attr2',o) +{"attr2": [{"attr1": "root"}]} +drop table t1; +create view v1 as select json_object(_latin1 'a', _latin1'b') as v1_json; +select v1_json from v1; +v1_json +{"a": "b"} +select json_arrayagg(v1_json) from v1; +json_arrayagg(v1_json) +[{"a": "b"}] +drop view v1; +# # End of 10.5 tests # diff --git a/mysql-test/main/type_json.test b/mysql-test/main/type_json.test index 38754ba6e1e..8effe78f803 100644 --- a/mysql-test/main/type_json.test +++ b/mysql-test/main/type_json.test @@ -121,6 +121,20 @@ SELECT json_object('a', (SELECT json_objectagg(b, c) FROM (SELECT 'b','c') d)) A --disable_ps_protocol --enable_view_protocol +--echo # +--echo # MDEV-26506 Over-quoted JSON when combining JSON_ARRAYAGG with JSON_OBJECT +--echo # +--echo # maintain JSON property through internal temporary tables +create table t1 (a varchar(30)); +insert into t1 values ('root'); +select json_object('attr2',o) from (select a, json_arrayagg(json_object('attr1', a)) as o from t1) u; +drop table t1; + +create view v1 as select json_object(_latin1 'a', _latin1'b') as v1_json; +select v1_json from v1; +select json_arrayagg(v1_json) from v1; +drop view v1; + --echo # --echo # End of 10.5 tests --echo # From a4817e1520de799ae55f27444a50be54b59b09bc Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 27 Jun 2023 14:09:52 +0200 Subject: [PATCH 08/40] cleanup: String::strstr() const --- sql/sql_string.cc | 6 +++--- sql/sql_string.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 7a8aa4ef0f4..208805b91ba 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -677,7 +677,7 @@ bool String::append_with_prefill(const char *s,uint32 arg_length, } -int Binary_string::strstr(const char *search, uint32 search_length, uint32 offset) +int Binary_string::strstr(const char *search, uint32 search_length, uint32 offset) const { if (search_length + offset <= str_length) { @@ -703,7 +703,7 @@ skip: return -1; } -int Binary_string::strstr(const Binary_string &s, uint32 offset) +int Binary_string::strstr(const Binary_string &s, uint32 offset) const { return strstr(s.ptr(), s.length(), offset); } @@ -712,7 +712,7 @@ int Binary_string::strstr(const Binary_string &s, uint32 offset) ** Search string from end. Offset is offset to the end of string */ -int Binary_string::strrstr(const Binary_string &s, uint32 offset) +int Binary_string::strrstr(const Binary_string &s, uint32 offset) const { if (s.length() <= offset && offset <= str_length) { diff --git a/sql/sql_string.h b/sql/sql_string.h index dbb4760ab34..d112a8842b9 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -406,10 +406,10 @@ public: } // Returns offset to substring or -1 - int strstr(const Binary_string &search, uint32 offset=0); - int strstr(const char *search, uint32 search_length, uint32 offset=0); + int strstr(const Binary_string &search, uint32 offset=0) const; + int strstr(const char *search, uint32 search_length, uint32 offset=0) const; // Returns offset to substring or -1 - int strrstr(const Binary_string &search, uint32 offset=0); + int strrstr(const Binary_string &search, uint32 offset=0) const; /* The following append operations do not extend the strings and in production From 5bf80af06eca4372af1e73c680eb59a4e6501f1c Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Tue, 16 May 2023 22:26:57 +0200 Subject: [PATCH 09/40] cleanup: remove Type_collection::handler_by_name() it's a hard-coded geometry-specific method, move it into geometry-specific function. Will go away in the future. --- plugin/type_mysql_json/type.cc | 7 ------- plugin/type_mysql_timestamp/plugin.cc | 5 ----- plugin/type_test/plugin.cc | 4 ---- sql/sql_type.cc | 10 +--------- sql/sql_type.h | 1 - sql/sql_type_fixedbin.h | 7 ------- sql/sql_type_geom.cc | 2 +- sql/sql_type_geom.h | 3 ++- sql/sql_type_json.cc | 14 -------------- 9 files changed, 4 insertions(+), 49 deletions(-) diff --git a/plugin/type_mysql_json/type.cc b/plugin/type_mysql_json/type.cc index 2b3c415f346..9cb69c8aa28 100644 --- a/plugin/type_mysql_json/type.cc +++ b/plugin/type_mysql_json/type.cc @@ -176,13 +176,6 @@ public: { return NULL; } - - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override - { - if (type_handler_mysql_json.name().eq(name)) - return &type_handler_mysql_json; - return NULL; - } }; const Type_collection *Type_handler_mysql_json::type_collection() const diff --git a/plugin/type_mysql_timestamp/plugin.cc b/plugin/type_mysql_timestamp/plugin.cc index f361ab6c0eb..c148f6dc067 100644 --- a/plugin/type_mysql_timestamp/plugin.cc +++ b/plugin/type_mysql_timestamp/plugin.cc @@ -31,11 +31,6 @@ protected: return NULL; } public: - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override - { - return NULL; - } - const Type_handler *aggregate_for_result(const Type_handler *h1, const Type_handler *h2) const override diff --git a/plugin/type_test/plugin.cc b/plugin/type_test/plugin.cc index 4c26c35f976..a649ebb3e41 100644 --- a/plugin/type_test/plugin.cc +++ b/plugin/type_test/plugin.cc @@ -26,10 +26,6 @@ protected: const Type_handler *aggregate_common(const Type_handler *h1, const Type_handler *h2) const; public: - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override - { - return NULL; - } const Type_handler *aggregate_for_result(const Type_handler *h1, const Type_handler *h2) const override; diff --git a/sql/sql_type.cc b/sql/sql_type.cc index a09d2648757..827eefba3fd 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -94,10 +94,6 @@ Vers_type_trx vers_type_trx; class Type_collection_std: public Type_collection { public: - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override - { - return NULL; - } const Type_handler *aggregate_for_result(const Type_handler *a, const Type_handler *b) const override @@ -137,10 +133,6 @@ public: { return false; } - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override - { - return NULL; - } const Type_handler *aggregate_for_result(const Type_handler *a, const Type_handler *b) const override @@ -212,7 +204,7 @@ Type_handler::handler_by_name(THD *thd, const LEX_CSTRING &name) } #ifdef HAVE_SPATIAL - const Type_handler *ha= type_collection_geometry.handler_by_name(name); + const Type_handler *ha= Type_collection_geometry_handler_by_name(name); if (ha) return ha; #endif diff --git a/sql/sql_type.h b/sql/sql_type.h index 479f924a727..471fe519847 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -7415,7 +7415,6 @@ class Type_collection public: virtual ~Type_collection() = default; virtual bool init(Type_handler_data *) { return false; } - virtual const Type_handler *handler_by_name(const LEX_CSTRING &name) const= 0; virtual const Type_handler *aggregate_for_result(const Type_handler *h1, const Type_handler *h2) const= 0; diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h index 093587c4deb..6163512d08b 100644 --- a/sql/sql_type_fixedbin.h +++ b/sql/sql_type_fixedbin.h @@ -1892,13 +1892,6 @@ public: { return NULL; } - - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override - { - if (type_handler_fbt()->name().eq(name)) - return type_handler_fbt(); - return NULL; - } }; static Type_handler_fbt *type_handler_fbt() { diff --git a/sql/sql_type_geom.cc b/sql/sql_type_geom.cc index 5732ae47217..c555022a99d 100644 --- a/sql/sql_type_geom.cc +++ b/sql/sql_type_geom.cc @@ -67,7 +67,7 @@ Type_handler_geometry::type_handler_geom_by_type(uint type) const Type_handler * -Type_collection_geometry::handler_by_name(const LEX_CSTRING &name) const +Type_collection_geometry_handler_by_name(const LEX_CSTRING &name) { if (type_handler_point.name().eq(name)) return &type_handler_point; diff --git a/sql/sql_type_geom.h b/sql/sql_type_geom.h index 3bc25808bc3..f3e34526f26 100644 --- a/sql/sql_type_geom.h +++ b/sql/sql_type_geom.h @@ -297,7 +297,6 @@ class Type_collection_geometry: public Type_collection #endif public: bool init(Type_handler_data *data) override; - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override; const Type_handler *aggregate_for_result(const Type_handler *a, const Type_handler *b) const override; @@ -316,6 +315,8 @@ public: }; extern Type_collection_geometry type_collection_geometry; +const Type_handler * +Type_collection_geometry_handler_by_name(const LEX_CSTRING &name); #include "field.h" diff --git a/sql/sql_type_json.cc b/sql/sql_type_json.cc index c12b868e6b9..27072de2d55 100644 --- a/sql/sql_type_json.cc +++ b/sql/sql_type_json.cc @@ -233,20 +233,6 @@ public: */ return NULL; } - - const Type_handler *handler_by_name(const LEX_CSTRING &name) const override - { - /* - Name resolution is not needed yet. - JSON is not fully pluggable at the moment: - - It is parsed using a hard-coded rule in sql_yacc.yy - - It does not store extended data type information into - FRM file yet. JSON is detected by CHECK(JSON_VALID(col)) - and this detection is also hard-coded. - This will change in the future. - */ - return NULL; - } }; From bbe44da24013aaa27baa07a0ab6d218d968e038d Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sun, 25 Jun 2023 16:38:57 +0200 Subject: [PATCH 10/40] cleanup: udt in sql_yac.yy --- sql/sql_yacc.yy | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 439f2a86052..062b6366246 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1323,6 +1323,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize); sp_opt_label BIN_NUM TEXT_STRING_filesystem opt_constraint constraint opt_ident sp_block_label sp_control_label opt_place opt_db + udt_name %type IDENT_sys @@ -6296,23 +6297,19 @@ qualified_field_type: } ; +udt_name: + IDENT_sys { $$= $1; } + | reserved_keyword_udt { $$= $1; } + | non_reserved_keyword_udt { $$= $1; } + ; + field_type_all: field_type_numeric | field_type_temporal | field_type_string | field_type_lob | field_type_misc - | IDENT_sys float_options srid_option - { - if (Lex->set_field_type_udt(&$$, $1, $2)) - MYSQL_YYABORT; - } - | reserved_keyword_udt float_options srid_option - { - if (Lex->set_field_type_udt(&$$, $1, $2)) - MYSQL_YYABORT; - } - | non_reserved_keyword_udt float_options srid_option + | udt_name float_options srid_option { if (Lex->set_field_type_udt(&$$, $1, $2)) MYSQL_YYABORT; @@ -11468,17 +11465,7 @@ cast_type: } | cast_type_numeric { $$= $1; Lex->charset= NULL; } | cast_type_temporal { $$= $1; Lex->charset= NULL; } - | IDENT_sys - { - if (Lex->set_cast_type_udt(&$$, $1)) - MYSQL_YYABORT; - } - | reserved_keyword_udt - { - if (Lex->set_cast_type_udt(&$$, $1)) - MYSQL_YYABORT; - } - | non_reserved_keyword_udt + | udt_name { if (Lex->set_cast_type_udt(&$$, $1)) MYSQL_YYABORT; From 238cfcc7290c7d5805bd7e747408e9186e0cc5bb Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Jun 2023 17:22:26 +0200 Subject: [PATCH 11/40] cleanup: remove unused and unlinkable method it was calling Fbt::to_string(char*, size_t) which didn't exist --- sql/sql_type_fixedbin.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h index 6163512d08b..a825fe269ca 100644 --- a/sql/sql_type_fixedbin.h +++ b/sql/sql_type_fixedbin.h @@ -200,10 +200,6 @@ public: { return to_fbt().to_binary(to); } - size_t to_string(char *dst, size_t dstsize) const - { - return to_fbt().to_string(dst, dstsize); - } bool to_string(String *to) const { return to_fbt().to_string(to); From c09b1583f56c2a3d4ca8899979dbcbad92a3bf1e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Jun 2023 14:33:35 +0200 Subject: [PATCH 12/40] cleanup: remove FixedBinTypeBundle now the main class is the Type_handler_fbt. It contains everything and generates objects of all other classes as needed. --- plugin/type_inet/item_inetfunc.cc | 10 +- plugin/type_inet/plugin.cc | 2 +- plugin/type_inet/sql_type_inet.h | 2 +- sql/sql_type_fixedbin.h | 2146 +++++++++++++++-------------- 4 files changed, 1083 insertions(+), 1077 deletions(-) diff --git a/plugin/type_inet/item_inetfunc.cc b/plugin/type_inet/item_inetfunc.cc index b23ae04a861..1bdae5e896b 100644 --- a/plugin/type_inet/item_inetfunc.cc +++ b/plugin/type_inet/item_inetfunc.cc @@ -158,7 +158,7 @@ String *Item_func_inet6_aton::val_str(String *buffer) return buffer; } - Inet6Bundle::Fbt_null ipv6(*tmp.string()); + Type_handler_inet6::Fbt_null ipv6(*tmp.string()); if (!ipv6.is_null()) { ipv6.to_binary(buffer); @@ -197,7 +197,7 @@ String *Item_func_inet6_ntoa::val_str_ascii(String *buffer) return buffer; } - Inet6Bundle::Fbt_null ipv6(static_cast(*tmp.string())); + Type_handler_inet6::Fbt_null ipv6(static_cast(*tmp.string())); if (!ipv6.is_null()) { ipv6.to_string(buffer); @@ -221,10 +221,10 @@ longlong Item_func_is_ipv4::val_int() return !tmp.is_null() && !Inet4_null(*tmp.string()).is_null(); } -class IP6 : public Inet6Bundle::Fbt_null +class IP6 : public Type_handler_inet6::Fbt_null { public: - IP6(Item* arg) : Inet6Bundle::Fbt_null(arg) {} + IP6(Item* arg) : Type_handler_inet6::Fbt_null(arg) {} bool is_v4compat() const { static_assert(sizeof(in6_addr) == IN6_ADDR_SIZE, "unexpected in6_addr size"); @@ -246,7 +246,7 @@ longlong Item_func_is_ipv6::val_int() { DBUG_ASSERT(fixed()); String_ptr_and_buffer tmp(args[0]); - return !tmp.is_null() && !Inet6Bundle::Fbt_null(*tmp.string()).is_null(); + return !tmp.is_null() && !Type_handler_inet6::Fbt_null(*tmp.string()).is_null(); } /** diff --git a/plugin/type_inet/plugin.cc b/plugin/type_inet/plugin.cc index 0b57e2bec1f..bb7603d5abe 100644 --- a/plugin/type_inet/plugin.cc +++ b/plugin/type_inet/plugin.cc @@ -24,7 +24,7 @@ static struct st_mariadb_data_type plugin_descriptor_type_inet6= { MariaDB_DATA_TYPE_INTERFACE_VERSION, - Inet6Bundle::type_handler_fbt() + Type_handler_inet6::singleton() }; diff --git a/plugin/type_inet/sql_type_inet.h b/plugin/type_inet/sql_type_inet.h index 69836ca215b..2c1865a7cef 100644 --- a/plugin/type_inet/sql_type_inet.h +++ b/plugin/type_inet/sql_type_inet.h @@ -44,7 +44,7 @@ public: #include "sql_type_fixedbin.h" -typedef FixedBinTypeBundle Inet6Bundle; +typedef Type_handler_fbt Type_handler_inet6; /***********************************************************************/ diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h index a825fe269ca..fb9ec6a5a5a 100644 --- a/sql/sql_type_fixedbin.h +++ b/sql/sql_type_fixedbin.h @@ -32,8 +32,10 @@ template -class FixedBinTypeBundle +class Type_handler_fbt: public Type_handler { + /* =[ internal helper classes ]=============================== */ + public: class Fbt: public FbtImpl { @@ -41,7 +43,7 @@ public: using FbtImpl::m_buffer; bool make_from_item(Item *item, bool warn) { - if (item->type_handler() == type_handler_fbt()) + if (item->type_handler() == singleton()) { Native tmp(m_buffer, sizeof(m_buffer)); bool rc= item->val_native(current_thd, &tmp); @@ -78,14 +80,14 @@ public: str->charset()); if (rc && warn) current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, - type_handler_fbt()->name().ptr(), ErrConvString(str).ptr()); + singleton()->name().ptr(), ErrConvString(str).ptr()); return rc; } if (str->length() != sizeof(m_buffer)) { if (warn) current_thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, - type_handler_fbt()->name().ptr(), ErrConvString(str).ptr()); + singleton()->name().ptr(), ErrConvString(str).ptr()); return true; } DBUG_ASSERT(str->ptr() != m_buffer); @@ -125,7 +127,7 @@ public: { if (item->maybe_null()) return true; - if (item->type_handler() == type_handler_fbt()) + if (item->type_handler() == singleton()) return false; if (!item->const_item() || item->is_expensive()) return true; @@ -206,6 +208,76 @@ public: } }; + /* =[ API classes ]=========================================== */ + + class Type_collection_fbt: public Type_collection + { + const Type_handler *aggregate_common(const Type_handler *a, + const Type_handler *b) const + { + if (a == b) + return a; + return NULL; + } + const Type_handler *aggregate_if_string(const Type_handler *a, + const Type_handler *b) const + { + static const Type_aggregator::Pair agg[]= + { + {singleton(), &type_handler_null, singleton()}, + {singleton(), &type_handler_varchar, singleton()}, + {singleton(), &type_handler_string, singleton()}, + {singleton(), &type_handler_tiny_blob, singleton()}, + {singleton(), &type_handler_blob, singleton()}, + {singleton(), &type_handler_medium_blob, singleton()}, + {singleton(), &type_handler_long_blob, singleton()}, + {singleton(), &type_handler_hex_hybrid, singleton()}, + {NULL,NULL,NULL} + }; + return Type_aggregator::find_handler_in_array(agg, a, b, true); + } + public: + const Type_handler *aggregate_for_result(const Type_handler *a, + const Type_handler *b) + const override + { + const Type_handler *h; + if ((h= aggregate_common(a, b)) || + (h= aggregate_if_string(a, b))) + return h; + return NULL; + } + + const Type_handler *aggregate_for_min_max(const Type_handler *a, + const Type_handler *b) + const override + { + return aggregate_for_result(a, b); + } + + const Type_handler *aggregate_for_comparison(const Type_handler *a, + const Type_handler *b) + const override + { + if (const Type_handler *h= aggregate_common(a, b)) + return h; + static const Type_aggregator::Pair agg[]= + { + {singleton(), &type_handler_null, singleton()}, + {singleton(), &type_handler_long_blob, singleton()}, + {NULL,NULL,NULL} + }; + return Type_aggregator::find_handler_in_array(agg, a, b, true); + } + + const Type_handler *aggregate_for_num_op(const Type_handler *a, + const Type_handler *b) + const override + { + return NULL; + } + }; + class Type_std_attributes_fbt: public Type_std_attributes { public: @@ -216,847 +288,66 @@ public: { } }; - class Type_handler_fbt: public Type_handler + class Item_literal_fbt: public Item_literal { - bool character_or_binary_string_to_native(THD *thd, const String *str, - Native *to) const - { - if (str->charset() == &my_charset_bin) - { - // Convert from a binary string - if (str->length() != FbtImpl::binary_length() || - to->copy(str->ptr(), str->length())) - { - thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, - name().ptr(), ErrConvString(str).ptr()); - return true; - } - return false; - } - // Convert from a character string - Fbt_null tmp(*str); - if (tmp.is_null()) - thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, - name().ptr(), ErrConvString(str).ptr()); - return tmp.is_null() || tmp.to_native(to); - } - + Fbt m_value; public: - ~Type_handler_fbt() override {} - - const Type_collection *type_collection() const override + Item_literal_fbt(THD *thd) + :Item_literal(thd), + m_value(Fbt::zero()) + { } + Item_literal_fbt(THD *thd, const Fbt &value) + :Item_literal(thd), + m_value(value) + { } + const Type_handler *type_handler() const override { - static Type_collection_fbt type_collection_fbt; - return &type_collection_fbt; + return singleton(); } - - const Name &default_value() const override - { - return FbtImpl::default_value(); - } - ulong KEY_pack_flags(uint column_nr) const override - { - return FbtImpl::KEY_pack_flags(column_nr); - } - protocol_send_type_t protocol_send_type() const override - { - return PROTOCOL_SEND_STRING; - } - bool Item_append_extended_type_info(Send_field_extended_metadata *to, - const Item *item) const override - { - return to->set_data_type_name(name().lex_cstring()); - } - - enum_field_types field_type() const override - { - return MYSQL_TYPE_STRING; - } - - Item_result result_type() const override - { - return STRING_RESULT; - } - - Item_result cmp_type() const override - { - return STRING_RESULT; - } - - enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) - const override - { - return DYN_COL_STRING; - } - - uint32 max_display_length_for_field(const Conv_source &src) const override - { - return FbtImpl::max_char_length(); - } - - const Type_handler *type_handler_for_comparison() const override - { - return this; - } - - int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override - { - DBUG_ASSERT(field->type_handler() == this); - Fbt_null ni(item); // Convert Item to Fbt - if (ni.is_null()) - return 0; - NativeBuffer tmp; - if (field->val_native(&tmp)) - { - DBUG_ASSERT(0); - return 0; - } - return -ni.cmp(tmp); - } - CHARSET_INFO *charset_for_protocol(const Item *item) const override - { - return item->collation.collation; - } - - bool is_scalar_type() const override { return true; } - bool is_val_native_ready() const override { return true; } - bool can_return_int() const override { return false; } - bool can_return_decimal() const override { return false; } - bool can_return_real() const override { return false; } - bool can_return_str() const override { return true; } - bool can_return_text() const override { return true; } - bool can_return_date() const override { return false; } - bool can_return_time() const override { return false; } - bool convert_to_binary_using_val_native() const override { return true; } - - decimal_digits_t Item_time_precision(THD *thd, Item *item) const override + longlong val_int() override { return 0; } - decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const override + double val_real() override { return 0; } - decimal_digits_t Item_decimal_scale(const Item *item) const override + String *val_str(String *to) override { - return 0; + return m_value.to_string(to) ? NULL : to; } - decimal_digits_t Item_decimal_precision(const Item *item) const override + my_decimal *val_decimal(my_decimal *to) override { - /* This will be needed if we ever allow cast from Fbt to DECIMAL. */ - return (FbtImpl::binary_length()*8+7)/10*3; // = bytes to decimal digits + my_decimal_set_zero(to); + return to; } - - /* - Returns how many digits a divisor adds into a division result. - See Item::divisor_precision_increment() in item.h for more comments. - */ - decimal_digits_t Item_divisor_precision_increment(const Item *) const override - { - return 0; - } - /** - Makes a temporary table Field to handle numeric aggregate functions, - e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc. - */ - Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override - { - DBUG_ASSERT(0); - return 0; - } - Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, - const Field *target) const override - { - const Record_addr tmp(NULL, Bit_addr(true)); - return new (table->in_use->mem_root) Field_fbt(&empty_clex_str, tmp); - } - // Fix attributes after the parser - bool Column_definition_fix_attributes(Column_definition *c) const override - { - c->length= FbtImpl::max_char_length(); - return false; - } - - bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, - Column_definition *def, handler *file, - ulonglong table_flags, - const Column_derived_attributes *derived_attr) - const override - { - def->prepare_stage1_simple(&my_charset_numeric); - return false; - } - - bool Column_definition_redefine_stage1(Column_definition *def, - const Column_definition *dup, - const handler *file) const override - { - def->redefine_stage1_common(dup, file); - def->set_compression_method(dup->compression_method()); - def->create_length_to_internal_length_string(); - return false; - } - - bool Column_definition_prepare_stage2(Column_definition *def, handler *file, - ulonglong table_flags) const override - { - def->pack_flag= FIELDFLAG_BINARY; - return false; - } - - bool partition_field_check(const LEX_CSTRING &field_name, - Item *item_expr) const override - { - if (item_expr->cmp_type() != STRING_RESULT) - { - my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); - return true; - } - return false; - } - - bool partition_field_append_value(String *to, Item *item_expr, - CHARSET_INFO *field_cs, - partition_value_print_mode_t mode) - const override - { - StringBuffer fbtstr; - Fbt_null fbt(item_expr); - if (fbt.is_null()) - { - my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); - return true; - } - return fbt.to_string(&fbtstr) || - to->append('\'') || - to->append(fbtstr) || - to->append('\''); - } - - Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, - const Record_addr &addr, - const Type_all_attributes &attr, - TABLE_SHARE *table) const override - { - return new (root) Field_fbt(name, addr); - } - - Field * make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, - const LEX_CSTRING *name, const Record_addr &addr, - const Bit_addr &bit, - const Column_definition_attributes *attr, - uint32 flags) const override - { - return new (mem_root) Field_fbt(name, addr); - } - void Column_definition_attributes_frm_pack(const Column_definition_attributes *def, - uchar *buff) const override - { - def->frm_pack_basic(buff); - def->frm_pack_charset(buff); - } - bool Column_definition_attributes_frm_unpack(Column_definition_attributes *def, - TABLE_SHARE *share, const uchar *buffer, - LEX_CUSTRING *gis_options) - const override - { - def->frm_unpack_basic(buffer); - return def->frm_unpack_charset(share, buffer); - } - void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, - String *) const override - { - DBUG_ASSERT(item->type_handler() == this); - NativeBuffer tmp; - item->val_native_result(current_thd, &tmp); - if (item->maybe_null()) - { - if (item->null_value) - { - memset(to, 0, FbtImpl::binary_length() + 1); - return; - } - *to++= 1; - } - DBUG_ASSERT(!item->null_value); - DBUG_ASSERT(FbtImpl::binary_length() == tmp.length()); - DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length); - FbtImpl::memory_to_record((char*) to, tmp.ptr()); - } - uint make_packed_sort_key_part(uchar *to, Item *item, - const SORT_FIELD_ATTR *sort_field, - String *) const override - { - DBUG_ASSERT(item->type_handler() == this); - NativeBuffer tmp; - item->val_native_result(current_thd, &tmp); - if (item->maybe_null()) - { - if (item->null_value) - { - *to++=0; - return 0; - } - *to++= 1; - } - DBUG_ASSERT(!item->null_value); - DBUG_ASSERT(FbtImpl::binary_length() == tmp.length()); - DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length); - FbtImpl::memory_to_record((char*) to, tmp.ptr()); - return tmp.length(); - } - void sort_length(THD *thd, const Type_std_attributes *item, - SORT_FIELD_ATTR *attr) const override - { - attr->original_length= attr->length= FbtImpl::binary_length(); - attr->suffix_length= 0; - } - uint32 max_display_length(const Item *item) const override - { - return FbtImpl::max_char_length(); - } - uint32 calc_pack_length(uint32 length) const override - { - return FbtImpl::binary_length(); - } - void Item_update_null_value(Item *item) const override - { - NativeBuffer tmp; - item->val_native(current_thd, &tmp); - } - bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override - { - value->m_type= DYN_COL_STRING; - String *str= item->val_str(&value->m_string); - if (str != &value->m_string && !item->null_value) - { - // "item" returned a non-NULL value - if (Fbt_null(*str).is_null()) - { - /* - The value was not-null, but conversion to FBT failed: - SELECT a, DECODE_ORACLE(fbtcol, 'garbage', '', '::01', '01') - FROM t1; - */ - thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, - name().ptr(), ErrConvString(str).ptr()); - value->m_type= DYN_COL_NULL; - return true; - } - // "item" returned a non-NULL value, and it was a valid FBT - value->m_string.set(str->ptr(), str->length(), str->charset()); - } - return check_null(item, value); - } - void Item_param_setup_conversion(THD *thd, Item_param *param) const override - { - param->setup_conversion_string(thd, thd->variables.character_set_client); - } - void Item_param_set_param_func(Item_param *param, - uchar **pos, ulong len) const override - { - param->set_param_str(pos, len); - } - bool Item_param_set_from_value(THD *thd, Item_param *param, - const Type_all_attributes *attr, - const st_value *val) const override - { - param->unsigned_flag= false; - param->setup_conversion_string(thd, attr->collation.collation); - /* - Exact value of max_length is not known unless fbt is converted to - charset of connection, so we have to set it later. - */ - return param->set_str(val->m_string.ptr(), val->m_string.length(), - attr->collation.collation, - attr->collation.collation); - } - bool Item_param_val_native(THD *thd, Item_param *item, Native *to) - const override - { - StringBuffer buffer; - String *str= item->val_str(&buffer); - if (!str) - return true; - Fbt_null tmp(*str); - return tmp.is_null() || tmp.to_native(to); - } - bool Item_send(Item *item, Protocol *p, st_value *buf) const override - { - return Item_send_str(item, p, buf); - } - int Item_save_in_field(Item *item, Field *field, bool no_conversions) - const override - { - if (field->type_handler() == this) - { - NativeBuffer tmp; - bool rc= item->val_native(current_thd, &tmp); - if (rc || item->null_value) - return set_field_to_null_with_conversions(field, no_conversions); - field->set_notnull(); - return field->store_native(tmp); - } - return item->save_str_in_field(field, no_conversions); - } - - String *print_item_value(THD *thd, Item *item, String *str) const override - { - StringBuffer buf; - String *result= item->val_str(&buf); - /* - TODO: This should eventually use one of these notations: - 1. CAST('xxx' AS Fbt) - Problem: CAST is not supported as a NAME_CONST() argument. - 2. Fbt'xxx' - Problem: This syntax is not supported by the parser yet. - */ - return !result || str->realloc(result->length() + 2) || - str->append(STRING_WITH_LEN("'")) || - str->append(result->ptr(), result->length()) || - str->append(STRING_WITH_LEN("'")) ? nullptr : str; - } - - /** - Check if - WHERE expr=value AND expr=const - can be rewritten as: - WHERE const=value AND expr=const - - "this" is the comparison handler that is used by "target". - - @param target - the predicate expr=value, - whose "expr" argument will be replaced to "const". - @param target_expr - the target's "expr" which will be replaced to "const". - @param target_value - the target's second argument, it will remain unchanged. - @param source - the equality predicate expr=const (or expr<=>const) - that can be used to rewrite the "target" part - (under certain conditions, see the code). - @param source_expr - the source's "expr". It should be exactly equal to - the target's "expr" to make condition rewrite possible. - @param source_const - the source's "const" argument, it will be inserted - into "target" instead of "expr". - */ - bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, - Item *target_value, Item_bool_func2 *source, - Item *source_expr, Item *source_const) - const override - { - /* - WHERE COALESCE(col)='xxx' AND COALESCE(col)=CONCAT(a); --> - WHERE COALESCE(col)='xxx' AND 'xxx'=CONCAT(a); - */ - return target->compare_type_handler() == source->compare_type_handler(); - } - bool subquery_type_allows_materialization(const Item *inner, - const Item *outer, bool) const override - { - /* - Example: - SELECT * FROM t1 WHERE a IN (SELECT col FROM t1 GROUP BY col); - Allow materialization only if the outer column is also FBT. - This can be changed for more relaxed rules in the future. - */ - DBUG_ASSERT(inner->type_handler() == this); - return outer->type_handler() == this; - } - /** - Make a simple constant replacement item for a constant "src", - so the new item can futher be used for comparison with "cmp", e.g.: - src = cmp -> replacement = cmp - - "this" is the type handler that is used to compare "src" and "cmp". - - @param thd - current thread, for mem_root - @param src - The item that we want to replace. It's a const item, - but it can be complex enough to calculate on every row. - @param cmp - The src's comparand. - @retval - a pointer to the created replacement Item - @retval - NULL, if could not create a replacement (e.g. on EOM). - NULL is also returned for ROWs, because instead of replacing - a Item_row to a new Item_row, Type_handler_row just replaces - its elements. - */ - Item *make_const_item_for_comparison(THD *thd, Item *src, - const Item *cmp) const override - { - Fbt_null tmp(src); - if (tmp.is_null()) - return new (thd->mem_root) Item_null(thd, src->name.str); - return new (thd->mem_root) Item_literal_fbt(thd, tmp); - } - Item_cache *Item_get_cache(THD *thd, const Item *item) const override - { - return new (thd->mem_root) Item_cache_fbt(thd); - } - - Item *create_typecast_item(THD *thd, Item *item, - const Type_cast_attributes &attr) const override - { - return new (thd->mem_root) Item_typecast_fbt(thd, item); - } - Item_copy *create_item_copy(THD *thd, Item *item) const override - { - return new (thd->mem_root) Item_copy_fbt(thd, item); - } - int cmp_native(const Native &a, const Native &b) const override - { - return FbtImpl::cmp(a.to_lex_cstring(), b.to_lex_cstring()); - } - bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override - { - return cmp->set_cmp_func_native(thd); - } - bool Item_const_eq(const Item_const *a, const Item_const *b, - bool binary_cmp) const override - { - return false; - } - bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, - Item *a, Item *b) const override - { - Fbt_null na(a), nb(b); - return !na.is_null() && !nb.is_null() && !na.cmp(nb); - } - bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, - Type_handler_hybrid_field_type *h, - Type_all_attributes *attr, - Item **items, uint nitems) const override - { - attr->Type_std_attributes::operator=(Type_std_attributes_fbt()); - h->set_handler(this); - /* - If some of the arguments cannot be safely converted to "FBT NOT NULL", - then mark the entire function nullability as NULL-able. - Otherwise, keep the generic nullability calculated by earlier stages: - - either by the most generic way in Item_func::fix_fields() - - or by Item_func_xxx::fix_length_and_dec() before the call of - Item_hybrid_func_fix_attributes() - IFNULL() is special. It does not need to test args[0]. - */ - uint first= dynamic_cast(attr) ? 1 : 0; - for (uint i= first; i < nitems; i++) - { - if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(items[i])) - { - attr->set_type_maybe_null(true); - break; - } - } - return false; - } - bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, - Item **items, uint nitems) const override - { - return Item_hybrid_func_fix_attributes(thd, func->func_name_cstring(), - func, func, items, nitems); - - } - bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override - { - func->Type_std_attributes::operator=(Type_std_attributes_fbt()); - func->set_handler(this); - return false; - } - bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *func) const override - { - return Item_func_or_sum_illegal_param(func); - } - bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *func) const override - { - return Item_func_or_sum_illegal_param(func); - } - bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *func) const override - { - return Item_func_or_sum_illegal_param(func); - } - - bool Item_val_native_with_conversion(THD *thd, Item *item, - Native *to) const override - { - if (item->type_handler() == this) - return item->val_native(thd, to); // No conversion needed - StringBuffer buffer; - String *str= item->val_str(&buffer); - return str ? character_or_binary_string_to_native(thd, str, to) : true; - } - bool Item_val_native_with_conversion_result(THD *thd, Item *item, - Native *to) const override - { - if (item->type_handler() == this) - return item->val_native_result(thd, to); // No conversion needed - StringBuffer buffer; - String *str= item->str_result(&buffer); - return str ? character_or_binary_string_to_native(thd, str, to) : true; - } - - bool Item_val_bool(Item *item) const override - { - NativeBuffer tmp; - if (item->val_native(current_thd, &tmp)) - return false; - return !Fbt::only_zero_bytes(tmp.ptr(), tmp.length()); - } - void Item_get_date(THD *thd, Item *item, Temporal::Warn *buff, - MYSQL_TIME *ltime, date_mode_t fuzzydate) const override + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override { set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); - } - - longlong Item_val_int_signed_typecast(Item *item) const override - { - DBUG_ASSERT(0); - return 0; - } - - longlong Item_val_int_unsigned_typecast(Item *item) const override - { - DBUG_ASSERT(0); - return 0; - } - - String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) - const override - { - NativeBuffer tmp; - if ((item->null_value= item->arguments()[0]->val_native(current_thd, &tmp))) - return nullptr; - DBUG_ASSERT(tmp.length() == FbtImpl::binary_length()); - if (str->set_hex(tmp.ptr(), tmp.length())) - { - str->length(0); - str->set_charset(item->collation.collation); - } - return str; - } - - String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *item, - String *str) const override - { - NativeBuffer native; - if (item->val_native(current_thd, &native)) - { - DBUG_ASSERT(item->null_value); - return nullptr; - } - DBUG_ASSERT(native.length() == FbtImpl::binary_length()); - Fbt_null tmp(native.ptr(), native.length()); - return tmp.is_null() || tmp.to_string(str) ? nullptr : str; - } - double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) - const override - { - return 0; - } - longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) - const override - { - return 0; - } - my_decimal * - Item_func_hybrid_field_type_val_decimal(Item_func_hybrid_field_type *, - my_decimal *to) const override - { - my_decimal_set_zero(to); - return to; - } - void Item_func_hybrid_field_type_get_date(THD *, - Item_func_hybrid_field_type *, - Temporal::Warn *, - MYSQL_TIME *to, - date_mode_t fuzzydate) - const override - { - set_zero_time(to, MYSQL_TIMESTAMP_TIME); - } - // WHERE is Item_func_min_max_val_native??? - String *Item_func_min_max_val_str(Item_func_min_max *func, String *str) - const override - { - Fbt_null tmp(func); - return tmp.is_null() || tmp.to_string(str) ? nullptr : str; - } - double Item_func_min_max_val_real(Item_func_min_max *) const override - { - return 0; - } - longlong Item_func_min_max_val_int(Item_func_min_max *) const override - { - return 0; - } - my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, - my_decimal *to) const override - { - my_decimal_set_zero(to); - return to; - } - bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *to, - date_mode_t fuzzydate) const override - { - set_zero_time(to, MYSQL_TIMESTAMP_TIME); return false; } + bool val_native(THD *thd, Native *to) override + { + return m_value.to_native(to); + } + void print(String *str, enum_query_type query_type) override + { + StringBuffer tmp; + tmp.append(singleton()->name().lex_cstring()); + my_caseup_str(&my_charset_latin1, tmp.c_ptr()); + str->append(tmp); + str->append('\''); + m_value.to_string(&tmp); + str->append(tmp); + str->append('\''); + } + Item *get_copy(THD *thd) override + { return get_item_copy(thd, this); } - bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override + // Non-overriding methods + void set_value(const Fbt &value) { - return false; - } - longlong Item_func_between_val_int(Item_func_between *func) const override - { - return func->val_int_cmp_native(); - } - - cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override - { - return new (thd->mem_root) cmp_item_fbt; - } - - in_vector *make_in_vector(THD *thd, const Item_func_in *func, - uint nargs) const override - { - return new (thd->mem_root) in_fbt(thd, nargs); - } - - bool Item_func_in_fix_comparator_compatible_types(THD *thd, - Item_func_in *func) - const override - { - if (func->compatible_types_scalar_bisection_possible()) - { - return func->value_list_convert_const_to_int(thd) || - func->fix_for_scalar_comparison_using_bisection(thd); - } - return - func->fix_for_scalar_comparison_using_cmp_items(thd, - 1U << (uint) STRING_RESULT); - } - bool Item_func_round_fix_length_and_dec(Item_func_round *func) const override - { - return Item_func_or_sum_illegal_param(func); - } - bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *func) const override - { - return Item_func_or_sum_illegal_param(func); - } - - bool Item_func_abs_fix_length_and_dec(Item_func_abs *func) const override - { - return Item_func_or_sum_illegal_param(func); - } - - bool Item_func_neg_fix_length_and_dec(Item_func_neg *func) const override - { - return Item_func_or_sum_illegal_param(func); - } - - bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) - const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) - const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) - const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) - const override - { - if (item->cast_charset() == &my_charset_bin) - { - static Item_char_typecast_func_handler_fbt_to_binary - item_char_typecast_func_handler_fbt_to_binary; - item->fix_length_and_dec_native_to_binary(FbtImpl::binary_length()); - item->set_func_handler(&item_char_typecast_func_handler_fbt_to_binary); - return false; - } - item->fix_length_and_dec_str(); - return false; - } - - bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) - const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_func_plus_fix_length_and_dec(Item_func_plus *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_func_minus_fix_length_and_dec(Item_func_minus *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_func_mul_fix_length_and_dec(Item_func_mul *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_func_div_fix_length_and_dec(Item_func_div *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - bool Item_func_mod_fix_length_and_dec(Item_func_mod *item) const override - { - return Item_func_or_sum_illegal_param(item); - } - }; - - class cmp_item_fbt: public cmp_item_scalar - { - Fbt m_native; - public: - cmp_item_fbt() - :cmp_item_scalar(), - m_native(Fbt::zero()) - { } - void store_value(Item *item) override - { - m_native= Fbt(item, &m_null_value); - } - int cmp_not_null(const Value *val) override - { - DBUG_ASSERT(!val->is_null()); - DBUG_ASSERT(val->is_string()); - Fbt_null tmp(val->m_string); - DBUG_ASSERT(!tmp.is_null()); - return m_native.cmp(tmp); - } - int cmp(Item *arg) override - { - Fbt_null tmp(arg); - return m_null_value || tmp.is_null() ? UNKNOWN : m_native.cmp(tmp) != 0; - } - int compare(cmp_item *ci) override - { - cmp_item_fbt *tmp= static_cast(ci); - DBUG_ASSERT(!m_null_value); - DBUG_ASSERT(!tmp->m_null_value); - return m_native.cmp(tmp->m_native); - } - cmp_item *make_same(THD *thd) override - { - return new (thd->mem_root) cmp_item_fbt(); + m_value= value; } }; @@ -1076,7 +367,7 @@ public: if (get_thd()->count_cuted_fields <= CHECK_FIELD_EXPRESSION) return; const TABLE_SHARE *s= table->s; - static const Name type_name= type_handler_fbt()->name(); + static const Name type_name= singleton()->name(); get_thd()->push_warning_truncated_value_for_field(level, type_name.ptr(), str.ptr(), s ? s->db.str : nullptr, s ? s->table_name.str : nullptr, field_name.str); @@ -1119,7 +410,7 @@ public: } const Type_handler *type_handler() const override { - return type_handler_fbt(); + return singleton(); } uint32 max_display_length() const override { return field_length; } bool str_needs_quotes() const override { return true; } @@ -1168,14 +459,14 @@ public: void sql_type(String &str) const override { - static Name name= type_handler_fbt()->name(); + static Name name= singleton()->name(); str.set_ascii(name.ptr(), name.length()); } void make_send_field(Send_field *to) override { Field::make_send_field(to); - to->set_data_type_name(type_handler_fbt()->name().lex_cstring()); + to->set_data_type_name(singleton()->name().lex_cstring()); } bool validate_value_in_record(THD *thd, const uchar *record) const override @@ -1491,13 +782,171 @@ public: uint size_of() const override { return sizeof(*this); } }; + + class cmp_item_fbt: public cmp_item_scalar + { + Fbt m_native; + public: + cmp_item_fbt() + :cmp_item_scalar(), + m_native(Fbt::zero()) + { } + void store_value(Item *item) override + { + m_native= Fbt(item, &m_null_value); + } + int cmp_not_null(const Value *val) override + { + DBUG_ASSERT(!val->is_null()); + DBUG_ASSERT(val->is_string()); + Fbt_null tmp(val->m_string); + DBUG_ASSERT(!tmp.is_null()); + return m_native.cmp(tmp); + } + int cmp(Item *arg) override + { + Fbt_null tmp(arg); + return m_null_value || tmp.is_null() ? UNKNOWN : m_native.cmp(tmp) != 0; + } + int compare(cmp_item *ci) override + { + cmp_item_fbt *tmp= static_cast(ci); + DBUG_ASSERT(!m_null_value); + DBUG_ASSERT(!tmp->m_null_value); + return m_native.cmp(tmp->m_native); + } + cmp_item *make_same(THD *thd) override + { + return new (thd->mem_root) cmp_item_fbt(); + } + }; + + class in_fbt :public in_vector + { + Fbt m_value; + static int cmp_fbt(void *cmp_arg, Fbt *a, Fbt *b) + { + return a->cmp(*b); + } + public: + in_fbt(THD *thd, uint elements) + :in_vector(thd, elements, sizeof(Fbt), (qsort2_cmp) cmp_fbt, 0), + m_value(Fbt::zero()) + { } + const Type_handler *type_handler() const override + { + return singleton(); + } + void set(uint pos, Item *item) override + { + Fbt *buff= &((Fbt *) base)[pos]; + Fbt_null value(item); + if (value.is_null()) + *buff= Fbt::zero(); + else + *buff= value; + } + uchar *get_value(Item *item) override + { + Fbt_null value(item); + if (value.is_null()) + return 0; + m_value= value; + return (uchar *) &m_value; + } + Item* create_item(THD *thd) override + { + return new (thd->mem_root) Item_literal_fbt(thd); + } + void value_to_item(uint pos, Item *item) override + { + const Fbt &buff= (((Fbt*) base)[pos]); + static_cast(item)->set_value(buff); + } + }; + + class Item_copy_fbt: public Item_copy + { + NativeBuffer m_value; + public: + Item_copy_fbt(THD *thd, Item *item_arg): Item_copy(thd, item_arg) {} + + bool val_native(THD *thd, Native *to) override + { + if (null_value) + return true; + return to->copy(m_value.ptr(), m_value.length()); + } + String *val_str(String *to) override + { + if (null_value) + return NULL; + Fbt_null tmp(m_value.ptr(), m_value.length()); + return tmp.is_null() || tmp.to_string(to) ? NULL : to; + } + my_decimal *val_decimal(my_decimal *to) override + { + my_decimal_set_zero(to); + return to; + } + double val_real() override + { + return 0; + } + longlong val_int() override + { + return 0; + } + bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override + { + set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); + return null_value; + } + void copy() override + { + null_value= item->val_native(current_thd, &m_value); + DBUG_ASSERT(null_value == item->null_value); + } + int save_in_field(Field *field, bool no_conversions) override + { + return Item::save_in_field(field, no_conversions); + } + Item *get_copy(THD *thd) override + { return get_item_copy(thd, this); } + }; + + class Item_char_typecast_func_handler_fbt_to_binary: + public Item_handled_func::Handler_str + { + public: + const Type_handler *return_type_handler(const Item_handled_func *item) + const override + { + if (item->max_length > MAX_FIELD_VARCHARLENGTH) + return Type_handler::blob_type_handler(item->max_length); + if (item->max_length > 255) + return &type_handler_varchar; + return &type_handler_string; + } + bool fix_length_and_dec(Item_handled_func *xitem) const override + { + return false; + } + String *val_str(Item_handled_func *item, String *to) const override + { + DBUG_ASSERT(dynamic_cast(item)); + return static_cast(item)-> + val_str_binary_from_native(to); + } + }; + class Item_typecast_fbt: public Item_func { public: Item_typecast_fbt(THD *thd, Item *a) :Item_func(thd, a) {} const Type_handler *type_handler() const override - { return type_handler_fbt(); } + { return singleton(); } enum Functype functype() const override { return CHAR_TYPECAST_FUNC; } bool eq(const Item *item, bool binary_cmp) const override @@ -1514,7 +963,7 @@ public: } LEX_CSTRING func_name_cstring() const override { - static Name name= type_handler_fbt()->name(); + static Name name= singleton()->name(); size_t len= 9+name.length()+1; char *buf= (char*)current_thd->alloc(len); strmov(strmov(buf, "cast_as_"), name.ptr()); @@ -1525,7 +974,7 @@ public: str->append(STRING_WITH_LEN("cast(")); args[0]->print(str, query_type); str->append(STRING_WITH_LEN(" as ")); - str->append(type_handler_fbt()->name().lex_cstring()); + str->append(singleton()->name().lex_cstring()); str->append(')'); } bool fix_length_and_dec() override @@ -1572,7 +1021,7 @@ public: NativeBuffer m_value; public: Item_cache_fbt(THD *thd) - :Item_cache(thd, type_handler_fbt()) { } + :Item_cache(thd, singleton()) { } Item *get_copy(THD *thd) { return get_item_copy(thd, this); } bool cache_value() @@ -1640,256 +1089,813 @@ public: } }; - class Item_literal_fbt: public Item_literal + /* =[ methods ]=============================================== */ +private: + + bool character_or_binary_string_to_native(THD *thd, const String *str, + Native *to) const { - Fbt m_value; - public: - Item_literal_fbt(THD *thd) - :Item_literal(thd), - m_value(Fbt::zero()) - { } - Item_literal_fbt(THD *thd, const Fbt &value) - :Item_literal(thd), - m_value(value) - { } - const Type_handler *type_handler() const override + if (str->charset() == &my_charset_bin) { - return type_handler_fbt(); - } - longlong val_int() override - { - return 0; - } - double val_real() override - { - return 0; - } - String *val_str(String *to) override - { - return m_value.to_string(to) ? NULL : to; - } - my_decimal *val_decimal(my_decimal *to) override - { - my_decimal_set_zero(to); - return to; - } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override - { - set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); - return false; - } - bool val_native(THD *thd, Native *to) override - { - return m_value.to_native(to); - } - void print(String *str, enum_query_type query_type) override - { - StringBuffer tmp; - tmp.append(type_handler_fbt()->name().lex_cstring()); - my_caseup_str(&my_charset_latin1, tmp.c_ptr()); - str->append(tmp); - str->append('\''); - m_value.to_string(&tmp); - str->append(tmp); - str->append('\''); - } - Item *get_copy(THD *thd) override - { return get_item_copy(thd, this); } - - // Non-overriding methods - void set_value(const Fbt &value) - { - m_value= value; - } - }; - - class Item_copy_fbt: public Item_copy - { - NativeBuffer m_value; - public: - Item_copy_fbt(THD *thd, Item *item_arg): Item_copy(thd, item_arg) {} - - bool val_native(THD *thd, Native *to) override - { - if (null_value) + // Convert from a binary string + if (str->length() != FbtImpl::binary_length() || + to->copy(str->ptr(), str->length())) + { + thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, + name().ptr(), ErrConvString(str).ptr()); return true; - return to->copy(m_value.ptr(), m_value.length()); - } - String *val_str(String *to) override - { - if (null_value) - return NULL; - Fbt_null tmp(m_value.ptr(), m_value.length()); - return tmp.is_null() || tmp.to_string(to) ? NULL : to; - } - my_decimal *val_decimal(my_decimal *to) override - { - my_decimal_set_zero(to); - return to; - } - double val_real() override - { - return 0; - } - longlong val_int() override - { - return 0; - } - bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override - { - set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); - return null_value; - } - void copy() override - { - null_value= item->val_native(current_thd, &m_value); - DBUG_ASSERT(null_value == item->null_value); - } - int save_in_field(Field *field, bool no_conversions) override - { - return Item::save_in_field(field, no_conversions); - } - Item *get_copy(THD *thd) override - { return get_item_copy(thd, this); } - }; - - class in_fbt :public in_vector - { - Fbt m_value; - static int cmp_fbt(void *cmp_arg, Fbt *a, Fbt *b) - { - return a->cmp(*b); - } - public: - in_fbt(THD *thd, uint elements) - :in_vector(thd, elements, sizeof(Fbt), (qsort2_cmp) cmp_fbt, 0), - m_value(Fbt::zero()) - { } - const Type_handler *type_handler() const override - { - return type_handler_fbt(); - } - void set(uint pos, Item *item) override - { - Fbt *buff= &((Fbt *) base)[pos]; - Fbt_null value(item); - if (value.is_null()) - *buff= Fbt::zero(); - else - *buff= value; - } - uchar *get_value(Item *item) override - { - Fbt_null value(item); - if (value.is_null()) - return 0; - m_value= value; - return (uchar *) &m_value; - } - Item* create_item(THD *thd) override - { - return new (thd->mem_root) Item_literal_fbt(thd); - } - void value_to_item(uint pos, Item *item) override - { - const Fbt &buff= (((Fbt*) base)[pos]); - static_cast(item)->set_value(buff); - } - }; - - class Item_char_typecast_func_handler_fbt_to_binary: - public Item_handled_func::Handler_str - { - public: - const Type_handler *return_type_handler(const Item_handled_func *item) - const override - { - if (item->max_length > MAX_FIELD_VARCHARLENGTH) - return Type_handler::blob_type_handler(item->max_length); - if (item->max_length > 255) - return &type_handler_varchar; - return &type_handler_string; - } - bool fix_length_and_dec(Item_handled_func *xitem) const override - { + } return false; } - String *val_str(Item_handled_func *item, String *to) const override - { - DBUG_ASSERT(dynamic_cast(item)); - return static_cast(item)-> - val_str_binary_from_native(to); - } - }; + // Convert from a character string + Fbt_null tmp(*str); + if (tmp.is_null()) + thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, + name().ptr(), ErrConvString(str).ptr()); + return tmp.is_null() || tmp.to_native(to); + } - class Type_collection_fbt: public Type_collection +public: + ~Type_handler_fbt() override {} + + const Type_collection *type_collection() const override { - const Type_handler *aggregate_common(const Type_handler *a, - const Type_handler *b) const - { - if (a == b) - return a; - return NULL; - } - const Type_handler *aggregate_if_string(const Type_handler *a, - const Type_handler *b) const - { - static const Type_aggregator::Pair agg[]= - { - {type_handler_fbt(), &type_handler_null, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_varchar, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_string, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_tiny_blob, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_blob, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_medium_blob, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_long_blob, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_hex_hybrid, type_handler_fbt()}, - {NULL,NULL,NULL} - }; - return Type_aggregator::find_handler_in_array(agg, a, b, true); - } - public: - const Type_handler *aggregate_for_result(const Type_handler *a, - const Type_handler *b) - const override - { - const Type_handler *h; - if ((h= aggregate_common(a, b)) || - (h= aggregate_if_string(a, b))) - return h; - return NULL; - } + static Type_collection_fbt type_collection_fbt; + return &type_collection_fbt; + } - const Type_handler *aggregate_for_min_max(const Type_handler *a, - const Type_handler *b) + const Name &default_value() const override + { + return FbtImpl::default_value(); + } + ulong KEY_pack_flags(uint column_nr) const override + { + return FbtImpl::KEY_pack_flags(column_nr); + } + protocol_send_type_t protocol_send_type() const override + { + return PROTOCOL_SEND_STRING; + } + bool Item_append_extended_type_info(Send_field_extended_metadata *to, + const Item *item) const override + { + return to->set_data_type_name(name().lex_cstring()); + } + + enum_field_types field_type() const override + { + return MYSQL_TYPE_STRING; + } + + Item_result result_type() const override + { + return STRING_RESULT; + } + + Item_result cmp_type() const override + { + return STRING_RESULT; + } + + enum_dynamic_column_type dyncol_type(const Type_all_attributes *attr) + const override + { + return DYN_COL_STRING; + } + + uint32 max_display_length_for_field(const Conv_source &src) const override + { + return FbtImpl::max_char_length(); + } + + const Type_handler *type_handler_for_comparison() const override + { + return this; + } + + int stored_field_cmp_to_item(THD *thd, Field *field, Item *item) const override + { + DBUG_ASSERT(field->type_handler() == this); + Fbt_null ni(item); // Convert Item to Fbt + if (ni.is_null()) + return 0; + NativeBuffer tmp; + if (field->val_native(&tmp)) + { + DBUG_ASSERT(0); + return 0; + } + return -ni.cmp(tmp); + } + CHARSET_INFO *charset_for_protocol(const Item *item) const override + { + return item->collation.collation; + } + + bool is_scalar_type() const override { return true; } + bool is_val_native_ready() const override { return true; } + bool can_return_int() const override { return false; } + bool can_return_decimal() const override { return false; } + bool can_return_real() const override { return false; } + bool can_return_str() const override { return true; } + bool can_return_text() const override { return true; } + bool can_return_date() const override { return false; } + bool can_return_time() const override { return false; } + bool convert_to_binary_using_val_native() const override { return true; } + + decimal_digits_t Item_time_precision(THD *thd, Item *item) const override + { + return 0; + } + decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const override + { + return 0; + } + decimal_digits_t Item_decimal_scale(const Item *item) const override + { + return 0; + } + decimal_digits_t Item_decimal_precision(const Item *item) const override + { + /* This will be needed if we ever allow cast from Fbt to DECIMAL. */ + return (FbtImpl::binary_length()*8+7)/10*3; // = bytes to decimal digits + } + + /* + Returns how many digits a divisor adds into a division result. + See Item::divisor_precision_increment() in item.h for more comments. + */ + decimal_digits_t Item_divisor_precision_increment(const Item *) const override + { + return 0; + } + /** + Makes a temporary table Field to handle numeric aggregate functions, + e.g. SUM(DISTINCT expr), AVG(DISTINCT expr), etc. + */ + Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const override + { + DBUG_ASSERT(0); + return 0; + } + Field *make_conversion_table_field(MEM_ROOT *root, TABLE *table, uint metadata, + const Field *target) const override + { + const Record_addr tmp(NULL, Bit_addr(true)); + return new (table->in_use->mem_root) Field_fbt(&empty_clex_str, tmp); + } + // Fix attributes after the parser + bool Column_definition_fix_attributes(Column_definition *c) const override + { + c->length= FbtImpl::max_char_length(); + return false; + } + + bool Column_definition_prepare_stage1(THD *thd, MEM_ROOT *mem_root, + Column_definition *def, + handler *file, ulonglong table_flags, + const Column_derived_attributes *derived_attr) + const override + { + def->prepare_stage1_simple(&my_charset_numeric); + return false; + } + + bool Column_definition_redefine_stage1(Column_definition *def, + const Column_definition *dup, + const handler *file) const override + { + def->redefine_stage1_common(dup, file); + def->set_compression_method(dup->compression_method()); + def->create_length_to_internal_length_string(); + return false; + } + + bool Column_definition_prepare_stage2(Column_definition *def, handler *file, + ulonglong table_flags) const override + { + def->pack_flag= FIELDFLAG_BINARY; + return false; + } + + bool partition_field_check(const LEX_CSTRING &field_name, + Item *item_expr) const override + { + if (item_expr->cmp_type() != STRING_RESULT) + { + my_error(ER_WRONG_TYPE_COLUMN_VALUE_ERROR, MYF(0)); + return true; + } + return false; + } + + bool partition_field_append_value(String *to, Item *item_expr, + CHARSET_INFO *field_cs, + partition_value_print_mode_t mode) + const override + { + StringBuffer fbtstr; + Fbt_null fbt(item_expr); + if (fbt.is_null()) + { + my_error(ER_PARTITION_FUNCTION_IS_NOT_ALLOWED, MYF(0)); + return true; + } + return fbt.to_string(&fbtstr) || + to->append('\'') || + to->append(fbtstr) || + to->append('\''); + } + + Field *make_table_field(MEM_ROOT *root, const LEX_CSTRING *name, + const Record_addr &addr, + const Type_all_attributes &attr, + TABLE_SHARE *table) const override + { + return new (root) Field_fbt(name, addr); + } + + Field * make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root, + const LEX_CSTRING *name, const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const override + { + return new (mem_root) Field_fbt(name, addr); + } + void Column_definition_attributes_frm_pack(const Column_definition_attributes *def, + uchar *buff) const override + { + def->frm_pack_basic(buff); + def->frm_pack_charset(buff); + } + bool Column_definition_attributes_frm_unpack(Column_definition_attributes *def, + TABLE_SHARE *share, const uchar *buffer, + LEX_CUSTRING *gis_options) + const override + { + def->frm_unpack_basic(buffer); + return def->frm_unpack_charset(share, buffer); + } + void make_sort_key_part(uchar *to, Item *item, const SORT_FIELD_ATTR *sort_field, + String *) const override + { + DBUG_ASSERT(item->type_handler() == this); + NativeBuffer tmp; + item->val_native_result(current_thd, &tmp); + if (item->maybe_null()) + { + if (item->null_value) + { + memset(to, 0, FbtImpl::binary_length() + 1); + return; + } + *to++= 1; + } + DBUG_ASSERT(!item->null_value); + DBUG_ASSERT(FbtImpl::binary_length() == tmp.length()); + DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length); + FbtImpl::memory_to_record((char*) to, tmp.ptr()); + } + uint make_packed_sort_key_part(uchar *to, Item *item, + const SORT_FIELD_ATTR *sort_field, + String *) const override + { + DBUG_ASSERT(item->type_handler() == this); + NativeBuffer tmp; + item->val_native_result(current_thd, &tmp); + if (item->maybe_null()) + { + if (item->null_value) + { + *to++=0; + return 0; + } + *to++= 1; + } + DBUG_ASSERT(!item->null_value); + DBUG_ASSERT(FbtImpl::binary_length() == tmp.length()); + DBUG_ASSERT(FbtImpl::binary_length() == sort_field->length); + FbtImpl::memory_to_record((char*) to, tmp.ptr()); + return tmp.length(); + } + void sort_length(THD *thd, const Type_std_attributes *item, + SORT_FIELD_ATTR *attr) const override + { + attr->original_length= attr->length= FbtImpl::binary_length(); + attr->suffix_length= 0; + } + uint32 max_display_length(const Item *item) const override + { + return FbtImpl::max_char_length(); + } + uint32 calc_pack_length(uint32 length) const override + { + return FbtImpl::binary_length(); + } + void Item_update_null_value(Item *item) const override + { + NativeBuffer tmp; + item->val_native(current_thd, &tmp); + } + bool Item_save_in_value(THD *thd, Item *item, st_value *value) const override + { + value->m_type= DYN_COL_STRING; + String *str= item->val_str(&value->m_string); + if (str != &value->m_string && !item->null_value) + { + // "item" returned a non-NULL value + if (Fbt_null(*str).is_null()) + { + /* + The value was not-null, but conversion to FBT failed: + SELECT a, DECODE_ORACLE(fbtcol, 'garbage', '', '::01', '01') + FROM t1; + */ + thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, + name().ptr(), ErrConvString(str).ptr()); + value->m_type= DYN_COL_NULL; + return true; + } + // "item" returned a non-NULL value, and it was a valid FBT + value->m_string.set(str->ptr(), str->length(), str->charset()); + } + return check_null(item, value); + } + void Item_param_setup_conversion(THD *thd, Item_param *param) const override + { + param->setup_conversion_string(thd, thd->variables.character_set_client); + } + void Item_param_set_param_func(Item_param *param, + uchar **pos, ulong len) const override + { + param->set_param_str(pos, len); + } + bool Item_param_set_from_value(THD *thd, Item_param *param, + const Type_all_attributes *attr, + const st_value *val) const override + { + param->unsigned_flag= false; + param->setup_conversion_string(thd, attr->collation.collation); + /* + Exact value of max_length is not known unless fbt is converted to + charset of connection, so we have to set it later. + */ + return param->set_str(val->m_string.ptr(), val->m_string.length(), + attr->collation.collation, + attr->collation.collation); + } + bool Item_param_val_native(THD *thd, Item_param *item, Native *to) + const override + { + StringBuffer buffer; + String *str= item->val_str(&buffer); + if (!str) + return true; + Fbt_null tmp(*str); + return tmp.is_null() || tmp.to_native(to); + } + bool Item_send(Item *item, Protocol *p, st_value *buf) const override + { + return Item_send_str(item, p, buf); + } + int Item_save_in_field(Item *item, Field *field, bool no_conversions) + const override + { + if (field->type_handler() == this) + { + NativeBuffer tmp; + bool rc= item->val_native(current_thd, &tmp); + if (rc || item->null_value) + return set_field_to_null_with_conversions(field, no_conversions); + field->set_notnull(); + return field->store_native(tmp); + } + return item->save_str_in_field(field, no_conversions); + } + + String *print_item_value(THD *thd, Item *item, String *str) const override + { + StringBuffer buf; + String *result= item->val_str(&buf); + /* + TODO: This should eventually use one of these notations: + 1. CAST('xxx' AS Fbt) + Problem: CAST is not supported as a NAME_CONST() argument. + 2. Fbt'xxx' + Problem: This syntax is not supported by the parser yet. + */ + return !result || str->realloc(result->length() + 2) || + str->append(STRING_WITH_LEN("'")) || + str->append(result->ptr(), result->length()) || + str->append(STRING_WITH_LEN("'")) ? nullptr : str; + } + + /** + Check if + WHERE expr=value AND expr=const + can be rewritten as: + WHERE const=value AND expr=const + + "this" is the comparison handler that is used by "target". + + @param target - the predicate expr=value, + whose "expr" argument will be replaced to "const". + @param target_expr - the target's "expr" which will be replaced to "const". + @param target_value - the target's second argument, it will remain unchanged. + @param source - the equality predicate expr=const (or expr<=>const) + that can be used to rewrite the "target" part + (under certain conditions, see the code). + @param source_expr - the source's "expr". It should be exactly equal to + the target's "expr" to make condition rewrite possible. + @param source_const - the source's "const" argument, it will be inserted + into "target" instead of "expr". + */ + bool can_change_cond_ref_to_const(Item_bool_func2 *target, Item *target_expr, + Item *target_value, Item_bool_func2 *source, + Item *source_expr, Item *source_const) + const override + { + /* + WHERE COALESCE(col)='xxx' AND COALESCE(col)=CONCAT(a); --> + WHERE COALESCE(col)='xxx' AND 'xxx'=CONCAT(a); + */ + return target->compare_type_handler() == source->compare_type_handler(); + } + bool subquery_type_allows_materialization(const Item *inner, + const Item *outer, bool) const override + { + /* + Example: + SELECT * FROM t1 WHERE a IN (SELECT col FROM t1 GROUP BY col); + Allow materialization only if the outer column is also FBT. + This can be changed for more relaxed rules in the future. + */ + DBUG_ASSERT(inner->type_handler() == this); + return outer->type_handler() == this; + } + /** + Make a simple constant replacement item for a constant "src", + so the new item can futher be used for comparison with "cmp", e.g.: + src = cmp -> replacement = cmp + + "this" is the type handler that is used to compare "src" and "cmp". + + @param thd - current thread, for mem_root + @param src - The item that we want to replace. It's a const item, + but it can be complex enough to calculate on every row. + @param cmp - The src's comparand. + @retval - a pointer to the created replacement Item + @retval - NULL, if could not create a replacement (e.g. on EOM). + NULL is also returned for ROWs, because instead of replacing + a Item_row to a new Item_row, Type_handler_row just replaces + its elements. + */ + Item *make_const_item_for_comparison(THD *thd, Item *src, + const Item *cmp) const override + { + Fbt_null tmp(src); + if (tmp.is_null()) + return new (thd->mem_root) Item_null(thd, src->name.str); + return new (thd->mem_root) Item_literal_fbt(thd, tmp); + } + Item_cache *Item_get_cache(THD *thd, const Item *item) const override + { + return new (thd->mem_root) Item_cache_fbt(thd); + } + + Item *create_typecast_item(THD *thd, Item *item, + const Type_cast_attributes &attr) const override + { + return new (thd->mem_root) Item_typecast_fbt(thd, item); + } + Item_copy *create_item_copy(THD *thd, Item *item) const override + { + return new (thd->mem_root) Item_copy_fbt(thd, item); + } + int cmp_native(const Native &a, const Native &b) const override + { + return FbtImpl::cmp(a.to_lex_cstring(), b.to_lex_cstring()); + } + bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override + { + return cmp->set_cmp_func_native(thd); + } + bool Item_const_eq(const Item_const *a, const Item_const *b, + bool binary_cmp) const override + { + return false; + } + bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr, + Item *a, Item *b) const override + { + Fbt_null na(a), nb(b); + return !na.is_null() && !nb.is_null() && !na.cmp(nb); + } + bool Item_hybrid_func_fix_attributes(THD *thd, const LEX_CSTRING &name, + Type_handler_hybrid_field_type *h, + Type_all_attributes *attr, + Item **items, uint nitems) const override + { + attr->Type_std_attributes::operator=(Type_std_attributes_fbt()); + h->set_handler(this); + /* + If some of the arguments cannot be safely converted to "FBT NOT NULL", + then mark the entire function nullability as NULL-able. + Otherwise, keep the generic nullability calculated by earlier stages: + - either by the most generic way in Item_func::fix_fields() + - or by Item_func_xxx::fix_length_and_dec() before the call of + Item_hybrid_func_fix_attributes() + IFNULL() is special. It does not need to test args[0]. + */ + uint first= dynamic_cast(attr) ? 1 : 0; + for (uint i= first; i < nitems; i++) + { + if (Fbt::fix_fields_maybe_null_on_conversion_to_fbt(items[i])) + { + attr->set_type_maybe_null(true); + break; + } + } + return false; + } + bool Item_func_min_max_fix_attributes(THD *thd, Item_func_min_max *func, + Item **items, uint nitems) const override + { + return Item_hybrid_func_fix_attributes(thd, func->func_name_cstring(), + func, func, items, nitems); + + } + bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *func) const override + { + func->Type_std_attributes::operator=(Type_std_attributes_fbt()); + func->set_handler(this); + return false; + } + bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *func) const override + { + return Item_func_or_sum_illegal_param(func); + } + bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *func) const override + { + return Item_func_or_sum_illegal_param(func); + } + bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *func) const override + { + return Item_func_or_sum_illegal_param(func); + } + + bool Item_val_native_with_conversion(THD *thd, Item *item, + Native *to) const override + { + if (item->type_handler() == this) + return item->val_native(thd, to); // No conversion needed + StringBuffer buffer; + String *str= item->val_str(&buffer); + return str ? character_or_binary_string_to_native(thd, str, to) : true; + } + bool Item_val_native_with_conversion_result(THD *thd, Item *item, + Native *to) const override + { + if (item->type_handler() == this) + return item->val_native_result(thd, to); // No conversion needed + StringBuffer buffer; + String *str= item->str_result(&buffer); + return str ? character_or_binary_string_to_native(thd, str, to) : true; + } + + bool Item_val_bool(Item *item) const override + { + NativeBuffer tmp; + if (item->val_native(current_thd, &tmp)) + return false; + return !Fbt::only_zero_bytes(tmp.ptr(), tmp.length()); + } + void Item_get_date(THD *thd, Item *item, Temporal::Warn *buff, + MYSQL_TIME *ltime, date_mode_t fuzzydate) const override + { + set_zero_time(ltime, MYSQL_TIMESTAMP_TIME); + } + + longlong Item_val_int_signed_typecast(Item *item) const override + { + DBUG_ASSERT(0); + return 0; + } + + longlong Item_val_int_unsigned_typecast(Item *item) const override + { + DBUG_ASSERT(0); + return 0; + } + + String *Item_func_hex_val_str_ascii(Item_func_hex *item, String *str) + const override + { + NativeBuffer tmp; + if ((item->null_value= item->arguments()[0]->val_native(current_thd, &tmp))) + return nullptr; + DBUG_ASSERT(tmp.length() == FbtImpl::binary_length()); + if (str->set_hex(tmp.ptr(), tmp.length())) + { + str->length(0); + str->set_charset(item->collation.collation); + } + return str; + } + + String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *item, + String *str) const override + { + NativeBuffer native; + if (item->val_native(current_thd, &native)) + { + DBUG_ASSERT(item->null_value); + return nullptr; + } + DBUG_ASSERT(native.length() == FbtImpl::binary_length()); + Fbt_null tmp(native.ptr(), native.length()); + return tmp.is_null() || tmp.to_string(str) ? nullptr : str; + } + double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *) const override - { - return aggregate_for_result(a, b); - } + { + return 0; + } + longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *) + const override + { + return 0; + } + my_decimal * + Item_func_hybrid_field_type_val_decimal(Item_func_hybrid_field_type *, + my_decimal *to) const override + { + my_decimal_set_zero(to); + return to; + } + void Item_func_hybrid_field_type_get_date(THD *, + Item_func_hybrid_field_type *, + Temporal::Warn *, + MYSQL_TIME *to, + date_mode_t fuzzydate) + const override + { + set_zero_time(to, MYSQL_TIMESTAMP_TIME); + } + // WHERE is Item_func_min_max_val_native??? + String *Item_func_min_max_val_str(Item_func_min_max *func, String *str) + const override + { + Fbt_null tmp(func); + return tmp.is_null() || tmp.to_string(str) ? nullptr : str; + } + double Item_func_min_max_val_real(Item_func_min_max *) const override + { + return 0; + } + longlong Item_func_min_max_val_int(Item_func_min_max *) const override + { + return 0; + } + my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *, + my_decimal *to) const override + { + my_decimal_set_zero(to); + return to; + } + bool Item_func_min_max_get_date(THD *thd, Item_func_min_max*, MYSQL_TIME *to, + date_mode_t fuzzydate) const override + { + set_zero_time(to, MYSQL_TIMESTAMP_TIME); + return false; + } - const Type_handler *aggregate_for_comparison(const Type_handler *a, - const Type_handler *b) - const override - { - if (const Type_handler *h= aggregate_common(a, b)) - return h; - static const Type_aggregator::Pair agg[]= - { - {type_handler_fbt(), &type_handler_null, type_handler_fbt()}, - {type_handler_fbt(), &type_handler_long_blob, type_handler_fbt()}, - {NULL,NULL,NULL} - }; - return Type_aggregator::find_handler_in_array(agg, a, b, true); - } + bool Item_func_between_fix_length_and_dec(Item_func_between *func) const override + { + return false; + } + longlong Item_func_between_val_int(Item_func_between *func) const override + { + return func->val_int_cmp_native(); + } - const Type_handler *aggregate_for_num_op(const Type_handler *a, - const Type_handler *b) + cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override + { + return new (thd->mem_root) cmp_item_fbt; + } + + in_vector *make_in_vector(THD *thd, const Item_func_in *func, + uint nargs) const override + { + return new (thd->mem_root) in_fbt(thd, nargs); + } + + bool Item_func_in_fix_comparator_compatible_types(THD *thd, + Item_func_in *func) + const override + { + if (func->compatible_types_scalar_bisection_possible()) + { + return func->value_list_convert_const_to_int(thd) || + func->fix_for_scalar_comparison_using_bisection(thd); + } + return + func->fix_for_scalar_comparison_using_cmp_items(thd, + 1U << (uint) STRING_RESULT); + } + bool Item_func_round_fix_length_and_dec(Item_func_round *func) const override + { + return Item_func_or_sum_illegal_param(func); + } + bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *func) const override + { + return Item_func_or_sum_illegal_param(func); + } + + bool Item_func_abs_fix_length_and_dec(Item_func_abs *func) const override + { + return Item_func_or_sum_illegal_param(func); + } + + bool Item_func_neg_fix_length_and_dec(Item_func_neg *func) const override + { + return Item_func_or_sum_illegal_param(func); + } + + bool Item_func_signed_fix_length_and_dec(Item_func_signed *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *item) + const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *item) + const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *item) + const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *item) const override + { + if (item->cast_charset() == &my_charset_bin) { - return NULL; + static Item_char_typecast_func_handler_fbt_to_binary + item_char_typecast_func_handler_fbt_to_binary; + item->fix_length_and_dec_native_to_binary(FbtImpl::binary_length()); + item->set_func_handler(&item_char_typecast_func_handler_fbt_to_binary); + return false; } - }; - static Type_handler_fbt *type_handler_fbt() + item->fix_length_and_dec_str(); + return false; + } + + bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *item) + const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_func_plus_fix_length_and_dec(Item_func_plus *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_func_minus_fix_length_and_dec(Item_func_minus *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_func_mul_fix_length_and_dec(Item_func_mul *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_func_div_fix_length_and_dec(Item_func_div *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + bool Item_func_mod_fix_length_and_dec(Item_func_mod *item) const override + { + return Item_func_or_sum_illegal_param(item); + } + + static Type_handler_fbt *singleton() { static Type_handler_fbt th; return &th; From af38a8b4383858d47bcc576e5a8bfc47b84c6f59 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 26 Jun 2023 17:47:47 +0200 Subject: [PATCH 13/40] cleanup: move Type_collection_fbt<> template out of Type_handler_fbt<> --- sql/sql_type_fixedbin.h | 149 +++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 71 deletions(-) diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h index fb9ec6a5a5a..134e76e8cb5 100644 --- a/sql/sql_type_fixedbin.h +++ b/sql/sql_type_fixedbin.h @@ -31,7 +31,9 @@ /***********************************************************************/ -template +template class Type_collection_fbt; + +template > class Type_handler_fbt: public Type_handler { /* =[ internal helper classes ]=============================== */ @@ -210,74 +212,6 @@ public: /* =[ API classes ]=========================================== */ - class Type_collection_fbt: public Type_collection - { - const Type_handler *aggregate_common(const Type_handler *a, - const Type_handler *b) const - { - if (a == b) - return a; - return NULL; - } - const Type_handler *aggregate_if_string(const Type_handler *a, - const Type_handler *b) const - { - static const Type_aggregator::Pair agg[]= - { - {singleton(), &type_handler_null, singleton()}, - {singleton(), &type_handler_varchar, singleton()}, - {singleton(), &type_handler_string, singleton()}, - {singleton(), &type_handler_tiny_blob, singleton()}, - {singleton(), &type_handler_blob, singleton()}, - {singleton(), &type_handler_medium_blob, singleton()}, - {singleton(), &type_handler_long_blob, singleton()}, - {singleton(), &type_handler_hex_hybrid, singleton()}, - {NULL,NULL,NULL} - }; - return Type_aggregator::find_handler_in_array(agg, a, b, true); - } - public: - const Type_handler *aggregate_for_result(const Type_handler *a, - const Type_handler *b) - const override - { - const Type_handler *h; - if ((h= aggregate_common(a, b)) || - (h= aggregate_if_string(a, b))) - return h; - return NULL; - } - - const Type_handler *aggregate_for_min_max(const Type_handler *a, - const Type_handler *b) - const override - { - return aggregate_for_result(a, b); - } - - const Type_handler *aggregate_for_comparison(const Type_handler *a, - const Type_handler *b) - const override - { - if (const Type_handler *h= aggregate_common(a, b)) - return h; - static const Type_aggregator::Pair agg[]= - { - {singleton(), &type_handler_null, singleton()}, - {singleton(), &type_handler_long_blob, singleton()}, - {NULL,NULL,NULL} - }; - return Type_aggregator::find_handler_in_array(agg, a, b, true); - } - - const Type_handler *aggregate_for_num_op(const Type_handler *a, - const Type_handler *b) - const override - { - return NULL; - } - }; - class Type_std_attributes_fbt: public Type_std_attributes { public: @@ -1120,8 +1054,7 @@ public: const Type_collection *type_collection() const override { - static Type_collection_fbt type_collection_fbt; - return &type_collection_fbt; + return TypeCollectionImpl::singleton(); } const Name &default_value() const override @@ -1902,4 +1835,78 @@ public: } }; +template +class Type_collection_fbt: public Type_collection +{ + const Type_handler *aggregate_common(const Type_handler *a, + const Type_handler *b) const + { + if (a == b) + return a; + return NULL; + } + const Type_handler *aggregate_if_string(const Type_handler *a, + const Type_handler *b) const + { + static const Type_aggregator::Pair agg[]= + { + {Type_handler_fbt::singleton(), &type_handler_null, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_varchar, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_string, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_tiny_blob, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_blob, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_medium_blob, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_long_blob, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_hex_hybrid, Type_handler_fbt::singleton()}, + {NULL,NULL,NULL} + }; + return Type_aggregator::find_handler_in_array(agg, a, b, true); + } +public: + const Type_handler *aggregate_for_result(const Type_handler *a, + const Type_handler *b) + const override + { + const Type_handler *h; + if ((h= aggregate_common(a, b)) || (h= aggregate_if_string(a, b))) + return h; + return NULL; + } + + const Type_handler *aggregate_for_min_max(const Type_handler *a, + const Type_handler *b) + const override + { + return aggregate_for_result(a, b); + } + + const Type_handler *aggregate_for_comparison(const Type_handler *a, + const Type_handler *b) + const override + { + if (const Type_handler *h= aggregate_common(a, b)) + return h; + static const Type_aggregator::Pair agg[]= + { + {Type_handler_fbt::singleton(), &type_handler_null, Type_handler_fbt::singleton()}, + {Type_handler_fbt::singleton(), &type_handler_long_blob, Type_handler_fbt::singleton()}, + {NULL,NULL,NULL} + }; + return Type_aggregator::find_handler_in_array(agg, a, b, true); + } + + const Type_handler *aggregate_for_num_op(const Type_handler *a, + const Type_handler *b) + const override + { + return NULL; + } + + static Type_collection_fbt *singleton() + { + static Type_collection_fbt tc; + return &tc; + } +}; + #endif /* SQL_TYPE_FIXEDBIN_H */ From f6ecadfee87da7f3cd9c5d334b3183425397a025 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 3 Jul 2023 18:18:02 +0200 Subject: [PATCH 14/40] fix ASAN+safemalloc builds debug_sync refactoring introduced a statically instantiated object debug_sync_global of the structure st_debug_sync_globals. st_debug_sync_globals includes Hash_set<> which allocates memory in the constructor. sf_malloc() calls _my_thread_var()->dbug_id which is pthread_getspecific(THR_KEY_mysys), and THR_KEY_mysys is 0 before pthread_key_create(). pthread_getspecific(0) returns a valid pointer, not EINVAL. And safemalloc dereferences it. let's statically initialize THR_KEY_mysys to -1, this makes pthread_getspecific(THR_KEY_mysys) to fail before pthread_key_create() is called. followup for 8885225de66 --- mysys/my_thr_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysys/my_thr_init.c b/mysys/my_thr_init.c index fd8a99c2196..2e8decd7d06 100644 --- a/mysys/my_thr_init.c +++ b/mysys/my_thr_init.c @@ -23,7 +23,7 @@ #include #include -pthread_key(struct st_my_thread_var*, THR_KEY_mysys); +pthread_key(struct st_my_thread_var*, THR_KEY_mysys=-1); mysql_mutex_t THR_LOCK_malloc, THR_LOCK_open, THR_LOCK_lock, THR_LOCK_myisam, THR_LOCK_heap, THR_LOCK_net, THR_LOCK_charset, THR_LOCK_threads, From 46b79b8cd1c8becbc9fffad503a584e0edaf91a3 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Mon, 3 Jul 2023 22:05:02 +0200 Subject: [PATCH 15/40] MDEV-30084 Shutdown hangs in some tests debug-only issue. the test was doing set debug_sync='now SIGNAL go3'; ... set debug_sync='reset'; which translated into add "go3" to the hash of active signals pthread_broadcast to wake up waiting threads ... clear the hash of active signals as a result a waiting thread was awoken, but the hash was emptied before the thread checked if its signal was in the hash. so the thread didn't find its signal and went back to sleep. let's wait until the awoken thread has completely finished disconnecting and was added to the thread cache. --- mysql-test/main/kill_debug.result | 1 + mysql-test/main/kill_debug.test | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/mysql-test/main/kill_debug.result b/mysql-test/main/kill_debug.result index 061e7602383..0c910906b92 100644 --- a/mysql-test/main/kill_debug.result +++ b/mysql-test/main/kill_debug.result @@ -234,6 +234,7 @@ connection default; set debug_sync='now WAIT_FOR go0'; set debug_sync='found_killee SIGNAL go1 WAIT_FOR go2'; kill $id; +select variable_value into @threads_cached from information_schema.global_status where variable_name='threads_cached'; set debug_sync='now SIGNAL go3'; drop table t1; set debug_sync='reset'; diff --git a/mysql-test/main/kill_debug.test b/mysql-test/main/kill_debug.test index 32a764004e3..6bade1d8d90 100644 --- a/mysql-test/main/kill_debug.test +++ b/mysql-test/main/kill_debug.test @@ -313,6 +313,12 @@ connection default; set debug_sync='now WAIT_FOR go0'; set debug_sync='found_killee SIGNAL go1 WAIT_FOR go2'; evalp kill $id; +select variable_value into @threads_cached from information_schema.global_status where variable_name='threads_cached'; set debug_sync='now SIGNAL go3'; +if (`select @@thread_handling != 'pool-of-threads'`) { + # cannot check that a thread was added to thread pool on windows, but the test works there w/o the wait + let wait_condition= select variable_value>@threads_cached from information_schema.global_status where variable_name='threads_cached'; + source include/wait_condition.inc; +} drop table t1; set debug_sync='reset'; From 5b62644e68370d504ce4b779ed53e625d500451c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 5 Jul 2023 08:48:37 +0300 Subject: [PATCH 16/40] MDEV-31621 Remove ibuf_read_merge_pages() call from ibuf_insert_low() When InnoDB attempts to buffer a change operation of a secondary index leaf page (to insert, delete-mark or remove a record) and the change buffer is too large, InnoDB used to trigger a change buffer merge that could affect any tables. This could lead to huge variance in system throughput and potentially unpredictable crashes, in case the change buffer was corrupted and a crash occurred while attempting to merge changes to a table that is not being accessed by the current SQL statement. ibuf_insert_low(): Simply return DB_STRONG_FAIL when the maximum size of the change buffer is exceeded. ibuf_contract_after_insert(): Remove. ibuf_get_merge_page_nos_func(): Remove a constant parameter. The function ibuf_contract() will be our only caller, during shutdown with innodb_fast_shutdown=0. --- storage/innobase/ibuf/ibuf0ibuf.cc | 129 ++++------------------------- 1 file changed, 17 insertions(+), 112 deletions(-) diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc index d1d6176720a..8226ebbfd54 100644 --- a/storage/innobase/ibuf/ibuf0ibuf.cc +++ b/storage/innobase/ibuf/ibuf0ibuf.cc @@ -243,21 +243,11 @@ mysql_mutex_t ibuf_mutex, ibuf_pessimistic_insert_mutex; /** The area in pages from which contract looks for page numbers for merge */ -const ulint IBUF_MERGE_AREA = 8; +constexpr ulint IBUF_MERGE_AREA = 8; -/** Inside the merge area, pages which have at most 1 per this number less -buffered entries compared to maximum volume that can buffered for a single -page are merged along with the page whose buffer became full */ -const ulint IBUF_MERGE_THRESHOLD = 4; - -/** In ibuf_contract at most this number of pages is read to memory in one -batch, in order to merge the entries for them in the insert buffer */ -const ulint IBUF_MAX_N_PAGES_MERGED = IBUF_MERGE_AREA; - -/** If the combined size of the ibuf trees exceeds ibuf.max_size by -this many pages, we start to contract it synchronous contract, but do -not insert */ -const ulint IBUF_CONTRACT_DO_NOT_INSERT = 10; +/** In ibuf_contract() at most this number of pages is read to memory in one +batch, in order to merge the entries for them in the change buffer */ +constexpr ulint IBUF_MAX_N_PAGES_MERGED = IBUF_MERGE_AREA; /* TODO: how to cope with drop table if there are records in the insert buffer for the indexes of the table? Is there actually any problem, @@ -2004,11 +1994,11 @@ ibuf_free_excess_pages(void) } #ifdef UNIV_DEBUG -# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \ - ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,pages,n_stored) +# define ibuf_get_merge_page_nos(rec,mtr,ids,pages,n_stored) \ + ibuf_get_merge_page_nos_func(rec,mtr,ids,pages,n_stored) #else /* UNIV_DEBUG */ -# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \ - ibuf_get_merge_page_nos_func(contract,rec,ids,pages,n_stored) +# define ibuf_get_merge_page_nos(rec,mtr,ids,pages,n_stored) \ + ibuf_get_merge_page_nos_func(rec,ids,pages,n_stored) #endif /* UNIV_DEBUG */ /*********************************************************************//** @@ -2019,10 +2009,6 @@ static ulint ibuf_get_merge_page_nos_func( /*=========================*/ - ibool contract,/*!< in: TRUE if this function is called to - contract the tree, FALSE if this is called - when a single page becomes full and we look - if it pays to read also nearby pages */ const rec_t* rec, /*!< in: insert buffer record */ #ifdef UNIV_DEBUG mtr_t* mtr, /*!< in: mini-transaction holding rec */ @@ -2153,22 +2139,10 @@ corruption: || rec_page_no != prev_page_no) && (prev_space_id != 0 || prev_page_no != 0)) { - if (contract - || (prev_page_no == first_page_no - && prev_space_id == first_space_id) - || (volume_for_page - > ((IBUF_MERGE_THRESHOLD - 1) - * 4U << srv_page_size_shift - / IBUF_PAGE_SIZE_PER_FREE_SPACE) - / IBUF_MERGE_THRESHOLD)) { - - space_ids[*n_stored] = prev_space_id; - page_nos[*n_stored] = prev_page_no; - - (*n_stored)++; - - sum_volumes += volume_for_page; - } + space_ids[*n_stored] = prev_space_id; + page_nos[*n_stored] = prev_page_no; + (*n_stored)++; + sum_volumes += volume_for_page; if (rec_space_id != first_space_id || rec_page_no / IBUF_MERGE_AREA @@ -2428,7 +2402,7 @@ tablespace_deleted: @return a lower limit for the combined size in bytes of entries which will be merged from ibuf trees to the pages read @retval 0 if ibuf.empty */ -ulint ibuf_contract() +ATTRIBUTE_COLD ulint ibuf_contract() { if (UNIV_UNLIKELY(!ibuf.index)) return 0; mtr_t mtr; @@ -2460,10 +2434,8 @@ ulint ibuf_contract() } ulint n_pages = 0; - sum_sizes = ibuf_get_merge_page_nos(TRUE, - btr_cur_get_rec(&cur), &mtr, - space_ids, - page_nos, &n_pages); + sum_sizes = ibuf_get_merge_page_nos(btr_cur_get_rec(&cur), &mtr, + space_ids, page_nos, &n_pages); ibuf_mtr_commit(&mtr); ibuf_read_merge_pages(space_ids, page_nos, n_pages); @@ -2553,30 +2525,6 @@ ibuf_merge_space( return(n_pages); } -/*********************************************************************//** -Contract insert buffer trees after insert if they are too big. */ -UNIV_INLINE -void -ibuf_contract_after_insert( -/*=======================*/ - ulint entry_size) /*!< in: size of a record which was inserted - into an ibuf tree */ -{ - /* dirty comparison, to avoid contention on ibuf_mutex */ - if (ibuf.size < ibuf.max_size) { - return; - } - - /* Contract at least entry_size many bytes */ - ulint sum_sizes = 0; - ulint size; - - do { - size = ibuf_contract(); - sum_sizes += size; - } while (size > 0 && sum_sizes < entry_size); -} - /** Determine if a change buffer record has been encountered already. @param rec change buffer record in the MySQL 5.5 format @param hash hash table of encountered records @@ -3175,10 +3123,6 @@ ibuf_insert_low( buf_block_t* block = NULL; page_t* root; dberr_t err; - ibool do_merge; - uint32_t space_ids[IBUF_MAX_N_PAGES_MERGED]; - uint32_t page_nos[IBUF_MAX_N_PAGES_MERGED]; - ulint n_stored; mtr_t mtr; mtr_t bitmap_mtr; @@ -3189,28 +3133,9 @@ ibuf_insert_low( ut_ad(page_id.space() == index->table->space_id); ut_a(op < IBUF_OP_COUNT); - do_merge = FALSE; - /* Perform dirty comparison of ibuf.max_size and ibuf.size to - reduce ibuf_mutex contention. This should be OK; at worst we - are doing some excessive ibuf_contract() or occasionally - skipping an ibuf_contract(). */ - const ulint max_size = ibuf.max_size; - - if (max_size == 0) { - return(DB_STRONG_FAIL); - } - - if (ibuf.size >= max_size + IBUF_CONTRACT_DO_NOT_INSERT) { - /* Insert buffer is now too big, contract it but do not try - to insert */ - - -#ifdef UNIV_IBUF_DEBUG - fputs("Ibuf too big\n", stderr); -#endif - ibuf_contract(); - + reduce ibuf_mutex contention. */ + if (ibuf.size >= ibuf.max_size) { return(DB_STRONG_FAIL); } @@ -3262,17 +3187,6 @@ func_exit: ibuf_mtr_commit(&mtr); ut_free(pcur.old_rec_buf); mem_heap_free(heap); - - if (err == DB_SUCCESS && mode == BTR_INSERT_TREE) { - ibuf_contract_after_insert(entry_size); - } - - if (do_merge) { -#ifdef UNIV_IBUF_DEBUG - ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED); -#endif - ibuf_read_merge_pages(space_ids, page_nos, n_stored); - } return err; } @@ -3362,15 +3276,6 @@ commit_exit: bits)) { /* Release the bitmap page latch early. */ ibuf_mtr_commit(&bitmap_mtr); - - /* It may not fit */ - do_merge = TRUE; - - ibuf_get_merge_page_nos(FALSE, - btr_pcur_get_rec(&pcur), &mtr, - space_ids, - page_nos, &n_stored); - goto fail_exit; } } From b1317c178eb51b60e3156fcbef89e9c2b994533f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 5 Jul 2023 13:54:20 +0300 Subject: [PATCH 17/40] MDEV-31628: InnoDB reports the wrong system tablespace size on bootstrap SysTablespace::set_size(): Use correct 64-bit arithmetics for reporting the initial size of the InnoDB system or temporary tablespace. --- storage/innobase/fsp/fsp0sysspace.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc index 9aef6f389ef..3016f71afad 100644 --- a/storage/innobase/fsp/fsp0sysspace.cc +++ b/storage/innobase/fsp/fsp0sysspace.cc @@ -393,11 +393,11 @@ SysTablespace::set_size( Datafile& file) { ut_ad(!srv_read_only_mode || m_ignore_read_only); + const ib::bytes_iec b{uint64_t{file.m_size} << srv_page_size_shift}; /* We created the data file and now write it full of zeros */ - ib::info() << "Setting file '" << file.filepath() << "' size to " - << ib::bytes_iec{file.m_size << srv_page_size_shift} << - ". Physically writing the file full; Please wait ..."; + ib::info() << "Setting file '" << file.filepath() << "' size to " << b + << ". Physically writing the file full; Please wait ..."; bool success = os_file_set_size( file.m_filepath, file.m_handle, @@ -405,7 +405,7 @@ SysTablespace::set_size( if (success) { ib::info() << "File '" << file.filepath() << "' size is now " - << ib::bytes_iec{file.m_size << srv_page_size_shift} + << b << "."; } else { ib::error() << "Could not set the file size of '" From bd7908e6ace1edce3530a0aa663ec3527e53c8e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Wed, 5 Jul 2023 15:15:04 +0300 Subject: [PATCH 18/40] MDEV-31568 InnoDB protection against dual processes accessing data insufficient fil_node_open_file_low(): Always acquire an advisory lock on the system tablespace. Originally, we already did this in SysTablespace::open_file(), but SysTablespace::open_or_create() would release those locks when it is closing the file handles. This is a 10.5+ specific follow up to commit 0ee1082bd2e7e7049c4f0e686bad53cf7ba053ab (MDEV-28495). Thanks to Daniel Black for verifying this bug. --- storage/innobase/fil/fil0fil.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index c75144413ac..725345957ee 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -391,8 +391,16 @@ static bool fil_node_open_file_low(fil_node_t *node) : OS_FILE_OPEN | OS_FILE_ON_ERROR_NO_EXIT, OS_FILE_AIO, type, srv_read_only_mode, &success); - if (success) + if (node->is_open()) + { + ut_ad(success); +#ifndef _WIN32 + if (!node->space->id && !srv_read_only_mode && my_disable_locking && + os_file_lock(node->handle, node->name)) + goto fail; +#endif break; + } /* The following call prints an error message */ if (os_file_get_last_error(true) == EMFILE + 100 && @@ -406,6 +414,9 @@ static bool fil_node_open_file_low(fil_node_t *node) if (node->size); else if (!node->read_page0() || !fil_comp_algo_validate(node->space)) { +#ifndef _WIN32 + fail: +#endif os_file_close(node->handle); node->handle= OS_FILE_CLOSED; return false; From f3bacd708a2d35572f73c8ff030fdb7a29d3312e Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 5 Jul 2023 14:43:46 +0200 Subject: [PATCH 19/40] cleanup: make Name and STRING_WITH_LEN usable in constexpr --- include/m_string.h | 2 +- sql/sql_type.h | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/include/m_string.h b/include/m_string.h index 6a645b20a7f..28ad9ee7c88 100644 --- a/include/m_string.h +++ b/include/m_string.h @@ -201,7 +201,7 @@ extern ulonglong strtoull(const char *str, char **ptr, int base); #ifdef __cplusplus #include -template inline const char *_swl_check(T s) +template inline constexpr const char *_swl_check(T s) { static_assert(std::is_same::value || std::is_same::value, diff --git a/sql/sql_type.h b/sql/sql_type.h index f496914017b..b39157c3706 100644 --- a/sql/sql_type.h +++ b/sql/sql_type.h @@ -3384,17 +3384,12 @@ public: class Name: private LEX_CSTRING { public: - Name(const char *str_arg, uint length_arg) - { - DBUG_ASSERT(length_arg < UINT_MAX32); - LEX_CSTRING::str= str_arg; - LEX_CSTRING::length= length_arg; - } - Name(const LEX_CSTRING &lcs) - { - LEX_CSTRING::str= lcs.str; - LEX_CSTRING::length= lcs.length; - } + constexpr Name(const char *str_arg, uint length_arg) : + LEX_CSTRING({str_arg, length_arg}) + { } + constexpr Name(const LEX_CSTRING &lcs) : + LEX_CSTRING(lcs) + { } const char *ptr() const { return LEX_CSTRING::str; } uint length() const { return (uint) LEX_CSTRING::length; } const LEX_CSTRING &lex_cstring() const { return *this; } From 8bf25f3fb324a6d124baf80600510574f199b4f2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Sat, 6 May 2023 22:11:03 +0200 Subject: [PATCH 20/40] cleanup: remove sql_type_uuid.cc this is a necessary prerequisite for making UUID itself a template --- plugin/type_uuid/CMakeLists.txt | 2 +- plugin/type_uuid/sql_type_uuid.cc | 117 ------------------------------ plugin/type_uuid/sql_type_uuid.h | 92 ++++++++++++++++++++++- 3 files changed, 90 insertions(+), 121 deletions(-) delete mode 100644 plugin/type_uuid/sql_type_uuid.cc diff --git a/plugin/type_uuid/CMakeLists.txt b/plugin/type_uuid/CMakeLists.txt index 9a379abef04..6b0d6a458bf 100644 --- a/plugin/type_uuid/CMakeLists.txt +++ b/plugin/type_uuid/CMakeLists.txt @@ -14,5 +14,5 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA MYSQL_ADD_PLUGIN(type_uuid - plugin.cc sql_type_uuid.cc item_uuidfunc.cc + plugin.cc item_uuidfunc.cc MANDATORY RECOMPILE_FOR_EMBEDDED) diff --git a/plugin/type_uuid/sql_type_uuid.cc b/plugin/type_uuid/sql_type_uuid.cc deleted file mode 100644 index 9b4a731dbb2..00000000000 --- a/plugin/type_uuid/sql_type_uuid.cc +++ /dev/null @@ -1,117 +0,0 @@ -/* Copyright (c) 2019,2021 MariaDB Corporation - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ - -#define MYSQL_SERVER -#include "mariadb.h" -#include "my_net.h" -#include "sql_class.h" // THD, SORT_FIELD_ATTR -#include "opt_range.h" // SEL_ARG -#include "sql_type_uuid.h" - - -static bool get_digit(char ch, uint *val) -{ - if (ch >= '0' && ch <= '9') - { - *val= (uint) ch - '0'; - return false; - } - if (ch >= 'a' && ch <= 'f') - { - *val= (uint) ch - 'a' + 0x0a; - return false; - } - if (ch >= 'A' && ch <= 'F') - { - *val= (uint) ch - 'A' + 0x0a; - return false; - } - return true; -} - - -static bool get_digit(uint *val, const char *str, const char *end) -{ - if (str >= end) - return true; - return get_digit(*str, val); -} - - -static size_t skip_hyphens(const char *str, const char *end) -{ - const char *str0= str; - for ( ; str < end; str++) - { - if (str[0] != '-') - break; - } - return str - str0; -} - - -static const char *get_two_digits(char *val, const char *str, const char *end) -{ - uint hi, lo; - if (get_digit(&hi, str++, end)) - return NULL; - str+= skip_hyphens(str, end); - if (get_digit(&lo, str++, end)) - return NULL; - *val= (char) ((hi << 4) + lo); - return str; -} - - -bool UUID::ascii_to_fbt(const char *str, size_t str_length) -{ - const char *end= str + str_length; - /* - The format understood: - - Hyphen is not allowed on the first and the last position. - - Otherwise, hyphens are allowed on any (odd and even) position, - with any amount. - */ - if (str_length < 32) - goto err; - - for (uint oidx= 0; oidx < binary_length(); oidx++) - { - if (!(str= get_two_digits(&m_buffer[oidx], str, end))) - goto err; - // Allow hypheps after two digits, but not after the last digit - if (oidx + 1 < binary_length()) - str+= skip_hyphens(str, end); - } - if (str < end) - goto err; // Some input left - return false; -err: - bzero(m_buffer, sizeof(m_buffer)); - return true; -} - -size_t UUID::to_string(char *dst, size_t dstsize) const -{ - my_uuid2str((const uchar *) m_buffer, dst, 1); - return MY_UUID_STRING_LENGTH; -} - - -const Name &UUID::default_value() -{ - static Name def(STRING_WITH_LEN("00000000-0000-0000-0000-000000000000")); - return def; -} diff --git a/plugin/type_uuid/sql_type_uuid.h b/plugin/type_uuid/sql_type_uuid.h index d0d0906b441..091954b3b86 100644 --- a/plugin/type_uuid/sql_type_uuid.h +++ b/plugin/type_uuid/sql_type_uuid.h @@ -19,11 +19,97 @@ #include "sql_type_fixedbin_storage.h" class UUID: public FixedBinTypeStorage { + bool get_digit(char ch, uint *val) + { + if (ch >= '0' && ch <= '9') + { + *val= (uint) ch - '0'; + return false; + } + if (ch >= 'a' && ch <= 'f') + { + *val= (uint) ch - 'a' + 0x0a; + return false; + } + if (ch >= 'A' && ch <= 'F') + { + *val= (uint) ch - 'A' + 0x0a; + return false; + } + return true; + } + + bool get_digit(uint *val, const char *str, const char *end) + { + if (str >= end) + return true; + return get_digit(*str, val); + } + + size_t skip_hyphens(const char *str, const char *end) + { + const char *str0= str; + for ( ; str < end; str++) + { + if (str[0] != '-') + break; + } + return str - str0; + } + + const char *get_two_digits(char *val, const char *str, const char *end) + { + uint hi, lo; + if (get_digit(&hi, str++, end)) + return NULL; + str+= skip_hyphens(str, end); + if (get_digit(&lo, str++, end)) + return NULL; + *val= (char) ((hi << 4) + lo); + return str; + } + public: using FixedBinTypeStorage::FixedBinTypeStorage; - bool ascii_to_fbt(const char *str, size_t str_length); - size_t to_string(char *dst, size_t dstsize) const; - static const Name &default_value(); + bool ascii_to_fbt(const char *str, size_t str_length) + { + const char *end= str + str_length; + /* + The format understood: + - Hyphen is not allowed on the first and the last position. + - Otherwise, hyphens are allowed on any (odd and even) position, + with any amount. + */ + if (str_length < 32) + goto err; + + for (uint oidx= 0; oidx < binary_length(); oidx++) + { + if (!(str= get_two_digits(&m_buffer[oidx], str, end))) + goto err; + // Allow hypheps after two digits, but not after the last digit + if (oidx + 1 < binary_length()) + str+= skip_hyphens(str, end); + } + if (str < end) + goto err; // Some input left + return false; + err: + bzero(m_buffer, sizeof(m_buffer)); + return true; + } + + size_t to_string(char *dst, size_t dstsize) const + { + my_uuid2str((const uchar *) m_buffer, dst, 1); + return MY_UUID_STRING_LENGTH; + } + + static const Name &default_value() + { + static Name def(STRING_WITH_LEN("00000000-0000-0000-0000-000000000000")); + return def; + } /* Binary (in-memory) UUIDv1 representation: From ef84f8137b7c150635c23e1493f8620a4c8527ef Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 17 May 2023 16:14:24 +0200 Subject: [PATCH 21/40] MDEV-29959 UUID Sorting * UUIDs version >= 6 are now stored without byte-swapping * UUIDs with version >=8 and variant=0 are now considered invalid * old tables are supported * old (always byte swapped) and new (swapped for version < 6) UUIDs can be compared and converted transparently --- plugin/type_uuid/item_uuidfunc.cc | 2 +- .../mysql-test/type_uuid/order.result | 425 ++++++++++++ .../type_uuid/mysql-test/type_uuid/order.test | 26 + .../type_uuid/std_data/mdev-29959.MYD | Bin 0 -> 1344 bytes .../type_uuid/std_data/mdev-29959.MYI | Bin 0 -> 2048 bytes .../type_uuid/std_data/mdev-29959.frm | Bin 0 -> 967 bytes .../mysql-test/type_uuid/type_uuid.result | 606 +++++++++--------- .../type_uuid/type_uuid_memory.result | 8 +- .../type_uuid/type_uuid_myisam.result | 10 +- plugin/type_uuid/plugin.cc | 86 ++- plugin/type_uuid/sql_type_uuid.h | 66 +- sql/sql_type_fixedbin.h | 6 +- 12 files changed, 906 insertions(+), 329 deletions(-) create mode 100644 plugin/type_uuid/mysql-test/type_uuid/order.result create mode 100644 plugin/type_uuid/mysql-test/type_uuid/order.test create mode 100644 plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.MYD create mode 100644 plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.MYI create mode 100644 plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.frm diff --git a/plugin/type_uuid/item_uuidfunc.cc b/plugin/type_uuid/item_uuidfunc.cc index 6234e04ee2d..3f2b7434f73 100644 --- a/plugin/type_uuid/item_uuidfunc.cc +++ b/plugin/type_uuid/item_uuidfunc.cc @@ -33,7 +33,7 @@ String *Item_func_sys_guid::val_str(String *str) const Type_handler *Item_func_uuid::type_handler() const { - return UUIDBundle::singleton(); + return Type_handler_uuid_new::singleton(); } bool Item_func_uuid::val_native(THD *, Native *to) diff --git a/plugin/type_uuid/mysql-test/type_uuid/order.result b/plugin/type_uuid/mysql-test/type_uuid/order.result new file mode 100644 index 00000000000..7266bbbb9eb --- /dev/null +++ b/plugin/type_uuid/mysql-test/type_uuid/order.result @@ -0,0 +1,425 @@ +create table t1 (a uuid, b int not null, index (a)); +insert t1 select sformat('11223344-5566-{:x}777-{}888-99aabbccddee', seq div 4, elt(1+(seq % 4),0,8,'c','e')),seq from seq_0_to_63; +Warnings: +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 33 +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 37 +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 41 +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 45 +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 49 +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 53 +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 57 +Warning 1292 Incorrect uuid value: '11223344-5566-f777-0888-99aabbccddee' for column `test`.`t1`.`a` at row 61 +select * from t1; +a b +11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 +NULL 32 +11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 +NULL 36 +11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 +NULL 40 +11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 +NULL 44 +11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 +NULL 48 +11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 +NULL 52 +11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 +NULL 56 +11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 +NULL 60 +11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 +select * from t1 order by a; +a b +NULL 40 +NULL 32 +NULL 36 +NULL 44 +NULL 48 +NULL 52 +NULL 56 +NULL 60 +11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 +11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-e888-99aabbccddee 23 +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `a` uuid DEFAULT NULL, + `b` int(11) NOT NULL, + KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +# now let's use the table as above, but created in 10.11.4 +select * from t2; +a b +11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-0888-99aabbccddee 32 +11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-0888-99aabbccddee 36 +11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-0888-99aabbccddee 40 +11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-0888-99aabbccddee 44 +11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-0888-99aabbccddee 48 +11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-0888-99aabbccddee 52 +11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-0888-99aabbccddee 56 +11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-0888-99aabbccddee 60 +11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 +select * from t2 order by a; +a b +11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-8777-0888-99aabbccddee 32 +11223344-5566-9777-0888-99aabbccddee 36 +11223344-5566-a777-0888-99aabbccddee 40 +11223344-5566-b777-0888-99aabbccddee 44 +11223344-5566-c777-0888-99aabbccddee 48 +11223344-5566-d777-0888-99aabbccddee 52 +11223344-5566-e777-0888-99aabbccddee 56 +11223344-5566-f777-0888-99aabbccddee 60 +11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-e888-99aabbccddee 63 +show create table t2; +Table Create Table +t2 CREATE TABLE `t2` ( + `a` uuid DEFAULT NULL, + `b` int(11) NOT NULL, + KEY `a` (`a`) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci +select * from t1, t2 where t1.a=t2.a; +a b a b +11223344-5566-0777-0888-99aabbccddee 0 11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-0777-8888-99aabbccddee 1 11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-0777-c888-99aabbccddee 2 11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-0777-e888-99aabbccddee 3 11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-0888-99aabbccddee 4 11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-1777-8888-99aabbccddee 5 11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-1777-c888-99aabbccddee 6 11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-1777-e888-99aabbccddee 7 11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-0888-99aabbccddee 8 11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-2777-8888-99aabbccddee 9 11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-2777-c888-99aabbccddee 10 11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-2777-e888-99aabbccddee 11 11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-0888-99aabbccddee 12 11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-3777-8888-99aabbccddee 13 11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-3777-c888-99aabbccddee 14 11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-3777-e888-99aabbccddee 15 11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-0888-99aabbccddee 16 11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-4777-8888-99aabbccddee 17 11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-4777-c888-99aabbccddee 18 11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-4777-e888-99aabbccddee 19 11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-0888-99aabbccddee 20 11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-5777-8888-99aabbccddee 21 11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-5777-c888-99aabbccddee 22 11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-5777-e888-99aabbccddee 23 11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-0888-99aabbccddee 24 11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-8888-99aabbccddee 33 11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-8888-99aabbccddee 37 11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-8888-99aabbccddee 41 11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-8888-99aabbccddee 45 11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-8888-99aabbccddee 49 11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-8888-99aabbccddee 53 11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-8888-99aabbccddee 57 11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-8888-99aabbccddee 61 11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 11223344-5566-f777-e888-99aabbccddee 63 +select * from t1 union select * from t2; +a b +11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 +NULL 32 +NULL 36 +NULL 40 +NULL 44 +NULL 48 +NULL 52 +NULL 56 +NULL 60 +alter ignore table t2 force; +Warnings: +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 33 +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 37 +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 41 +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 45 +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 49 +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 53 +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 57 +Warning 1292 Incorrect uuid value: '11223344-5566-f777-0888-99aabbccddee' for column `test`.`t2`.`a` at row 61 +drop table t1, t2; diff --git a/plugin/type_uuid/mysql-test/type_uuid/order.test b/plugin/type_uuid/mysql-test/type_uuid/order.test new file mode 100644 index 00000000000..154d2bde523 --- /dev/null +++ b/plugin/type_uuid/mysql-test/type_uuid/order.test @@ -0,0 +1,26 @@ +# try all combinations of version and variant +source include/have_sequence.inc; + +create table t1 (a uuid, b int not null, index (a)); +insert t1 select sformat('11223344-5566-{:x}777-{}888-99aabbccddee', seq div 4, elt(1+(seq % 4),0,8,'c','e')),seq from seq_0_to_63; +select * from t1; +select * from t1 order by a; +show create table t1; + +--echo # now let's use the table as above, but created in 10.11.4 +let $datadir= `select @@datadir`; +--copy_file $MTR_SUITE_DIR/std_data/mdev-29959.frm $datadir/test/t2.frm +--copy_file $MTR_SUITE_DIR/std_data/mdev-29959.MYI $datadir/test/t2.MYI +--copy_file $MTR_SUITE_DIR/std_data/mdev-29959.MYD $datadir/test/t2.MYD +select * from t2; +select * from t2 order by a; +show create table t2; + +select * from t1, t2 where t1.a=t2.a; + +--sorted_result +select * from t1 union select * from t2; + +alter ignore table t2 force; + +drop table t1, t2; diff --git a/plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.MYD b/plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.MYD new file mode 100644 index 0000000000000000000000000000000000000000..138a08deeb789c0e9c5fc59c0292687f8bea95df GIT binary patch literal 1344 zcmYMsw@m{85QSl~kBmts2NO)rIW|a4fY<;=@CdvO5ECG=00jeZ1w9otSJ6^g!V;(V z{_-pS+SAM1$JdXcP`$Y;mUpij>ec=c#73bLn}k7Z78*+VY!QOkDs*C-Fo*@Ap^{G% zg4ix}Vuvt@okGK5KD&e6@p%bTsL7WyE9`ZRO1aVgA#Ii7mb3(&oKIerX zE(o2tC=6mnXn4-&k`TmYp%YhxL0lCYUh}yo1aV#H#0_B(H-(1xd~OLr+!i`-Y!D%Sk@~ literal 0 HcmV?d00001 diff --git a/plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.MYI b/plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.MYI new file mode 100644 index 0000000000000000000000000000000000000000..6dde55b27da5d211f3332e10d771faa6dcf78da1 GIT binary patch literal 2048 zcmeIyJ5Rz;6bJBgTcABYK|y?=B0lgfii&SKnD_~dgDX)7cRqq7egNa>U`(9c99&Iw zaB*^S*2&ckye$>Ze=x?;gxmJE|9ft4`|Hqh*-~VveY&9n-IF4{+qx&pRNP)S$Ls5z zQ}J7M$o4Bir#|JUtHi0U680AA5ySXT1f=^^j@|lbyd?n*J-^w`64>D%> zMaD&blW~PVW!$hzC{`#AqL@+KisA^0V<_%HaX*TOP&|s_2^7zucpk+|C|*VJruB$o z1H~Z}H=(!<#T_W_LUAvO2T+_s@feCHQ9O&{1r#r%cn!r{);o$#6k8~6MsYieJ5d}* eaUY5YQ9O*|G>WHCJcr^eigPGlM{)j-|C}$K_sPlt literal 0 HcmV?d00001 diff --git a/plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.frm b/plugin/type_uuid/mysql-test/type_uuid/std_data/mdev-29959.frm new file mode 100644 index 0000000000000000000000000000000000000000..d03c730aff7d01664b41d0747200e8b67c72120e GIT binary patch literal 967 zcmeyz$i*qkkjTKuaGaTe;U}Xg0~|0(GjK34u!8tN8UlVYGBAATVq_422`~s;ULv?% z+Enn}ZlgPjF-H`Fn%EdvN=q|SSQ#1WnHU%tfjU?ioPj!k349jqc6nE9*iEKWHEvPFh4Np1F='00000000-0000-0000-0000-0000000000fe'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 17 NULL 3 Using where; Using index +1 SIMPLE t1 range a a 17 NULL 28 Using where; Using index SELECT * FROM t1 WHERE a>='garbage'; a EXPLAIN SELECT * FROM t1 WHERE a>='garbage'; @@ -64,7 +64,7 @@ EXPLAIN SELECT * FROM t1 WHERE a IN '00000000-0000-0000-0000-0000000000f0' ); id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 17 NULL 4 Using where; Using index +1 SIMPLE t1 range a a 17 NULL 3 Using where; Using index SELECT * FROM t1 WHERE a IN ( '00000000-0000-0000-0000-000000000080', @@ -96,7 +96,7 @@ EXPLAIN SELECT * FROM t1 WHERE a BETWEEN '00000000-0000-0000-0000-000000000080' AND '00000000-0000-0000-0000-000000000081'; id select_type table type possible_keys key key_len ref rows Extra -1 SIMPLE t1 range a a 17 NULL 2 Using where; Using index +1 SIMPLE t1 range a a 17 NULL 1 Using where; Using index SELECT * FROM t1 WHERE a BETWEEN '00000000-0000-0000-0000-000000000080' AND 'garbage'; @@ -111,7 +111,7 @@ a 00000000-0000-0000-0000-0000000000ff EXPLAIN EXTENDED SELECT * FROM t1 WHERE a=CAST('00000000-0000-0000-0000-0000000000ff' AS UUID); id select_type table type possible_keys key key_len ref rows filtered Extra -1 SIMPLE t1 ref a a 17 const 1 100.00 Using where; Using index +1 SIMPLE t1 ref a a 17 const 7 100.00 Using where; Using index Warnings: Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = UUID'00000000-0000-0000-0000-0000000000ff' DROP TABLE t1; diff --git a/plugin/type_uuid/plugin.cc b/plugin/type_uuid/plugin.cc index e5b0cd9be70..499019e948c 100644 --- a/plugin/type_uuid/plugin.cc +++ b/plugin/type_uuid/plugin.cc @@ -21,12 +21,83 @@ #include #include +/* + The whole purpose of this Type_handler_uuid_dispatcher is to choose + whether the field should use Type_handler_uuid_new or Type_handler_uuid_old + based on the version of MariaDB that created the table. + When created every field will use either Type_handler_uuid_new or _old. + Literals and functions always use _new. +*/ +class Type_handler_uuid_dispatcher: public Type_handler_uuid_new +{ +public: + Field *make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *root, + const LEX_CSTRING *name, const Record_addr &addr, + const Bit_addr &bit, + const Column_definition_attributes *attr, + uint32 flags) const override + { + bool new_uuid= share->mysql_version == 0 || + (share->mysql_version >= 100908 && share->mysql_version < 100999) || + (share->mysql_version >= 101006 && share->mysql_version < 101099) || + (share->mysql_version >= 101105 && share->mysql_version < 101199) || + (share->mysql_version >= 110003 && share->mysql_version < 110099) || + (share->mysql_version >= 110102 && share->mysql_version < 110199) || + share->mysql_version >= 110201; + static Type_handler *th[]= { + Type_handler_uuid_old::singleton(), Type_handler_uuid_new::singleton() + }; + return th[new_uuid]-> + make_table_field_from_def(share, root, name, addr, bit, attr, flags); + } +}; + +static Type_handler_uuid_dispatcher type_handler_uuid_dispatcher; + static struct st_mariadb_data_type plugin_descriptor_type_uuid= { MariaDB_DATA_TYPE_INTERFACE_VERSION, - UUIDBundle::singleton() + &type_handler_uuid_dispatcher }; + +const Type_handler *Type_collection_uuid::find_in_array(const Type_handler *a, + const Type_handler *b, + bool for_cmp) const +{ + if (a == b) return a; + + /* + in the search below we'll find if we can convert `b` to `a`. + So, if one of the arguments is uuid and the other is not, + we should put uuid type in `a` and not-uuid in `b`. And if one type is + new uuid and the other is old uuid, new uuid should be in `a` + */ + if (a != Type_handler_uuid_new::singleton() && b->type_collection() == this) + std::swap(a, b); + + DBUG_ASSERT(a != &type_handler_uuid_dispatcher); + DBUG_ASSERT(b != &type_handler_uuid_dispatcher); + + /* + Search in the array for an element, equal to `b`. + If found - return `a`, if not found - return NULL. + Array is terminated by `a`. + */ + static const Type_handler *arr[]={ &type_handler_varchar, + &type_handler_string, &type_handler_tiny_blob, &type_handler_blob, + &type_handler_medium_blob, &type_handler_hex_hybrid, + // in aggregate_for_comparison() all types above cannot happen, + // so we'll start the search from here: + &type_handler_null, &type_handler_long_blob, + Type_handler_uuid_old::singleton(), Type_handler_uuid_new::singleton() }; + + for (int i= for_cmp ? 6 : 0; arr[i] != a; i++) + if (arr[i] == b) + return a; + return NULL; +} + /*************************************************************************/ class Create_func_uuid : public Create_func_arg0 @@ -71,17 +142,26 @@ static Plugin_function plugin_descriptor_function_uuid(&Create_func_uuid::s_singleton), plugin_descriptor_function_sys_guid(&Create_func_sys_guid::s_singleton); +static constexpr Name type_name={STRING_WITH_LEN("uuid")}; + +int uuid_init(void*) +{ + Type_handler_uuid_new::singleton()->set_name(type_name); + Type_handler_uuid_old::singleton()->set_name(type_name); + return 0; +} + /*************************************************************************/ maria_declare_plugin(type_uuid) { MariaDB_DATA_TYPE_PLUGIN, // the plugin type (see include/mysql/plugin.h) &plugin_descriptor_type_uuid, // pointer to type-specific plugin descriptor - "uuid", // plugin name + type_name.ptr(), // plugin name "MariaDB Corporation", // plugin author "Data type UUID", // the plugin description PLUGIN_LICENSE_GPL, // the plugin license (see include/mysql/plugin.h) - 0, // Pointer to plugin initialization function + uuid_init, // Pointer to plugin initialization function 0, // Pointer to plugin deinitialization function 0x0100, // Numeric version 0xAABB means AA.BB version NULL, // Status variables diff --git a/plugin/type_uuid/sql_type_uuid.h b/plugin/type_uuid/sql_type_uuid.h index 091954b3b86..5a2f7c75422 100644 --- a/plugin/type_uuid/sql_type_uuid.h +++ b/plugin/type_uuid/sql_type_uuid.h @@ -17,6 +17,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */ #include "sql_type_fixedbin_storage.h" + +template class UUID: public FixedBinTypeStorage { bool get_digit(char ch, uint *val) @@ -93,6 +95,8 @@ public: } if (str < end) goto err; // Some input left + if (m_buffer[6] < 0 && m_buffer[8] > 0) + goto err; // impossible combination: version >= 8, variant = 0 return false; err: bzero(m_buffer, sizeof(m_buffer)); @@ -172,21 +176,31 @@ public: // Convert the in-memory representation to the in-record representation static void memory_to_record(char *to, const char *from) { - segment(0).memory_to_record(to, from); - segment(1).memory_to_record(to, from); - segment(2).memory_to_record(to, from); - segment(3).memory_to_record(to, from); - segment(4).memory_to_record(to, from); + if (force_swap || (from[6] > 0 && from[6] < 0x60 && from[8] < 0)) + { + segment(0).memory_to_record(to, from); + segment(1).memory_to_record(to, from); + segment(2).memory_to_record(to, from); + segment(3).memory_to_record(to, from); + segment(4).memory_to_record(to, from); + } + else + memcpy(to, from, binary_length()); } // Convert the in-record representation to the in-memory representation static void record_to_memory(char *to, const char *from) { - segment(0).record_to_memory(to, from); - segment(1).record_to_memory(to, from); - segment(2).record_to_memory(to, from); - segment(3).record_to_memory(to, from); - segment(4).record_to_memory(to, from); + if (force_swap || (from[6] < 0 && from[8] > 0)) + { + segment(0).record_to_memory(to, from); + segment(1).record_to_memory(to, from); + segment(2).record_to_memory(to, from); + segment(3).record_to_memory(to, from); + segment(4).record_to_memory(to, from); + } + else + memcpy(to, from, binary_length()); } /* @@ -265,8 +279,38 @@ public: }; +class Type_collection_uuid: public Type_collection +{ + const Type_handler *find_in_array(const Type_handler *what, + const Type_handler *stop, + bool for_comparison) const; +public: + const Type_handler *aggregate_for_result(const Type_handler *a, + const Type_handler *b) + const override + { return find_in_array(a, b, false); } + const Type_handler *aggregate_for_min_max(const Type_handler *a, + const Type_handler *b) + const override + { return find_in_array(a, b, false); } + const Type_handler *aggregate_for_comparison(const Type_handler *a, + const Type_handler *b) + const override + { return find_in_array(a, b, true); } + const Type_handler *aggregate_for_num_op(const Type_handler *a, + const Type_handler *b) + const override + { return NULL; } + + static Type_collection_uuid *singleton() + { + static Type_collection_uuid tc; + return &tc; + } +}; #include "sql_type_fixedbin.h" -typedef Type_handler_fbt UUIDBundle; +typedef Type_handler_fbt, Type_collection_uuid> Type_handler_uuid_old; +typedef Type_handler_fbt, Type_collection_uuid> Type_handler_uuid_new; #endif // SQL_TYPE_UUID_INCLUDED diff --git a/sql/sql_type_fixedbin.h b/sql/sql_type_fixedbin.h index 15722935eb8..2a2cc1e1ff6 100644 --- a/sql/sql_type_fixedbin.h +++ b/sql/sql_type_fixedbin.h @@ -631,7 +631,8 @@ public: */ DBUG_ASSERT(item->type_handler()->type_handler_base_or_self()-> is_traditional_scalar_type() || - item->type_handler() == type_handler()); + item->type_handler()->type_collection() == + type_handler()->type_collection()); return true; } /** @@ -646,7 +647,8 @@ public: // See the DBUG_ASSERT comment in can_optimize_keypart_ref() DBUG_ASSERT(item->type_handler()->type_handler_base_or_self()-> is_traditional_scalar_type() || - item->type_handler() == type_handler()); + item->type_handler()->type_collection() == + type_handler()->type_collection()); return true; } void hash_not_null(Hasher *hasher) override From 1570c6e3e04fae7afd33748ce741f726e4fcfaa2 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 5 Jul 2023 21:51:52 +0200 Subject: [PATCH 22/40] bugfix: join a=b where cast(a as type_of_b) can produce NULL optimizer implicitly assumed that if `a` in `a=b` is not NULL, then it's safe to convert `a` to the type of `b` and search the result in the index(b). which is not always the case, as converting a non-null value to a different type might produce NULL. And searching for NULL in the index might find NULL there, so NULL will be equal to NULL, making `a=b` behave as if it was `a<=>b` --- mysql-test/main/subselect_cache.result | 4 +- .../mysql-test/type_uuid/order.result | 345 +++++++++++++++++- .../type_uuid/mysql-test/type_uuid/order.test | 16 +- sql/sql_select.cc | 3 +- 4 files changed, 363 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/subselect_cache.result b/mysql-test/main/subselect_cache.result index e859ebbd2e8..ab02d309143 100644 --- a/mysql-test/main/subselect_cache.result +++ b/mysql-test/main/subselect_cache.result @@ -1698,7 +1698,7 @@ Subquery_cache_miss 18 show status like '%Handler_read%'; Variable_name Value Handler_read_first 0 -Handler_read_key 32 +Handler_read_key 29 Handler_read_last 0 Handler_read_next 0 Handler_read_prev 0 @@ -1763,7 +1763,7 @@ Subquery_cache_miss 10 show status like '%Handler_read%'; Variable_name Value Handler_read_first 0 -Handler_read_key 13 +Handler_read_key 12 Handler_read_last 0 Handler_read_next 0 Handler_read_prev 0 diff --git a/plugin/type_uuid/mysql-test/type_uuid/order.result b/plugin/type_uuid/mysql-test/type_uuid/order.result index 7266bbbb9eb..2f6ae3ed47c 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/order.result +++ b/plugin/type_uuid/mysql-test/type_uuid/order.result @@ -288,7 +288,11 @@ t2 CREATE TABLE `t2` ( `b` int(11) NOT NULL, KEY `a` (`a`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci -select * from t1, t2 where t1.a=t2.a; +explain select * from t1 left join t2 on (t1.a=t2.a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 64 +1 SIMPLE t2 ref a a 17 test.t1.a 1 Using where +select * from t1 left join t2 on (t1.a=t2.a); a b a b 11223344-5566-0777-0888-99aabbccddee 0 11223344-5566-0777-0888-99aabbccddee 0 11223344-5566-0777-8888-99aabbccddee 1 11223344-5566-0777-8888-99aabbccddee 1 @@ -346,6 +350,345 @@ a b a b 11223344-5566-f777-8888-99aabbccddee 61 11223344-5566-f777-8888-99aabbccddee 61 11223344-5566-f777-c888-99aabbccddee 62 11223344-5566-f777-c888-99aabbccddee 62 11223344-5566-f777-e888-99aabbccddee 63 11223344-5566-f777-e888-99aabbccddee 63 +NULL 32 NULL NULL +NULL 36 NULL NULL +NULL 40 NULL NULL +NULL 44 NULL NULL +NULL 48 NULL NULL +NULL 52 NULL NULL +NULL 56 NULL NULL +NULL 60 NULL NULL +explain select * from t1 left join t2 on (t1.a<=>t2.a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t1 ALL NULL NULL NULL NULL 64 +1 SIMPLE t2 ref a a 17 test.t1.a 1 Using where +select * from t1 left join t2 on (t1.a<=>t2.a); +a b a b +11223344-5566-0777-0888-99aabbccddee 0 11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-0777-8888-99aabbccddee 1 11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-0777-c888-99aabbccddee 2 11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-0777-e888-99aabbccddee 3 11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-0888-99aabbccddee 4 11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-1777-8888-99aabbccddee 5 11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-1777-c888-99aabbccddee 6 11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-1777-e888-99aabbccddee 7 11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-0888-99aabbccddee 8 11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-2777-8888-99aabbccddee 9 11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-2777-c888-99aabbccddee 10 11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-2777-e888-99aabbccddee 11 11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-0888-99aabbccddee 12 11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-3777-8888-99aabbccddee 13 11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-3777-c888-99aabbccddee 14 11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-3777-e888-99aabbccddee 15 11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-0888-99aabbccddee 16 11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-4777-8888-99aabbccddee 17 11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-4777-c888-99aabbccddee 18 11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-4777-e888-99aabbccddee 19 11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-0888-99aabbccddee 20 11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-5777-8888-99aabbccddee 21 11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-5777-c888-99aabbccddee 22 11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-5777-e888-99aabbccddee 23 11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-0888-99aabbccddee 24 11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-8888-99aabbccddee 33 11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-8888-99aabbccddee 37 11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-8888-99aabbccddee 41 11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-8888-99aabbccddee 45 11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-8888-99aabbccddee 49 11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-8888-99aabbccddee 53 11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-8888-99aabbccddee 57 11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-8888-99aabbccddee 61 11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 11223344-5566-f777-e888-99aabbccddee 63 +NULL 32 NULL NULL +NULL 36 NULL NULL +NULL 40 NULL NULL +NULL 44 NULL NULL +NULL 48 NULL NULL +NULL 52 NULL NULL +NULL 56 NULL NULL +NULL 60 NULL NULL +explain select * from t2 left join t1 on (t1.a=t2.a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 64 +1 SIMPLE t1 ref a a 17 test.t2.a 1 Using where +select * from t2 left join t1 on (t1.a=t2.a); +a b a b +11223344-5566-0777-0888-99aabbccddee 0 11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-0777-8888-99aabbccddee 1 11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-0777-c888-99aabbccddee 2 11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-0777-e888-99aabbccddee 3 11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-0888-99aabbccddee 4 11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-1777-8888-99aabbccddee 5 11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-1777-c888-99aabbccddee 6 11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-1777-e888-99aabbccddee 7 11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-0888-99aabbccddee 8 11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-2777-8888-99aabbccddee 9 11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-2777-c888-99aabbccddee 10 11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-2777-e888-99aabbccddee 11 11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-0888-99aabbccddee 12 11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-3777-8888-99aabbccddee 13 11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-3777-c888-99aabbccddee 14 11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-3777-e888-99aabbccddee 15 11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-0888-99aabbccddee 16 11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-4777-8888-99aabbccddee 17 11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-4777-c888-99aabbccddee 18 11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-4777-e888-99aabbccddee 19 11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-0888-99aabbccddee 20 11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-5777-8888-99aabbccddee 21 11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-5777-c888-99aabbccddee 22 11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-5777-e888-99aabbccddee 23 11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-0888-99aabbccddee 24 11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-0888-99aabbccddee 32 NULL NULL +11223344-5566-8777-8888-99aabbccddee 33 11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-0888-99aabbccddee 36 NULL NULL +11223344-5566-9777-8888-99aabbccddee 37 11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-0888-99aabbccddee 40 NULL NULL +11223344-5566-a777-8888-99aabbccddee 41 11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-0888-99aabbccddee 44 NULL NULL +11223344-5566-b777-8888-99aabbccddee 45 11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-0888-99aabbccddee 48 NULL NULL +11223344-5566-c777-8888-99aabbccddee 49 11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-0888-99aabbccddee 52 NULL NULL +11223344-5566-d777-8888-99aabbccddee 53 11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-0888-99aabbccddee 56 NULL NULL +11223344-5566-e777-8888-99aabbccddee 57 11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-0888-99aabbccddee 60 NULL NULL +11223344-5566-f777-8888-99aabbccddee 61 11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 11223344-5566-f777-e888-99aabbccddee 63 +explain select * from t2 left join t1 on (t1.a<=>t2.a); +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 64 +1 SIMPLE t1 ref a a 17 test.t2.a 1 Using where +select * from t2 left join t1 on (t1.a<=>t2.a); +a b a b +11223344-5566-0777-0888-99aabbccddee 0 11223344-5566-0777-0888-99aabbccddee 0 +11223344-5566-0777-8888-99aabbccddee 1 11223344-5566-0777-8888-99aabbccddee 1 +11223344-5566-0777-c888-99aabbccddee 2 11223344-5566-0777-c888-99aabbccddee 2 +11223344-5566-0777-e888-99aabbccddee 3 11223344-5566-0777-e888-99aabbccddee 3 +11223344-5566-1777-0888-99aabbccddee 4 11223344-5566-1777-0888-99aabbccddee 4 +11223344-5566-1777-8888-99aabbccddee 5 11223344-5566-1777-8888-99aabbccddee 5 +11223344-5566-1777-c888-99aabbccddee 6 11223344-5566-1777-c888-99aabbccddee 6 +11223344-5566-1777-e888-99aabbccddee 7 11223344-5566-1777-e888-99aabbccddee 7 +11223344-5566-2777-0888-99aabbccddee 8 11223344-5566-2777-0888-99aabbccddee 8 +11223344-5566-2777-8888-99aabbccddee 9 11223344-5566-2777-8888-99aabbccddee 9 +11223344-5566-2777-c888-99aabbccddee 10 11223344-5566-2777-c888-99aabbccddee 10 +11223344-5566-2777-e888-99aabbccddee 11 11223344-5566-2777-e888-99aabbccddee 11 +11223344-5566-3777-0888-99aabbccddee 12 11223344-5566-3777-0888-99aabbccddee 12 +11223344-5566-3777-8888-99aabbccddee 13 11223344-5566-3777-8888-99aabbccddee 13 +11223344-5566-3777-c888-99aabbccddee 14 11223344-5566-3777-c888-99aabbccddee 14 +11223344-5566-3777-e888-99aabbccddee 15 11223344-5566-3777-e888-99aabbccddee 15 +11223344-5566-4777-0888-99aabbccddee 16 11223344-5566-4777-0888-99aabbccddee 16 +11223344-5566-4777-8888-99aabbccddee 17 11223344-5566-4777-8888-99aabbccddee 17 +11223344-5566-4777-c888-99aabbccddee 18 11223344-5566-4777-c888-99aabbccddee 18 +11223344-5566-4777-e888-99aabbccddee 19 11223344-5566-4777-e888-99aabbccddee 19 +11223344-5566-5777-0888-99aabbccddee 20 11223344-5566-5777-0888-99aabbccddee 20 +11223344-5566-5777-8888-99aabbccddee 21 11223344-5566-5777-8888-99aabbccddee 21 +11223344-5566-5777-c888-99aabbccddee 22 11223344-5566-5777-c888-99aabbccddee 22 +11223344-5566-5777-e888-99aabbccddee 23 11223344-5566-5777-e888-99aabbccddee 23 +11223344-5566-6777-0888-99aabbccddee 24 11223344-5566-6777-0888-99aabbccddee 24 +11223344-5566-6777-8888-99aabbccddee 25 11223344-5566-6777-8888-99aabbccddee 25 +11223344-5566-6777-c888-99aabbccddee 26 11223344-5566-6777-c888-99aabbccddee 26 +11223344-5566-6777-e888-99aabbccddee 27 11223344-5566-6777-e888-99aabbccddee 27 +11223344-5566-7777-0888-99aabbccddee 28 11223344-5566-7777-0888-99aabbccddee 28 +11223344-5566-7777-8888-99aabbccddee 29 11223344-5566-7777-8888-99aabbccddee 29 +11223344-5566-7777-c888-99aabbccddee 30 11223344-5566-7777-c888-99aabbccddee 30 +11223344-5566-7777-e888-99aabbccddee 31 11223344-5566-7777-e888-99aabbccddee 31 +11223344-5566-8777-0888-99aabbccddee 32 NULL 32 +11223344-5566-8777-0888-99aabbccddee 32 NULL 36 +11223344-5566-8777-0888-99aabbccddee 32 NULL 40 +11223344-5566-8777-0888-99aabbccddee 32 NULL 44 +11223344-5566-8777-0888-99aabbccddee 32 NULL 48 +11223344-5566-8777-0888-99aabbccddee 32 NULL 52 +11223344-5566-8777-0888-99aabbccddee 32 NULL 56 +11223344-5566-8777-0888-99aabbccddee 32 NULL 60 +11223344-5566-8777-8888-99aabbccddee 33 11223344-5566-8777-8888-99aabbccddee 33 +11223344-5566-8777-c888-99aabbccddee 34 11223344-5566-8777-c888-99aabbccddee 34 +11223344-5566-8777-e888-99aabbccddee 35 11223344-5566-8777-e888-99aabbccddee 35 +11223344-5566-9777-0888-99aabbccddee 36 NULL 32 +11223344-5566-9777-0888-99aabbccddee 36 NULL 36 +11223344-5566-9777-0888-99aabbccddee 36 NULL 40 +11223344-5566-9777-0888-99aabbccddee 36 NULL 44 +11223344-5566-9777-0888-99aabbccddee 36 NULL 48 +11223344-5566-9777-0888-99aabbccddee 36 NULL 52 +11223344-5566-9777-0888-99aabbccddee 36 NULL 56 +11223344-5566-9777-0888-99aabbccddee 36 NULL 60 +11223344-5566-9777-8888-99aabbccddee 37 11223344-5566-9777-8888-99aabbccddee 37 +11223344-5566-9777-c888-99aabbccddee 38 11223344-5566-9777-c888-99aabbccddee 38 +11223344-5566-9777-e888-99aabbccddee 39 11223344-5566-9777-e888-99aabbccddee 39 +11223344-5566-a777-0888-99aabbccddee 40 NULL 32 +11223344-5566-a777-0888-99aabbccddee 40 NULL 36 +11223344-5566-a777-0888-99aabbccddee 40 NULL 40 +11223344-5566-a777-0888-99aabbccddee 40 NULL 44 +11223344-5566-a777-0888-99aabbccddee 40 NULL 48 +11223344-5566-a777-0888-99aabbccddee 40 NULL 52 +11223344-5566-a777-0888-99aabbccddee 40 NULL 56 +11223344-5566-a777-0888-99aabbccddee 40 NULL 60 +11223344-5566-a777-8888-99aabbccddee 41 11223344-5566-a777-8888-99aabbccddee 41 +11223344-5566-a777-c888-99aabbccddee 42 11223344-5566-a777-c888-99aabbccddee 42 +11223344-5566-a777-e888-99aabbccddee 43 11223344-5566-a777-e888-99aabbccddee 43 +11223344-5566-b777-0888-99aabbccddee 44 NULL 32 +11223344-5566-b777-0888-99aabbccddee 44 NULL 36 +11223344-5566-b777-0888-99aabbccddee 44 NULL 40 +11223344-5566-b777-0888-99aabbccddee 44 NULL 44 +11223344-5566-b777-0888-99aabbccddee 44 NULL 48 +11223344-5566-b777-0888-99aabbccddee 44 NULL 52 +11223344-5566-b777-0888-99aabbccddee 44 NULL 56 +11223344-5566-b777-0888-99aabbccddee 44 NULL 60 +11223344-5566-b777-8888-99aabbccddee 45 11223344-5566-b777-8888-99aabbccddee 45 +11223344-5566-b777-c888-99aabbccddee 46 11223344-5566-b777-c888-99aabbccddee 46 +11223344-5566-b777-e888-99aabbccddee 47 11223344-5566-b777-e888-99aabbccddee 47 +11223344-5566-c777-0888-99aabbccddee 48 NULL 32 +11223344-5566-c777-0888-99aabbccddee 48 NULL 36 +11223344-5566-c777-0888-99aabbccddee 48 NULL 40 +11223344-5566-c777-0888-99aabbccddee 48 NULL 44 +11223344-5566-c777-0888-99aabbccddee 48 NULL 48 +11223344-5566-c777-0888-99aabbccddee 48 NULL 52 +11223344-5566-c777-0888-99aabbccddee 48 NULL 56 +11223344-5566-c777-0888-99aabbccddee 48 NULL 60 +11223344-5566-c777-8888-99aabbccddee 49 11223344-5566-c777-8888-99aabbccddee 49 +11223344-5566-c777-c888-99aabbccddee 50 11223344-5566-c777-c888-99aabbccddee 50 +11223344-5566-c777-e888-99aabbccddee 51 11223344-5566-c777-e888-99aabbccddee 51 +11223344-5566-d777-0888-99aabbccddee 52 NULL 32 +11223344-5566-d777-0888-99aabbccddee 52 NULL 36 +11223344-5566-d777-0888-99aabbccddee 52 NULL 40 +11223344-5566-d777-0888-99aabbccddee 52 NULL 44 +11223344-5566-d777-0888-99aabbccddee 52 NULL 48 +11223344-5566-d777-0888-99aabbccddee 52 NULL 52 +11223344-5566-d777-0888-99aabbccddee 52 NULL 56 +11223344-5566-d777-0888-99aabbccddee 52 NULL 60 +11223344-5566-d777-8888-99aabbccddee 53 11223344-5566-d777-8888-99aabbccddee 53 +11223344-5566-d777-c888-99aabbccddee 54 11223344-5566-d777-c888-99aabbccddee 54 +11223344-5566-d777-e888-99aabbccddee 55 11223344-5566-d777-e888-99aabbccddee 55 +11223344-5566-e777-0888-99aabbccddee 56 NULL 32 +11223344-5566-e777-0888-99aabbccddee 56 NULL 36 +11223344-5566-e777-0888-99aabbccddee 56 NULL 40 +11223344-5566-e777-0888-99aabbccddee 56 NULL 44 +11223344-5566-e777-0888-99aabbccddee 56 NULL 48 +11223344-5566-e777-0888-99aabbccddee 56 NULL 52 +11223344-5566-e777-0888-99aabbccddee 56 NULL 56 +11223344-5566-e777-0888-99aabbccddee 56 NULL 60 +11223344-5566-e777-8888-99aabbccddee 57 11223344-5566-e777-8888-99aabbccddee 57 +11223344-5566-e777-c888-99aabbccddee 58 11223344-5566-e777-c888-99aabbccddee 58 +11223344-5566-e777-e888-99aabbccddee 59 11223344-5566-e777-e888-99aabbccddee 59 +11223344-5566-f777-0888-99aabbccddee 60 NULL 32 +11223344-5566-f777-0888-99aabbccddee 60 NULL 36 +11223344-5566-f777-0888-99aabbccddee 60 NULL 40 +11223344-5566-f777-0888-99aabbccddee 60 NULL 44 +11223344-5566-f777-0888-99aabbccddee 60 NULL 48 +11223344-5566-f777-0888-99aabbccddee 60 NULL 52 +11223344-5566-f777-0888-99aabbccddee 60 NULL 56 +11223344-5566-f777-0888-99aabbccddee 60 NULL 60 +11223344-5566-f777-8888-99aabbccddee 61 11223344-5566-f777-8888-99aabbccddee 61 +11223344-5566-f777-c888-99aabbccddee 62 11223344-5566-f777-c888-99aabbccddee 62 +11223344-5566-f777-e888-99aabbccddee 63 11223344-5566-f777-e888-99aabbccddee 63 +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-8777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-9777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-a777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-b777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-c777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-d777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-e777-0888-99aabbccddee' +Warning 1292 Incorrect uuid value: '11223344-5566-f777-0888-99aabbccddee' +Warnings: select * from t1 union select * from t2; a b 11223344-5566-0777-0888-99aabbccddee 0 diff --git a/plugin/type_uuid/mysql-test/type_uuid/order.test b/plugin/type_uuid/mysql-test/type_uuid/order.test index 154d2bde523..46f76da98e3 100644 --- a/plugin/type_uuid/mysql-test/type_uuid/order.test +++ b/plugin/type_uuid/mysql-test/type_uuid/order.test @@ -16,7 +16,21 @@ select * from t2; select * from t2 order by a; show create table t2; -select * from t1, t2 where t1.a=t2.a; +explain select * from t1 left join t2 on (t1.a=t2.a); +--sorted_result +select * from t1 left join t2 on (t1.a=t2.a); + +explain select * from t1 left join t2 on (t1.a<=>t2.a); +--sorted_result +select * from t1 left join t2 on (t1.a<=>t2.a); + +explain select * from t2 left join t1 on (t1.a=t2.a); +--sorted_result +select * from t2 left join t1 on (t1.a=t2.a); + +explain select * from t2 left join t1 on (t1.a<=>t2.a); +--sorted_result +select * from t2 left join t1 on (t1.a<=>t2.a); --sorted_result select * from t1 union select * from t2; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ea39c4c4353..b90595442c9 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -25562,7 +25562,8 @@ cp_buffer_from_ref(THD *thd, TABLE *table, TABLE_REF *ref) thd->count_cuted_fields= CHECK_FIELD_IGNORE; for (store_key **copy=ref->key_copy ; *copy ; copy++) { - if ((*copy)->copy(thd) & 1) + if ((*copy)->copy(thd) & 1 || + (ref->null_rejecting && (*copy)->null_key)) { result= 1; break; From 0df346306ae5b31561bdf1990010fba84790b749 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Thu, 6 Jul 2023 22:17:35 +0200 Subject: [PATCH 23/40] MDEV-29959 fix for aarch64 on aarch64 `char` by default is unsigned for performance reasons. let's adjust checks to work for both signed and unsigned `char` followup for ef84f8137b7 --- plugin/type_uuid/sql_type_uuid.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugin/type_uuid/sql_type_uuid.h b/plugin/type_uuid/sql_type_uuid.h index 5a2f7c75422..272898efc8c 100644 --- a/plugin/type_uuid/sql_type_uuid.h +++ b/plugin/type_uuid/sql_type_uuid.h @@ -95,7 +95,7 @@ public: } if (str < end) goto err; // Some input left - if (m_buffer[6] < 0 && m_buffer[8] > 0) + if (m_buffer[6] & -m_buffer[8] & 0x80) goto err; // impossible combination: version >= 8, variant = 0 return false; err: @@ -176,7 +176,7 @@ public: // Convert the in-memory representation to the in-record representation static void memory_to_record(char *to, const char *from) { - if (force_swap || (from[6] > 0 && from[6] < 0x60 && from[8] < 0)) + if (force_swap || (from[6] > 0 && from[6] < 0x60 && from[8] & 0x80)) { segment(0).memory_to_record(to, from); segment(1).memory_to_record(to, from); @@ -191,7 +191,7 @@ public: // Convert the in-record representation to the in-memory representation static void record_to_memory(char *to, const char *from) { - if (force_swap || (from[6] < 0 && from[8] > 0)) + if (force_swap || (from[6] & -from[8] & 0x80)) { segment(0).record_to_memory(to, from); segment(1).record_to_memory(to, from); From 99bd22605938c42d876194f2ec75b32e658f00f5 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 7 Jul 2023 08:38:55 +0300 Subject: [PATCH 24/40] MDEV-31558 Add InnoDB engine information to the slow query log The new statistics is enabled by adding the "engine", "innodb" or "full" option to --log-slow-verbosity Example output: # Pages_accessed: 184 Pages_read: 95 Pages_updated: 0 Old_rows_read: 1 # Pages_read_time: 17.0204 Engine_time: 248.1297 Page_read_time is time doing physical reads inside a storage engine. (Writes cannot be tracked as these are usually done in the background). Engine_time is the time spent inside the storage engine for the full duration of the read/write/update calls. It uses the same code as 'analyze statement' for calculating the time spent. The engine statistics is done with a generic interface that should be easy for any engine to use. It can also easily be extended to provide even more statistics. Currently only InnoDB has counters for Pages_% and Undo_% status. Engine_time works for all engines. Implementation details: class ha_handler_stats holds all engine stats. This class is included in handler and THD classes. While a query is running, all statistics is updated in the handler. In close_thread_tables() the statistics is added to the THD. handler::handler_stats is a pointer to where statistics should be collected. This is set to point to handler::active_handler_stats if stats are requested. If not, it is set to 0. handler_stats has also an element, 'active' that is 1 if stats are requested. This is to allow engines to avoid doing any 'if's while updating the statistics. Cloned or partition tables have the pointer set to the base table if status are requested. There is a small performance impact when using --log-slow-verbosity=engine: - All engine calls in 'select' will be timed. - IO calls for InnoDB reads will be timed. - Incrementation of counters are done on local variables and accesses are inline, so these should have very little impact. - Statistics has to be reset for each statement for the THD and each used handler. This is only 40 bytes, which should be neglectable. - For partition tables we have to loop over all partitions to update the handler_status as part of table_init(). Can be optimized in the future to only do this is log-slow-verbosity changes. For this to work we have to update handler_status for all opened partitions and also for all partitions opened in the future. Other things: - Added options 'engine' and 'full' to log-slow-verbosity. - Some of the new files in the test suite comes from Percona server, which has similar status information. - buf_page_optimistic_get(): Do not increment any counter, since we are only validating a pointer, not performing any buf_pool.page_hash lookup. - Added THD argument to save_explain_data_intern(). - Switched arguments for save_explain_.*_data() to have always THD first (generates better code as other functions also have THD first). --- mysql-test/include/log_grep.inc | 85 +++++++++++++ mysql-test/include/log_slow_cleanup.inc | 6 + mysql-test/include/log_slow_grep.inc | 25 ++++ mysql-test/include/log_slow_prepare.inc | 8 ++ mysql-test/include/log_slow_start.inc | 6 + mysql-test/include/log_slow_stop.inc | 4 + .../analyze_stmt_slow_query_log-master.opt | 2 +- mysql-test/main/log_slow_innodb.result | 78 ++++++++++++ mysql-test/main/log_slow_innodb.test | 75 +++++++++++ mysql-test/main/mysqld--help.result | 2 +- .../r/log_slow_verbosity_basic.result | 8 +- .../sys_vars/r/sysvars_server_embedded.result | 2 +- .../r/sysvars_server_notembedded.result | 2 +- .../sys_vars/t/log_slow_verbosity_basic.test | 4 +- sql/ha_handler_stats.h | 59 +++++++++ sql/ha_partition.cc | 21 ++++ sql/ha_partition.h | 1 + sql/handler.cc | 1 + sql/handler.h | 32 ++++- sql/log.cc | 39 +++++- sql/log_slow.h | 8 +- sql/sql_analyze_stmt.h | 48 +++++-- sql/sql_base.cc | 25 ++-- sql/sql_class.cc | 5 + sql/sql_class.h | 3 + sql/sql_delete.cc | 21 ++-- sql/sql_lex.h | 6 +- sql/sql_select.cc | 12 +- sql/sql_update.cc | 4 +- sql/sys_vars.cc | 5 +- sql/table.cc | 6 + storage/innobase/buf/buf0buf.cc | 7 +- storage/innobase/buf/buf0rea.cc | 6 + storage/innobase/handler/ha_innodb.cc | 14 ++- storage/innobase/include/mariadb_stats.h | 119 ++++++++++++++++++ storage/innobase/include/row0mysql.h | 1 + storage/innobase/mtr/mtr0mtr.cc | 5 + storage/innobase/trx/trx0rec.cc | 2 + 38 files changed, 694 insertions(+), 63 deletions(-) create mode 100644 mysql-test/include/log_grep.inc create mode 100644 mysql-test/include/log_slow_cleanup.inc create mode 100644 mysql-test/include/log_slow_grep.inc create mode 100644 mysql-test/include/log_slow_prepare.inc create mode 100644 mysql-test/include/log_slow_start.inc create mode 100644 mysql-test/include/log_slow_stop.inc create mode 100644 mysql-test/main/log_slow_innodb.result create mode 100644 mysql-test/main/log_slow_innodb.test create mode 100644 sql/ha_handler_stats.h create mode 100644 storage/innobase/include/mariadb_stats.h diff --git a/mysql-test/include/log_grep.inc b/mysql-test/include/log_grep.inc new file mode 100644 index 00000000000..a2b0c383ae0 --- /dev/null +++ b/mysql-test/include/log_grep.inc @@ -0,0 +1,85 @@ +if ($log_expected_matches) { + --echo [log_grep.inc] file: $log_file pattern: $grep_pattern expected_matches: $log_expected_matches +} +if (!$log_expected_matches) { + --echo [log_grep.inc] file: $log_file pattern: $grep_pattern +} +--let LOG_GREP_PERL_RESULT=$MYSQL_TMP_DIR/log_grep_perl_result.test +perl; + + open my $command_file, ">", "$ENV{'LOG_GREP_PERL_RESULT'}" or die "Cannot create file"; + + $log_file= $ENV{'log_file'}; + $log_file_full_path= $ENV{'log_file_full_path'}; + $log_slow_rate_test= $ENV{'log_slow_rate_test'}; + open(FILE, "$log_file_full_path") + or die("Cannot open file $log_file_full_path: $!\n"); + + if ($log_slow_rate_test) { + $one= 0; + $two= 0; + $three= 0; + while() { + $one++ if(/'connection_one'/); + $two++ if(/'connection_two'/); + $three++ if(/'connection_three'/); + } + $sum= $one + $two + $three; + $zero= 0; + if ($one == 0) { + $zero++; + } + if ($two == 0) { + $zero++; + } + if ($three == 0) { + $zero++; + } + print "[log_grep.inc] sum: $sum\n"; + print "[log_grep.inc] zero: $zero\n"; + } + else { + $grep_pattern= $ENV{'grep_pattern'}; + $lines= 0; + while() { + $lines++ if (/$grep_pattern/); + } + $log_expected_matches= $ENV{'log_expected_matches'}; + if ($log_expected_matches) { + if ($log_expected_matches != $lines) { + print "[log_grep.inc] ERROR: expected matches: $log_expected_matches, actual matches: $lines\n"; + print "[log_grep.inc] log file at $log_file_full_path\n"; + close(FILE); + open(FILE, "$log_file_full_path") + or die("Cannot open file $log_file_full_path: $!\n"); + while () { + print ; + } + print $command_file "--let \$log_grep_failed= 1;\n"; + } else { + print "[log_grep.inc] found expected match count: $log_expected_matches\n"; + } + } else { + print "[log_grep.inc] lines: $lines\n"; + } + } + close(FILE); + close($command_file); +EOF +--source $LOG_GREP_PERL_RESULT +--remove_file $LOG_GREP_PERL_RESULT +if ($log_grep_failed) +{ + SHOW SESSION STATUS LIKE 'Slow_queries'; + SHOW GLOBAL VARIABLES LIKE 'log%'; + SHOW GLOBAL VARIABLES LIKE 'long_query_time'; + SHOW GLOBAL VARIABLES LIKE 'min_examined_row_limit'; + SHOW GLOBAL VARIABLES LIKE 'query_cache%'; + SHOW GLOBAL VARIABLES LIKE 'slow_query%'; + SHOW SESSION VARIABLES LIKE 'log%'; + SHOW SESSION VARIABLES LIKE 'long_query_time'; + SHOW SESSION VARIABLES LIKE 'min_examined_row_limit'; + SHOW SESSION VARIABLES LIKE 'query_cache%'; + SHOW SESSION VARIABLES LIKE 'slow_query%'; + --die Testcase failed! +} diff --git a/mysql-test/include/log_slow_cleanup.inc b/mysql-test/include/log_slow_cleanup.inc new file mode 100644 index 00000000000..f3d87275a31 --- /dev/null +++ b/mysql-test/include/log_slow_cleanup.inc @@ -0,0 +1,6 @@ +--remove_files_wildcard $MYSQLTEST_VARDIR/tmp $log_slow_prefix-*.slog +--disable_query_log +EVAL SET GLOBAL log_output= $log_output_old; +EVAL SET GLOBAL slow_query_log_file= "$slow_query_log_file_old"; +EVAL SET GLOBAL slow_query_log= $slow_query_log_old; +--enable_query_log diff --git a/mysql-test/include/log_slow_grep.inc b/mysql-test/include/log_slow_grep.inc new file mode 100644 index 00000000000..004c8ccefbc --- /dev/null +++ b/mysql-test/include/log_slow_grep.inc @@ -0,0 +1,25 @@ +# Common extensions to the slow query log +--let grep_pattern = ^# Thread_id: .+ Schema: .+ QC_hit: (Yes|No)\$ +--let log_expected_matches = $log_slow_verbosity_expected_matches +--source include/log_grep.inc +--let grep_pattern = ^# Query_time: \d+\.\d+ Lock_time: \d+\.\d+ Rows_sent: \d+ Rows_examined: \d+\$ +--source include/log_grep.inc + --let grep_pattern = ^# Rows_affected: \d+ Bytes_sent: \d+\$ +--source include/log_grep.inc + +# Query plan +--let log_expected_matches = $log_slow_verbosity_queryplan_expected_matches +--let grep_pattern = ^# Full_scan: (Yes|No) Full_join: (Yes|No) Tmp_table: (Yes|No) Tmp_table_on_disk: (Yes|No)\$ +--source include/log_grep.inc +--let grep_pattern = ^# Filesort: (Yes|No) Filesort_on_disk: (Yes|No) Merge_passes: \d+\ Priority_queue: (Yes|No)\$ +--source include/log_grep.inc + +# Temp tables +--let log_expected_matches = $log_slow_verbosity_tmptable_expected_matches +--source include/log_grep.inc +--let grep_pattern = ^# Tmp_tables: \d+ Tmp_disk_tables: \d+\$ +--source include/log_grep.inc + +# InnoDB/Engines +--let log_expected_matches = $log_slow_innodb_expected_matches +--let grep_pattern = ^# Pages_accessed: \d+ Pages_read: \d+ Pages_updated: \d+ Old_rows_read: \d+\n# Pages_read_time: \d+\.\d+ Engine_time: \d+\.\d+\$ diff --git a/mysql-test/include/log_slow_prepare.inc b/mysql-test/include/log_slow_prepare.inc new file mode 100644 index 00000000000..7abc56b7fb5 --- /dev/null +++ b/mysql-test/include/log_slow_prepare.inc @@ -0,0 +1,8 @@ +--disable_query_log +--let slow_query_log_old= `select @@slow_query_log` +--let slow_query_log_file_old= `select @@slow_query_log_file` +--let log_output_old= `select @@log_output` + +SET GLOBAL slow_query_log=0; +SET GLOBAL log_output=FILE; +--enable_query_log diff --git a/mysql-test/include/log_slow_start.inc b/mysql-test/include/log_slow_start.inc new file mode 100644 index 00000000000..e562a6976d3 --- /dev/null +++ b/mysql-test/include/log_slow_start.inc @@ -0,0 +1,6 @@ +--disable_query_log +--let log_file_full_path=$MYSQLTEST_VARDIR/tmp/$log_file.slog +--echo [slow_log_start.inc] $log_file +EVAL SET GLOBAL slow_query_log_file="$log_file_full_path"; +SET GLOBAL slow_query_log=1; +--enable_query_log diff --git a/mysql-test/include/log_slow_stop.inc b/mysql-test/include/log_slow_stop.inc new file mode 100644 index 00000000000..7ee24af9d8a --- /dev/null +++ b/mysql-test/include/log_slow_stop.inc @@ -0,0 +1,4 @@ +--disable_query_log +SET GLOBAL slow_query_log=0; +--echo [log_slow_stop.inc] $log_file +--enable_query_log diff --git a/mysql-test/main/analyze_stmt_slow_query_log-master.opt b/mysql-test/main/analyze_stmt_slow_query_log-master.opt index 1c80c45b0c1..a0fe99a1676 100644 --- a/mysql-test/main/analyze_stmt_slow_query_log-master.opt +++ b/mysql-test/main/analyze_stmt_slow_query_log-master.opt @@ -1 +1 @@ ---slow-query-log --long-query-time=0.00001 --log-slow-verbosity=query_plan,explain +--slow-query-log --long-query-time=0.00001 --log-slow-verbosity=query_plan,explain,innodb diff --git a/mysql-test/main/log_slow_innodb.result b/mysql-test/main/log_slow_innodb.result new file mode 100644 index 00000000000..a7c2ac86eed --- /dev/null +++ b/mysql-test/main/log_slow_innodb.result @@ -0,0 +1,78 @@ +CREATE TABLE t1(a INT primary key, b int) ENGINE=InnoDB; +INSERT INTO t1 select seq, seq from seq_1_to_1000; +SET SESSION min_examined_row_limit=0; +SET SESSION long_query_time=0; +SET SESSION log_slow_verbosity='innodb,query_plan'; +[slow_log_start.inc] log_slow_innodb-verbosity_1 +SELECT sum(a+b) FROM t1; +sum(a+b) +1001000 +UPDATE t1 set b=b+1 where a=1 or a=999; +[log_slow_stop.inc] log_slow_innodb-verbosity_1 +[log_grep.inc] file: log_slow_innodb-verbosity_1 pattern: ^# Thread_id: .+ Schema: .+ QC_hit: (Yes|No)$ expected_matches: 3 +[log_grep.inc] found expected match count: 3 +[log_grep.inc] file: log_slow_innodb-verbosity_1 pattern: ^# Query_time: \d+\.\d+ Lock_time: \d+\.\d+ Rows_sent: \d+ Rows_examined: \d+$ expected_matches: 3 +[log_grep.inc] found expected match count: 3 +[log_grep.inc] file: log_slow_innodb-verbosity_1 pattern: ^# Rows_affected: \d+ Bytes_sent: \d+$ expected_matches: 3 +[log_grep.inc] found expected match count: 3 +[log_grep.inc] file: log_slow_innodb-verbosity_1 pattern: ^# Full_scan: (Yes|No) Full_join: (Yes|No) Tmp_table: (Yes|No) Tmp_table_on_disk: (Yes|No)$ +[log_grep.inc] lines: 1 +[log_grep.inc] file: log_slow_innodb-verbosity_1 pattern: ^# Filesort: (Yes|No) Filesort_on_disk: (Yes|No) Merge_passes: \d+\ Priority_queue: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_1 pattern: ^# Filesort: (Yes|No) Filesort_on_disk: (Yes|No) Merge_passes: \d+\ Priority_queue: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_1 pattern: ^# Tmp_tables: \d+ Tmp_disk_tables: \d+$ +[log_grep.inc] lines: 0 +SET SESSION log_slow_verbosity='innodb,query_plan'; +[slow_log_start.inc] log_slow_innodb-verbosity_2 +SELECT 1; +1 +1 +[log_slow_stop.inc] log_slow_innodb-verbosity_2 +[log_grep.inc] file: log_slow_innodb-verbosity_2 pattern: ^# Thread_id: .+ Schema: .+ QC_hit: (Yes|No)$ expected_matches: 2 +[log_grep.inc] found expected match count: 2 +[log_grep.inc] file: log_slow_innodb-verbosity_2 pattern: ^# Query_time: \d+\.\d+ Lock_time: \d+\.\d+ Rows_sent: \d+ Rows_examined: \d+$ expected_matches: 2 +[log_grep.inc] found expected match count: 2 +[log_grep.inc] file: log_slow_innodb-verbosity_2 pattern: ^# Rows_affected: \d+ Bytes_sent: \d+$ expected_matches: 2 +[log_grep.inc] found expected match count: 2 +[log_grep.inc] file: log_slow_innodb-verbosity_2 pattern: ^# Full_scan: (Yes|No) Full_join: (Yes|No) Tmp_table: (Yes|No) Tmp_table_on_disk: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_2 pattern: ^# Filesort: (Yes|No) Filesort_on_disk: (Yes|No) Merge_passes: \d+\ Priority_queue: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_2 pattern: ^# Filesort: (Yes|No) Filesort_on_disk: (Yes|No) Merge_passes: \d+\ Priority_queue: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_2 pattern: ^# Tmp_tables: \d+ Tmp_disk_tables: \d+$ +[log_grep.inc] lines: 0 +SET SESSION log_slow_verbosity='query_plan'; +[log_slow_stop.inc] log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) +[log_grep.inc] file: log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) pattern: ^# Thread_id: .+ Schema: .+ QC_hit: (Yes|No)$ expected_matches: 2 +[log_grep.inc] found expected match count: 2 +[log_grep.inc] file: log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) pattern: ^# Query_time: \d+\.\d+ Lock_time: \d+\.\d+ Rows_sent: \d+ Rows_examined: \d+$ expected_matches: 2 +[log_grep.inc] found expected match count: 2 +[log_grep.inc] file: log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) pattern: ^# Rows_affected: \d+ Bytes_sent: \d+$ expected_matches: 2 +[log_grep.inc] found expected match count: 2 +[log_grep.inc] file: log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) pattern: ^# Full_scan: (Yes|No) Full_join: (Yes|No) Tmp_table: (Yes|No) Tmp_table_on_disk: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) pattern: ^# Filesort: (Yes|No) Filesort_on_disk: (Yes|No) Merge_passes: \d+\ Priority_queue: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) pattern: ^# Filesort: (Yes|No) Filesort_on_disk: (Yes|No) Merge_passes: \d+\ Priority_queue: (Yes|No)$ +[log_grep.inc] lines: 0 +[log_grep.inc] file: log_slow_innodb-verbosity_3 +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000) pattern: ^# Tmp_tables: \d+ Tmp_disk_tables: \d+$ +[log_grep.inc] lines: 0 +DROP TABLE t1; diff --git a/mysql-test/main/log_slow_innodb.test b/mysql-test/main/log_slow_innodb.test new file mode 100644 index 00000000000..2cd2b654ee5 --- /dev/null +++ b/mysql-test/main/log_slow_innodb.test @@ -0,0 +1,75 @@ +# +# Test the extended slow query log output format for various log_slow_verbosity values. +# Test that InnoDB stats for the extended slow query log are collected. +# +# This test file is based on tests from Percona server +# + +--source include/have_innodb.inc +--source include/have_sequence.inc +--source include/log_slow_prepare.inc +# Cannot be used with view protocol as number of temporary tables changes +--source include/no_view_protocol.inc + +--let $log_slow_prefix=log_slow_innodb + +# Force cold buffer pool +#--let $restart_parameters=--innodb_buffer_pool_load_at_startup=OFF +#--source include/restart_mysqld.inc + +CREATE TABLE t1(a INT primary key, b int) ENGINE=InnoDB; +INSERT INTO t1 select seq, seq from seq_1_to_1000; + +SET SESSION min_examined_row_limit=0; +SET SESSION long_query_time=0; + +# +# Test all enabled options with InnoDB-involving query +# +SET SESSION log_slow_verbosity='innodb,query_plan'; +--let log_file=$log_slow_prefix-verbosity_1 + +--source include/log_slow_start.inc +SELECT sum(a+b) FROM t1; +UPDATE t1 set b=b+1 where a=1 or a=999; +--source include/log_slow_stop.inc + +--let log_slow_verbosity_expected_matches= 3 +--let log_slow_verbosity_queryplan_matches= 1 +--let log_slow_verbosity_innodb_expected_matches= 2 +--let log_slow_verbosity_tmptable_expected_matches= 0 +--source include/log_slow_grep.inc + +# +# Test for "No InnoDB statistics available" in output when InnoDB stats are requested +# but the query does not involve InnoDB tables +# + +SET SESSION log_slow_verbosity='innodb,query_plan'; +--let log_file=$log_slow_prefix-verbosity_2 + +--source include/log_slow_start.inc +SELECT 1; +--source include/log_slow_stop.inc + +--let log_slow_verbosity_expected_matches= 2 +--let log_slow_verbosity_queryplan_matches= 1 +--let log_slow_verbosity_innodb_expected_matches= 0 +--source include/log_slow_grep.inc + +# +# Test 'query_plan' +# + +SET SESSION log_slow_verbosity='query_plan'; +let log_file=$log_slow_prefix-verbosity_3 + +--source include/log_slow_start.inc +INSERT INTO t1 VALUE(1000); +--source include/log_slow_stop.inc + +--let log_slow_verbosity_innodb_expected_matches= 1 +--source include/log_slow_grep.inc + +DROP TABLE t1; +--source include/log_slow_cleanup.inc diff --git a/mysql-test/main/mysqld--help.result b/mysql-test/main/mysqld--help.result index 5c1a8840fa5..764f5037105 100644 --- a/mysql-test/main/mysqld--help.result +++ b/mysql-test/main/mysqld--help.result @@ -528,7 +528,7 @@ The following specify which files/extra groups are read (specified before remain (Defaults to on; use --skip-log-slow-slave-statements to disable.) --log-slow-verbosity=name Verbosity level for the slow log. Any combination of: - innodb, query_plan, explain + innodb, query_plan, explain, engine, full --log-tc=name Path to transaction coordinator log (used for transactions that affect more than one storage engine, when binary log is disabled). diff --git a/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result b/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result index 8b5b06ee4b7..13f8f91ba04 100644 --- a/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result +++ b/mysql-test/suite/sys_vars/r/log_slow_verbosity_basic.result @@ -67,10 +67,10 @@ set session log_slow_verbosity='explain'; select @@session.log_slow_verbosity; @@session.log_slow_verbosity explain -set session log_slow_verbosity='innodb,query_plan,explain'; +set session log_slow_verbosity='innodb,query_plan,explain,engine,full'; select @@session.log_slow_verbosity; @@session.log_slow_verbosity -innodb,query_plan,explain +innodb,query_plan,explain,engine,full set session log_slow_verbosity=''; select @@session.log_slow_verbosity; @@session.log_slow_verbosity @@ -81,6 +81,6 @@ set session log_slow_verbosity=1e1; ERROR 42000: Incorrect argument type to variable 'log_slow_verbosity' set session log_slow_verbosity="foo"; ERROR 42000: Variable 'log_slow_verbosity' can't be set to the value of 'foo' -set session log_slow_verbosity=8; -ERROR 42000: Variable 'log_slow_verbosity' can't be set to the value of '8' +set session log_slow_verbosity=32; +ERROR 42000: Variable 'log_slow_verbosity' can't be set to the value of '32' SET @@global.log_slow_verbosity = @start_global_value; diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result index 40da0c920be..3cb3525f5fc 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_embedded.result @@ -1719,7 +1719,7 @@ VARIABLE_COMMENT Verbosity level for the slow log NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST innodb,query_plan,explain +ENUM_VALUE_LIST innodb,query_plan,explain,engine,full READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME LOG_WARNINGS diff --git a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result index 2e3173a2544..d57c1f63a07 100644 --- a/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result +++ b/mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result @@ -1859,7 +1859,7 @@ VARIABLE_COMMENT Verbosity level for the slow log NUMERIC_MIN_VALUE NULL NUMERIC_MAX_VALUE NULL NUMERIC_BLOCK_SIZE NULL -ENUM_VALUE_LIST innodb,query_plan,explain +ENUM_VALUE_LIST innodb,query_plan,explain,engine,full READ_ONLY NO COMMAND_LINE_ARGUMENT REQUIRED VARIABLE_NAME LOG_WARNINGS diff --git a/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test b/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test index 9f1cf6351a0..d3ed1a9465b 100644 --- a/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test +++ b/mysql-test/suite/sys_vars/t/log_slow_verbosity_basic.test @@ -47,7 +47,7 @@ set session log_slow_verbosity='innodb,query_plan'; select @@session.log_slow_verbosity; set session log_slow_verbosity='explain'; select @@session.log_slow_verbosity; -set session log_slow_verbosity='innodb,query_plan,explain'; +set session log_slow_verbosity='innodb,query_plan,explain,engine,full'; select @@session.log_slow_verbosity; set session log_slow_verbosity=''; select @@session.log_slow_verbosity; @@ -62,6 +62,6 @@ set session log_slow_verbosity=1e1; --error ER_WRONG_VALUE_FOR_VAR set session log_slow_verbosity="foo"; --error ER_WRONG_VALUE_FOR_VAR -set session log_slow_verbosity=8; +set session log_slow_verbosity=32; SET @@global.log_slow_verbosity = @start_global_value; diff --git a/sql/ha_handler_stats.h b/sql/ha_handler_stats.h new file mode 100644 index 00000000000..726ba6041dc --- /dev/null +++ b/sql/ha_handler_stats.h @@ -0,0 +1,59 @@ +#ifndef HA_HANDLER_STATS_INCLUDED +#define HA_HANDLER_STATS_INCLUDED +/* + Copyright (c) 2023, MariaDB Foundation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA +*/ + +/* Definitions for parameters to do with handler-routines */ + +class ha_handler_stats +{ +public: + ulonglong pages_accessed; /* Pages accessed from page cache */ + ulonglong pages_updated; /* Pages changed in page cache */ + ulonglong pages_read_count; /* Pages read from disk */ + ulonglong pages_read_time; /* Time reading pages, in microsec. */ + ulonglong undo_records_read; + ulonglong engine_time; /* Time spent in engine in microsec */ + uint active; /* <> 0 if status has to be updated */ +#define first_stat pages_accessed +#define last_stat engine_time + inline void reset() + { + bzero((void*) this, sizeof(*this)); + } + inline void add(ha_handler_stats *stats) + { + ulonglong *to= &first_stat; + ulonglong *from= &stats->first_stat; + do + { + (*to)+= *from++; + } while (to++ != &last_stat); + } + inline bool has_stats() + { + ulonglong *to= &first_stat; + do + { + if (*to) + return 1; + } while (to++ != &last_stat); + return 0; + } +}; +#endif /* HA_HANDLER_STATS_INCLUDED */ diff --git a/sql/ha_partition.cc b/sql/ha_partition.cc index ea5bcfe29c2..bddba4211a2 100644 --- a/sql/ha_partition.cc +++ b/sql/ha_partition.cc @@ -590,6 +590,7 @@ bool ha_partition::initialize_partition(MEM_ROOT *mem_root) my_error(ER_MIX_HANDLER_ERROR, MYF(0)); DBUG_RETURN(1); } + file->handler_stats= handler_stats; } while (*(++file_array)); m_handler_status= handler_initialized; DBUG_RETURN(0); @@ -4038,6 +4039,13 @@ int ha_partition::discover_check_version() return m_file[0]->discover_check_version(); } +static int set_part_handler_stats(handler *h, void *stats) +{ + h->handler_stats= (ha_handler_stats*) stats; + return 0; +} + + /** Clone the open and locked partitioning handler. @@ -4085,6 +4093,9 @@ handler *ha_partition::clone(const char *name, MEM_ROOT *mem_root) HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_NO_PSI_CALL)) goto err; + if (handler_stats) + new_handler->loop_partitions(set_part_handler_stats, handler_stats); + DBUG_RETURN((handler*) new_handler); err: @@ -4093,6 +4104,16 @@ err: } +/* + Update all sub partitions to point to handler stats +*/ + +void ha_partition::handler_stats_updated() +{ + loop_partitions(set_part_handler_stats, handler_stats); +} + + /* Close handler object diff --git a/sql/ha_partition.h b/sql/ha_partition.h index c6ec0e5660a..d75e38ec272 100644 --- a/sql/ha_partition.h +++ b/sql/ha_partition.h @@ -1645,5 +1645,6 @@ public: bool can_convert_nocopy(const Field &field, const Column_definition &new_field) const override; + void handler_stats_updated() override; }; #endif /* HA_PARTITION_INCLUDED */ diff --git a/sql/handler.cc b/sql/handler.cc index 957d7c52883..fc59204bcb7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -3226,6 +3226,7 @@ handler *handler::clone(const char *name, MEM_ROOT *mem_root) if (new_handler->ha_open(table, name, table->db_stat, HA_OPEN_IGNORE_IF_LOCKED, mem_root)) goto err; + new_handler->handler_stats= handler_stats; return new_handler; diff --git a/sql/handler.h b/sql/handler.h index ca118813656..b25f38212d1 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -35,6 +35,7 @@ #include "sql_array.h" /* Dynamic_array<> */ #include "mdl.h" #include "vers_string.h" +#include "ha_handler_stats.h" #include "sql_analyze_stmt.h" // for Exec_time_tracker @@ -3220,13 +3221,23 @@ protected: ha_rows estimation_rows_to_insert; handler *lookup_handler; + /* Statistics for the query. Updated if handler_stats.in_use is set */ + ha_handler_stats active_handler_stats; + void set_handler_stats(); public: handlerton *ht; /* storage engine of this handler */ uchar *ref; /* Pointer to current row */ uchar *dup_ref; /* Pointer to duplicate row */ uchar *lookup_buffer; + /* General statistics for the table like number of row, file sizes etc */ ha_statistics stats; + /* + Collect query stats here if pointer is != NULL. + This is a pointer because if we do a clone of the handler, we want to + use the original handler for collecting statistics. + */ + ha_handler_stats *handler_stats; /** MultiRangeRead-related members: */ range_seq_t mrr_iter; /* Iterator to traverse the range sequence */ @@ -3420,8 +3431,8 @@ public: :table_share(share_arg), table(0), estimation_rows_to_insert(0), lookup_handler(this), - ht(ht_arg), ref(0), lookup_buffer(NULL), end_range(NULL), - implicit_emptied(0), + ht(ht_arg), ref(0), lookup_buffer(NULL), handler_stats(NULL), + end_range(NULL), implicit_emptied(0), mark_trx_read_write_done(0), check_table_binlog_row_based_done(0), check_table_binlog_row_based_result(0), @@ -4851,6 +4862,22 @@ public: { check_table_binlog_row_based_done= 0; } + virtual void handler_stats_updated() {} + + inline void ha_handler_stats_reset() + { + handler_stats= &active_handler_stats; + active_handler_stats.reset(); + active_handler_stats.active= 1; + handler_stats_updated(); + } + inline void ha_handler_stats_disable() + { + handler_stats= 0; + active_handler_stats.active= 0; + handler_stats_updated(); + } + private: /* Cache result to avoid extra calls */ inline void mark_trx_read_write() @@ -5206,6 +5233,7 @@ public: } bool log_not_redoable_operation(const char *operation); + protected: Handler_share *get_ha_share_ptr(); void set_ha_share_ptr(Handler_share *arg_ha_share); diff --git a/sql/log.cc b/sql/log.cc index 811921d8322..50d1372be56 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -3204,6 +3204,10 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, char buff[80], *end; char query_time_buff[22+7], lock_time_buff[22+7]; size_t buff_len; + ulonglong log_slow_verbosity= thd->variables.log_slow_verbosity; + if (log_slow_verbosity & LOG_SLOW_VERBOSITY_FULL) + log_slow_verbosity= ~(ulonglong) 0; + end= buff; if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT)) @@ -3230,7 +3234,6 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, my_b_write(&log_file, (uchar*) "\n", 1)) goto err; - /* For slow query log */ sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0); sprintf(lock_time_buff, "%.6f", ulonglong2double(lock_utime)/1000000.0); if (my_b_printf(&log_file, @@ -3246,8 +3249,33 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, (ulong) (thd->status_var.bytes_sent - thd->bytes_sent_old))) goto err; - if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) - && thd->tmp_tables_used && + if (unlikely(log_slow_verbosity & + LOG_SLOW_VERBOSITY_ENGINE) && + thd->handler_stats.has_stats()) + { + ha_handler_stats *stats= &thd->handler_stats; + double tracker_frequency= timer_tracker_frequency(); + sprintf(query_time_buff, "%.4f", + 1000.0 * ulonglong2double(stats->pages_read_time)/ + tracker_frequency); + sprintf(lock_time_buff, "%.4f", + 1000.0 * ulonglong2double(stats->engine_time)/ + tracker_frequency); + + if (my_b_printf(&log_file, + "# Pages_accessed: %lu Pages_read: %lu " + "Pages_updated: %lu Old_rows_read: %lu\n" + "# Pages_read_time: %s Engine_time: %s\n", + (ulong) stats->pages_accessed, + (ulong) stats->pages_read_count, + (ulong) stats->pages_updated, + (ulong) stats->undo_records_read, + query_time_buff, lock_time_buff)) + goto err; + } + + if ((log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) && + thd->tmp_tables_used && my_b_printf(&log_file, "# Tmp_tables: %lu Tmp_disk_tables: %lu " "Tmp_table_sizes: %s\n", @@ -3261,7 +3289,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, ErrConvDQName(thd->spcont->m_sp).ptr())) goto err; - if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) && + if ((log_slow_verbosity & LOG_SLOW_VERBOSITY_QUERY_PLAN) && (thd->query_plan_flags & (QPLAN_FULL_SCAN | QPLAN_FULL_JOIN | QPLAN_TMP_TABLE | QPLAN_TMP_DISK | QPLAN_FILESORT | QPLAN_FILESORT_DISK | @@ -3283,8 +3311,7 @@ bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time, "Yes" : "No") )) goto err; - if (thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_EXPLAIN && - thd->lex->explain) + if (log_slow_verbosity & LOG_SLOW_VERBOSITY_EXPLAIN && thd->lex->explain) { StringBuffer<128> buf; DBUG_ASSERT(!thd->free_list); diff --git a/sql/log_slow.h b/sql/log_slow.h index c6b3407a811..366906d7cb3 100644 --- a/sql/log_slow.h +++ b/sql/log_slow.h @@ -19,9 +19,15 @@ #define LOG_SLOW_INCLUDED #define LOG_SLOW_VERBOSITY_INIT 0 -#define LOG_SLOW_VERBOSITY_INNODB (1U << 0) +#define LOG_SLOW_VERBOSITY_INNODB (1U << 0) /* Old option */ #define LOG_SLOW_VERBOSITY_QUERY_PLAN (1U << 1) #define LOG_SLOW_VERBOSITY_EXPLAIN (1U << 2) +#define LOG_SLOW_VERBOSITY_STORAGE_ENGINE (1U << 3) /* Replaces InnoDB */ +#define LOG_SLOW_VERBOSITY_FULL (1U << 4) + +#define LOG_SLOW_VERBOSITY_ENGINE (LOG_SLOW_VERBOSITY_FULL | \ + LOG_SLOW_VERBOSITY_INNODB | \ + LOG_SLOW_VERBOSITY_STORAGE_ENGINE) #define QPLAN_INIT QPLAN_QC_NO diff --git a/sql/sql_analyze_stmt.h b/sql/sql_analyze_stmt.h index e2037279a7a..996668cf6b9 100644 --- a/sql/sql_analyze_stmt.h +++ b/sql/sql_analyze_stmt.h @@ -35,9 +35,20 @@ log, should the query be slow. 2. Timing data. Measuring the time it took to run parts of query has noticeable overhead. Because of that, we measure the time only when running "ANALYZE $stmt"). - */ +/* fake microseconds as cycles if cycles isn't available */ + +static inline double timer_tracker_frequency() +{ +#if (MY_TIMER_ROUTINE_CYCLES) + return static_cast(sys_timer_info.cycles.frequency); +#else + return static_cast(sys_timer_info.microseconds.frequency); +#endif +} + + class Gap_time_tracker; void attach_gap_time_tracker(THD *thd, Gap_time_tracker *gap_tracker, ulonglong timeval); void process_gap_time_tracker(THD *thd, ulonglong timeval); @@ -52,12 +63,19 @@ protected: ulonglong cycles; ulonglong last_start; + ulonglong measure() const + { +#if (MY_TIMER_ROUTINE_CYCLES) + return my_timer_cycles(); +#else + return my_timer_microseconds(); +#endif + } + void cycles_stop_tracking(THD *thd) { - ulonglong end= my_timer_cycles(); + ulonglong end= measure(); cycles += end - last_start; - if (unlikely(end < last_start)) - cycles += ULONGLONG_MAX; process_gap_time_tracker(thd, end); if (my_gap_tracker) @@ -80,7 +98,7 @@ public: // interface for collecting time void start_tracking(THD *thd) { - last_start= my_timer_cycles(); + last_start= measure(); process_gap_time_tracker(thd, last_start); } @@ -92,12 +110,22 @@ public: // interface for getting the time ulonglong get_loops() const { return count; } - double get_time_ms() const + + inline double cycles_to_ms(ulonglong cycles_arg) const { // convert 'cycles' to milliseconds. - return 1000.0 * static_cast(cycles) / - static_cast(sys_timer_info.cycles.frequency); + return 1000.0 * static_cast(cycles_arg) / + timer_tracker_frequency(); } + double get_time_ms() const + { + return cycles_to_ms(cycles); + } + ulonglong get_cycles() const + { + return cycles; + } + bool has_timed_statistics() const { return cycles > 0; } }; @@ -120,13 +148,11 @@ public: double get_time_ms() const { // convert 'cycles' to milliseconds. - return 1000.0 * static_cast(cycles) / - static_cast(sys_timer_info.cycles.frequency); + return 1000.0 * static_cast(cycles) / timer_tracker_frequency(); } }; - /* A class for counting certain actions (in all queries), and optionally collecting the timings (in ANALYZE queries). diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 30a8d2c2d6f..00b384b6e0e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -958,11 +958,12 @@ int close_thread_tables(THD *thd) void close_thread_table(THD *thd, TABLE **table_ptr) { TABLE *table= *table_ptr; + handler *file= table->file; DBUG_ENTER("close_thread_table"); DBUG_PRINT("tcache", ("table: '%s'.'%s' %p", table->s->db.str, table->s->table_name.str, table)); - DBUG_ASSERT(!table->file->keyread_enabled()); - DBUG_ASSERT(!table->file || table->file->inited == handler::NONE); + DBUG_ASSERT(!file->keyread_enabled()); + DBUG_ASSERT(file->inited == handler::NONE); /* The metadata lock must be released after giving back @@ -972,16 +973,20 @@ void close_thread_table(THD *thd, TABLE **table_ptr) table->s->db.str, table->s->table_name.str, MDL_SHARED)); - table->vcol_cleanup_expr(thd); table->mdl_ticket= NULL; - if (table->file) + file->update_global_table_stats(); + file->update_global_index_stats(); + if (unlikely(thd->variables.log_slow_verbosity & + LOG_SLOW_VERBOSITY_ENGINE) && + likely(file->handler_stats)) { - table->file->update_global_table_stats(); - table->file->update_global_index_stats(); + Exec_time_tracker *tracker; + if ((tracker= file->get_time_tracker())) + file->handler_stats->engine_time+= tracker->get_cycles(); + thd->handler_stats.add(file->handler_stats); } - /* This look is needed to allow THD::notify_shared_lock() to traverse the thd->open_tables list without having to worry that @@ -995,17 +1000,17 @@ void close_thread_table(THD *thd, TABLE **table_ptr) if (! table->needs_reopen()) { /* Avoid having MERGE tables with attached children in table cache. */ - table->file->extra(HA_EXTRA_DETACH_CHILDREN); + file->extra(HA_EXTRA_DETACH_CHILDREN); /* Free memory and reset for next loop. */ free_field_buffers_larger_than(table, MAX_TDC_BLOB_SIZE); - table->file->ha_reset(); + file->ha_reset(); } /* Do this *before* entering the TABLE_SHARE::tdc.LOCK_table_share critical section. */ - MYSQL_UNBIND_TABLE(table->file); + MYSQL_UNBIND_TABLE(file); tc_release_table(table); DBUG_VOID_RETURN; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a49271125cc..6ac277d9525 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -5836,6 +5836,7 @@ void THD::store_slow_query_state(Sub_statement_state *backup) backup->tmp_tables_disk_used= tmp_tables_disk_used; backup->tmp_tables_size= tmp_tables_size; backup->tmp_tables_used= tmp_tables_used; + backup->handler_stats= handler_stats; } /* Reset variables related to slow query log */ @@ -5851,6 +5852,8 @@ void THD::reset_slow_query_state() tmp_tables_disk_used= 0; tmp_tables_size= 0; tmp_tables_used= 0; + if ((variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_ENGINE)) + handler_stats.reset(); } /* @@ -5869,6 +5872,8 @@ void THD::add_slow_query_state(Sub_statement_state *backup) tmp_tables_disk_used+= backup->tmp_tables_disk_used; tmp_tables_size+= backup->tmp_tables_size; tmp_tables_used+= backup->tmp_tables_used; + if ((variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_ENGINE)) + handler_stats.add(&backup->handler_stats); } diff --git a/sql/sql_class.h b/sql/sql_class.h index 2bca2c993fc..5648b4a60cb 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -51,6 +51,7 @@ #include "backup.h" #include "xa.h" #include "ddl_log.h" /* DDL_LOG_STATE */ +#include "ha_handler_stats.h" // ha_handler_stats */ extern "C" void set_thd_stage_info(void *thd, @@ -1870,6 +1871,7 @@ public: ulonglong cuted_fields, sent_row_count, examined_row_count; ulonglong affected_rows; ulonglong bytes_sent_old; + ha_handler_stats handler_stats; ulong tmp_tables_used; ulong tmp_tables_disk_used; ulong query_plan_fsort_passes; @@ -2707,6 +2709,7 @@ public: struct system_status_var status_var; // Per thread statistic vars struct system_status_var org_status_var; // For user statistics struct system_status_var *initial_status_var; /* used by show status */ + ha_handler_stats handler_stats; // Handler statistics THR_LOCK_INFO lock_info; // Locking info of this thread /** Protects THD data accessed from other threads: diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index b2e5d1ba397..f615e287fa9 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -56,7 +56,7 @@ invoked on a running DELETE statement. */ -Explain_delete* Delete_plan::save_explain_delete_data(MEM_ROOT *mem_root, THD *thd) +Explain_delete* Delete_plan::save_explain_delete_data(THD *thd, MEM_ROOT *mem_root) { Explain_query *query= thd->lex->explain; Explain_delete *explain= @@ -73,7 +73,7 @@ Explain_delete* Delete_plan::save_explain_delete_data(MEM_ROOT *mem_root, THD *t else { explain->deleting_all_rows= false; - if (Update_plan::save_explain_data_intern(mem_root, explain, + if (Update_plan::save_explain_data_intern(thd, mem_root, explain, thd->lex->analyze_stmt)) return 0; } @@ -84,21 +84,22 @@ Explain_delete* Delete_plan::save_explain_delete_data(MEM_ROOT *mem_root, THD *t Explain_update* -Update_plan::save_explain_update_data(MEM_ROOT *mem_root, THD *thd) +Update_plan::save_explain_update_data(THD *thd, MEM_ROOT *mem_root) { Explain_query *query= thd->lex->explain; Explain_update* explain= new (mem_root) Explain_update(mem_root, thd->lex->analyze_stmt); if (!explain) return 0; - if (save_explain_data_intern(mem_root, explain, thd->lex->analyze_stmt)) + if (save_explain_data_intern(thd, mem_root, explain, thd->lex->analyze_stmt)) return 0; query->add_upd_del_plan(explain); return explain; } -bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, +bool Update_plan::save_explain_data_intern(THD *thd, + MEM_ROOT *mem_root, Explain_update *explain, bool is_analyze) { @@ -120,7 +121,9 @@ bool Update_plan::save_explain_data_intern(MEM_ROOT *mem_root, return 0; } - if (is_analyze) + if (is_analyze || + (thd->variables.log_slow_verbosity & + LOG_SLOW_VERBOSITY_ENGINE)) table->file->set_time_tracker(&explain->table_tracker); select_lex->set_explain_type(TRUE); @@ -473,7 +476,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, query_type= THD::STMT_QUERY_TYPE; error= -1; deleted= maybe_deleted; - if (!query_plan.save_explain_delete_data(thd->mem_root, thd)) + if (!query_plan.save_explain_delete_data(thd, thd->mem_root)) error= 1; goto cleanup; } @@ -594,7 +597,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, if (thd->lex->describe) goto produce_explain_and_leave; - if (!(explain= query_plan.save_explain_delete_data(thd->mem_root, thd))) + if (!(explain= query_plan.save_explain_delete_data(thd, thd->mem_root))) goto got_error; ANALYZE_START_TRACKING(thd, &explain->command_tracker); @@ -977,7 +980,7 @@ produce_explain_and_leave: We come here for various "degenerate" query plans: impossible WHERE, no-partitions-used, impossible-range, etc. */ - if (!(query_plan.save_explain_delete_data(thd->mem_root, thd))) + if (!(query_plan.save_explain_delete_data(thd, thd->mem_root))) goto got_error; send_nothing_and_leave: diff --git a/sql/sql_lex.h b/sql/sql_lex.h index a7384967ce7..5725a603ead 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3010,9 +3010,9 @@ public: void set_impossible_where() { impossible_where= true; } void set_no_partitions() { no_partitions= true; } - Explain_update* save_explain_update_data(MEM_ROOT *mem_root, THD *thd); + Explain_update* save_explain_update_data(THD *thd, MEM_ROOT *mem_root); protected: - bool save_explain_data_intern(MEM_ROOT *mem_root, Explain_update *eu, bool is_analyze); + bool save_explain_data_intern(THD *thd, MEM_ROOT *mem_root, Explain_update *eu, bool is_analyze); public: virtual ~Update_plan() = default; @@ -3047,7 +3047,7 @@ public: deleting_all_rows= false; } - Explain_delete* save_explain_delete_data(MEM_ROOT *mem_root, THD *thd); + Explain_delete* save_explain_delete_data(THD *thd, MEM_ROOT *mem_root); }; enum account_lock_type diff --git a/sql/sql_select.cc b/sql/sql_select.cc index f9b655d5af7..27c51879f4f 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -27750,12 +27750,16 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, jbuf_unpack_tracker= &eta->jbuf_unpack_tracker; /* Enable the table access time tracker only for "ANALYZE stmt" */ - if (thd->lex->analyze_stmt) + if (unlikely(thd->lex->analyze_stmt || + thd->variables.log_slow_verbosity & + LOG_SLOW_VERBOSITY_ENGINE)) { table->file->set_time_tracker(&eta->op_tracker); - eta->op_tracker.set_gap_tracker(&eta->extra_time_tracker); - - eta->jbuf_unpack_tracker.set_gap_tracker(&eta->jbuf_extra_time_tracker); + if (likely(thd->lex->analyze_stmt)) + { + eta->op_tracker.set_gap_tracker(&eta->extra_time_tracker); + eta->jbuf_unpack_tracker.set_gap_tracker(&eta->jbuf_extra_time_tracker); + } } /* No need to save id and select_type here, they are kept in Explain_select */ diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 4c45822a802..ea368cce0e1 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -689,7 +689,7 @@ int mysql_update(THD *thd, */ if (thd->lex->describe) goto produce_explain_and_leave; - if (!(explain= query_plan.save_explain_update_data(query_plan.mem_root, thd))) + if (!(explain= query_plan.save_explain_update_data(thd, query_plan.mem_root))) goto err; ANALYZE_START_TRACKING(thd, &explain->command_tracker); @@ -1375,7 +1375,7 @@ produce_explain_and_leave: We come here for various "degenerate" query plans: impossible WHERE, no-partitions-used, impossible-range, etc. */ - if (unlikely(!query_plan.save_explain_update_data(query_plan.mem_root, thd))) + if (unlikely(!query_plan.save_explain_update_data(thd, query_plan.mem_root))) goto err; emit_explain_and_leave: diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 29cd5809ea1..76bc29d623b 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -6429,8 +6429,9 @@ static Sys_var_ulong Sys_log_slow_rate_limit( SESSION_VAR(log_slow_rate_limit), CMD_LINE(REQUIRED_ARG), VALID_RANGE(1, UINT_MAX), DEFAULT(1), BLOCK_SIZE(1)); -static const char *log_slow_verbosity_names[]= { "innodb", "query_plan", - "explain", 0 }; +static const char *log_slow_verbosity_names[]= +{ "innodb", "query_plan", "explain", "engine", "full", 0}; + static Sys_var_set Sys_log_slow_verbosity( "log_slow_verbosity", "Verbosity level for the slow log", diff --git a/sql/table.cc b/sql/table.cc index 218b1bd8287..cd66a3466ce 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5677,6 +5677,12 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) (*f_ptr)->cond_selectivity= 1.0; } + /* enable and clear or disable engine query statistics */ + if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_ENGINE)) + file->ha_handler_stats_reset(); + else + file->ha_handler_stats_disable(); + notnull_cond= 0; DBUG_ASSERT(!file->keyread_enabled()); diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index 90886173b1b..14b5f0e682b 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -37,6 +37,7 @@ Created 11/5/1995 Heikki Tuuri #include "buf0buf.h" #include "buf0checksum.h" #include "ut0crc32.h" +#include "mariadb_stats.h" #include #ifndef UNIV_INNOCHECKSUM @@ -2177,6 +2178,7 @@ buf_page_t* buf_page_get_zip(const page_id_t page_id, ulint zip_size) ut_ad(zip_size); ut_ad(ut_is_2pow(zip_size)); ++buf_pool.stat.n_page_gets; + mariadb_increment_pages_accessed(); buf_pool_t::hash_chain &chain= buf_pool.page_hash.cell_get(page_id.fold()); page_hash_latch &hash_lock= buf_pool.page_hash.lock_get(chain); @@ -2272,6 +2274,7 @@ must_read_page: switch (dberr_t err= buf_read_page(page_id, zip_size)) { case DB_SUCCESS: case DB_SUCCESS_LOCKED_REC: + mariadb_increment_pages_read(); goto lookup; default: ib::error() << "Reading compressed page " << page_id @@ -2449,6 +2452,7 @@ buf_page_get_low( || ibuf_page_low(page_id, zip_size, FALSE, NULL)); ++buf_pool.stat.n_page_gets; + mariadb_increment_pages_accessed(); auto& chain= buf_pool.page_hash.cell_get(page_id.fold()); page_hash_latch& hash_lock = buf_pool.page_hash.lock_get(chain); @@ -2520,6 +2524,7 @@ loop: switch (dberr_t local_err = buf_read_page(page_id, zip_size)) { case DB_SUCCESS: case DB_SUCCESS_LOCKED_REC: + mariadb_increment_pages_read(); buf_read_ahead_random(page_id, zip_size, ibuf_inside(mtr)); break; default: @@ -3080,7 +3085,6 @@ bool buf_page_optimistic_get(ulint rw_latch, buf_block_t *block, ut_ad(~buf_page_t::LRU_MASK & state); ut_ad(block->page.frame); - ++buf_pool.stat.n_page_gets; return true; } @@ -3118,6 +3122,7 @@ buf_block_t *buf_page_try_get(const page_id_t page_id, mtr_t *mtr) ut_ad(block->page.id() == page_id); ++buf_pool.stat.n_page_gets; + mariadb_increment_pages_accessed(); return block; } diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc index cf76a9bd93a..dae1527dde6 100644 --- a/storage/innobase/buf/buf0rea.cc +++ b/storage/innobase/buf/buf0rea.cc @@ -42,6 +42,7 @@ Created 11/5/1995 Heikki Tuuri #include "srv0start.h" #include "srv0srv.h" #include "log.h" +#include "mariadb_stats.h" /** If there are buf_pool.curr_size per the number below pending reads, then read-ahead is not done: this is to prevent flooding the buffer pool with @@ -295,9 +296,12 @@ buf_read_page_low( } ut_ad(bpage->in_file()); + ulonglong mariadb_timer= 0; if (sync) { thd_wait_begin(nullptr, THD_WAIT_DISKIO); + if (mariadb_stats_active()) + mariadb_timer= mariadb_measure(); } DBUG_LOG("ib_buf", @@ -322,6 +326,8 @@ buf_read_page_low( if (fio.err == DB_FAIL) { fio.err = DB_PAGE_CORRUPTED; } + if (mariadb_timer) + mariadb_increment_pages_read_time(mariadb_timer); } return fio.err; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ca03a5cdf0b..3d0da6bbf74 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -113,6 +113,9 @@ this program; if not, write to the Free Software Foundation, Inc., #include "fil0pagecompress.h" #include "ut0mem.h" #include "row0ext.h" +#include "mariadb_stats.h" +thread_local ha_handler_stats mariadb_dummy_stats; +thread_local ha_handler_stats *mariadb_stats= &mariadb_dummy_stats; #include @@ -7845,6 +7848,7 @@ ha_innobase::write_row( #endif int error_result = 0; bool auto_inc_used = false; + mariadb_set_stats set_stats_temporary(handler_stats); DBUG_ENTER("ha_innobase::write_row"); @@ -8605,6 +8609,7 @@ ha_innobase::update_row( dberr_t error; trx_t* trx = thd_to_trx(m_user_thd); + mariadb_set_stats set_stats_temporary(handler_stats); DBUG_ENTER("ha_innobase::update_row"); @@ -8784,6 +8789,7 @@ ha_innobase::delete_row( { dberr_t error; trx_t* trx = thd_to_trx(m_user_thd); + mariadb_set_stats set_stats_temporary(handler_stats); DBUG_ENTER("ha_innobase::delete_row"); @@ -9027,6 +9033,7 @@ ha_innobase::index_read( enum ha_rkey_function find_flag)/*!< in: search flags from my_base.h */ { DBUG_ENTER("index_read"); + mariadb_set_stats set_stats_temporary(handler_stats); DEBUG_SYNC_C("ha_innobase_index_read_begin"); ut_a(m_prebuilt->trx == thd_to_trx(m_user_thd)); @@ -9353,6 +9360,7 @@ ha_innobase::general_fetch( { DBUG_ENTER("general_fetch"); + mariadb_set_stats set_stats_temporary(handler_stats); const trx_t* trx = m_prebuilt->trx; ut_ad(trx == thd_to_trx(m_user_thd)); @@ -9560,7 +9568,6 @@ ha_innobase::rnd_next( in MySQL format */ { int error; - DBUG_ENTER("rnd_next"); if (m_start_of_scan) { @@ -9825,6 +9832,7 @@ ha_innobase::ft_read( uchar* buf) /*!< in/out: buf contain result row */ { row_prebuilt_t* ft_prebuilt; + mariadb_set_stats set_stats_temporary(handler_stats); ft_prebuilt = reinterpret_cast(ft_handler)->ft_prebuilt; @@ -13862,6 +13870,7 @@ static dberr_t innobase_rename_table(trx_t *trx, const char *from, @retval 0 on success */ int ha_innobase::truncate() { + mariadb_set_stats set_stats_temporary(handler_stats); DBUG_ENTER("ha_innobase::truncate"); update_thd(); @@ -14427,7 +14436,7 @@ ha_innobase::estimate_rows_upper_bound() const dict_index_t* index; ulonglong estimate; ulonglong local_data_file_length; - + mariadb_set_stats set_stats_temporary(handler_stats); DBUG_ENTER("estimate_rows_upper_bound"); /* We do not know if MySQL can call this function before calling @@ -16644,6 +16653,7 @@ ha_innobase::get_auto_increment( trx_t* trx; dberr_t error; ulonglong autoinc = 0; + mariadb_set_stats set_stats_temporary(handler_stats); /* Prepare m_prebuilt->trx in the table handle */ update_thd(ha_thd()); diff --git a/storage/innobase/include/mariadb_stats.h b/storage/innobase/include/mariadb_stats.h new file mode 100644 index 00000000000..e9051c0c08b --- /dev/null +++ b/storage/innobase/include/mariadb_stats.h @@ -0,0 +1,119 @@ +/***************************************************************************** + +Copyright (c) 2023, MariaDB Foundation + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; version 2 of the License. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA + +*****************************************************************************/ + +#ifndef mariadb_stats_h +#define mariadb_stats_h + +/* Include file to handle mariadbd handler specific stats */ + +#include "ha_handler_stats.h" +#include "my_rdtsc.h" + +/* Not active threads are ponting to this structure */ +extern thread_local ha_handler_stats mariadb_dummy_stats; + +/* Points to either THD->handler_stats or mariad_dummy_stats */ +extern thread_local ha_handler_stats *mariadb_stats; + +/* + Returns 1 if MariaDB wants engine status +*/ + +inline bool mariadb_stats_active() +{ + return mariadb_stats->active != 0; +} + +inline bool mariadb_stats_active(ha_handler_stats *stats) +{ + return stats->active != 0; +} + +/* The following functions increment different engine status */ + +inline void mariadb_increment_pages_accessed() +{ + mariadb_stats->pages_accessed++; +} + +inline void mariadb_increment_pages_updated(ulonglong count) +{ + mariadb_stats->pages_updated+= count; +} + +inline void mariadb_increment_pages_read() +{ + mariadb_stats->pages_read_count++; +} + +inline void mariadb_increment_undo_records_read() +{ + mariadb_stats->undo_records_read++; +} + +/* + The following has to be identical code as measure() in sql_analyze_stmt.h + + One should only call this if mariadb_stats_active() is true. +*/ + +inline ulonglong mariadb_measure() +{ +#if (MY_TIMER_ROUTINE_CYCLES) + return my_timer_cycles(); +#else + return my_timer_microseconds(); +#endif +} + +/* + Call this only of start_time != 0 + See buf0rea.cc for an example of how to use it efficiently +*/ + +inline void mariadb_increment_pages_read_time(ulonglong start_time) +{ + ha_handler_stats *stats= mariadb_stats; + ulonglong end_time= mariadb_measure(); + /* Check that we only call this if active, see example! */ + DBUG_ASSERT(start_time); + DBUG_ASSERT(mariadb_stats_active(stats)); + + stats->pages_read_time+= (end_time - start_time); +} + + +/* + Helper class to set mariadb_stats temporarly for one call in handler.cc +*/ + +class mariadb_set_stats +{ +public: + uint flag; + mariadb_set_stats(ha_handler_stats *stats) + { + mariadb_stats= stats ? stats : &mariadb_dummy_stats; + } + ~mariadb_set_stats() + { + mariadb_stats= &mariadb_dummy_stats; + } +}; + +#endif /* mariadb_stats_h */ diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index a9f1c87d600..2e5bdceb677 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -39,6 +39,7 @@ Created 9/17/2000 Heikki Tuuri struct row_prebuilt_t; class ha_innobase; +class ha_handler_stats; /*******************************************************************//** Frees the blob heap in prebuilt when no longer needed. */ diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc index 8817c77a6f4..6fc72386928 100644 --- a/storage/innobase/mtr/mtr0mtr.cc +++ b/storage/innobase/mtr/mtr0mtr.cc @@ -37,6 +37,7 @@ Created 11/26/1995 Heikki Tuuri #endif #include "srv0start.h" #include "log.h" +#include "mariadb_stats.h" void mtr_memo_slot_t::release() const { @@ -139,6 +140,7 @@ void mtr_t::commit() ut_ad(!srv_read_only_mode || m_log_mode == MTR_LOG_NO_REDO); std::pair lsns; + size_t modified= 0; if (UNIV_LIKELY(is_logged())) { @@ -188,6 +190,7 @@ void mtr_t::commit() { if (slot.type & MTR_MEMO_MODIFY) { + modified++; ut_ad(slot.type == MTR_MEMO_PAGE_X_MODIFY || slot.type == MTR_MEMO_PAGE_SX_MODIFY); buf_flush_note_modification(static_cast(slot.object), @@ -200,6 +203,8 @@ void mtr_t::commit() release(); + mariadb_increment_pages_updated(modified); + if (UNIV_UNLIKELY(lsns.second != PAGE_FLUSH_NO)) buf_flush_ahead(m_commit_lsn, lsns.second == PAGE_FLUSH_SYNC); diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index d3f64754d89..364877346c0 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -39,6 +39,7 @@ Created 3/26/1996 Heikki Tuuri #include "row0row.h" #include "row0mysql.h" #include "row0ins.h" +#include "mariadb_stats.h" /** The search tuple corresponding to TRX_UNDO_INSERT_METADATA. */ const dtuple_t trx_undo_metadata = { @@ -2175,6 +2176,7 @@ trx_undo_prev_version_build( return DB_SUCCESS; } + mariadb_increment_undo_records_read(); rec_trx_id = row_get_rec_trx_id(rec, index, offsets); ut_ad(!index->table->skip_alter_undo); From 6ed14bcc0692ea0973cd8114af0dc63b4089efb3 Mon Sep 17 00:00:00 2001 From: Monty Date: Fri, 7 Jul 2023 12:53:50 +0300 Subject: [PATCH 25/40] Disable view protocol for opt_trace.test This is because some plan changes because of views --- mysql-test/main/opt_trace.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mysql-test/main/opt_trace.test b/mysql-test/main/opt_trace.test index 171f5a2627f..07e0694cf7a 100644 --- a/mysql-test/main/opt_trace.test +++ b/mysql-test/main/opt_trace.test @@ -1,5 +1,8 @@ --source include/not_embedded.inc --source include/have_sequence.inc +# View protocol changes some plans +--source include/no_view_protocol.inc + SELECT table_name, column_name FROM information_schema.columns where table_name="OPTIMIZER_TRACE"; set optimizer_trace="enabled=on"; show variables like 'optimizer_trace'; From c358e216d989a57f4188e766799fc83a4675c5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 10 Jul 2023 11:14:54 +0300 Subject: [PATCH 26/40] MDEV-31642: Upgrade may crash if innodb_log_file_buffering=OFF recv_log_recover_10_5(): Make reads aligned by 4096 bytes, to avoid any trouble in case the file was opened in O_DIRECT mode and the physical block size is larger than 512 bytes. Because innodb_log_file_size used to be defined in whole megabytes, reading multiples of 4096 bytes instead of 512 should not be an issue. --- mysql-test/suite/innodb/t/log_corruption.test | 6 +++--- storage/innobase/log/log0recv.cc | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/mysql-test/suite/innodb/t/log_corruption.test b/mysql-test/suite/innodb/t/log_corruption.test index 6f7080f5b50..b4466c5efde 100644 --- a/mysql-test/suite/innodb/t/log_corruption.test +++ b/mysql-test/suite/innodb/t/log_corruption.test @@ -591,11 +591,11 @@ print OUT pack("x[470]N", 0x677700cf); # invalid (all-zero) checkpoint page 1 and an empty log page print OUT chr(0) x 1024; # valid checkpoint block 2 -print OUT pack("x[12]NNNx[264]", 0x12860c, 0, 0x80c); +print OUT pack("x[12]NNNx[264]", 0x12860c, 0, 0x120c); # pointer to the FILE_CHECKPOINT record, and checkpoint page checksum -print OUT pack("H*x[204]NNN", "590DBAACFE922582", 0x128612, 0, 0x101741b); +print OUT pack("H*x[204]NNN", "590DBAACFE922582", 0x128612, 0, 0x3b4ce62d); # log page -print OUT pack("NnnNx[496]N", 0x80000944, 12, 12, 1, 0x46c8a2a2); +print OUT pack("x[2560]NnnNx[496]N", 0x80000944, 12, 12, 1, 0x46c8a2a2); close OUT or die; EOF diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 042e7981d73..8aba2981092 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1639,7 +1639,10 @@ static dberr_t recv_log_recover_10_5(lsn_t lsn_offset) if (lsn_offset < (log_sys.is_pmem() ? log_sys.file_size : 4096)) memcpy_aligned<512>(buf, &log_sys.buf[lsn_offset & ~511], 512); else - recv_sys.read(lsn_offset & ~lsn_t{511}, {buf, 512}); + { + recv_sys.read(lsn_offset & ~lsn_t{4095}, {buf, 4096}); + buf+= lsn_offset & 0xe00; + } if (!recv_check_log_block(buf)) { @@ -1757,7 +1760,7 @@ dberr_t recv_sys_t::find_checkpoint() if (dberr_t err= recv_log_recover_pre_10_2()) return err; upgrade: - memset_aligned<512>(const_cast(field_ref_zero), 0, 512); + memset_aligned<4096>(const_cast(field_ref_zero), 0, 4096); /* Mark the redo log for upgrading. */ log_sys.last_checkpoint_lsn= log_sys.next_checkpoint_lsn; log_sys.set_recovered_lsn(log_sys.next_checkpoint_lsn); From 090a84366ad27564ae5e8be01fa1c672508d13ab Mon Sep 17 00:00:00 2001 From: Vlad Lesin Date: Thu, 6 Jul 2023 11:49:28 +0300 Subject: [PATCH 27/40] MDEV-29311 Server Status Innodb_row_lock_time% is reported in seconds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before MDEV-24671, the wait time was derived from my_interval_timer() / 1000 (nanoseconds converted to microseconds, and not microseconds to milliseconds like I must have assumed). The lock_sys.wait_time and lock_sys.wait_time_max are already in milliseconds; we should not divide them by 1000. In MDEV-24738 the millisecond counts lock_sys.wait_time and lock_sys.wait_time_max were changed to a 32-bit type. That would overflow in 49.7 days. Keep using a 64-bit type for those millisecond counters. Reviewed by: Marko Mäkelä --- .../innodb/r/innodb_row_lock_time_ms.result | 40 ++++++++++++++++++ .../innodb/t/innodb_row_lock_time_ms.test | 42 +++++++++++++++++++ storage/innobase/handler/ha_innodb.cc | 4 +- storage/innobase/include/lock0lock.h | 8 ++-- storage/innobase/include/srv0srv.h | 11 ++--- storage/innobase/lock/lock0lock.cc | 4 +- storage/innobase/srv/srv0mon.cc | 7 ++-- storage/innobase/srv/srv0srv.cc | 7 ++-- 8 files changed, 100 insertions(+), 23 deletions(-) create mode 100644 mysql-test/suite/innodb/r/innodb_row_lock_time_ms.result create mode 100644 mysql-test/suite/innodb/t/innodb_row_lock_time_ms.test diff --git a/mysql-test/suite/innodb/r/innodb_row_lock_time_ms.result b/mysql-test/suite/innodb/r/innodb_row_lock_time_ms.result new file mode 100644 index 00000000000..984d789e058 --- /dev/null +++ b/mysql-test/suite/innodb/r/innodb_row_lock_time_ms.result @@ -0,0 +1,40 @@ +CREATE TABLE `t`(`id` INT, PRIMARY KEY(`id`)) ENGINE=InnoDB STATS_PERSISTENT=0; +INSERT INTO t VALUES (1); +SET GLOBAL innodb_monitor_reset = "module_innodb"; +BEGIN; +SELECT * FROM t FOR UPDATE; +id +1 +connect con1,localhost,root,,; +SET innodb_lock_wait_timeout = 1; +SELECT * FROM t FOR UPDATE; +ERROR HY000: Lock wait timeout exceeded; try restarting transaction +disconnect con1; +connection default; +COMMIT; +SELECT variable_value > 100 FROM information_schema.global_status +WHERE LOWER(variable_name) = 'innodb_row_lock_time'; +variable_value > 100 +1 +SELECT variable_value > 100 FROM information_schema.global_status +WHERE LOWER(variable_name) = 'innodb_row_lock_time_max'; +variable_value > 100 +1 +SELECT variable_value > 100 FROM information_schema.global_status +WHERE LOWER(variable_name) = 'innodb_row_lock_time_avg'; +variable_value > 100 +1 +SELECT count_reset > 100 FROM INFORMATION_SCHEMA.INNODB_METRICS +WHERE NAME="lock_row_lock_time"; +count_reset > 100 +1 +SELECT count_reset > 100 FROM INFORMATION_SCHEMA.INNODB_METRICS +WHERE NAME="lock_row_lock_time_max"; +count_reset > 100 +1 +SELECT count_reset > 100 FROM INFORMATION_SCHEMA.INNODB_METRICS +WHERE NAME="lock_row_lock_time_avg"; +count_reset > 100 +1 +DROP TABLE t; +SET GLOBAL innodb_monitor_reset=default; diff --git a/mysql-test/suite/innodb/t/innodb_row_lock_time_ms.test b/mysql-test/suite/innodb/t/innodb_row_lock_time_ms.test new file mode 100644 index 00000000000..4a100821819 --- /dev/null +++ b/mysql-test/suite/innodb/t/innodb_row_lock_time_ms.test @@ -0,0 +1,42 @@ +--source include/have_innodb.inc +--source include/count_sessions.inc + +CREATE TABLE `t`(`id` INT, PRIMARY KEY(`id`)) ENGINE=InnoDB STATS_PERSISTENT=0; + +INSERT INTO t VALUES (1); + +SET GLOBAL innodb_monitor_reset = "module_innodb"; + +BEGIN; +SELECT * FROM t FOR UPDATE; + +--connect(con1,localhost,root,,) +SET innodb_lock_wait_timeout = 1; +--error ER_LOCK_WAIT_TIMEOUT +SELECT * FROM t FOR UPDATE; +--disconnect con1 + +--connection default +COMMIT; + +SELECT variable_value > 100 FROM information_schema.global_status + WHERE LOWER(variable_name) = 'innodb_row_lock_time'; +SELECT variable_value > 100 FROM information_schema.global_status + WHERE LOWER(variable_name) = 'innodb_row_lock_time_max'; +SELECT variable_value > 100 FROM information_schema.global_status + WHERE LOWER(variable_name) = 'innodb_row_lock_time_avg'; + +SELECT count_reset > 100 FROM INFORMATION_SCHEMA.INNODB_METRICS + WHERE NAME="lock_row_lock_time"; +SELECT count_reset > 100 FROM INFORMATION_SCHEMA.INNODB_METRICS + WHERE NAME="lock_row_lock_time_max"; +SELECT count_reset > 100 FROM INFORMATION_SCHEMA.INNODB_METRICS + WHERE NAME="lock_row_lock_time_avg"; + +DROP TABLE t; + +--disable_warnings +SET GLOBAL innodb_monitor_reset=default; +--enable_warnings + +--source include/wait_until_count_sessions.inc diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3d0da6bbf74..c44748d3c5f 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -1010,8 +1010,8 @@ static SHOW_VAR innodb_status_variables[]= { {"row_lock_current_waits", &export_vars.innodb_row_lock_current_waits, SHOW_SIZE_T}, {"row_lock_time", &export_vars.innodb_row_lock_time, SHOW_LONGLONG}, - {"row_lock_time_avg", &export_vars.innodb_row_lock_time_avg, SHOW_SIZE_T}, - {"row_lock_time_max", &export_vars.innodb_row_lock_time_max, SHOW_SIZE_T}, + {"row_lock_time_avg", &export_vars.innodb_row_lock_time_avg, SHOW_ULONGLONG}, + {"row_lock_time_max", &export_vars.innodb_row_lock_time_max, SHOW_ULONGLONG}, {"row_lock_waits", &export_vars.innodb_row_lock_waits, SHOW_SIZE_T}, {"rows_deleted", &export_vars.innodb_rows_deleted, SHOW_SIZE_T}, {"rows_inserted", &export_vars.innodb_rows_inserted, SHOW_SIZE_T}, diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h index e8299bb1189..4c92984f2f6 100644 --- a/storage/innobase/include/lock0lock.h +++ b/storage/innobase/include/lock0lock.h @@ -755,9 +755,9 @@ private: /** waits and total number of lock waits; protected by wait_mutex */ uint64_t wait_count; /** Cumulative wait time; protected by wait_mutex */ - uint32_t wait_time; + uint64_t wait_time; /** Longest wait time; protected by wait_mutex */ - uint32_t wait_time_max; + uint64_t wait_time_max; public: /** number of deadlocks detected; protected by wait_mutex */ ulint deadlocks; @@ -916,9 +916,9 @@ public: ulint get_wait_cumulative() const { return static_cast(wait_count / WAIT_COUNT_STEP); } /** Cumulative wait time; protected by wait_mutex */ - ulint get_wait_time_cumulative() const { return wait_time; } + uint64_t get_wait_time_cumulative() const { return wait_time; } /** Longest wait time; protected by wait_mutex */ - ulint get_wait_time_max() const { return wait_time_max; } + uint64_t get_wait_time_max() const { return wait_time_max; } /** Get the lock hash table for a mode */ hash_table &hash_get(ulint mode) diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h index c4c854f6b9c..0052f015239 100644 --- a/storage/innobase/include/srv0srv.h +++ b/storage/innobase/include/srv0srv.h @@ -708,13 +708,10 @@ struct export_var_t{ ulint innodb_os_log_pending_fsyncs; /*!< n_pending_log_flushes */ ulint innodb_row_lock_waits; /*!< srv_n_lock_wait_count */ ulint innodb_row_lock_current_waits; /*!< srv_n_lock_wait_current_count */ - int64_t innodb_row_lock_time; /*!< srv_n_lock_wait_time - / 1000 */ - ulint innodb_row_lock_time_avg; /*!< srv_n_lock_wait_time - / 1000 - / srv_n_lock_wait_count */ - ulint innodb_row_lock_time_max; /*!< srv_n_lock_max_wait_time - / 1000 */ + int64_t innodb_row_lock_time; /*!< srv_n_lock_wait_time */ + uint64_t innodb_row_lock_time_avg; /*!< srv_n_lock_wait_time + / srv_n_lock_wait_count */ + uint64_t innodb_row_lock_time_max; /*!< srv_n_lock_max_wait_time */ ulint innodb_rows_read; /*!< srv_n_rows_read */ ulint innodb_rows_inserted; /*!< srv_n_rows_inserted */ ulint innodb_rows_updated; /*!< srv_n_rows_updated */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 08547f169f3..6a7e4a2843e 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -1648,8 +1648,8 @@ void lock_sys_t::wait_resume(THD *thd, my_hrtime_t start, my_hrtime_t now) wait_count--; if (now.val >= start.val) { - const uint32_t diff_time= - static_cast((now.val - start.val) / 1000); + const uint64_t diff_time= + static_cast((now.val - start.val) / 1000); wait_time+= diff_time; if (diff_time > wait_time_max) diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc index 3065ab19462..aa14bc00976 100644 --- a/storage/innobase/srv/srv0mon.cc +++ b/storage/innobase/srv/srv0mon.cc @@ -1677,21 +1677,20 @@ srv_mon_process_existing_counter( /* innodb_row_lock_time */ case MONITOR_OVLD_LOCK_WAIT_TIME: // dirty read without lock_sys.wait_mutex - value = lock_sys.get_wait_time_cumulative() / 1000; + value = lock_sys.get_wait_time_cumulative(); break; /* innodb_row_lock_time_max */ case MONITOR_OVLD_LOCK_MAX_WAIT_TIME: // dirty read without lock_sys.wait_mutex - value = lock_sys.get_wait_time_max() / 1000; + value = lock_sys.get_wait_time_max(); break; /* innodb_row_lock_time_avg */ case MONITOR_OVLD_LOCK_AVG_WAIT_TIME: mysql_mutex_lock(&lock_sys.wait_mutex); if (auto count = lock_sys.get_wait_cumulative()) { - value = lock_sys.get_wait_time_cumulative() / 1000 - / count; + value = lock_sys.get_wait_time_cumulative() / count; } else { value = 0; } diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 8a4df1b0d14..38ec7377fa4 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -1057,10 +1057,9 @@ srv_export_innodb_status(void) export_vars.innodb_row_lock_current_waits= lock_sys.get_wait_pending(); - export_vars.innodb_row_lock_time = lock_sys.get_wait_time_cumulative() - / 1000; - export_vars.innodb_row_lock_time_max = lock_sys.get_wait_time_max() - / 1000; + export_vars.innodb_row_lock_time = lock_sys.get_wait_time_cumulative(); + export_vars.innodb_row_lock_time_max = lock_sys.get_wait_time_max(); + mysql_mutex_unlock(&lock_sys.wait_mutex); export_vars.innodb_row_lock_time_avg= export_vars.innodb_row_lock_waits From 90cd3b38f68a52d2c08630750900693b77842697 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Mon, 8 May 2023 10:58:17 +0300 Subject: [PATCH 28/40] MDEV-31118: Remove version-substvar-for-external-package problems In debian/control file there is several mariadb-*-10.9 Conflicts or Replaces that which are not neede on MariaDB 10.9 anymore as there is not suffix anymore. Package libmariadbclient-dev is part of Ubuntu and it's not build with official package so there can't be variable: '${source:Version}' which is used with packages that are part of package. NOTE TO MERGER: This is only up-to MariaDB 10.10. --- debian/control | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/debian/control b/debian/control index 2c59314bb4b..cc1e3410be0 100644 --- a/debian/control +++ b/debian/control @@ -341,7 +341,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-client-10.6, mariadb-client-10.7, mariadb-client-10.8, - mariadb-client-10.9 (<< ${source:Version}), mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3, @@ -371,7 +370,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-server-core-10.6, mariadb-server-core-10.7, mariadb-server-core-10.8, - mariadb-server-core-10.9 (<< ${source:Version}), mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, @@ -423,7 +421,6 @@ Conflicts: mariadb-client (<< ${source:Version}), mariadb-client-10.6, mariadb-client-10.7, mariadb-client-10.8, - mariadb-client-10.9 (<< ${source:Version}), mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3, @@ -453,7 +450,6 @@ Breaks: mariadb-client-core (<< ${source:Version}), mariadb-client-core-10.6, mariadb-client-core-10.7, mariadb-client-core-10.8, - mariadb-client-core-10.9 (<< ${source:Version}), mariadb-server (<< ${source:Version}), mariadb-server-10.0, mariadb-server-10.1, @@ -464,7 +460,6 @@ Breaks: mariadb-client-core (<< ${source:Version}), mariadb-server-10.6, mariadb-server-10.7, mariadb-server-10.8, - mariadb-server-10.9 (<< ${source:Version}), mariadb-server-core (<< ${source:Version}), mariadb-server-core-10.0, mariadb-server-core-10.1, @@ -496,7 +491,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-client-10.6, mariadb-client-10.7, mariadb-client-10.8, - mariadb-client-10.9 (<< ${source:Version}), mariadb-client-5.1, mariadb-client-5.2, mariadb-client-5.3, @@ -511,7 +505,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-client-core-10.6, mariadb-client-core-10.7, mariadb-client-core-10.8, - mariadb-client-core-10.9 (<< ${source:Version}), mariadb-server (<< ${source:Version}), mariadb-server-10.0, mariadb-server-10.1, @@ -522,7 +515,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-server-10.6, mariadb-server-10.7, mariadb-server-10.8, - mariadb-server-10.9 (<< ${source:Version}), mariadb-server-core (<< ${source:Version}), mariadb-server-core-10.0, mariadb-server-core-10.1, @@ -533,7 +525,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-server-core-10.6, mariadb-server-core-10.7, mariadb-server-core-10.8, - mariadb-server-core-10.9 (<< ${source:Version}), mysql-client (<< 5.0.51), mysql-client-5.0, mysql-client-5.1, @@ -589,7 +580,6 @@ Conflicts: mariadb-server-core-10.0, mariadb-server-core-10.6, mariadb-server-core-10.7, mariadb-server-core-10.8, - mariadb-server-core-10.9 (<< ${source:Version}), mariadb-server-core-5.1, mariadb-server-core-5.2, mariadb-server-core-5.3, @@ -612,7 +602,6 @@ Breaks: mariadb-client (<< ${source:Version}), mariadb-client-10.6, mariadb-client-10.7, mariadb-client-10.8, - mariadb-client-10.9 (<< ${source:Version}), mariadb-server (<< ${source:Version}), mariadb-server-10.0, mariadb-server-10.1, @@ -623,7 +612,6 @@ Breaks: mariadb-client (<< ${source:Version}), mariadb-server-10.6, mariadb-server-10.7, mariadb-server-10.8, - mariadb-server-10.9 (<< ${source:Version}), mysql-client-5.5, mysql-server-5.5, mysql-server-5.6, @@ -642,7 +630,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-client-10.6, mariadb-client-10.7, mariadb-client-10.8, - mariadb-client-10.9 (<< ${source:Version}), mariadb-server (<< ${source:Version}), mariadb-server-10.0, mariadb-server-10.1, @@ -653,7 +640,6 @@ Replaces: mariadb-client (<< ${source:Version}), mariadb-server-10.6, mariadb-server-10.7, mariadb-server-10.8, - mariadb-server-10.9 (<< ${source:Version}), mariadb-server-core-10.0, mariadb-server-core-10.1, mariadb-server-core-10.2, @@ -728,7 +714,6 @@ Conflicts: mariadb-server (<< ${source:Version}), mariadb-server-10.6, mariadb-server-10.7, mariadb-server-10.8, - mariadb-server-10.9 (<< ${source:Version}), mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3, @@ -763,7 +748,6 @@ Replaces: handlersocket-mysql-5.5, mariadb-client-10.6, mariadb-client-10.7, mariadb-client-10.8, - mariadb-client-10.9 (<< ${source:Version}), mariadb-server (<< ${source:Version}), mariadb-server-10.0, mariadb-server-10.1, @@ -774,7 +758,6 @@ Replaces: handlersocket-mysql-5.5, mariadb-server-10.6, mariadb-server-10.7, mariadb-server-10.8, - mariadb-server-10.9 (<< ${source:Version}), mariadb-server-5.1, mariadb-server-5.2, mariadb-server-5.3, From 3dd3308152e1514e5b6808159f26156e994fd24c Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Mon, 8 May 2023 11:06:52 +0300 Subject: [PATCH 29/40] MDEV-31118: Rework Salsa-CI YAML work again Salsa-CI file has got in malfunction state and if fails with YAML error: mariadb-10.3 with Buster backports upgrade job: undefined need: build buster-backports Also remove Salsa-CI MariaDB 10.3 double upgrade target. There is also several upgrades which makes test green again. NOTE TO MERGER: This is only up-to MariaDB 10.10. Remove --- debian/salsa-ci.yml | 174 +++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 82 deletions(-) diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml index e30a96c41e2..27b9c2c5bad 100644 --- a/debian/salsa-ci.yml +++ b/debian/salsa-ci.yml @@ -56,6 +56,14 @@ build i386: script: - *autobake-deb-steps +build bullseye-backports: + extends: .build-package + variables: + RELEASE: bullseye-backports + +# Buster only has libfmt 6.1 but 7.0 is required, so backport build for Buster +# is not possible unless somebody packages libfmt7-dev for Buster. + build sid: extends: .build-package script: @@ -112,6 +120,12 @@ blhc: mysql --table -e "SELECT * FROM plugin;" mysql mysql --table -e "SHOW PLUGINS;" mysql +# Readline was removed from Debian Sid (and Bullseye) in Feb 2021. To be able to install older +# versions of MariaDB that depend on it, fetch and install it from Buster. +.test-install-readline-in-sid-for-backwards-compat: &test-install-readline-in-sid-for-backwards-compat | + curl -sS -O http://ftp.de.debian.org/debian/pool/main/r/readline5/libreadline5_5.2+dfsg-3+b13_amd64.deb + apt-get -qq install --no-install-recommends --yes ./libreadline5_5.2+dfsg-3+b13_amd64.deb + .test-enable-bullseye-repos: &test-enable-bullseye-repos # Replace any old repos with just Sid - echo 'deb http://deb.debian.org/debian bullseye main' > /etc/apt/sources.list @@ -119,6 +133,17 @@ blhc: - apt-get update -qq - apt-get install -y apt +.test-enable-buster-backports-repos: &test-enable-buster-backports-repos | + # Enable buster-backports (assumes environment already Debian Buster) + echo 'deb http://deb.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/buster-backports.list + # Increase default backports priority policy from '100' to '500' so it can actually be used + cat << EOF > /etc/apt/preferences.d/enable-backports-to-satisfy-dependencies + Package: * + Pin: release n=buster-* + Pin-Priority: 500 + EOF + apt-get update -qq + .test-enable-bullseye-backports-repos: &test-enable-bullseye-backports-repos | # Enable bullseye-backports (assumes environment already Debian Bullseye) echo 'deb http://deb.debian.org/debian bullseye-backports main' > /etc/apt/sources.list.d/bullseye-backports.list @@ -130,16 +155,28 @@ blhc: EOF apt-get update -qq -.test-enable-buster-backports-repos: &test-enable-buster-backports-repos | - # Enable buster-backports (assumes environment already Debian Buster) - echo 'deb http://deb.debian.org/debian buster-backports main' > /etc/apt/sources.list.d/buster-backports.list - # Increase default backports priority policy from '100' to '500' so it can actually be used - cat << EOF > /etc/apt/preferences.d/enable-backports-to-satisfy-dependencies - Package: * - Pin: release n=buster-* - Pin-Priority: 500 - EOF - apt-get update -qq +.test-enable-sid-repos: &test-enable-sid-repos + # Apply usrmerge workaround for Stretch/Buster/Bullseye to Bookworm/Sid upgrades + - echo 'this system will not be supported in the future' > /etc/unsupported-skip-usrmerge-conversion + # Replace any old repos with just Sid + - echo 'deb http://deb.debian.org/debian sid main' > /etc/apt/sources.list + # Upgrade minimal stack first + - apt-get update -qq + # Next step will fail on https://bugs.debian.org/993755 + # /usr/bin/perl: error while loading shared libraries: libcrypt.so.1: cannot + # open shared object file: No such file or directory + # dpkg: error processing package libc6:amd64 (--configure): + - apt-get install -y apt || true + # Apply workaround + - cd $(mktemp -d) # Use temp dir where apt can download and unpack files + - apt-get -y download libcrypt1 + - dpkg-deb -x libcrypt1_*.deb . + - cp -ra lib/* /lib/ + - cd - # Back to /builds/$USER/mariadb-server/debian/output + - find /lib/*/libcrypt.* -ls # Show that new libcrypt is there + - apt-get -y --fix-broken install + # Complete upgrade of minimal stack + - apt-get install -y apt .test-install: &test-install # Install MariaDB built in this commit @@ -252,35 +289,6 @@ mariadb-10.5 Bullseye upgrade: variables: - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ -mariadb-10.3 with Buster backports upgrade: - stage: upgrade extras - needs: - - job: build buster-backports - image: debian:buster - artifacts: - when: always - name: "$CI_BUILD_NAME" - paths: - - ${WORKING_DIR}/debug - script: - - *test-prepare-container - # Install everything MariaDB 10.3 currently in Debian Buster - - apt-get install -y 'default-mysql*' 'mariadb-*' 'libmariadb*' - # Verify installation of MariaDB from Buster - - *test-verify-initial - # Buster backports is needed for liburing1 (>= 0.7) and galera-4 (>= 26.4) - - *test-enable-buster-backports-repos - - *test-install - # mariadb-10.3 in Buster ships a /etc/init.d/mysql so it should continue to work - - service mysql status - - service mariadb status - - *test-verify-final - variables: - GIT_STRATEGY: none - except: - variables: - - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ - mariadb-10.3 Buster upgrade: stage: upgrade from Buster needs: @@ -490,6 +498,43 @@ mysql-8.0 from Ubuntu 22.04 upgrade: variables: - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ +# Upgrading from MySQL 8.0 with datadir in place is not possible. Users need to do a data dump. +# The Debian maintainer scripts detect this situation and simply moves old datadir aside and start fresh. +mysql-community-cluster-8.0 from MySQL.com upgrade: + stage: upgrade extras + needs: + - job: build + image: debian:${RELEASE} + artifacts: + when: always + name: "$CI_BUILD_NAME" + paths: + - ${WORKING_DIR}/debug + script: + - *test-prepare-container + - apt-get install --no-install-recommends --yes ca-certificates curl systemctl + - curl -sS "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x859be8d7c586f538430b19c2467b942d3a79bd29" -o /etc/apt/trusted.gpg.d/mysql.asc + - echo "deb https://repo.mysql.com/apt/debian/ bullseye mysql-cluster-8.0" > /etc/apt/sources.list.d/mysql.list + - apt-get update -qq + - apt-get install -y mysql-cluster-community-server + - sed 's/ExecStartPre=+/ExecStartPre=/' -i /lib/systemd/system/mysql.service # Hack to make file compatible with systemctl shim + - systemctl start mysql + - dpkg -l | grep -iE 'maria|mysql|galera' + - systemctl status mysql; mysql -e 'SELECT VERSION()' + - systemctl stop mysql # Stop manually as maintainer scripts don't handle this with systemctl shim + - *test-install + # Ignore systemctl shim result as MariaDB systemd file is incompatible with it and yields: + # ERROR:systemctl:the ExecStartPre control process exited with error code + - systemctl status mysql || true + - mysql -e 'SELECT VERSION()' || true + - sleep 5 # Give the mysql_upgrade a bit of time to complete before querying the server + - *test-verify-final + variables: + GIT_STRATEGY: none + except: + variables: + - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ + mariadb.org 10.9 to mariadb upgrade: stage: upgrade extras needs: @@ -556,43 +601,6 @@ mariadb.org-10.8 to mariadb upgrade: - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ allow_failure: true -# Upgrading from MySQL 8.0 with datadir in place is not possible. Users need to do a data dump. -# The Debian maintainer scripts detect this situation and simply moves old datadir aside and start fresh. -mysql-community-cluster-8.0 from MySQL.com upgrade: - stage: upgrade extras - needs: - - job: build - image: debian:${RELEASE} - artifacts: - when: always - name: "$CI_BUILD_NAME" - paths: - - ${WORKING_DIR}/debug - script: - - *test-prepare-container - - apt-get install --no-install-recommends --yes ca-certificates curl systemctl - - curl -sS "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x859be8d7c586f538430b19c2467b942d3a79bd29" -o /etc/apt/trusted.gpg.d/mysql.asc - - echo "deb https://repo.mysql.com/apt/debian/ bullseye mysql-cluster-8.0" > /etc/apt/sources.list.d/mysql.list - - apt-get update -qq - - apt-get install -y mysql-cluster-community-server - - sed 's/ExecStartPre=+/ExecStartPre=/' -i /lib/systemd/system/mysql.service # Hack to make file compatible with systemctl shim - - systemctl start mysql - - dpkg -l | grep -iE 'maria|mysql|galera' - - systemctl status mysql; mysql -e 'SELECT VERSION()' - - systemctl stop mysql # Stop manually as maintainer scripts don't handle this with systemctl shim - - *test-install - # Ignore systemctl shim result as MariaDB systemd file is incompatible with it and yields: - # ERROR:systemctl:the ExecStartPre control process exited with error code - - systemctl status mysql || true - - mysql -e 'SELECT VERSION()' || true - - sleep 5 # Give the mysql_upgrade a bit of time to complete before querying the server - - *test-verify-final - variables: - GIT_STRATEGY: none - except: - variables: - - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ - mariadb.org-10.7 to mariadb upgrade: stage: upgrade extras needs: @@ -685,11 +693,11 @@ mariadb.org-10.5 to mariadb upgrade: variables: - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ -mariadb.org-10.4 to mariadb with Buster backports upgrade: +mariadb.org-10.4 to mariadb upgrade: stage: upgrade extras needs: - - job: build buster-backports - image: debian:buster + - job: build + image: debian:${RELEASE} artifacts: when: always name: "$CI_BUILD_NAME" @@ -701,6 +709,7 @@ mariadb.org-10.4 to mariadb with Buster backports upgrade: - curl -sS https://mariadb.org/mariadb_release_signing_key.asc -o /etc/apt/trusted.gpg.d/mariadb.asc - echo "deb https://archive.mariadb.org/mariadb-10.4/repo/debian buster main" > /etc/apt/sources.list.d/mariadb.list - apt-get update -qq + - *test-install-readline-in-sid-for-backwards-compat - apt-get install -y mariadb-server-10.4 # MariaDB.org version of 10.4 and early 10.5 do not install an init file, so # it must be installed here manually @@ -719,11 +728,11 @@ mariadb.org-10.4 to mariadb with Buster backports upgrade: variables: - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/ -mariadb.org-10.3 to mariadb with Buster backports upgrade: +mariadb.org-10.3 to mariadb upgrade: stage: upgrade extras needs: - - job: build bullseye-backports - image: debian:bullseye + - job: build + image: debian:${RELEASE} artifacts: when: always name: "$CI_BUILD_NAME" @@ -735,6 +744,7 @@ mariadb.org-10.3 to mariadb with Buster backports upgrade: - curl -sS https://mariadb.org/mariadb_release_signing_key.asc -o /etc/apt/trusted.gpg.d/mariadb.asc - echo "deb https://archive.mariadb.org/mariadb-10.3/repo/debian buster main" > /etc/apt/sources.list.d/mariadb.list - apt-get update -qq + - *test-install-readline-in-sid-for-backwards-compat - apt-get install -y mariadb-server-10.3 - *test-verify-initial # Buster backports is needed for liburing1 (>= 0.7) and galera-4 (>= 26.4) From 14eff727c3716efdf1328c3df30ed023241c835b Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Mon, 8 May 2023 11:09:44 +0300 Subject: [PATCH 30/40] MDEV-31118: Override lintian dh-addon for systemd Lintian erros with missing-build-dependency-for-dh-addon systemd (*) One of these premises should be installed: debhelper:any (>= 9.20160709~) debhelper-compat:any dh-sequence-systemd:any dh-systemd:any As there is package debhelper version 10 or higher required for build. This is false positive Lintian error which should be supressed.. NOTE TO MERGER: This is only up-to MariaDB 10.10. --- debian/source/lintian-overrides | 3 +++ 1 file changed, 3 insertions(+) diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides index 0666044ac38..bb41cac9f8f 100644 --- a/debian/source/lintian-overrides +++ b/debian/source/lintian-overrides @@ -1,3 +1,6 @@ +# MariaDB use high enough debhelper so this is should +# be considered as bug in lintia +missing-build-dependency-for-dh-addon systemd (*) # Necessary for drop-in-place-replacement upgrades on mysql-server/-client # since package breaks/replaces these but at the same time also provides them version-substvar-for-external-package mariadb-client-core -> mysql-client-5.5 From fe5957ee92df6ef54b3396c04ee151386fbcd1bc Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Tue, 9 May 2023 09:01:02 +0300 Subject: [PATCH 31/40] MDEV-31118: Add Lintian overrides for false positives MariaDB Compression pluging pacakages mariadb-plugin-provider-* have only one shared object and those are not linked against libc and it's intentional so supressing error library-not-linked-against-libc There is needed dependency for Systemd DH plugin which makes error missing-build-dependency-for-dh-addon obsolette. Reworked debian/control that makes most of version-substvar-for-external-package error not correct so remove those that are not available anymore and update those that are still relevant. NOTE TO MERGER: This is only up-to MariaDB 10.10. --- ...db-plugin-provider-bzip2.lintian-overrides | 3 ++- ...iadb-plugin-provider-lz4.lintian-overrides | 3 ++- ...adb-plugin-provider-lzma.lintian-overrides | 3 ++- ...iadb-plugin-provider-lzo.lintian-overrides | 3 ++- ...b-plugin-provider-snappy.lintian-overrides | 3 ++- debian/source/lintian-overrides | 20 ++++--------------- 6 files changed, 14 insertions(+), 21 deletions(-) diff --git a/debian/mariadb-plugin-provider-bzip2.lintian-overrides b/debian/mariadb-plugin-provider-bzip2.lintian-overrides index 563c05a3a6b..50e280b56da 100644 --- a/debian/mariadb-plugin-provider-bzip2.lintian-overrides +++ b/debian/mariadb-plugin-provider-bzip2.lintian-overrides @@ -1,3 +1,4 @@ # It's intentional that bzip2 compression plugin doesn't have symbols from libc # More info https://jira.mariadb.org/browse/MDEV-28120 -library-not-linked-against-libc usr/lib/mysql/plugin/provider_bzip2.so \ No newline at end of file +library-not-linked-against-libc usr/lib/mysql/plugin/provider_bzip2.so +library-not-linked-against-libc [usr/lib/mysql/plugin/provider_bzip2.so] diff --git a/debian/mariadb-plugin-provider-lz4.lintian-overrides b/debian/mariadb-plugin-provider-lz4.lintian-overrides index 3f7d7e9ecfb..4df09a0af4e 100644 --- a/debian/mariadb-plugin-provider-lz4.lintian-overrides +++ b/debian/mariadb-plugin-provider-lz4.lintian-overrides @@ -1,3 +1,4 @@ # It's intentional that LZ4 compression plugin doesn't have symbols from libc # More info https://jira.mariadb.org/browse/MDEV-28120 -library-not-linked-against-libc usr/lib/mysql/plugin/provider_lz4.so \ No newline at end of file +library-not-linked-against-libc usr/lib/mysql/plugin/provider_lz4.so +library-not-linked-against-libc [usr/lib/mysql/plugin/provider_lz4.so] diff --git a/debian/mariadb-plugin-provider-lzma.lintian-overrides b/debian/mariadb-plugin-provider-lzma.lintian-overrides index 94eafa766a4..2d9f4b8adc2 100644 --- a/debian/mariadb-plugin-provider-lzma.lintian-overrides +++ b/debian/mariadb-plugin-provider-lzma.lintian-overrides @@ -1,3 +1,4 @@ # It's intentional that LZMA compression plugin doesn't have symbols from libc # More info https://jira.mariadb.org/browse/MDEV-28120 -library-not-linked-against-libc usr/lib/mysql/plugin/provider_lzma.so \ No newline at end of file +library-not-linked-against-libc usr/lib/mysql/plugin/provider_lzma.so +library-not-linked-against-libc [usr/lib/mysql/plugin/provider_lzma.so] diff --git a/debian/mariadb-plugin-provider-lzo.lintian-overrides b/debian/mariadb-plugin-provider-lzo.lintian-overrides index 8184923cf9a..13015fde854 100644 --- a/debian/mariadb-plugin-provider-lzo.lintian-overrides +++ b/debian/mariadb-plugin-provider-lzo.lintian-overrides @@ -1,3 +1,4 @@ # It's intentional that LZO compression plugin doesn't have symbols from libc # More info https://jira.mariadb.org/browse/MDEV-28120 -library-not-linked-against-libc usr/lib/mysql/plugin/provider_lzo.so \ No newline at end of file +library-not-linked-against-libc usr/lib/mysql/plugin/provider_lzo.so +library-not-linked-against-libc [usr/lib/mysql/plugin/provider_lzo.so] diff --git a/debian/mariadb-plugin-provider-snappy.lintian-overrides b/debian/mariadb-plugin-provider-snappy.lintian-overrides index 6c76162573d..2ddf25d0dd0 100644 --- a/debian/mariadb-plugin-provider-snappy.lintian-overrides +++ b/debian/mariadb-plugin-provider-snappy.lintian-overrides @@ -1,3 +1,4 @@ # It's intentional that Snappy compression plugin doesn't have symbols from libc # More info https://jira.mariadb.org/browse/MDEV-28120 -library-not-linked-against-libc usr/lib/mysql/plugin/provider_snappy.so \ No newline at end of file +library-not-linked-against-libc usr/lib/mysql/plugin/provider_snappy.so +library-not-linked-against-libc [usr/lib/mysql/plugin/provider_snappy.so] diff --git a/debian/source/lintian-overrides b/debian/source/lintian-overrides index bb41cac9f8f..3ff96f76556 100644 --- a/debian/source/lintian-overrides +++ b/debian/source/lintian-overrides @@ -1,6 +1,6 @@ # MariaDB use high enough debhelper so this is should # be considered as bug in lintia -missing-build-dependency-for-dh-addon systemd (*) +missing-build-dependency-for-dh-addon systemd * # Necessary for drop-in-place-replacement upgrades on mysql-server/-client # since package breaks/replaces these but at the same time also provides them version-substvar-for-external-package mariadb-client-core -> mysql-client-5.5 @@ -12,23 +12,11 @@ version-substvar-for-external-package mariadb-server-10.9 -> mysql-client-8.* version-substvar-for-external-package mariadb-client-10.9 -> mysql-client-core-5.* version-substvar-for-external-package mariadb-client-10.9 -> mysql-client-core-8.* version-substvar-for-external-package libmariadbd-dev -> libmariadbclient-dev -# Intentional version-substvar-for-external-package as long as mariadb-server -# provides mariadb-server-10.9 and mariadb-client provides mariadb-client-10.9 -version-substvar-for-external-package Conflicts (line 408) ${source:Version} mariadb-client -> mariadb-client-10.9 -version-substvar-for-external-package Conflicts (line 575) ${source:Version} mariadb-server-core -> mariadb-server-core-10.9 -version-substvar-for-external-package Conflicts (line 711) ${source:Version} mariadb-server -> mariadb-server-10.9 +# These are left for reason version-substvar-for-external-package version-substvar-for-external-package Conflicts (line 95) ${source:Version} libmariadb-dev-compat -> libmariadbclient-dev version-substvar-for-external-package Replaces (line 109) ${source:Version} libmariadb-dev-compat -> libmariadbclient-dev -version-substvar-for-external-package Replaces (line 330) ${source:Version} mariadb-client-core -> mariadb-client-10.9 -version-substvar-for-external-package Replaces (line 330) ${source:Version} mariadb-client-core -> mariadb-server-core-10.9 -version-substvar-for-external-package Replaces (line 481) ${source:Version} mariadb-client -> mariadb-client-10.9 -version-substvar-for-external-package Replaces (line 481) ${source:Version} mariadb-client -> mariadb-client-core-10.9 -version-substvar-for-external-package Replaces (line 481) ${source:Version} mariadb-client -> mariadb-server-10.9 -version-substvar-for-external-package Replaces (line 481) ${source:Version} mariadb-client -> mariadb-server-core-10.9 -version-substvar-for-external-package Replaces (line 626) ${source:Version} mariadb-server-core -> mariadb-client-10.9 -version-substvar-for-external-package Replaces (line 626) ${source:Version} mariadb-server-core -> mariadb-server-10.9 -version-substvar-for-external-package Replaces (line 748) ${source:Version} mariadb-server -> mariadb-client-10.9 -version-substvar-for-external-package Replaces (line 748) ${source:Version} mariadb-server -> mariadb-server-10.9 +version-substvar-for-external-package Conflicts ${source:Version} libmariadb-dev-compat -> libmariadbclient-dev [*] +version-substvar-for-external-package Replaces ${source:Version} libmariadb-dev-compat -> libmariadbclient-dev [*] # ColumnStore not used in Debian, safe to ignore. Reported upstream in https://jira.mariadb.org/browse/MDEV-24124 source-is-missing storage/columnstore/columnstore/utils/jemalloc/libjemalloc.so.2 source-is-missing [storage/columnstore/columnstore/utils/jemalloc/libjemalloc.so.2] From b27167c6d6f2ab4ed6659e519c75bfc02eb91549 Mon Sep 17 00:00:00 2001 From: Tuukka Pasanen Date: Thu, 15 Jun 2023 13:40:13 +0300 Subject: [PATCH 32/40] Make sure that here is MariaDB client available --- debian/salsa-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/salsa-ci.yml b/debian/salsa-ci.yml index 27b9c2c5bad..49063722988 100644 --- a/debian/salsa-ci.yml +++ b/debian/salsa-ci.yml @@ -551,7 +551,7 @@ mariadb.org 10.9 to mariadb upgrade: - curl -sS https://mariadb.org/mariadb_release_signing_key.asc -o /etc/apt/trusted.gpg.d/mariadb.asc - echo "deb https://deb.mariadb.org/10.9/debian ${RELEASE} main" > /etc/apt/sources.list.d/mariadb.list - apt-get update - - apt-get install -y mariadb-server-10.9 + - apt-get install -y mariadb-server-10.9 mariadb-client-10.9 - *test-verify-initial # Install MariaDB built in this commit # Force downgrades so our version installs on top of upstream revision, e.g. 1:10.9.1-1 vs 1:10.9.1+mariadb~sid From feaeb27b6913e3c1dc67f01bb80b381fec333b56 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Tue, 11 Jul 2023 20:24:28 +0300 Subject: [PATCH 33/40] MDEV-29152: Assertion failed ... upon TO_CHAR with wrong argument Item_func_tochar::check_arguments() didn't check if its arguments each had one column. Failing to make this check and proceeding would eventually cause either an assertion failure or the execution would reach "MY_ASSERT_UNREACHABLE();" which would produce a crash with a misleading stack trace. * Fixed Item_func_tochar::check_arguments() to do the required check. * Also fixed MY_ASSERT_UNREACHABLE() to terminate the program. Just "executing" __builtin_unreachable() used to cause "undefined results", which in my experience was a crash with corrupted stack trace. --- include/my_compiler.h | 12 ++++++++++-- mysql-test/suite/compat/oracle/r/func_to_char.result | 7 +++++++ mysql-test/suite/compat/oracle/t/func_to_char.test | 10 ++++++++++ sql/item_timefunc.h | 5 ++++- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/my_compiler.h b/include/my_compiler.h index ff049f3d8a6..b979b5a5b73 100644 --- a/include/my_compiler.h +++ b/include/my_compiler.h @@ -40,7 +40,15 @@ /* GNU C/C++ */ #if defined __GNUC__ # define MY_ALIGN_EXT -# define MY_ASSERT_UNREACHABLE() __builtin_unreachable() + +/* + __builtin_unreachable() removes the "statement may fall through" warning-as- + error when MY_ASSERT_UNREACHABLE() is used in "case xxx:" in switch (...) + statements. + abort() is there to prevent the execution from reaching the + __builtin_unreachable() as this may cause misleading stack traces. +*/ +# define MY_ASSERT_UNREACHABLE() { abort(); __builtin_unreachable(); } /* Microsoft Visual C++ */ #elif defined _MSC_VER @@ -88,7 +96,7 @@ #endif #ifndef MY_ASSERT_UNREACHABLE -# define MY_ASSERT_UNREACHABLE() do { assert(0); } while (0) +# define MY_ASSERT_UNREACHABLE() do { abort(); } while (0) #endif /** diff --git a/mysql-test/suite/compat/oracle/r/func_to_char.result b/mysql-test/suite/compat/oracle/r/func_to_char.result index a4978b07579..1f95acece5e 100644 --- a/mysql-test/suite/compat/oracle/r/func_to_char.result +++ b/mysql-test/suite/compat/oracle/r/func_to_char.result @@ -439,3 +439,10 @@ NULL 2021-01-24 drop table t1,t2; set @local.sql_mode=@sql_mode; +# +# MDEV-29152: Assertion failed ... upon TO_CHAR with wrong argument +# +SELECT TO_CHAR((VALUES('2022-12-12','2020-10-10'))); +ERROR HY000: Illegal parameter data type row for operation 'to_char' +SELECT TO_CHAR((STR_TO_DATE('2023-01-01', '%d-%m-%Y'), 'YYYY-MM-DD') ); +ERROR HY000: Illegal parameter data type row for operation 'to_char' diff --git a/mysql-test/suite/compat/oracle/t/func_to_char.test b/mysql-test/suite/compat/oracle/t/func_to_char.test index 9910fe60a84..7a40321538d 100644 --- a/mysql-test/suite/compat/oracle/t/func_to_char.test +++ b/mysql-test/suite/compat/oracle/t/func_to_char.test @@ -224,3 +224,13 @@ select * from t2; drop table t1,t2; set @local.sql_mode=@sql_mode; +--echo # +--echo # MDEV-29152: Assertion failed ... upon TO_CHAR with wrong argument +--echo # + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT TO_CHAR((VALUES('2022-12-12','2020-10-10'))); + +--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION +SELECT TO_CHAR((STR_TO_DATE('2023-01-01', '%d-%m-%Y'), 'YYYY-MM-DD') ); + diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 9b78d6c159e..1cf1a614ece 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -996,7 +996,10 @@ class Item_func_tochar :public Item_str_func bool check_arguments() const override { - return check_argument_types_can_return_text(1, arg_count); + return + (args[0]->check_type_can_return_date(func_name_cstring()) && + args[0]->check_type_can_return_time(func_name_cstring())) || + check_argument_types_can_return_text(1, arg_count); } public: From a4e103ad825f872e0c07a717984ec05357e02837 Mon Sep 17 00:00:00 2001 From: Monty Date: Wed, 12 Jul 2023 22:55:26 +0300 Subject: [PATCH 34/40] Fixed bug in ddl log This issue could only be noticed in very extraordinary circumstances when trying to rename a temporary table that is not in the file system. The issue was found when I temporarly disabled check_if_frm_exists() while searching for another bug. --- sql/ddl_log.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/ddl_log.cc b/sql/ddl_log.cc index 8722d88ba95..ec688a8cc86 100644 --- a/sql/ddl_log.cc +++ b/sql/ddl_log.cc @@ -1099,7 +1099,7 @@ static void execute_rename_table(DDL_LOG_ENTRY *ddl_log_entry, handler *file, { fr_length= build_table_filename(from_path, FN_REFLEN, from_db->str, from_table->str, "", - flags & FN_TO_IS_TMP); + flags & FN_FROM_IS_TMP); to_length= build_table_filename(to_path, FN_REFLEN, to_db->str, to_table->str, "", flags & FN_TO_IS_TMP); From a03ce7b99cde33855965a8c2edb5e973d09e7871 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Thu, 13 Jul 2023 16:05:02 +0400 Subject: [PATCH 35/40] MDEV-31521 bzero wipes more bytes than necessary in set_global_from_ddl_log_entry. 'defaults' made into 'constexpr' variables. --- sql/ddl_log.cc | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sql/ddl_log.cc b/sql/ddl_log.cc index ec688a8cc86..b65305918e3 100644 --- a/sql/ddl_log.cc +++ b/sql/ddl_log.cc @@ -141,23 +141,23 @@ static st_ddl_recovery recovery_state; mysql_mutex_t LOCK_gdl; /* Positions to different data in a ddl log block */ -#define DDL_LOG_ENTRY_TYPE_POS 0 +static constexpr unsigned DDL_LOG_ENTRY_TYPE_POS= 0; /* Note that ACTION_TYPE and PHASE_POS must be after each other. See update_phase() */ -#define DDL_LOG_ACTION_TYPE_POS 1 -#define DDL_LOG_PHASE_POS 2 -#define DDL_LOG_NEXT_ENTRY_POS 4 +static constexpr unsigned DDL_LOG_ACTION_TYPE_POS= 1; +static constexpr unsigned DDL_LOG_PHASE_POS= 2; +static constexpr unsigned DDL_LOG_NEXT_ENTRY_POS= 4; /* Flags to remember something unique about the query, like if .frm was used */ -#define DDL_LOG_FLAG_POS 8 +static constexpr unsigned DDL_LOG_FLAG_POS= 8; /* Used to store XID entry that was written to binary log */ -#define DDL_LOG_XID_POS 10 +static constexpr unsigned DDL_LOG_XID_POS= 10; /* Used to store unique uuid from the .frm file */ -#define DDL_LOG_UUID_POS 18 +static constexpr unsigned DDL_LOG_UUID_POS= 18; /* ID_POS can be used to store something unique, like file size (4 bytes) */ -#define DDL_LOG_ID_POS DDL_LOG_UUID_POS + MY_UUID_SIZE -#define DDL_LOG_END_POS DDL_LOG_ID_POS + 8 +static constexpr unsigned DDL_LOG_ID_POS= DDL_LOG_UUID_POS + MY_UUID_SIZE; +static constexpr unsigned DDL_LOG_END_POS= DDL_LOG_ID_POS + 8; /* Position to where names are stored in the ddl log blocks. The current @@ -165,19 +165,19 @@ mysql_mutex_t LOCK_gdl; space for constants in the header than what is between DDL_LOG_ID_POS and DDL_LOG_TMP_NAME_POS. */ -#define DDL_LOG_TMP_NAME_POS 56 +static constexpr unsigned DDL_LOG_TMP_NAME_POS= 56; /* Definitions for the ddl log header, the first block in the file */ /* IO_SIZE is stored in the header and can thus be changed */ -#define DDL_LOG_IO_SIZE IO_SIZE +static constexpr unsigned DDL_LOG_IO_SIZE= IO_SIZE; /* Header is stored in positions 0-3 */ -#define DDL_LOG_IO_SIZE_POS 4 -#define DDL_LOG_NAME_OFFSET_POS 6 +static constexpr unsigned DDL_LOG_IO_SIZE_POS= 4; +static constexpr unsigned DDL_LOG_NAME_OFFSET_POS= 6; /* Marks if we have done a backup of the ddl log */ -#define DDL_LOG_BACKUP_OFFSET_POS 8 +static constexpr unsigned DDL_LOG_BACKUP_OFFSET_POS= 8; /* Sum of the above variables */ -#define DDL_LOG_HEADER_SIZE 4+2+2+1 +static constexpr unsigned DDL_LOG_HEADER_SIZE= 4+2+2+1; /** Sync the ddl log file. From 42738f5f4d5c1cef5a9166ff496827b2abd6344c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 17 Jul 2023 06:52:18 +0400 Subject: [PATCH 36/40] MDEV-30681 SIGFPE / UBSAN runtime error: division by zero in String::needs_conversion on ALTER The problem was earlier fixed by MDEV-30805. Adding an MTR test only. --- mysql-test/main/partition_charset.result | 12 ++++++++++++ mysql-test/main/partition_charset.test | 11 +++++++++++ 2 files changed, 23 insertions(+) diff --git a/mysql-test/main/partition_charset.result b/mysql-test/main/partition_charset.result index a0019dd8fc3..d9e496c475e 100644 --- a/mysql-test/main/partition_charset.result +++ b/mysql-test/main/partition_charset.result @@ -39,5 +39,17 @@ t1 CREATE TABLE `t1` ( (PARTITION `p0` VALUES LESS THAN ('a') ENGINE = MyISAM) DROP TABLE t1; # +# MDEV-30681 SIGFPE / UBSAN runtime error: division by zero in String::needs_conversion on ALTER +# +CREATE TABLE t1 (a BINARY (10)) PARTITION BY LIST COLUMNS (a) (PARTITION p VALUES IN (0xFF)); +SELECT COLUMN_TYPE, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1'; +COLUMN_TYPE COLLATION_NAME +binary(10) NULL +ALTER TABLE t1 CHANGE COLUMN a a CHAR(10) BINARY; +SELECT COLUMN_TYPE, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1'; +COLUMN_TYPE COLLATION_NAME +char(10) latin1_bin +DROP TABLE t1; +# # End of 10.9 tests # diff --git a/mysql-test/main/partition_charset.test b/mysql-test/main/partition_charset.test index b8a17ce4fca..87aa42b4f7c 100644 --- a/mysql-test/main/partition_charset.test +++ b/mysql-test/main/partition_charset.test @@ -43,6 +43,17 @@ ALTER TABLE t1 CHANGE COLUMN a a CHAR BINARY; SHOW CREATE TABLE t1; DROP TABLE t1; +--echo # +--echo # MDEV-30681 SIGFPE / UBSAN runtime error: division by zero in String::needs_conversion on ALTER +--echo # + +CREATE TABLE t1 (a BINARY (10)) PARTITION BY LIST COLUMNS (a) (PARTITION p VALUES IN (0xFF)); +SELECT COLUMN_TYPE, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1'; +ALTER TABLE t1 CHANGE COLUMN a a CHAR(10) BINARY; +SELECT COLUMN_TYPE, COLLATION_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='t1'; +DROP TABLE t1; + + --echo # --echo # End of 10.9 tests --echo # From b9c7da4c91919b188ea04c528bef5fbf8f9222e6 Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Thu, 20 Jul 2023 07:44:05 +0400 Subject: [PATCH 37/40] MDEV-30003 Assertion failure upon 2nd execution of SP trying to set collation on non-existing database The DBUG_ASSER in HA_CREATE_INFO::resolve_to_charset_collation_context() didn't take into account that the second execution is possible not only during a prepared EXECUTE, but also during a CALL. --- mysql-test/main/ctype_collate_context.result | 28 ++++++++++++++++ mysql-test/main/ctype_collate_context.test | 35 ++++++++++++++++++++ sql/sql_table.cc | 7 ++-- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/mysql-test/main/ctype_collate_context.result b/mysql-test/main/ctype_collate_context.result index 53eeaa4e713..d0625f18880 100644 --- a/mysql-test/main/ctype_collate_context.result +++ b/mysql-test/main/ctype_collate_context.result @@ -1958,3 +1958,31 @@ DROP TABLE results_alter_db; DROP TABLE results_create_table; DROP TABLE results_alter_table; DROP TABLE results_convert_table; +# +# MDEV-30003 Assertion failure upon 2nd execution of SP trying to set collation on non-existing database +# +CREATE PROCEDURE p() ALTER SCHEMA db DEFAULT COLLATE = utf8_bin; +CALL p; +ERROR HY000: Can't create/write to file 'db.opt' (Errcode: 2 "No such file or directory") +CALL p; +ERROR HY000: Can't create/write to file 'db.opt' (Errcode: 2 "No such file or directory") +DROP PROCEDURE p; +CREATE DATABASE db1; +CREATE PROCEDURE p() CREATE DATABASE db1 COLLATE DEFAULT; +CALL p; +ERROR HY000: Can't create database 'db1'; database exists +CALL p; +ERROR HY000: Can't create database 'db1'; database exists +DROP DATABASE db1; +DROP PROCEDURE p; +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p() CREATE TABLE t1 (a INT) COLLATE DEFAULT; +CALL p; +ERROR 42S01: Table 't1' already exists +CALL p; +ERROR 42S01: Table 't1' already exists +DROP TABLE t1; +DROP PROCEDURE p; +# +# End of 10.9 tests +# diff --git a/mysql-test/main/ctype_collate_context.test b/mysql-test/main/ctype_collate_context.test index 0867237a223..74444a71777 100644 --- a/mysql-test/main/ctype_collate_context.test +++ b/mysql-test/main/ctype_collate_context.test @@ -364,3 +364,38 @@ DROP TABLE results_alter_db; DROP TABLE results_create_table; DROP TABLE results_alter_table; DROP TABLE results_convert_table; + +--echo # +--echo # MDEV-30003 Assertion failure upon 2nd execution of SP trying to set collation on non-existing database +--echo # + +CREATE PROCEDURE p() ALTER SCHEMA db DEFAULT COLLATE = utf8_bin; +--replace_regex /to file '.*db.opt'/to file 'db.opt'/ +--error 1 +CALL p; +--replace_regex /to file '.*db.opt'/to file 'db.opt'/ +--error 1 +CALL p; +DROP PROCEDURE p; + +CREATE DATABASE db1; +CREATE PROCEDURE p() CREATE DATABASE db1 COLLATE DEFAULT; +--error ER_DB_CREATE_EXISTS +CALL p; +--error ER_DB_CREATE_EXISTS +CALL p; +DROP DATABASE db1; +DROP PROCEDURE p; + +CREATE TABLE t1 (a INT); +CREATE PROCEDURE p() CREATE TABLE t1 (a INT) COLLATE DEFAULT; +--error ER_TABLE_EXISTS_ERROR +CALL p; +--error ER_TABLE_EXISTS_ERROR +CALL p; +DROP TABLE t1; +DROP PROCEDURE p; + +--echo # +--echo # End of 10.9 tests +--echo # diff --git a/sql/sql_table.cc b/sql/sql_table.cc index f94e81cc3f7..5aa2d6b8080 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -12533,7 +12533,9 @@ bool HA_CREATE_INFO:: else { // Make sure we don't do double resolution in direct SQL execution - DBUG_ASSERT(!default_table_charset || thd->stmt_arena->is_stmt_execute()); + DBUG_ASSERT(!default_table_charset || + thd->stmt_arena->is_stmt_execute() || + thd->stmt_arena->state == Query_arena::STMT_INITIALIZED_FOR_SP); if (!(default_table_charset= default_cscl.resolved_to_context(ctx))) return true; @@ -12545,7 +12547,8 @@ bool HA_CREATE_INFO:: { // Make sure we don't do double resolution in direct SQL execution DBUG_ASSERT(!alter_table_convert_to_charset || - thd->stmt_arena->is_stmt_execute()); + thd->stmt_arena->is_stmt_execute() || + thd->stmt_arena->state == Query_arena::STMT_INITIALIZED_FOR_SP); if (!(alter_table_convert_to_charset= convert_cscl.resolved_to_context(ctx))) return true; From 6e484c3bd99a6709e3554f32a99167042ea88496 Mon Sep 17 00:00:00 2001 From: Sergei Petrunia Date: Thu, 6 Jul 2023 10:41:46 +0300 Subject: [PATCH 38/40] MDEV-31577: Make ANALYZE FORMAT=JSON print innodb stats ANALYZE FORMAT=JSON output now includes table.r_engine_stats which has the engine statistics. Only non-zero members are printed. Internally: EXPLAIN data structures Explain_table_acccess and Explain_update now have handler* handler_for_stats pointer. It is used to read statistics from handler_for_stats->handler_stats. The following applies only to 10.9+, backport doesn't use it: Explain data structures exist after the tables are closed. We avoid walking invalid pointers using this: - SQL layer calls Explain_query::notify_tables_are_closed() before closing tables. - After that call, printing of JSON output is disabled. Non-JSON output can be printed but we don't access handler_for_stats when doing that. --- mysql-test/include/analyze-format.inc | 8 +- .../main/analyze_engine_stats.combinations | 5 + mysql-test/main/analyze_engine_stats.result | 105 ++++++++++++++++++ mysql-test/main/analyze_engine_stats.test | 64 +++++++++++ mysql-test/main/analyze_format_json.result | 37 +++++- .../main/analyze_format_json_timings.result | 4 + mysql-test/main/analyze_stmt_orderby.result | 17 ++- mysql-test/main/cte_recursive.result | 6 + mysql-test/main/derived_cond_pushdown.result | 1 + mysql-test/main/derived_split_innodb.result | 5 + mysql-test/main/except.result | 12 ++ mysql-test/main/except_all.result | 12 ++ mysql-test/main/explain_json.result | 9 ++ .../explain_json_format_partitions.result | 3 + mysql-test/main/intersect.result | 12 ++ mysql-test/main/intersect_all.result | 12 ++ mysql-test/main/order_by.result | 8 ++ mysql-test/main/order_by_pack_big.result | 4 + mysql-test/main/rowid_filter.result | 31 ++++++ mysql-test/main/rowid_filter_innodb.result | 42 +++++++ mysql-test/main/subselect4.result | 3 + mysql-test/main/subselect_cache.result | 5 + mysql-test/main/win.result | 1 + .../encryption/r/tempfiles_encrypted.result | 1 + .../federatedx_create_handlers.result | 1 + sql/sql_class.h | 6 + sql/sql_delete.cc | 2 + sql/sql_explain.cc | 23 ++++ sql/sql_explain.h | 17 ++- sql/sql_lex.cc | 3 +- sql/sql_select.cc | 6 + sql/table.cc | 2 +- 32 files changed, 459 insertions(+), 8 deletions(-) create mode 100644 mysql-test/main/analyze_engine_stats.combinations create mode 100644 mysql-test/main/analyze_engine_stats.result create mode 100644 mysql-test/main/analyze_engine_stats.test diff --git a/mysql-test/include/analyze-format.inc b/mysql-test/include/analyze-format.inc index 330be82ef96..1fbf4e72b76 100644 --- a/mysql-test/include/analyze-format.inc +++ b/mysql-test/include/analyze-format.inc @@ -1,3 +1,7 @@ -# The time on ANALYSE FORMAT=JSON is rather variable +# Remove non-deterministic parts of ANALYZE FORMAT=JSON output: +# - any timings +# - Buffer sizes (depend on pointer size) +# - r_engine_stats depends on buffer pool state and whether old record versions +# were purged. ---replace_regex /("(r_[a-z_]*_time_ms|r_buffer_size)": )[^, \n]*/\1"REPLACED"/ +--replace_regex /("(r_[a-z_]*_time_ms|r_buffer_size)": )[^, \n]*/\1"REPLACED"/ /("r_engine_stats":) {[^}]*}/\1 REPLACED/ diff --git a/mysql-test/main/analyze_engine_stats.combinations b/mysql-test/main/analyze_engine_stats.combinations new file mode 100644 index 00000000000..09620f9f4da --- /dev/null +++ b/mysql-test/main/analyze_engine_stats.combinations @@ -0,0 +1,5 @@ +[slow_query_log_on] +slow_query_log=ON + +[slow_query_log_off] +slow_query_log=OFF diff --git a/mysql-test/main/analyze_engine_stats.result b/mysql-test/main/analyze_engine_stats.result new file mode 100644 index 00000000000..d21a55102da --- /dev/null +++ b/mysql-test/main/analyze_engine_stats.result @@ -0,0 +1,105 @@ +create table t1 ( +pk int not null, +a varchar(64), +b varchar(64), +c varchar(64) +) engine=innodb; +insert into t1 select +seq, seq, seq, seq +from +seq_1_to_10000; +analyze table t1 persistent for all; +Table Op Msg_type Msg_text +test.t1 analyze status Engine-independent statistics collected +test.t1 analyze status OK +# Note the r_engine_stats below. Only non-zero members are printed +select '$out' as X; +X +{ + "query_block": { + "select_id": 1, + "r_loops": 1, + "r_total_time_ms": "REPLACED", + "table": { + "table_name": "t1", + "access_type": "ALL", + "r_loops": 1, + "rows": 10000, + "r_rows": 10000, + "r_table_time_ms": "REPLACED", + "r_other_time_ms": "REPLACED", + "r_engine_stats": { + "pages_accessed": "REPLACED" + }, + "filtered": 99.21875, + "r_filtered": 100, + "attached_condition": "t1.pk < 120000" + } + } +} +set @js='$out'; +set @out=(select json_extract(@js,'$**.r_engine_stats.pages_accessed')); +select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_ACCESSED_MORE_THAN_ZERO; +PAGES_ACCESSED_MORE_THAN_ZERO +1 +# +# Try an UPDATE +# +select '$out' as X; +X +{ + "query_block": { + "select_id": 1, + "r_total_time_ms": "REPLACED", + "table": { + "update": 1, + "table_name": "t1", + "access_type": "ALL", + "rows": 10000, + "r_rows": 10000, + "r_filtered": 100, + "r_total_time_ms": "REPLACED", + "r_engine_stats": { + "pages_accessed": "REPLACED", + "pages_updated": "REPLACED" + }, + "attached_condition": "t1.pk < 120000" + } + } +} +set @js='$out'; +set @out=(select json_extract(@js,'$**.r_engine_stats.pages_updated')); +select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_UPDATED_MORE_THAN_ZERO; +PAGES_UPDATED_MORE_THAN_ZERO +1 +# +# Try a DELETE +# +select '$out' as X; +X +{ + "query_block": { + "select_id": 1, + "r_total_time_ms": "REPLACED", + "table": { + "delete": 1, + "table_name": "t1", + "access_type": "ALL", + "rows": 10000, + "r_rows": 10000, + "r_filtered": 50, + "r_total_time_ms": "REPLACED", + "r_engine_stats": { + "pages_accessed": "REPLACED", + "pages_updated": "REPLACED" + }, + "attached_condition": "t1.pk MOD 2 = 1" + } + } +} +set @js='$out'; +set @out=(select json_extract(@js,'$**.r_engine_stats.pages_updated')); +select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_UPDATED_MORE_THAN_ZERO; +PAGES_UPDATED_MORE_THAN_ZERO +1 +drop table t1; diff --git a/mysql-test/main/analyze_engine_stats.test b/mysql-test/main/analyze_engine_stats.test new file mode 100644 index 00000000000..a26c65a1aa4 --- /dev/null +++ b/mysql-test/main/analyze_engine_stats.test @@ -0,0 +1,64 @@ +# +# Tests for r_engine_stats in ANALYZE FORMAT=JSON output +# +--source include/analyze-format.inc +--source include/have_sequence.inc +--source include/have_innodb.inc + +create table t1 ( + pk int not null, + a varchar(64), + b varchar(64), + c varchar(64) +) engine=innodb; + +insert into t1 select + seq, seq, seq, seq +from + seq_1_to_10000; + +analyze table t1 persistent for all; + +--echo # Note the r_engine_stats below. Only non-zero members are printed +let $out=` +ANALYZE FORMAT=json +select * from t1 where pk < 120000; +`; + +# Don't use "source include/analyze-format.inc" as it replaces r_engine_stats +# Replace the "pages_accessed" value, too, as it is different for some +# platforms... +--replace_regex /("(r_[a-z_]*_time(_in_progress)?_ms|r_buffer_size|pages_accessed)": )[^, \n]*/\1"REPLACED"/ +evalp select '$out' as X; + +evalp set @js='$out'; +set @out=(select json_extract(@js,'$**.r_engine_stats.pages_accessed')); +select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_ACCESSED_MORE_THAN_ZERO; + +--echo # +--echo # Try an UPDATE +--echo # + +let $out=`analyze format=json update t1 set b = b-1 where pk < 120000`; + +--replace_regex /("(r_[a-z_]*_time_ms|pages_accessed|pages_updated)": )[^, \n]*/\1"REPLACED"/ +evalp select '$out' as X; + +evalp set @js='$out'; +set @out=(select json_extract(@js,'$**.r_engine_stats.pages_updated')); +select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_UPDATED_MORE_THAN_ZERO; + +--echo # +--echo # Try a DELETE +--echo # +let $out=`analyze format=json delete from t1 where mod(pk,2)=1`; + +--replace_regex /("(r_[a-z_]*_time_ms|pages_accessed|pages_updated)": )[^, \n]*/\1"REPLACED"/ +evalp select '$out' as X; + +evalp set @js='$out'; +set @out=(select json_extract(@js,'$**.r_engine_stats.pages_updated')); +select cast(json_extract(@out,'$[0]') as DOUBLE) > 0 as PAGES_UPDATED_MORE_THAN_ZERO; + +drop table t1; + diff --git a/mysql-test/main/analyze_format_json.result b/mysql-test/main/analyze_format_json.result index b9f275af742..ca10acc092e 100644 --- a/mysql-test/main/analyze_format_json.result +++ b/mysql-test/main/analyze_format_json.result @@ -17,6 +17,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 30, "attached_condition": "t0.a < 3" @@ -46,6 +47,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 0, "attached_condition": "t0.a > 9 and t0.a is not null" @@ -61,6 +63,7 @@ ANALYZE "r_loops": 0, "rows": 1, "r_rows": null, + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": null } @@ -87,6 +90,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t0.a is not null" @@ -104,6 +108,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 40, "attached_condition": "t1.b < 4" @@ -131,6 +136,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 20, "attached_condition": "tbl1.b < 20" @@ -144,6 +150,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 60, "attached_condition": "tbl2.b < 60" @@ -175,6 +182,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 20, "attached_condition": "tbl1.b < 20" @@ -188,6 +196,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 60, "attached_condition": "tbl2.b < 60" @@ -228,6 +237,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t1.a is not null" @@ -245,6 +255,7 @@ ANALYZE "r_rows": 0.2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "using_index": true @@ -280,6 +291,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 50, "attached_condition": "test.t1.a < 5" @@ -314,7 +326,8 @@ ANALYZE "rows": 1000, "r_rows": 1000, "r_filtered": 100, - "r_total_time_ms": "REPLACED" + "r_total_time_ms": "REPLACED", + "r_engine_stats": REPLACED } } } @@ -338,6 +351,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 50, "index_condition": "t1.pk < 10", @@ -364,6 +378,7 @@ ANALYZE "r_rows": 10, "r_filtered": 50, "r_total_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "attached_condition": "t1.pk < 10 and t1.b > 4" } } @@ -404,6 +419,7 @@ ANALYZE "r_rows": 5, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -428,6 +444,7 @@ ANALYZE "r_rows": 203.8, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 98.13542689 } @@ -465,6 +482,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 50, "attached_condition": "tbl1.a < 5" @@ -485,6 +503,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 20, "attached_condition": "tbl2.a in (2,3)" @@ -535,6 +554,7 @@ ANALYZE "r_rows": 256, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -567,6 +587,7 @@ ANALYZE "r_rows": 256, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -610,6 +631,7 @@ ANALYZE "r_rows": 256, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -640,6 +662,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -652,6 +675,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 0, "attached_condition": "(t2.b,t2.b in (subquery#2))" @@ -680,6 +704,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -735,6 +760,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -747,6 +773,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 0, "attached_condition": "t3.f3 in (1,2)" @@ -773,6 +800,7 @@ ANALYZE "r_loops": 0, "rows": 2, "r_rows": null, + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": null }, @@ -783,6 +811,7 @@ ANALYZE "r_loops": 0, "rows": 2, "r_rows": null, + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": null }, @@ -830,6 +859,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 0, "attached_condition": "t1.a < 0" @@ -856,6 +886,7 @@ ANALYZE "r_loops": 0, "rows": 10, "r_rows": null, + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": null, "attached_condition": "t2.a < t1.a" @@ -908,6 +939,7 @@ ANALYZE "r_rows": 1000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 10.15625, "r_filtered": 10, "attached_condition": "t11.a < 100" @@ -921,6 +953,7 @@ ANALYZE "r_rows": 1000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 70.3125, "r_filtered": 70, "attached_condition": "t10.a < 700" @@ -958,6 +991,7 @@ ANALYZE "r_rows": 1000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 10.15625, "r_filtered": 10, "attached_condition": "t11.a < 100 and t11.b is not null" @@ -975,6 +1009,7 @@ ANALYZE "r_rows": 1000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 70.3125, "r_filtered": 70, "attached_condition": "t10.a < 700" diff --git a/mysql-test/main/analyze_format_json_timings.result b/mysql-test/main/analyze_format_json_timings.result index 6cced9ec6b1..8b719eb9dee 100644 --- a/mysql-test/main/analyze_format_json_timings.result +++ b/mysql-test/main/analyze_format_json_timings.result @@ -49,6 +49,7 @@ X "r_rows": 500, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t1.a < 700 and t1.b is not null" @@ -66,6 +67,7 @@ X "r_rows": 500, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 20, "attached_condition": "t2.a < 100" @@ -131,6 +133,7 @@ X "r_rows": 1000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t1.a is not null" @@ -148,6 +151,7 @@ X "r_rows": 2000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, diff --git a/mysql-test/main/analyze_stmt_orderby.result b/mysql-test/main/analyze_stmt_orderby.result index 7f03e2b2673..9e098cb498e 100644 --- a/mysql-test/main/analyze_stmt_orderby.result +++ b/mysql-test/main/analyze_stmt_orderby.result @@ -52,7 +52,8 @@ ANALYZE "rows": 10000, "r_rows": 10000, "r_filtered": 100, - "r_total_time_ms": "REPLACED" + "r_total_time_ms": "REPLACED", + "r_engine_stats": REPLACED } } } @@ -105,6 +106,7 @@ ANALYZE "r_rows": 10, "r_filtered": 100, "r_total_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "attached_condition": "t2.a < 10" } } @@ -154,7 +156,8 @@ ANALYZE "rows": 10000, "r_rows": 10000, "r_filtered": 100, - "r_total_time_ms": "REPLACED" + "r_total_time_ms": "REPLACED", + "r_engine_stats": REPLACED } } } @@ -223,6 +226,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t0.a is not null" @@ -240,6 +244,7 @@ ANALYZE "r_rows": 0.4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -312,6 +317,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t0.a is not null" @@ -331,6 +337,7 @@ ANALYZE "r_rows": 0.4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -373,6 +380,7 @@ ANALYZE "r_rows": 1000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 50, "attached_condition": "t2.a MOD 2 = 0" @@ -422,6 +430,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -434,6 +443,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -500,6 +510,7 @@ ANALYZE "r_rows": 5, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 80, "attached_condition": "t6.b > 0 and t6.a <= 5" @@ -513,6 +524,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -612,6 +624,7 @@ ANALYZE "r_rows": 20, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "using_index_for_group_by": true diff --git a/mysql-test/main/cte_recursive.result b/mysql-test/main/cte_recursive.result index dd82ef46229..91bc452c92c 100644 --- a/mysql-test/main/cte_recursive.result +++ b/mysql-test/main/cte_recursive.result @@ -3807,6 +3807,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t1.a1 is not null" @@ -3851,6 +3852,7 @@ ANALYZE "r_loops": 0, "rows": 1, "r_rows": null, + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": null, "using_index": true @@ -3888,6 +3890,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -4086,6 +4089,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -4105,6 +4109,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t1.c is not null" @@ -4201,6 +4206,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } diff --git a/mysql-test/main/derived_cond_pushdown.result b/mysql-test/main/derived_cond_pushdown.result index 82a8dd89a05..97824dbde62 100644 --- a/mysql-test/main/derived_cond_pushdown.result +++ b/mysql-test/main/derived_cond_pushdown.result @@ -17315,6 +17315,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 50, "attached_condition": "t1.a = 3" diff --git a/mysql-test/main/derived_split_innodb.result b/mysql-test/main/derived_split_innodb.result index e491b631121..29a3261e9b8 100644 --- a/mysql-test/main/derived_split_innodb.result +++ b/mysql-test/main/derived_split_innodb.result @@ -378,6 +378,7 @@ ANALYZE "r_rows": 5, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -394,6 +395,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "trigcond(trigcond(t1.b is not null))" @@ -411,6 +413,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "trigcond(trigcond(t1.b is not null))" @@ -451,6 +454,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -463,6 +467,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, diff --git a/mysql-test/main/except.result b/mysql-test/main/except.result index 5614ab18bf0..677e3ce202e 100644 --- a/mysql-test/main/except.result +++ b/mysql-test/main/except.result @@ -84,6 +84,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -103,6 +104,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -150,6 +152,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -169,6 +172,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -316,6 +320,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -328,6 +333,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -356,6 +362,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -368,6 +375,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -425,6 +433,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -437,6 +446,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -465,6 +475,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -477,6 +488,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, diff --git a/mysql-test/main/except_all.result b/mysql-test/main/except_all.result index 113c161a98b..4f4fed2ffa7 100644 --- a/mysql-test/main/except_all.result +++ b/mysql-test/main/except_all.result @@ -142,6 +142,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -161,6 +162,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -211,6 +213,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -230,6 +233,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -435,6 +439,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -447,6 +452,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -475,6 +481,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -487,6 +494,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -543,6 +551,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -555,6 +564,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -583,6 +593,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -595,6 +606,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, diff --git a/mysql-test/main/explain_json.result b/mysql-test/main/explain_json.result index c3cff36626d..8fa729c8524 100644 --- a/mysql-test/main/explain_json.result +++ b/mysql-test/main/explain_json.result @@ -977,6 +977,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "using_index_for_group_by": true @@ -1281,6 +1282,7 @@ ANALYZE "r_loops": 0, "rows": 1, "r_rows": null, + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": null, "impossible_on_condition": true @@ -1293,6 +1295,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -1348,6 +1351,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -1364,6 +1368,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "trigcond(t2.pk is null) and trigcond(trigcond(t1.a is not null))", @@ -1425,6 +1430,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t1.a is not null" @@ -1442,6 +1448,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "using_index": true, @@ -1518,6 +1525,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t3.a is not null" @@ -1536,6 +1544,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "index_condition_bka": "t4.b + 1 <= t3.b + 1" diff --git a/mysql-test/main/explain_json_format_partitions.result b/mysql-test/main/explain_json_format_partitions.result index 0c7d9e93105..34411d8e121 100644 --- a/mysql-test/main/explain_json_format_partitions.result +++ b/mysql-test/main/explain_json_format_partitions.result @@ -38,6 +38,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 30, "attached_condition": "t1.a in (2,3,4)" @@ -60,6 +61,7 @@ ANALYZE "r_rows": 10, "r_filtered": 30, "r_total_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "attached_condition": "t1.a in (2,3,4)" } } @@ -80,6 +82,7 @@ ANALYZE "r_rows": 10, "r_filtered": 0, "r_total_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "attached_condition": "t1.a in (20,30,40)" } } diff --git a/mysql-test/main/intersect.result b/mysql-test/main/intersect.result index 25d81a7fc34..df4ae638c04 100644 --- a/mysql-test/main/intersect.result +++ b/mysql-test/main/intersect.result @@ -110,6 +110,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -129,6 +130,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -148,6 +150,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -195,6 +198,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -214,6 +218,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -233,6 +238,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -358,6 +364,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -377,6 +384,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -389,6 +397,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -445,6 +454,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -464,6 +474,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -476,6 +487,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, diff --git a/mysql-test/main/intersect_all.result b/mysql-test/main/intersect_all.result index da5d778daab..e72209c5f89 100644 --- a/mysql-test/main/intersect_all.result +++ b/mysql-test/main/intersect_all.result @@ -122,6 +122,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -141,6 +142,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -160,6 +162,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -207,6 +210,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -226,6 +230,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -245,6 +250,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -389,6 +395,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -408,6 +415,7 @@ ANALYZE "r_rows": 5, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -420,6 +428,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -476,6 +485,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -495,6 +505,7 @@ ANALYZE "r_rows": 5, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -507,6 +518,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, diff --git a/mysql-test/main/order_by.result b/mysql-test/main/order_by.result index 5f56201af9c..a8d779d6dc8 100644 --- a/mysql-test/main/order_by.result +++ b/mysql-test/main/order_by.result @@ -3420,6 +3420,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -3769,6 +3770,7 @@ ANALYZE "r_rows": 100, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -3928,6 +3930,7 @@ ANALYZE "r_rows": 5, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -3970,6 +3973,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -4018,6 +4022,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -4080,6 +4085,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -4245,6 +4251,7 @@ ANALYZE "r_rows": 50, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -4274,6 +4281,7 @@ ANALYZE "r_rows": 50, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 2, "attached_condition": "t1.b = t2.b" diff --git a/mysql-test/main/order_by_pack_big.result b/mysql-test/main/order_by_pack_big.result index a7cf2436bcc..b93a6a66c3b 100644 --- a/mysql-test/main/order_by_pack_big.result +++ b/mysql-test/main/order_by_pack_big.result @@ -111,6 +111,7 @@ ANALYZE "r_rows": 10000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -269,6 +270,7 @@ ANALYZE "r_rows": 10000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -423,6 +425,7 @@ ANALYZE "r_rows": 10000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } @@ -472,6 +475,7 @@ ANALYZE "r_rows": 10000, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } diff --git a/mysql-test/main/rowid_filter.result b/mysql-test/main/rowid_filter.result index e32b738c4e5..15b738ea940 100644 --- a/mysql-test/main/rowid_filter.result +++ b/mysql-test/main/rowid_filter.result @@ -138,6 +138,7 @@ ANALYZE "r_rows": 60, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 11.69025803, "r_filtered": 100, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'", @@ -261,6 +262,7 @@ ANALYZE "r_rows": 510, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 11.69025803, "r_filtered": 11.76470588, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'", @@ -414,6 +416,7 @@ ANALYZE "r_rows": 71, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "index_condition": "orders.o_totalprice between 200000 and 230000" @@ -449,6 +452,7 @@ ANALYZE "r_rows": 0.154929577, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 1.631973386, "r_filtered": 100, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-01-31'" @@ -550,6 +554,7 @@ ANALYZE "r_rows": 98, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-01-31'" @@ -567,6 +572,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 4.599999905, "r_filtered": 11.2244898, "attached_condition": "orders.o_totalprice between 200000 and 230000" @@ -704,6 +710,7 @@ ANALYZE "r_rows": 60, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 11.69025803, "r_filtered": 100, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'", @@ -735,6 +742,7 @@ ANALYZE "r_rows": 0.266666667, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 9.266666412, "r_filtered": 100, "attached_condition": "orders.o_totalprice between 180000 and 230000" @@ -849,6 +857,7 @@ ANALYZE "r_rows": 510, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 11.69025803, "r_filtered": 11.76470588, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'", @@ -867,6 +876,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 9.266666412, "r_filtered": 26.66666667, "attached_condition": "orders.o_totalprice between 180000 and 230000" @@ -977,6 +987,7 @@ ANALYZE "r_rows": 71, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "index_condition": "orders.o_totalprice between 200000 and 230000" @@ -1012,6 +1023,7 @@ ANALYZE "r_rows": 0.521126761, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 8.476269722, "r_filtered": 100, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'" @@ -1134,6 +1146,7 @@ ANALYZE "r_rows": 71, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "index_condition": "orders.o_totalprice between 200000 and 230000" @@ -1156,6 +1169,7 @@ ANALYZE "r_rows": 6.704225352, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 8.476269722, "r_filtered": 7.773109244, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'" @@ -1301,6 +1315,7 @@ ANALYZE "r_rows": 18, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 0.566194832, "r_filtered": 38.88888889, "index_condition": "lineitem.l_receiptDATE between '1996-10-05' and '1996-10-10'", @@ -1319,6 +1334,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 7.466666698, "r_filtered": 14.28571429, "attached_condition": "orders.o_totalprice between 200000 and 250000" @@ -1423,6 +1439,7 @@ ANALYZE "r_rows": 18, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 0.566194832, "r_filtered": 38.88888889, "index_condition": "lineitem.l_receiptDATE between '1996-10-05' and '1996-10-10'", @@ -1441,6 +1458,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 7.466666698, "r_filtered": 14.28571429, "attached_condition": "orders.o_totalprice between 200000 and 250000" @@ -1545,6 +1563,7 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.200000048, "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1568,6 +1587,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.047460556, "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -1668,6 +1688,7 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.200000048, "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1691,6 +1712,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.047460556, "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -1804,6 +1826,7 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": {}, "filtered": "REPLACED", "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1827,6 +1850,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": {}, "filtered": "REPLACED", "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -1937,6 +1961,7 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": {}, "filtered": "REPLACED", "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1960,6 +1985,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": {}, "filtered": "REPLACED", "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -2329,6 +2355,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 49.20000076, "r_filtered": 100, "index_condition": "t1.nm like '500%'", @@ -2375,6 +2402,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 49.20000076, "r_filtered": 100, "index_condition": "t1.nm like '500%'", @@ -2460,6 +2488,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 1.149999976, "r_filtered": 100, "attached_condition": "t1.nm like '75%'" @@ -2567,6 +2596,7 @@ ANALYZE "r_rows": 0, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 0.439999998, "r_filtered": 100, "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" @@ -2624,6 +2654,7 @@ ANALYZE "r_loops": 1, "rows": 853, "r_rows": 0, + "r_engine_stats": REPLACED, "filtered": 0.439999998, "r_filtered": 100, "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" diff --git a/mysql-test/main/rowid_filter_innodb.result b/mysql-test/main/rowid_filter_innodb.result index c5a27f8b60e..d94de99cf2c 100644 --- a/mysql-test/main/rowid_filter_innodb.result +++ b/mysql-test/main/rowid_filter_innodb.result @@ -141,6 +141,7 @@ ANALYZE "r_rows": 60, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 10.07493782, "r_filtered": 100, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'", @@ -264,6 +265,7 @@ ANALYZE "r_rows": 510, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 10.07493782, "r_filtered": 11.76470588, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'", @@ -415,6 +417,7 @@ ANALYZE "r_rows": 98, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-01-31'", @@ -433,6 +436,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 4.733333111, "r_filtered": 11.2244898, "attached_condition": "orders.o_totalprice between 200000 and 230000" @@ -535,6 +539,7 @@ ANALYZE "r_rows": 98, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-01-31'", @@ -553,6 +558,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 4.733333111, "r_filtered": 11.2244898, "attached_condition": "orders.o_totalprice between 200000 and 230000" @@ -682,6 +688,7 @@ ANALYZE "r_rows": 60, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 10.07493782, "r_filtered": 100, "index_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'", @@ -700,6 +707,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 9.600000381, "r_filtered": 26.66666667, "attached_condition": "orders.o_totalprice between 180000 and 230000" @@ -808,6 +816,7 @@ ANALYZE "r_rows": 144, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "orders.o_totalprice between 180000 and 230000", @@ -832,6 +841,7 @@ ANALYZE "r_rows": 6.625, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 0.855656624, "r_filtered": 1.677148847, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30' and lineitem.l_quantity > 45" @@ -935,6 +945,7 @@ ANALYZE "r_rows": 71, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "orders.o_totalprice between 200000 and 230000", @@ -958,6 +969,7 @@ ANALYZE "r_rows": 6.704225352, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 8.492922783, "r_filtered": 7.773109244, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'" @@ -1081,6 +1093,7 @@ ANALYZE "r_rows": 71, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "orders.o_totalprice between 200000 and 230000", @@ -1104,6 +1117,7 @@ ANALYZE "r_rows": 6.704225352, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 8.492922783, "r_filtered": 7.773109244, "attached_condition": "lineitem.l_shipDATE between '1997-01-01' and '1997-06-30'" @@ -1249,6 +1263,7 @@ ANALYZE "r_rows": 18, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 0.566194832, "r_filtered": 38.88888889, "index_condition": "lineitem.l_receiptDATE between '1996-10-05' and '1996-10-10'", @@ -1267,6 +1282,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 5.666666508, "r_filtered": 14.28571429, "attached_condition": "orders.o_totalprice between 200000 and 250000" @@ -1371,6 +1387,7 @@ ANALYZE "r_rows": 18, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 0.566194832, "r_filtered": 38.88888889, "index_condition": "lineitem.l_receiptDATE between '1996-10-05' and '1996-10-10'", @@ -1389,6 +1406,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 5.666666508, "r_filtered": 14.28571429, "attached_condition": "orders.o_totalprice between 200000 and 250000" @@ -1493,6 +1511,7 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.333333254, "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1516,6 +1535,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.047460556, "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -1616,6 +1636,7 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.333333254, "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1639,6 +1660,7 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 3.047460556, "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -1752,6 +1774,9 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": { + "pages_accessed": 84 + }, "filtered": "REPLACED", "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1775,6 +1800,9 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": { + "pages_accessed": 3 + }, "filtered": "REPLACED", "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -1885,6 +1913,9 @@ ANALYZE "r_rows": 41, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": { + "pages_accessed": 84 + }, "filtered": "REPLACED", "r_filtered": 2.43902439, "index_condition": "orders.o_totaldiscount between 18000 and 20000", @@ -1908,6 +1939,9 @@ ANALYZE "r_rows": 6, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": { + "pages_accessed": 3 + }, "filtered": "REPLACED", "r_filtered": 66.66666667, "attached_condition": "lineitem.l_shipDATE between '1996-10-01' and '1996-12-01'" @@ -2277,6 +2311,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 49.20000076, "r_filtered": 100, "index_condition": "t1.nm like '500%'", @@ -2323,6 +2358,7 @@ ANALYZE "r_rows": 1, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 49.20000076, "r_filtered": 100, "index_condition": "t1.nm like '500%'", @@ -2408,6 +2444,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 1.149999976, "r_filtered": 100, "attached_condition": "t1.nm like '75%'" @@ -2515,6 +2552,7 @@ ANALYZE "r_rows": 0, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 0.439999998, "r_filtered": 100, "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" @@ -2572,6 +2610,7 @@ ANALYZE "r_loops": 1, "rows": 853, "r_rows": 0, + "r_engine_stats": REPLACED, "filtered": 0.439999998, "r_filtered": 100, "attached_condition": "t1.nm like '3400%' or t1.nm like '3402%' or t1.nm like '3403%' or t1.nm like '3404%' or t1.nm like '3405%' or t1.nm like '3406%' or t1.nm like '3407%' or t1.nm like '3409%' or t1.nm like '3411%' or t1.nm like '3412%' or t1.nm like '3413%' or t1.nm like '3414%' or t1.nm like '3415%' or t1.nm like '3416%' or t1.nm like '3417%' or t1.nm like '3418%' or t1.nm like '3419%' or t1.nm like '3421%' or t1.nm like '3422%' or t1.nm like '3423%' or t1.nm like '3424%' or t1.nm like '3425%' or t1.nm like '3426%' or t1.nm like '3427%' or t1.nm like '3428%' or t1.nm like '3429%' or t1.nm like '3430%' or t1.nm like '3431%' or t1.nm like '3432%' or t1.nm like '3433%' or t1.nm like '3434%' or t1.nm like '3435%' or t1.nm like '3436%' or t1.nm like '3437%' or t1.nm like '3439%' or t1.nm like '3440%' or t1.nm like '3441%' or t1.nm like '3442%' or t1.nm like '3443%' or t1.nm like '3444%' or t1.nm like '3445%' or t1.nm like '3446%' or t1.nm like '3447%' or t1.nm like '3448%'" @@ -3658,6 +3697,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100, "attached_condition": "t.tp = 121 and t.rid = 'B5FCC8C7111E4E3CBC21AAF5012F59C2'", @@ -3677,6 +3717,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -3705,6 +3746,7 @@ ANALYZE "r_rows": 80, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 14.46428585, "r_filtered": 100 }, diff --git a/mysql-test/main/subselect4.result b/mysql-test/main/subselect4.result index c32872511b1..353becd2b69 100644 --- a/mysql-test/main/subselect4.result +++ b/mysql-test/main/subselect4.result @@ -2931,6 +2931,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -2951,6 +2952,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 50, "attached_condition": "((t1.b,(subquery#3) >= 4))" @@ -2969,6 +2971,7 @@ ANALYZE "r_rows": 2, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } diff --git a/mysql-test/main/subselect_cache.result b/mysql-test/main/subselect_cache.result index 9722acbd0e6..128071ec723 100644 --- a/mysql-test/main/subselect_cache.result +++ b/mysql-test/main/subselect_cache.result @@ -56,6 +56,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -76,6 +77,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 18.75, "attached_condition": "t1.b = t2.c" @@ -102,6 +104,7 @@ ANALYZE "r_rows": 10, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, @@ -130,6 +133,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 18.75, "attached_condition": "t1.b = t2.c" @@ -166,6 +170,7 @@ ANALYZE "r_rows": 4, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 18.75, "attached_condition": "t1.b = t2.c" diff --git a/mysql-test/main/win.result b/mysql-test/main/win.result index 48eea7a3add..bcfea2f1419 100644 --- a/mysql-test/main/win.result +++ b/mysql-test/main/win.result @@ -3775,6 +3775,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } diff --git a/mysql-test/suite/encryption/r/tempfiles_encrypted.result b/mysql-test/suite/encryption/r/tempfiles_encrypted.result index 8582d5dc713..9dfca3aadcb 100644 --- a/mysql-test/suite/encryption/r/tempfiles_encrypted.result +++ b/mysql-test/suite/encryption/r/tempfiles_encrypted.result @@ -3781,6 +3781,7 @@ ANALYZE "r_rows": 3, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 } diff --git a/mysql-test/suite/federated/federatedx_create_handlers.result b/mysql-test/suite/federated/federatedx_create_handlers.result index c0b91a68da7..11b1ee4109c 100644 --- a/mysql-test/suite/federated/federatedx_create_handlers.result +++ b/mysql-test/suite/federated/federatedx_create_handlers.result @@ -229,6 +229,7 @@ ANALYZE "r_rows": 7, "r_table_time_ms": "REPLACED", "r_other_time_ms": "REPLACED", + "r_engine_stats": REPLACED, "filtered": 100, "r_filtered": 100 }, diff --git a/sql/sql_class.h b/sql/sql_class.h index 5648b4a60cb..c220f02a2fd 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -5607,6 +5607,12 @@ public: { lex= backup_lex; } + + bool should_collect_handler_stats() const + { + return (variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_ENGINE) || + lex->analyze_stmt; + } }; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index f615e287fa9..7236d01e1b3 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -126,6 +126,8 @@ bool Update_plan::save_explain_data_intern(THD *thd, LOG_SLOW_VERBOSITY_ENGINE)) table->file->set_time_tracker(&explain->table_tracker); + explain->handler_for_stats= table->file; + select_lex->set_explain_type(TRUE); explain->select_type= select_lex->type; /* Partitions */ diff --git a/sql/sql_explain.cc b/sql/sql_explain.cc index e9bdc4be66f..45ea4a82c7d 100644 --- a/sql/sql_explain.cc +++ b/sql/sql_explain.cc @@ -1709,6 +1709,26 @@ void Explain_rowid_filter::print_explain_json(Explain_query *query, writer->end_object(); // rowid_filter } +static void trace_engine_stats(handler *file, Json_writer *writer) +{ + if (file && file->handler_stats) + { + ha_handler_stats *hs= file->handler_stats; + writer->add_member("r_engine_stats").start_object(); + if (hs->pages_accessed) + writer->add_member("pages_accessed").add_ull(hs->pages_accessed); + if (hs->pages_updated) + writer->add_member("pages_updated").add_ull(hs->pages_updated); + if (hs->pages_read_count) + writer->add_member("pages_read_count").add_ull(hs->pages_read_count); + if (hs->pages_read_time) + writer->add_member("pages_read_time_ms"). + add_double(hs->pages_read_time / 1000.0); + if (hs->undo_records_read) + writer->add_member("old_rows_read").add_ull(hs->undo_records_read); + writer->end_object(); + } +} void Explain_table_access::print_explain_json(Explain_query *query, Json_writer *writer, @@ -1850,6 +1870,7 @@ void Explain_table_access::print_explain_json(Explain_query *query, writer->add_member("r_table_time_ms").add_double(total_time); writer->add_member("r_other_time_ms").add_double(extra_time_tracker.get_time_ms()); } + trace_engine_stats(handler_for_stats, writer); } /* `filtered` */ @@ -2551,6 +2572,8 @@ void Explain_update::print_explain_json(Explain_query *query, } } + trace_engine_stats(handler_for_stats, writer); + if (where_cond) { writer->add_member("attached_condition"); diff --git a/sql/sql_explain.h b/sql/sql_explain.h index af110a25296..7b93ba74a42 100644 --- a/sql/sql_explain.h +++ b/sql/sql_explain.h @@ -735,6 +735,7 @@ public: pushed_index_cond(NULL), sjm_nest(NULL), pre_join_sort(NULL), + handler_for_stats(NULL), jbuf_unpack_tracker(timed), rowid_filter(NULL) {} @@ -843,6 +844,16 @@ public: Exec_time_tracker op_tracker; Gap_time_tracker extra_time_tracker; + /* + Note: This pointer is only valid until notify_tables_are_closed() is + called. After that, the tables may be freed or reused, together with their + handler_stats objects. + + notify_tables_are_closed() disables printing of FORMAT=JSON output. + r_engine_stats is only printed in FORMAT=JSON output, so we're fine. + */ + handler *handler_for_stats; + /* When using join buffer: Track the reads from join buffer */ Table_access_tracker jbuf_tracker; @@ -893,7 +904,8 @@ public: Explain_update(MEM_ROOT *root, bool is_analyze) : Explain_node(root), filesort_tracker(NULL), - command_tracker(is_analyze) + command_tracker(is_analyze), + handler_for_stats(NULL) {} virtual enum explain_node_type get_type() { return EXPLAIN_UPDATE; } @@ -953,6 +965,9 @@ public: /* TODO: This tracks time to read rows from the table */ Exec_time_tracker table_tracker; + /* The same as Explain_table_access::handler_for_stats */ + handler *handler_for_stats; + virtual int print_explain(Explain_query *query, select_result_sink *output, uint8 explain_flags, bool is_analyze); virtual void print_explain_json(Explain_query *query, Json_writer *writer, diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index d152eb8eeb8..9d765a31fe2 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -3969,7 +3969,8 @@ void Query_tables_list::destroy_query_tables_list() LEX::LEX() : explain(NULL), result(0), part_info(NULL), arena_for_set_stmt(0), - mem_root_for_set_stmt(0), json_table(NULL), default_used(0), + mem_root_for_set_stmt(0), json_table(NULL), analyze_stmt(0), + default_used(0), with_rownum(0), is_lex_started(0), option_type(OPT_DEFAULT), context_analysis_only(0), sphead(0), limit_rows_examined_cnt(ULONGLONG_MAX) { diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 27c51879f4f..5377d245c76 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -27755,6 +27755,12 @@ bool JOIN_TAB::save_explain_data(Explain_table_access *eta, LOG_SLOW_VERBOSITY_ENGINE)) { table->file->set_time_tracker(&eta->op_tracker); + /* + Set handler_for_stats even if we are not running an ANALYZE command. + There's no harm, and in case somebody runs a SHOW ANALYZE command we'll + be able to print the engine statistics. + */ + eta->handler_for_stats= table->file; if (likely(thd->lex->analyze_stmt)) { eta->op_tracker.set_gap_tracker(&eta->extra_time_tracker); diff --git a/sql/table.cc b/sql/table.cc index cd66a3466ce..a9d45b13b35 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -5678,7 +5678,7 @@ void TABLE::init(THD *thd, TABLE_LIST *tl) } /* enable and clear or disable engine query statistics */ - if ((thd->variables.log_slow_verbosity & LOG_SLOW_VERBOSITY_ENGINE)) + if (thd->should_collect_handler_stats()) file->ha_handler_stats_reset(); else file->ha_handler_stats_disable(); From 9bb5b253252f44b261fe87142b6468b22bbf915f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 24 Jul 2023 12:29:43 +0300 Subject: [PATCH 39/40] MDEV-31120 Duplicate entry allowed into a UNIQUE column row_ins_sec_index_entry_low(): Correct a condition that was inadvertently inverted in commit 89ec4b53ac4c7568b9c9765fff50d9bec7cf3534 (MDEV-29603). We are not supposed to buffer INSERT operations into unique indexes, because duplicate key values would not be checked for. It is only allowed when using unique_checks=0, and in that case the user is supposed to guarantee that there are no duplicates. --- storage/innobase/row/row0ins.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 3188c8c27ce..d9ba8bca64e 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -3005,8 +3005,8 @@ row_ins_sec_index_entry_low( search_mode = btr_latch_mode( search_mode | (thr_get_trx(thr)->check_unique_secondary - ? BTR_INSERT | BTR_IGNORE_SEC_UNIQUE - : BTR_INSERT)); + ? BTR_INSERT + : BTR_INSERT | BTR_IGNORE_SEC_UNIQUE)); } err = cursor.search_leaf(entry, PAGE_CUR_LE, search_mode, From b102872ad50cce5959ad95369740766d14e9e48c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Tue, 25 Jul 2023 11:40:58 +0300 Subject: [PATCH 40/40] MDEV-31767 InnoDB tables are being flagged as corrupted on an I/O bound server The main problem is that at ever since commit aaef2e1d8c843d1e40b1ce0c5199c3abb3c5da28 removed the function buf_wait_for_read(), it is not safe to invoke buf_page_get_low() with RW_NO_LATCH, that is, only buffer-fixing the page. If a page read (or decryption or decompression) is in progress, there would be a race condition when executing consistency checks, and a page would wrongly be flagged as corrupted. Furthermore, if the page is actually corrupted and the initial access to it was with RW_NO_LATCH (only buffer-fixing), the page read handler would likely end up in an infinite loop in buf_pool_t::corrupted_evict(). It is not safe to invoke mtr_t::upgrade_buffer_fix() on a block on which a page latch was not initially acquired in buf_page_get_low(). btr_block_reget(): Remove the constant parameter rw_latch=RW_X_LATCH. btr_block_get(): Assert that RW_NO_LATCH is not being used, and change the parameter type of rw_latch. btr_pcur_move_to_next_page(), innobase_table_is_empty(): Adjust for the parameter type change of btr_block_get(). btr_root_block_get(): If mode==RW_NO_LATCH, do not check the integrity of the page, because it is not safe to do so. btr_page_alloc_low(), btr_page_free(): If the root page latch is not previously held by the mini-transaction, invoke btr_root_block_get() again with the proper latching mode. btr_latch_prev(): Helper function to safely acquire a latch on a preceding sibling page while holding a latch on a B-tree page. To avoid deadlocks, we must not wait for the latch while holding a latch on the current page, because another thread may be waiting for our page latch when moving to the next page from our preceding sibling page. If s_lock_try() or x_lock_try() on the preceding page fails, we must release the current page latch, and wait for the latch on the preceding page as well as the current page, in that order. Page splits or merges will be prevented by the parent page latch that we are holding. btr_cur_t::search_leaf(): Make use of btr_latch_prev(). btr_cur_t::open_leaf(): Make use of btr_latch_prev(). Do not invoke mtr_t::upgrade_buffer_fix() (when latch_mode == BTR_MODIFY_TREE), because we will already have acquired all page latches upfront. btr_cur_t::pessimistic_search_leaf(): Do acquire an exclusive index latch before accessing the page. Make use of btr_latch_prev(). --- storage/innobase/btr/btr0btr.cc | 75 ++++---- storage/innobase/btr/btr0cur.cc | 201 ++++++++++++---------- storage/innobase/btr/btr0pcur.cc | 3 +- storage/innobase/handler/handler0alter.cc | 3 +- storage/innobase/include/btr0btr.h | 2 +- 5 files changed, 144 insertions(+), 140 deletions(-) diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc index 3b03df3f47c..ee2f8d00857 100644 --- a/storage/innobase/btr/btr0btr.cc +++ b/storage/innobase/btr/btr0btr.cc @@ -218,9 +218,10 @@ ATTRIBUTE_COLD void btr_decryption_failed(const dict_index_t &index) @param[out] err error code @return block */ buf_block_t *btr_block_get(const dict_index_t &index, - uint32_t page, ulint mode, bool merge, + uint32_t page, rw_lock_type_t mode, bool merge, mtr_t *mtr, dberr_t *err) { + ut_ad(mode != RW_NO_LATCH); dberr_t local_err; if (!err) err= &local_err; @@ -281,11 +282,13 @@ btr_root_block_get( if (UNIV_LIKELY(block != nullptr)) { - if (!!page_is_comp(block->page.frame) != index->table->not_redundant() || - btr_page_get_index_id(block->page.frame) != index->id || - !fil_page_index_page_check(block->page.frame) || - index->is_spatial() != - (fil_page_get_type(block->page.frame) == FIL_PAGE_RTREE)) + if (UNIV_UNLIKELY(mode == RW_NO_LATCH)); + else if (!!page_is_comp(block->page.frame) != + index->table->not_redundant() || + btr_page_get_index_id(block->page.frame) != index->id || + !fil_page_index_page_check(block->page.frame) || + index->is_spatial() != + (fil_page_get_type(block->page.frame) == FIL_PAGE_RTREE)) { *err= DB_PAGE_CORRUPTED; block= nullptr; @@ -515,18 +518,16 @@ static buf_block_t *btr_get_latched_root(const dict_index_t &index, mtr_t *mtr) mini-transaction. */ static buf_block_t * btr_block_reget(mtr_t *mtr, const dict_index_t &index, - const page_id_t id, rw_lock_type_t rw_latch, - dberr_t *err) + const page_id_t id, dberr_t *err) { - if (buf_block_t *block= - mtr->get_already_latched(id, mtr_memo_type_t(rw_latch))) + if (buf_block_t *block= mtr->get_already_latched(id, MTR_MEMO_PAGE_X_FIX)) { *err= DB_SUCCESS; return block; } ut_ad(mtr->memo_contains_flagged(&index.lock, MTR_MEMO_X_LOCK)); - return btr_block_get(index, id.page_no(), rw_latch, true, mtr, err); + return btr_block_get(index, id.page_no(), RW_X_LATCH, true, mtr, err); } /**************************************************************//** @@ -585,21 +586,15 @@ btr_page_alloc_low( if (UNIV_UNLIKELY(!root)) return root; - if (mtr->have_u_or_x_latch(*root)) - { + const bool have_latch= mtr->have_u_or_x_latch(*root); #ifdef BTR_CUR_HASH_ADAPT - ut_ad(!root->index || !root->index->freed()); + ut_ad(!have_latch || !root->index || !root->index->freed()); #endif - mtr->rollback_to_savepoint(savepoint); - } - else - { - mtr->lock_register(savepoint, MTR_MEMO_PAGE_SX_FIX); - root->page.lock.u_lock(); -#ifdef BTR_CUR_HASH_ADAPT - btr_search_drop_page_hash_index(root, true); -#endif - } + mtr->rollback_to_savepoint(savepoint); + + if (!have_latch && + UNIV_UNLIKELY(!(root= btr_root_block_get(index, RW_SX_LATCH, mtr, err)))) + return root; fseg_header_t *seg_header= root->page.frame + (level ? PAGE_HEADER + PAGE_BTR_SEG_TOP : PAGE_HEADER + PAGE_BTR_SEG_LEAF); @@ -696,26 +691,18 @@ dberr_t btr_page_free(dict_index_t* index, buf_block_t* block, mtr_t* mtr, const auto savepoint= mtr->get_savepoint(); if (buf_block_t *root= btr_root_block_get(index, RW_NO_LATCH, mtr, &err)) { - if (mtr->have_u_or_x_latch(*root)) - { + const bool have_latch= mtr->have_u_or_x_latch(*root); #ifdef BTR_CUR_HASH_ADAPT - ut_ad(!root->index || !root->index->freed()); + ut_ad(!have_latch || !root->index || !root->index->freed()); #endif - mtr->rollback_to_savepoint(savepoint); - } - else - { - mtr->lock_register(savepoint, MTR_MEMO_PAGE_SX_FIX); - root->page.lock.u_lock(); -#ifdef BTR_CUR_HASH_ADAPT - btr_search_drop_page_hash_index(root, true); -#endif - } - err= fseg_free_page(&root->page.frame[blob || - page_is_leaf(block->page.frame) - ? PAGE_HEADER + PAGE_BTR_SEG_LEAF - : PAGE_HEADER + PAGE_BTR_SEG_TOP], - space, page, mtr, space_latched); + mtr->rollback_to_savepoint(savepoint); + if (have_latch || + (root= btr_root_block_get(index, RW_SX_LATCH, mtr, &err))) + err= fseg_free_page(&root->page.frame[blob || + page_is_leaf(block->page.frame) + ? PAGE_HEADER + PAGE_BTR_SEG_LEAF + : PAGE_HEADER + PAGE_BTR_SEG_TOP], + space, page, mtr, space_latched); } if (err == DB_SUCCESS) buf_page_free(space, page, mtr); @@ -4293,7 +4280,7 @@ btr_discard_page( if (left_page_no != FIL_NULL) { merge_page_id.set_page_no(left_page_no); merge_block = btr_block_reget(mtr, *index, merge_page_id, - RW_X_LATCH, &err); + &err); if (UNIV_UNLIKELY(!merge_block)) { return err; } @@ -4319,7 +4306,7 @@ btr_discard_page( } else if (right_page_no != FIL_NULL) { merge_page_id.set_page_no(right_page_no); merge_block = btr_block_reget(mtr, *index, merge_page_id, - RW_X_LATCH, &err); + &err); if (UNIV_UNLIKELY(!merge_block)) { return err; } diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 8b7a5ffc623..6bf093f6d18 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -938,6 +938,76 @@ static inline page_cur_mode_t btr_cur_nonleaf_mode(page_cur_mode_t mode) return PAGE_CUR_LE; } +static MY_ATTRIBUTE((nonnull)) +/** Acquire a latch on the previous page without violating the latching order. +@param block index page +@param page_id page identifier with valid space identifier +@param zip_size ROW_FORMAT=COMPRESSED page size, or 0 +@param rw_latch the latch on block (RW_S_LATCH or RW_X_LATCH) +@param mtr mini-transaction +@param err error code +@retval 0 if an error occurred +@retval 1 if the page could be latched in the wrong order +@retval -1 if the latch on block was temporarily released */ +int btr_latch_prev(buf_block_t *block, page_id_t page_id, ulint zip_size, + rw_lock_type_t rw_latch, mtr_t *mtr, dberr_t *err) +{ + ut_ad(rw_latch == RW_S_LATCH || rw_latch == RW_X_LATCH); + ut_ad(page_id.space() == block->page.id().space()); + + const auto prev_savepoint= mtr->get_savepoint(); + ut_ad(block == mtr->at_savepoint(prev_savepoint - 1)); + + page_id.set_page_no(btr_page_get_prev(block->page.frame)); + buf_block_t *prev= buf_page_get_gen(page_id, zip_size, RW_NO_LATCH, nullptr, + BUF_GET, mtr, err, false); + if (UNIV_UNLIKELY(!prev)) + return 0; + + int ret= 1; + if (UNIV_UNLIKELY(rw_latch == RW_S_LATCH)) + { + if (UNIV_LIKELY(prev->page.lock.s_lock_try())) + { + mtr->lock_register(prev_savepoint, MTR_MEMO_PAGE_S_FIX); + goto prev_latched; + } + block->page.lock.s_unlock(); + } + else + { + if (UNIV_LIKELY(prev->page.lock.x_lock_try())) + { + mtr->lock_register(prev_savepoint, MTR_MEMO_PAGE_X_FIX); + goto prev_latched; + } + block->page.lock.x_unlock(); + } + + ret= -1; + mtr->lock_register(prev_savepoint - 1, MTR_MEMO_BUF_FIX); + mtr->rollback_to_savepoint(prev_savepoint); + prev= buf_page_get_gen(page_id, zip_size, rw_latch, prev, + BUF_GET, mtr, err, false); + if (UNIV_UNLIKELY(!prev)) + return 0; + mtr->upgrade_buffer_fix(prev_savepoint - 1, rw_latch); + + prev_latched: + if (memcmp_aligned<2>(FIL_PAGE_TYPE + prev->page.frame, + FIL_PAGE_TYPE + block->page.frame, 2) || + memcmp_aligned<2>(PAGE_HEADER + PAGE_INDEX_ID + prev->page.frame, + PAGE_HEADER + PAGE_INDEX_ID + block->page.frame, 8) || + page_is_comp(prev->page.frame) != page_is_comp(block->page.frame)) + { + ut_ad("corrupted" == 0); // FIXME: remove this + *err= DB_CORRUPTION; + ret= 0; + } + + return ret; +} + dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, btr_latch_mode latch_mode, mtr_t *mtr) { @@ -1192,11 +1262,12 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, page_cur.block= block; ut_ad(block == mtr->at_savepoint(block_savepoint)); + ut_ad(rw_latch != RW_NO_LATCH); #ifdef UNIV_ZIP_DEBUG - if (rw_latch == RW_NO_LATCH); - else if (const page_zip_des_t *page_zip= buf_block_get_page_zip(block)) + if (const page_zip_des_t *page_zip= buf_block_get_page_zip(block)) ut_a(page_zip_validate(page_zip, block->page.frame, index())); #endif /* UNIV_ZIP_DEBUG */ + const uint32_t page_level= btr_page_get_level(block->page.frame); if (height == ULINT_UNDEFINED) @@ -1240,7 +1311,7 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, goto reached_index_root_and_leaf; goto reached_root_and_leaf; case RW_NO_LATCH: - ut_ad(mtr->memo_contains_flagged(&index()->lock, MTR_MEMO_X_LOCK)); + ut_ad(0); } goto reached_leaf; } @@ -1257,14 +1328,8 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, if (tree_height <= height + 2) /* Retain the root page latch. */ break; - goto release_parent_page; + /* fall through */ default: - if (rw_latch == RW_NO_LATCH) - { - ut_ad(!height); - break; - } - release_parent_page: ut_ad(block_savepoint > savepoint); mtr->rollback_to_savepoint(block_savepoint - 1, block_savepoint); block_savepoint--; @@ -1301,29 +1366,20 @@ dberr_t btr_cur_t::search_leaf(const dtuple_t *tuple, page_cur_mode_t mode, static_assert(BTR_MODIFY_PREV & BTR_MODIFY_LEAF, ""); static_assert(BTR_SEARCH_PREV & BTR_SEARCH_LEAF, ""); ut_ad(!latch_by_caller); + ut_ad(rw_latch == + rw_lock_type_t(latch_mode & (RW_X_LATCH | RW_S_LATCH))); - if (rw_latch == RW_NO_LATCH) - { - /* latch also siblings from left to right */ - rw_latch= rw_lock_type_t(latch_mode & (RW_X_LATCH | RW_S_LATCH)); - if (page_has_prev(block->page.frame) && - !btr_block_get(*index(), btr_page_get_prev(block->page.frame), - rw_latch, false, mtr, &err)) - goto func_exit; - mtr->upgrade_buffer_fix(block_savepoint, rw_latch); - if (page_has_next(block->page.frame) && - !btr_block_get(*index(), btr_page_get_next(block->page.frame), - rw_latch, false, mtr, &err)) - goto func_exit; - } + /* latch also siblings from left to right */ + if (page_has_prev(block->page.frame) && + !btr_latch_prev(block, page_id, zip_size, rw_latch, mtr, &err)) + goto func_exit; + if (page_has_next(block->page.frame) && + !btr_block_get(*index(), btr_page_get_next(block->page.frame), + rw_latch, false, mtr, &err)) + goto func_exit; goto release_tree; case BTR_SEARCH_LEAF: case BTR_MODIFY_LEAF: - if (rw_latch == RW_NO_LATCH) - { - ut_ad(index()->is_ibuf()); - mtr->upgrade_buffer_fix(block_savepoint, rw_lock_type_t(latch_mode)); - } if (!latch_by_caller) { release_tree: @@ -1337,13 +1393,11 @@ release_tree: break; default: ut_ad(latch_mode == BTR_MODIFY_TREE); - ut_ad(rw_latch == RW_NO_LATCH); + ut_ad(rw_latch == RW_X_LATCH); /* x-latch also siblings from left to right */ if (page_has_prev(block->page.frame) && - !btr_block_get(*index(), btr_page_get_prev(block->page.frame), - RW_X_LATCH, false, mtr, &err)) + !btr_latch_prev(block, page_id, zip_size, rw_latch, mtr, &err)) goto func_exit; - mtr->upgrade_buffer_fix(block_savepoint, RW_X_LATCH); if (page_has_next(block->page.frame) && !btr_block_get(*index(), btr_page_get_next(block->page.frame), RW_X_LATCH, false, mtr, &err)) @@ -1491,25 +1545,15 @@ release_tree: page_rec_is_first(page_cur.rec, block->page.frame)) { ut_ad(block_savepoint + 1 == mtr->get_savepoint()); + /* Latch the previous page if the node pointer is the leftmost of the current page. */ - buf_block_t *left= btr_block_get(*index(), - btr_page_get_prev(block->page.frame), - RW_NO_LATCH, false, mtr, &err); - if (UNIV_UNLIKELY(!left)) + int ret= btr_latch_prev(block, page_id, zip_size, rw_latch, mtr, &err); + if (!ret) goto func_exit; ut_ad(block_savepoint + 2 == mtr->get_savepoint()); - if (UNIV_LIKELY(left->page.lock.s_lock_try())) - mtr->lock_register(block_savepoint + 1, MTR_MEMO_PAGE_S_FIX); - else + if (ret < 0) { - if (rw_latch == RW_S_LATCH) - block->page.lock.s_unlock(); - else - block->page.lock.x_unlock(); - mtr->upgrade_buffer_fix(block_savepoint + 1, RW_S_LATCH); - mtr->lock_register(block_savepoint, MTR_MEMO_BUF_FIX); - mtr->upgrade_buffer_fix(block_savepoint, RW_S_LATCH); /* While our latch on the level-2 page prevents splits or merges of this level-1 block, other threads may have modified it due to splitting or merging some level-0 (leaf) @@ -1524,13 +1568,12 @@ release_tree: offsets)); } } - goto leaf_with_no_latch; + rw_latch= rw_lock_type_t(latch_mode & (RW_X_LATCH | RW_S_LATCH)); + break; case BTR_MODIFY_LEAF: case BTR_SEARCH_LEAF: - if (index()->is_ibuf()) - goto leaf_with_no_latch; rw_latch= rw_lock_type_t(latch_mode); - if (btr_op != BTR_NO_OP && + if (btr_op != BTR_NO_OP && !index()->is_ibuf() && ibuf_should_try(index(), btr_op != BTR_INSERT_OP)) /* Try to buffer the operation if the leaf page is not in the buffer pool. */ @@ -1550,10 +1593,9 @@ release_tree: mtr->rollback_to_savepoint(block_savepoint); goto need_opposite_intention; } - /* fall through */ + break; default: - leaf_with_no_latch: - rw_latch= RW_NO_LATCH; + ut_ad(rw_latch == RW_X_LATCH); } } @@ -1578,8 +1620,8 @@ dberr_t btr_cur_t::pessimistic_search_leaf(const dtuple_t *tuple, ut_ad(index()->is_btree() || index()->is_ibuf()); ut_ad(!index()->is_ibuf() || ibuf_inside(mtr)); - rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; - rec_offs* offsets = offsets_; + rec_offs offsets_[REC_OFFS_NORMAL_SIZE]; + rec_offs* offsets= offsets_; rec_offs_init(offsets_); ut_ad(flag == BTR_CUR_BINARY); @@ -1653,9 +1695,8 @@ dberr_t btr_cur_t::pessimistic_search_leaf(const dtuple_t *tuple, /* Go to the child node */ page_id.set_page_no(btr_node_ptr_get_child_page_no(page_cur.rec, offsets)); - const auto block_savepoint= mtr->get_savepoint(); block= - buf_page_get_gen(page_id, block->zip_size(), RW_NO_LATCH, nullptr, BUF_GET, + buf_page_get_gen(page_id, block->zip_size(), RW_X_LATCH, nullptr, BUF_GET, mtr, &err, !--height && !index()->is_clust()); if (!block) @@ -1674,15 +1715,15 @@ dberr_t btr_cur_t::pessimistic_search_leaf(const dtuple_t *tuple, if (height != btr_page_get_level(block->page.frame)) goto corrupted; - if (page_has_prev(block->page.frame) && - !btr_block_get(*index(), btr_page_get_prev(block->page.frame), - RW_X_LATCH, false, mtr, &err)) - goto func_exit; - mtr->upgrade_buffer_fix(block_savepoint, RW_X_LATCH); #ifdef UNIV_ZIP_DEBUG const page_zip_des_t *page_zip= buf_block_get_page_zip(block); ut_a(!page_zip || page_zip_validate(page_zip, block->page.frame, index())); #endif /* UNIV_ZIP_DEBUG */ + + if (page_has_prev(block->page.frame) && + !btr_latch_prev(block, page_id, block->zip_size(), + RW_X_LATCH, mtr, &err)) + goto func_exit; if (page_has_next(block->page.frame) && !btr_block_get(*index(), btr_page_get_next(block->page.frame), RW_X_LATCH, false, mtr, &err)) @@ -1895,13 +1936,10 @@ index_locked: ut_ad(n_blocks < BTR_MAX_LEVELS); ut_ad(savepoint + n_blocks == mtr->get_savepoint()); - const rw_lock_type_t rw_latch= height && latch_mode != BTR_MODIFY_TREE - ? upper_rw_latch - : RW_NO_LATCH; buf_block_t* block= - btr_block_get(*index, page, rw_latch, !height && !index->is_clust(), mtr, - &err); - + btr_block_get(*index, page, + height ? upper_rw_latch : root_leaf_rw_latch, + !height, mtr, &err); ut_ad(!block == (err != DB_SUCCESS)); if (!block) @@ -1943,13 +1981,11 @@ index_locked: if (latch_mode == BTR_MODIFY_TREE) { - ut_ad(rw_latch == RW_NO_LATCH); /* x-latch also siblings from left to right */ if (page_has_prev(block->page.frame) && - !btr_block_get(*index, btr_page_get_prev(block->page.frame), - RW_X_LATCH, false, mtr, &err)) + !btr_latch_prev(block, block->page.id(), zip_size, RW_X_LATCH, + mtr, &err)) break; - mtr->upgrade_buffer_fix(leaf_savepoint - 1, RW_X_LATCH); if (page_has_next(block->page.frame) && !btr_block_get(*index, btr_page_get_next(block->page.frame), RW_X_LATCH, false, mtr, &err)) @@ -1964,10 +2000,6 @@ index_locked: } else { - if (rw_latch == RW_NO_LATCH) - mtr->upgrade_buffer_fix(leaf_savepoint - 1, - rw_lock_type_t(latch_mode & - (RW_X_LATCH | RW_S_LATCH))); if (latch_mode != BTR_CONT_MODIFY_TREE) { ut_ad(latch_mode == BTR_MODIFY_LEAF || @@ -2037,21 +2069,6 @@ index_locked: n_blocks= 1; } } - - if (!height) - { - if (page == index->page) - mtr->upgrade_buffer_fix(savepoint, RW_X_LATCH); - else - { - /* The U-latch protects BTR_SEG_HEAP, BTR_SEG_TOP. */ - mtr->upgrade_buffer_fix(savepoint, RW_SX_LATCH); - - /* Upgrade buffer-fix to exclusive latches on all remaining pages. */ - for (ulint i= 1; i <= n_blocks; i++) - mtr->upgrade_buffer_fix(savepoint + i, RW_X_LATCH); - } - } } /* Go to the child node */ diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index d48437e4bd0..01f8b2671b0 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -540,7 +540,8 @@ btr_pcur_move_to_next_page( dberr_t err; buf_block_t* next_block = btr_block_get( - *cursor->index(), next_page_no, cursor->latch_mode & ~12, + *cursor->index(), next_page_no, + rw_lock_type_t(cursor->latch_mode & (RW_X_LATCH | RW_S_LATCH)), page_is_leaf(page), mtr, &err); if (UNIV_UNLIKELY(!next_block)) { diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 1a18004533e..2f4de339d02 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -2156,8 +2156,7 @@ next_page: } next_page= false; - block= btr_block_get(*clust_index, next_page_no, BTR_SEARCH_LEAF, false, - &mtr); + block= btr_block_get(*clust_index, next_page_no, RW_S_LATCH, false, &mtr); if (!block) goto non_empty; page_cur_set_before_first(block, cur); diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h index a56598d3620..5a0401fad85 100644 --- a/storage/innobase/include/btr0btr.h +++ b/storage/innobase/include/btr0btr.h @@ -91,7 +91,7 @@ ATTRIBUTE_COLD void btr_decryption_failed(const dict_index_t &index); @param[out] err error code @return block */ buf_block_t *btr_block_get(const dict_index_t &index, - uint32_t page, ulint mode, bool merge, + uint32_t page, rw_lock_type_t mode, bool merge, mtr_t *mtr, dberr_t *err= nullptr); /**************************************************************//**