From cd26cdcd974725031e30393ff165fb0dfb365c4d Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 29 Apr 2019 00:11:48 +0400 Subject: [PATCH 01/43] MDEV-19141 server_audit_excl_users accepts only values with less than 1024 chars. Since this limit is imposed by the SHOW_VAR_FUNC_BUFF_SIZE, we just launch the error message. --- .../suite/plugins/r/server_audit.result | 14 +++++ mysql-test/suite/plugins/t/server_audit.test | 8 +++ plugin/server_audit/server_audit.c | 62 +++++++++++++++++-- 3 files changed, 78 insertions(+), 6 deletions(-) diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 01392760317..0709444e5f6 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -21,6 +21,16 @@ set global server_audit_incl_users=null; set global server_audit_file_path='server_audit.log'; set global server_audit_output_type=file; set global server_audit_logging=on; +set global server_audit_incl_users= repeat("'root',", 10000); +ERROR 42000: Variable 'server_audit_incl_users' can't be set to the value of ''root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','roo' +show variables like 'server_audit_incl_users'; +Variable_name Value +server_audit_incl_users +set global server_audit_excl_users= repeat("'root',", 10000); +ERROR 42000: Variable 'server_audit_excl_users' can't be set to the value of ''root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','root','roo' +show variables like 'server_audit_excl_users'; +Variable_name Value +server_audit_excl_users connect con1,localhost,root,,mysql; connection default; disconnect con1; @@ -251,6 +261,10 @@ uninstall plugin server_audit; Warnings: Warning 1620 Plugin is busy and will be uninstalled on shutdown TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_logging=on',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_incl_users= repeat("\'root\',", 10000)',ID +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show variables like \'server_audit_incl_users\'',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'set global server_audit_excl_users= repeat("\'root\',", 10000)',ID +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,test,'show variables like \'server_audit_excl_users\'',0 TIME,HOSTNAME,root,localhost,ID,0,CONNECT,mysql,,0 TIME,HOSTNAME,root,localhost,ID,0,DISCONNECT,mysql,,0 TIME,HOSTNAME,no_such_user,localhost,ID,0,FAILED_CONNECT,,,ID diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index 4af1ed883e3..fa23dc5caa3 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -13,6 +13,14 @@ set global server_audit_incl_users=null; set global server_audit_file_path='server_audit.log'; set global server_audit_output_type=file; set global server_audit_logging=on; + +--error ER_WRONG_VALUE_FOR_VAR +set global server_audit_incl_users= repeat("'root',", 10000); +show variables like 'server_audit_incl_users'; +--error ER_WRONG_VALUE_FOR_VAR +set global server_audit_excl_users= repeat("'root',", 10000); +show variables like 'server_audit_excl_users'; + --sleep 2 connect (con1,localhost,root,,mysql); connection default; diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 0995327a86d..2f9cd99fbd8 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -335,6 +335,10 @@ static void update_file_rotations(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); static void update_incl_users(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); +static int check_incl_users(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save, + struct st_mysql_value *value); +static int check_excl_users(MYSQL_THD thd, struct st_mysql_sys_var *var, void *save, + struct st_mysql_value *value); static void update_excl_users(MYSQL_THD thd, struct st_mysql_sys_var *var, void *var_ptr, const void *save); static void update_output_type(MYSQL_THD thd, struct st_mysql_sys_var *var, @@ -354,10 +358,10 @@ static void rotate_log(MYSQL_THD thd, struct st_mysql_sys_var *var, static MYSQL_SYSVAR_STR(incl_users, incl_users, PLUGIN_VAR_RQCMDARG, "Comma separated list of users to monitor.", - NULL, update_incl_users, NULL); + check_incl_users, update_incl_users, NULL); static MYSQL_SYSVAR_STR(excl_users, excl_users, PLUGIN_VAR_RQCMDARG, "Comma separated list of users to exclude from auditing.", - NULL, update_excl_users, NULL); + check_excl_users, update_excl_users, NULL); /* bits in the event filter. */ #define EVENT_CONNECT 1 #define EVENT_QUERY_ALL 2 @@ -2643,16 +2647,56 @@ static void update_file_rotate_size(MYSQL_THD thd __attribute__((unused)), } +static int check_users(void *save, struct st_mysql_value *value, + size_t s, const char *name) +{ + const char *users; + int len= 0; + + users= value->val_str(value, NULL, &len); + if ((size_t) len > s) + { + error_header(); + fprintf(stderr, + "server_audit_%s_users value can't be longer than %ld characters.\n", + name, s); + return 1; + } + *((const char**)save)= users; + return 0; +} + +static int check_incl_users(MYSQL_THD thd __attribute__((unused)), + struct st_mysql_sys_var *var __attribute__((unused)), + void *save, struct st_mysql_value *value) +{ + return check_users(save, value, sizeof(incl_user_buffer), "incl"); +} + +static int check_excl_users(MYSQL_THD thd __attribute__((unused)), + struct st_mysql_sys_var *var __attribute__((unused)), + void *save, struct st_mysql_value *value) +{ + return check_users(save, value, sizeof(excl_user_buffer), "excl"); +} + + static void update_incl_users(MYSQL_THD thd, struct st_mysql_sys_var *var __attribute__((unused)), void *var_ptr __attribute__((unused)), const void *save) { char *new_users= (*(char **) save) ? *(char **) save : empty_str; + size_t new_len= strlen(new_users) + 1; if (!maria_55_started || !debug_server_started) flogger_mutex_lock(&lock_operations); mark_always_logged(thd); - strncpy(incl_user_buffer, new_users, sizeof(incl_user_buffer)-1); - incl_user_buffer[sizeof(incl_user_buffer)-1]= 0; + + if (new_len > sizeof(incl_user_buffer)) + new_len= sizeof(incl_user_buffer); + + memcpy(incl_user_buffer, new_users, new_len - 1); + incl_user_buffer[new_len - 1]= 0; + incl_users= incl_user_buffer; user_coll_fill(&incl_user_coll, incl_users, &excl_user_coll, 1); error_header(); @@ -2667,11 +2711,17 @@ static void update_excl_users(MYSQL_THD thd __attribute__((unused)), void *var_ptr __attribute__((unused)), const void *save) { char *new_users= (*(char **) save) ? *(char **) save : empty_str; + size_t new_len= strlen(new_users) + 1; if (!maria_55_started || !debug_server_started) flogger_mutex_lock(&lock_operations); mark_always_logged(thd); - strncpy(excl_user_buffer, new_users, sizeof(excl_user_buffer)-1); - excl_user_buffer[sizeof(excl_user_buffer)-1]= 0; + + if (new_len > sizeof(excl_user_buffer)) + new_len= sizeof(excl_user_buffer); + + memcpy(excl_user_buffer, new_users, new_len - 1); + excl_user_buffer[new_len - 1]= 0; + excl_users= excl_user_buffer; user_coll_fill(&excl_user_coll, excl_users, &incl_user_coll, 0); error_header(); From a529188e05da8060c95eeb4c8caef05adbd6cc6a Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 29 Apr 2019 01:25:17 +0400 Subject: [PATCH 02/43] MDEV-17456 Malicious SUPER user can possibly change audit log configuration without leaving traces. The 'SET server_audit_logging ' statements should be logged no matter what. --- mysql-test/suite/plugins/r/server_audit.result | 3 +++ mysql-test/suite/plugins/t/server_audit.test | 3 +++ plugin/server_audit/server_audit.c | 7 ++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mysql-test/suite/plugins/r/server_audit.result b/mysql-test/suite/plugins/r/server_audit.result index 0709444e5f6..b8d2986feea 100644 --- a/mysql-test/suite/plugins/r/server_audit.result +++ b/mysql-test/suite/plugins/r/server_audit.result @@ -212,6 +212,8 @@ select 2; 2 2 drop table t1; +set global server_audit_logging= off; +set global server_audit_logging= on; set global server_audit_events=''; set global server_audit_query_log_limit= 15; select (1), (2), (3), (4); @@ -378,6 +380,7 @@ TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'SET PASSWORD FOR u1=',ID TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'CREATE USER u3 IDENTIFIED BY *****',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'drop user u1, u2, u3',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'insert into t1 values (1), (2)',0 +TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_logging= off',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global server_audit_events=\'\'',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'set global serv',0 TIME,HOSTNAME,root,localhost,ID,ID,QUERY,sa_db,'select (1), (2)',0 diff --git a/mysql-test/suite/plugins/t/server_audit.test b/mysql-test/suite/plugins/t/server_audit.test index fa23dc5caa3..f19c8f53b61 100644 --- a/mysql-test/suite/plugins/t/server_audit.test +++ b/mysql-test/suite/plugins/t/server_audit.test @@ -136,6 +136,9 @@ select * from t1; select 2; drop table t1; +set global server_audit_logging= off; +set global server_audit_logging= on; + set global server_audit_events=''; set global server_audit_query_log_limit= 15; diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index 2f9cd99fbd8..f03564e21d4 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -15,7 +15,7 @@ #define PLUGIN_VERSION 0x104 -#define PLUGIN_STR_VERSION "1.4.4" +#define PLUGIN_STR_VERSION "1.4.5" #define _my_thread_var loc_thread_var @@ -1623,7 +1623,7 @@ static int log_statement_ex(const struct connection_info *cn, } if (query && !(events & EVENT_QUERY_ALL) && - (events & EVENT_QUERY)) + (events & EVENT_QUERY && !cn->log_always)) { const char *orig_query= query; @@ -2556,9 +2556,10 @@ static void log_current_query(MYSQL_THD thd) if (!ci_needs_setup(cn) && cn->query_length && FILTER(EVENT_QUERY) && do_log_user(cn->user)) { + cn->log_always= 1; log_statement_ex(cn, cn->query_time, thd_get_thread_id(thd), cn->query, cn->query_length, 0, "QUERY"); - cn->log_always= 1; + cn->log_always= 0; } } From bb4f4b3a1b6c9287fcef6a6d290fd228e8a181f1 Mon Sep 17 00:00:00 2001 From: Alexey Botchkov Date: Mon, 29 Apr 2019 02:32:13 +0400 Subject: [PATCH 03/43] Make Win compiler happy. --- plugin/server_audit/server_audit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index f03564e21d4..e98d868bcba 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -2660,7 +2660,7 @@ static int check_users(void *save, struct st_mysql_value *value, error_header(); fprintf(stderr, "server_audit_%s_users value can't be longer than %ld characters.\n", - name, s); + name, (long int) s); return 1; } *((const char**)save)= users; From cc359eae3bd38a158690067f61f31de8524730c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Apr 2019 09:24:59 +0300 Subject: [PATCH 04/43] Remove a type cast, and use correct format instead --- plugin/server_audit/server_audit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugin/server_audit/server_audit.c b/plugin/server_audit/server_audit.c index e98d868bcba..4e8c7ad670e 100644 --- a/plugin/server_audit/server_audit.c +++ b/plugin/server_audit/server_audit.c @@ -2659,8 +2659,8 @@ static int check_users(void *save, struct st_mysql_value *value, { error_header(); fprintf(stderr, - "server_audit_%s_users value can't be longer than %ld characters.\n", - name, (long int) s); + "server_audit_%s_users value can't be longer than %zu characters.\n", + name, s); return 1; } *((const char**)save)= users; From e10b3fa97a47cad0e6dbcc1d1691bad655087f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Apr 2019 10:04:54 +0300 Subject: [PATCH 05/43] MDEV-19231: Correct an assertion BtrBulk::finish(): On error, the B-tree can be corrupted. Only upon successful completion, it makes sense to validate the index. --- storage/innobase/btr/btr0bulk.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc index 2655ce2a2ce..1296641d073 100644 --- a/storage/innobase/btr/btr0bulk.cc +++ b/storage/innobase/btr/btr0bulk.cc @@ -1050,7 +1050,7 @@ BtrBulk::finish(dberr_t err) ut_ad(!sync_check_iterate(dict_sync_check())); - ut_ad(err == DB_SUCCESS + ut_ad(err != DB_SUCCESS || btr_validate_index(m_index, NULL, false) == DB_SUCCESS); return(err); } From 1b577e4d8baf962a7eb0ff8c946697b1e3d8f412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Apr 2019 11:43:22 +0300 Subject: [PATCH 06/43] MDEV-19356 Assertion 'space->free_limit == 0 || space->free_limit == free_limit' fil_node_t::read_page0(): Do not replace up-to-date metadata with a possibly old version of page 0 that is being reread from the file. A more up-to-date page 0 could still exists in the buffer pool, waiting to be written back to the file. --- storage/innobase/fil/fil0fil.cc | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index ccf1ac0ecef..d892898f555 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -579,13 +579,9 @@ bool fil_node_t::read_page0(bool first) return false; } - ut_ad(space->free_limit == 0 || space->free_limit == free_limit); - ut_ad(space->free_len == 0 || space->free_len == free_len); - space->size_in_header = size; - space->free_limit = free_limit; - space->free_len = free_len; - if (first) { + ut_ad(space->id != TRX_SYS_SPACE); + /* Truncate the size to a multiple of extent size. */ ulint mask = psize * FSP_EXTENT_SIZE - 1; @@ -598,8 +594,19 @@ bool fil_node_t::read_page0(bool first) this->size = ulint(size_bytes / psize); space->size += this->size; + } else if (space->id != TRX_SYS_SPACE || space->size_in_header) { + /* If this is not the first-time open, do nothing. + For the system tablespace, we always get invoked as + first=false, so we detect the true first-time-open based + on size_in_header and proceed to initiailze the data. */ + return true; } + ut_ad(space->free_limit == 0 || space->free_limit == free_limit); + ut_ad(space->free_len == 0 || space->free_len == free_len); + space->size_in_header = size; + space->free_limit = free_limit; + space->free_len = free_len; return true; } From e03ad4f71ae9f897b3ddd94269c7ae922ca0505c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Wed, 24 Apr 2019 11:44:32 +0100 Subject: [PATCH 07/43] Fix a typo --- extra/mariabackup/xtrabackup.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index 07d21029733..eae55ddb02e 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -4203,7 +4203,7 @@ reread_log_header: memset(&stat_info, 0, sizeof(MY_STAT)); dst_log_file = ds_open(ds_redo, "ib_logfile0", &stat_info); if (dst_log_file == NULL) { - msg("§rror: failed to open the target stream for " + msg("Error: failed to open the target stream for " "'ib_logfile0'."); goto fail; } From d6e431dfa8a5653b669615cd9c9d2d206ce0d053 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Mon, 29 Apr 2019 12:44:00 +0100 Subject: [PATCH 08/43] MDEV-18131 : Update C/C to fix IP address SAN verification in 10.2+ --- libmariadb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libmariadb b/libmariadb index 2c5aebb3bc7..b5087161176 160000 --- a/libmariadb +++ b/libmariadb @@ -1 +1 @@ -Subproject commit 2c5aebb3bc724c1663c481ba2fedde00ab494fa4 +Subproject commit b50871611764d282874ad095d6c021163d1fe354 From 61f370a3c9997d2c7067b8cf5d39c8ad67dde5aa Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Thu, 25 Apr 2019 20:24:10 +0300 Subject: [PATCH 09/43] MDEV-18429 Consistent non-locking reads do not appear in TRANSACTIONS section of SHOW ENGINE INNODB STATUS lock_print_info_all_transactions(): print transactions which are started but not in RW or RO lists. print_not_started(): Replaces PrintNotStarted. Collect the skipped transactions. --- storage/innobase/lock/lock0lock.cc | 51 ++++++++++++++++++------------ 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 7f6171241ac..22ec2ee7f06 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4973,28 +4973,26 @@ lock_print_info_summary( return(TRUE); } -/** Functor to print not-started transaction from the mysql_trx_list. */ +/** Prints not started transaction or puts it into set. +@param[in] trx transaction +@param[in,out] file fd where to print +@param[in,out] started put transaction here if is started */ +static void +print_not_started(const trx_t* trx, FILE* file, std::set& started) +{ + ut_ad(trx->in_mysql_trx_list); + ut_ad(mutex_own(&trx_sys->mutex)); -struct PrintNotStarted { + /* See state transitions and locking rules in trx0trx.h */ - PrintNotStarted(FILE* file) : m_file(file) { } + if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { - void operator()(const trx_t* trx) - { - ut_ad(trx->in_mysql_trx_list); - ut_ad(mutex_own(&trx_sys->mutex)); - - /* See state transitions and locking rules in trx0trx.h */ - - if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { - - fputs("---", m_file); - trx_print_latched(m_file, trx, 600); - } + fputs("---", file); + trx_print_latched(file, trx, 600); + } else { + started.insert(trx); } - - FILE* m_file; -}; +} /** Iterate over a transaction's locks. Keeping track of the iterator using an ordinal value. */ @@ -5287,8 +5285,11 @@ lock_print_info_all_transactions( transactions will be omitted here. The information will be available from INFORMATION_SCHEMA.INNODB_TRX. */ - PrintNotStarted print_not_started(file); - ut_list_map(trx_sys->mysql_trx_list, print_not_started); + std::set not_printed_transactions; + for (const trx_t* trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); + trx; trx = UT_LIST_GET_NEXT(mysql_trx_list, trx)) { + print_not_started(trx, file, not_printed_transactions); + } const trx_t* trx; TrxListIterator trx_iter; @@ -5302,6 +5303,8 @@ lock_print_info_all_transactions( check_trx_state(trx); + not_printed_transactions.erase(trx); + if (trx != prev_trx) { lock_trx_print_wait_and_mvcc_state(file, trx); prev_trx = trx; @@ -5342,6 +5345,14 @@ lock_print_info_all_transactions( trx_iter.next(); } + for (std::set::const_iterator it + = not_printed_transactions.begin(), + end = not_printed_transactions.end(); + it != end; ++it) { + fputs("---", file); + trx_print_latched(file, *it, 600); + } + lock_mutex_exit(); mutex_exit(&trx_sys->mutex); From bdd6e33f00bff927358a7b03798a285ff41b35b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Apr 2019 14:05:44 +0300 Subject: [PATCH 10/43] MDEV-13626: Add a test case --- .../suite/innodb/r/page_reorganize.result | 27 +++++++++ .../suite/innodb/t/page_reorganize.test | 56 +++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 mysql-test/suite/innodb/r/page_reorganize.result create mode 100644 mysql-test/suite/innodb/t/page_reorganize.test diff --git a/mysql-test/suite/innodb/r/page_reorganize.result b/mysql-test/suite/innodb/r/page_reorganize.result new file mode 100644 index 00000000000..1059fc78531 --- /dev/null +++ b/mysql-test/suite/innodb/r/page_reorganize.result @@ -0,0 +1,27 @@ +# +# Bug# 20005279 ASSERT !OTHER_LOCK, LOCK_MOVE_REORGANIZE_PAGE() +# +create table t1 (f1 int auto_increment primary key, +f2 char(255)) engine=innodb; +start transaction; +commit; +start transaction; +select f1, f2 from t1 where f1 = 20 for update; +f1 f2 +20 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +connect con1,localhost,root,,; +select f1 from t1 where f1 = 20 for update; +connection default; +SET @save_dbug = @@debug_dbug; +SET DEBUG_DBUG = '+d,do_page_reorganize,do_lock_reverse_page_reorganize'; +insert into t1(f2) values (repeat('+', 100)); +SET DEBUG = @save_dbug; +Warnings: +Warning 1287 '@@debug' is deprecated and will be removed in a future release. Please use '@@debug_dbug' instead +commit; +connection con1; +f1 +20 +disconnect con1; +connection default; +drop table t1; diff --git a/mysql-test/suite/innodb/t/page_reorganize.test b/mysql-test/suite/innodb/t/page_reorganize.test new file mode 100644 index 00000000000..7408353976d --- /dev/null +++ b/mysql-test/suite/innodb/t/page_reorganize.test @@ -0,0 +1,56 @@ +--source include/have_innodb.inc +--source include/have_innodb_16k.inc +--source include/have_debug.inc + +--source include/count_sessions.inc + +--echo # +--echo # Bug# 20005279 ASSERT !OTHER_LOCK, LOCK_MOVE_REORGANIZE_PAGE() +--echo # + +create table t1 (f1 int auto_increment primary key, + f2 char(255)) engine=innodb; + +let $inc = 50; + +start transaction; +--disable_query_log + +while ($inc) +{ + insert into t1(f2) values (repeat('~', 50)); + dec $inc; +} + +--enable_query_log +commit; + +start transaction; +select f1, f2 from t1 where f1 = 20 for update; + +connect (con1,localhost,root,,); +--send +select f1 from t1 where f1 = 20 for update; + +connection default; + +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where INFO = 'select f1 from t1 where f1 = 20 for update'; + +--source include/wait_condition.inc + +SET @save_dbug = @@debug_dbug; +SET DEBUG_DBUG = '+d,do_page_reorganize,do_lock_reverse_page_reorganize'; +insert into t1(f2) values (repeat('+', 100)); +SET DEBUG = @save_dbug; +commit; + +connection con1; +reap; +disconnect con1; +connection default; + +drop table t1; + +--source include/wait_until_count_sessions.inc From 5fb4c0a8a877077e2835a9b39ac6e670fa4eaaac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Apr 2019 14:33:46 +0300 Subject: [PATCH 11/43] Clean up ut_list ut_list_validate(), ut_list_map(): Add variants with const Functor& so that these functions can be called with an rvalue. Remove wrapper macros, and add #ifdef UNIV_DEBUG around debug-only code. --- storage/innobase/buf/buf0buddy.cc | 11 ++- storage/innobase/buf/buf0flu.cc | 5 +- storage/innobase/fil/fil0fil.cc | 2 +- storage/innobase/include/buf0buf.h | 10 +-- storage/innobase/include/ut0lst.h | 134 +++++++++++++++++------------ storage/innobase/lock/lock0lock.cc | 4 +- 6 files changed, 92 insertions(+), 74 deletions(-) diff --git a/storage/innobase/buf/buf0buddy.cc b/storage/innobase/buf/buf0buddy.cc index 777188d045d..d4e47f136ac 100644 --- a/storage/innobase/buf/buf0buddy.cc +++ b/storage/innobase/buf/buf0buddy.cc @@ -175,13 +175,13 @@ buf_buddy_get( struct CheckZipFree { CheckZipFree(ulint i) : m_i(i) {} - void operator()(const buf_buddy_free_t* elem) const + void operator()(const buf_buddy_free_t* elem) const { - ut_a(buf_buddy_stamp_is_free(elem)); - ut_a(elem->stamp.size <= m_i); + ut_ad(buf_buddy_stamp_is_free(elem)); + ut_ad(elem->stamp.size <= m_i); } - ulint m_i; + const ulint m_i; }; /** Validate a buddy list. @@ -193,8 +193,7 @@ buf_buddy_list_validate( const buf_pool_t* buf_pool, ulint i) { - CheckZipFree check(i); - ut_list_validate(buf_pool->zip_free[i], check); + ut_list_validate(buf_pool->zip_free[i], CheckZipFree(i)); } /**********************************************************************//** diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index f6f566bb8c7..cffbdc1660c 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -3533,7 +3533,7 @@ buf_flush_request_force( /** Functor to validate the flush list. */ struct Check { - void operator()(const buf_page_t* elem) + void operator()(const buf_page_t* elem) const { ut_a(elem->in_flush_list); } @@ -3550,11 +3550,10 @@ buf_flush_validate_low( { buf_page_t* bpage; const ib_rbt_node_t* rnode = NULL; - Check check; ut_ad(buf_flush_list_mutex_own(buf_pool)); - ut_list_validate(buf_pool->flush_list, check); + ut_list_validate(buf_pool->flush_list, Check()); bpage = UT_LIST_GET_FIRST(buf_pool->flush_list); diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index d892898f555..2de94fe3e40 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -5327,7 +5327,7 @@ fil_validate(void) ut_a(fil_system->n_open == n_open); - UT_LIST_CHECK(fil_system->LRU); + ut_list_validate(fil_system->LRU); for (fil_node = UT_LIST_GET_FIRST(fil_system->LRU); fil_node != 0; diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h index 36175b9404e..361fd623f05 100644 --- a/storage/innobase/include/buf0buf.h +++ b/storage/innobase/include/buf0buf.h @@ -2423,8 +2423,7 @@ struct CheckInLRUList { static void validate(const buf_pool_t* buf_pool) { - CheckInLRUList check; - ut_list_validate(buf_pool->LRU, check); + ut_list_validate(buf_pool->LRU, CheckInLRUList()); } }; @@ -2437,8 +2436,7 @@ struct CheckInFreeList { static void validate(const buf_pool_t* buf_pool) { - CheckInFreeList check; - ut_list_validate(buf_pool->free, check); + ut_list_validate(buf_pool->free, CheckInFreeList()); } }; @@ -2451,8 +2449,8 @@ struct CheckUnzipLRUAndLRUList { static void validate(const buf_pool_t* buf_pool) { - CheckUnzipLRUAndLRUList check; - ut_list_validate(buf_pool->unzip_LRU, check); + ut_list_validate(buf_pool->unzip_LRU, + CheckUnzipLRUAndLRUList()); } }; #endif /* UNIV_DEBUG || defined UNIV_BUF_DEBUG */ diff --git a/storage/innobase/include/ut0lst.h b/storage/innobase/include/ut0lst.h index 09733da20a0..986f73ea17c 100644 --- a/storage/innobase/include/ut0lst.h +++ b/storage/innobase/include/ut0lst.h @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, 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 @@ -426,24 +427,19 @@ Gets the last node in a two-way list. @return last node, or NULL if the list is empty */ #define UT_LIST_GET_LAST(BASE) (BASE).end -struct NullValidate { void operator()(const void* elem) { } }; +struct NullValidate { void operator()(const void*) const {} }; -/********************************************************************//** -Iterate over all the elements and call the functor for each element. +/** Iterate over all the elements and call the functor for each element. @param[in] list base node (not a pointer to it) @param[in,out] functor Functor that is called for each element in the list */ template -void -ut_list_map( - const List& list, - Functor& functor) +inline void ut_list_map(const List& list, Functor& functor) { - ulint count = 0; + ulint count = 0; UT_LIST_IS_INITIALISED(list); - for (typename List::elem_type* elem = list.start; - elem != 0; + for (typename List::elem_type* elem = list.start; elem; elem = (elem->*list.node).next, ++count) { functor(elem); @@ -452,32 +448,30 @@ ut_list_map( ut_a(count == list.count); } -template -void -ut_list_reverse(List& list) +/** Iterate over all the elements and call the functor for each element. +@param[in] list base node (not a pointer to it) +@param[in] functor Functor that is called for each element in the list */ +template +inline void ut_list_map(const List& list, const Functor& functor) { + ulint count = 0; + UT_LIST_IS_INITIALISED(list); - for (typename List::elem_type* elem = list.start; - elem != 0; - elem = (elem->*list.node).prev) { - (elem->*list.node).reverse(); + for (typename List::elem_type* elem = list.start; elem; + elem = (elem->*list.node).next, ++count) { + + functor(elem); } - list.reverse(); + ut_a(count == list.count); } -#define UT_LIST_REVERSE(LIST) ut_list_reverse(LIST) - -/********************************************************************//** -Checks the consistency of a two-way list. -@param[in] list base node (not a pointer to it) -@param[in,out] functor Functor that is called for each element in the list */ +/** Check the consistency of a doubly linked list. +@param[in] list base node (not a pointer to it) +@param[in,out] functor Functor that is called for each element in the list */ template -void -ut_list_validate( - const List& list, - Functor& functor) +void ut_list_validate(const List& list, Functor& functor) { ut_list_map(list, functor); @@ -493,12 +487,62 @@ ut_list_validate( ut_a(count == list.count); } -/** Check the consistency of a two-way list. -@param[in] LIST base node reference */ -#define UT_LIST_CHECK(LIST) do { \ - NullValidate nullV; \ - ut_list_validate(LIST, nullV); \ -} while (0) +/** Check the consistency of a doubly linked list. +@param[in] list base node (not a pointer to it) +@param[in] functor Functor that is called for each element in the list */ +template +inline void ut_list_validate(const List& list, const Functor& functor) +{ + ut_list_map(list, functor); + + /* Validate the list backwards. */ + ulint count = 0; + + for (typename List::elem_type* elem = list.end; + elem != 0; + elem = (elem->*list.node).prev) { + ++count; + } + + ut_a(count == list.count); +} + +template +inline void ut_list_validate(const List& list) +{ + ut_list_validate(list, NullValidate()); +} + +#ifdef UNIV_DEBUG +template +inline void ut_list_reverse(List& list) +{ + UT_LIST_IS_INITIALISED(list); + + for (typename List::elem_type* elem = list.start; + elem != 0; + elem = (elem->*list.node).prev) { + (elem->*list.node).reverse(); + } + + list.reverse(); +} + +/** Check if the given element exists in the list. +@param[in,out] list the list object +@param[in] elem the element of the list which will be checked */ +template +inline bool ut_list_exists(const List& list, typename List::elem_type* elem) +{ + for (typename List::elem_type* e1 = UT_LIST_GET_FIRST(list); e1; + e1 = (e1->*list.node).next) { + if (elem == e1) { + return true; + } + } + return false; +} +#endif /** Move the given element to the beginning of the list. @param[in,out] list the list object @@ -519,28 +563,6 @@ ut_list_move_to_front( } #ifdef UNIV_DEBUG -/** Check if the given element exists in the list. -@param[in,out] list the list object -@param[in] elem the element of the list which will be checked */ -template -bool -ut_list_exists( - List& list, - typename List::elem_type* elem) -{ - typename List::elem_type* e1; - - for (e1 = UT_LIST_GET_FIRST(list); e1 != NULL; - e1 = (e1->*list.node).next) { - if (elem == e1) { - return(true); - } - } - return(false); -} #endif -#define UT_LIST_MOVE_TO_FRONT(LIST, ELEM) \ - ut_list_move_to_front(LIST, ELEM) - #endif /* ut0lst.h */ diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 22ec2ee7f06..67adee94d14 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -2738,7 +2738,7 @@ lock_move_granted_locks_to_front( if (!lock->is_waiting()) { lock_t* prev = UT_LIST_GET_PREV(trx_locks, lock); ut_a(prev); - UT_LIST_MOVE_TO_FRONT(lock_list, lock); + ut_list_move_to_front(lock_list, lock); lock = prev; } } @@ -2826,7 +2826,7 @@ lock_move_reorganize_page( lock_move_granted_locks_to_front(old_locks); DBUG_EXECUTE_IF("do_lock_reverse_page_reorganize", - UT_LIST_REVERSE(old_locks);); + ut_list_reverse(old_locks);); for (lock = UT_LIST_GET_FIRST(old_locks); lock; lock = UT_LIST_GET_NEXT(trx_locks, lock)) { From 092602ac9b650f921ec5380866d17d740f0eedb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Apr 2019 15:05:25 +0300 Subject: [PATCH 12/43] MDEV-14130 InnoDB messages should not refer to the MySQL 5.7 manual In InnoDB error messages, replace the hyperlink URLs to point to the MariaDB knowledge base. --- extra/innochecksum.cc | 7 ++++--- .../suite/innodb_zip/r/innochecksum_2.result | 2 ++ storage/innobase/handler/ha_innodb.cc | 19 +++++++------------ storage/innobase/include/ha_prototypes.h | 3 +-- storage/innobase/include/univ.i | 4 ---- storage/innobase/log/log0recv.cc | 2 +- 6 files changed, 15 insertions(+), 22 deletions(-) diff --git a/extra/innochecksum.cc b/extra/innochecksum.cc index 52e909ebbeb..5c4ad084c3c 100644 --- a/extra/innochecksum.cc +++ b/extra/innochecksum.cc @@ -1,6 +1,6 @@ /* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2014, 2017, MariaDB Corporation. + Copyright (c) 2014, 2019, 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 @@ -1231,7 +1231,7 @@ static struct my_option innochecksum_options[] = { {"verbose", 'v', "Verbose (prints progress every 5 seconds).", &verbose, &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifndef DBUG_OFF - {"debug", '#', "Output debug log. See " REFMAN "dbug-package.html", + {"debug", '#', "Output debug log. See https://mariadb.com/kb/en/library/creating-a-trace-file/", &dbug_setting, &dbug_setting, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, #endif /* !DBUG_OFF */ {"count", 'c', "Print the count of pages in the file and exits.", @@ -1298,7 +1298,8 @@ static void usage(void) "[-p ] [-i] [-v] [-a ] [-n] " "[-C ] [-w ] [-S] [-D ] " "[-l ] [-l] [-m ] \n", my_progname); - printf("See " REFMAN "innochecksum.html for usage hints.\n"); + printf("See https://mariadb.com/kb/en/library/innochecksum/" + " for usage hints.\n"); my_print_help(innochecksum_options); my_print_variables(innochecksum_options); } diff --git a/mysql-test/suite/innodb_zip/r/innochecksum_2.result b/mysql-test/suite/innodb_zip/r/innochecksum_2.result index 582bb42f0cb..bfd03c72f12 100644 --- a/mysql-test/suite/innodb_zip/r/innochecksum_2.result +++ b/mysql-test/suite/innodb_zip/r/innochecksum_2.result @@ -43,10 +43,12 @@ Copyright (c) YEAR, YEAR , Oracle, MariaDB Corporation Ab and others. InnoDB offline file checksum utility. Usage: innochecksum [-c] [-s ] [-e ] [-p ] [-i] [-v] [-a ] [-n] [-C ] [-w ] [-S] [-D ] [-l ] [-l] [-m ] +See https://mariadb.com/kb/en/library/innochecksum/ for usage hints. -?, --help Displays this help and exits. -I, --info Synonym for --help. -V, --version Displays version information and exits. -v, --verbose Verbose (prints progress every 5 seconds). + https://mariadb.com/kb/en/library/creating-a-trace-file/ -c, --count Print the count of pages in the file and exits. -s, --start-page=# Start on this page number (0 based). -e, --end-page=# End at this page number (0 based). diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 953a4d89037..64559b1dae2 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -6261,9 +6261,9 @@ no_such_table: << n_cols << " user" " defined columns in InnoDB, but " << n_fields << " columns in MariaDB. Please check" - " INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and " REFMAN - "innodb-troubleshooting.html for how to resolve the" - " issue."; + " INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and" + " https://mariadb.com/kb/en/innodb-data-dictionary-troubleshooting/" + " for how to resolve the issue."; /* Mark this table as corrupted, so the drop table or force recovery can still use it, but not others. */ @@ -22101,11 +22101,11 @@ ib_errf( /* Keep the first 16 characters as-is, since the url is sometimes used as an offset from this.*/ const char* TROUBLESHOOTING_MSG = - "Please refer to " REFMAN "innodb-troubleshooting.html" + "Please refer to https://mariadb.com/kb/en/innodb-troubleshooting/" " for how to resolve the issue."; const char* TROUBLESHOOT_DATADICT_MSG = - "Please refer to " REFMAN "innodb-troubleshooting-datadict.html" + "Please refer to https://mariadb.com/kb/en/innodb-data-dictionary-troubleshooting/" " for how to resolve the issue."; const char* BUG_REPORT_MSG = @@ -22116,9 +22116,6 @@ const char* FORCE_RECOVERY_MSG = "https://mariadb.com/kb/en/library/innodb-recovery-modes/" " for information about forcing recovery."; -const char* ERROR_CREATING_MSG = - "Please refer to " REFMAN "error-creating-innodb.html"; - const char* OPERATING_SYSTEM_ERROR_MSG = "Some operating system error numbers are described at" " https://mariadb.com/kb/en/library/operating-system-error-codes/"; @@ -22511,8 +22508,7 @@ ib_push_frm_error( " Have you mixed up " ".frm files from different " "installations? See " - REFMAN - "innodb-troubleshooting.html\n", + "https://mariadb.com/kb/en/innodb-troubleshooting/\n", ib_table->name.m_name); if (push_warning) { @@ -22555,8 +22551,7 @@ ib_push_frm_error( " Have you mixed up " ".frm files from different " "installations? See " - REFMAN - "innodb-troubleshooting.html\n", + "https://mariadb.com/kb/en/innodb-troubleshooting/\n", ib_table->name.m_name, n_keys, table->s->keys); diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h index 742914e97f1..37700393da2 100644 --- a/storage/innobase/include/ha_prototypes.h +++ b/storage/innobase/include/ha_prototypes.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 2006, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, 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 @@ -442,7 +442,6 @@ extern const char* TROUBLESHOOTING_MSG; extern const char* TROUBLESHOOT_DATADICT_MSG; extern const char* BUG_REPORT_MSG; extern const char* FORCE_RECOVERY_MSG; -extern const char* ERROR_CREATING_MSG; extern const char* OPERATING_SYSTEM_ERROR_MSG; extern const char* FOREIGN_KEY_CONSTRAINTS_MSG; extern const char* SET_TRANSACTION_MSG; diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i index d21de888320..69cb096bbe2 100644 --- a/storage/innobase/include/univ.i +++ b/storage/innobase/include/univ.i @@ -57,10 +57,6 @@ component, i.e. we show M.N.P as M.N */ IB_TO_STR(INNODB_VERSION_MINOR) "." \ IB_TO_STR(INNODB_VERSION_BUGFIX) -#define REFMAN "http://dev.mysql.com/doc/refman/" \ - IB_TO_STR(INNODB_VERSION_MAJOR) "." \ - IB_TO_STR(INNODB_VERSION_MINOR) "/en/" - /** How far ahead should we tell the service manager the timeout (time in seconds) */ #define INNODB_EXTEND_TIMEOUT_INTERVAL 30 diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index e342492fcfa..251ee2435f5 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -1325,7 +1325,7 @@ recv_find_max_checkpoint(ulint* max_field) " The redo log was created" " with " << creator << ". Please follow the instructions at " - REFMAN "upgrading-downgrading.html"; + "https://mariadb.com/kb/en/library/upgrading/"; /* Do not issue a message about a possibility to cleanly shut down the newer server version and to remove the redo logs, because the From 810f014ca7a705381e110cb26649c528bc00f179 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Mon, 29 Apr 2019 16:23:21 +0300 Subject: [PATCH 13/43] MDEV-18429: Simpler implementation This reverts commit 61f370a3c9997d2c7067b8cf5d39c8ad67dde5aa and implements a simpler fix that is straightforward to merge to 10.3. lock_print_info: Renamed from PrintNotStarted. Dump the entire contents of trx_sys->mysql_trx_list. lock_print_info_rw_recovered: Like lock_print_info, but dump only recovered transactions in trx_sys->rw_trx_list. lock_print_info_all_transactions(): Dump both trx_sys->mysql_trx_list and trx_sys->rw_trx_list. TrxLockIterator, TrxListIterator, lock_rec_fetch_page(): Remove. This is a partial backport of the 10.3 commit a447980ff3ba000968d89e0c0c16239addeaf438 which removed the race-condition-prone ability of the InnoDB monitor to read relevant pages into the buffer pool for some record locks. --- storage/innobase/lock/lock0lock.cc | 358 ++++------------------------- 1 file changed, 51 insertions(+), 307 deletions(-) diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc index 67adee94d14..fa0dae753dc 100644 --- a/storage/innobase/lock/lock0lock.cc +++ b/storage/innobase/lock/lock0lock.cc @@ -4973,137 +4973,6 @@ lock_print_info_summary( return(TRUE); } -/** Prints not started transaction or puts it into set. -@param[in] trx transaction -@param[in,out] file fd where to print -@param[in,out] started put transaction here if is started */ -static void -print_not_started(const trx_t* trx, FILE* file, std::set& started) -{ - ut_ad(trx->in_mysql_trx_list); - ut_ad(mutex_own(&trx_sys->mutex)); - - /* See state transitions and locking rules in trx0trx.h */ - - if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) { - - fputs("---", file); - trx_print_latched(file, trx, 600); - } else { - started.insert(trx); - } -} - -/** Iterate over a transaction's locks. Keeping track of the -iterator using an ordinal value. */ - -class TrxLockIterator { -public: - TrxLockIterator() { rewind(); } - - /** Get the m_index(th) lock of a transaction. - @return current lock or 0 */ - const lock_t* current(const trx_t* trx) const - { - lock_t* lock; - ulint i = 0; - - for (lock = UT_LIST_GET_FIRST(trx->lock.trx_locks); - lock != NULL && i < m_index; - lock = UT_LIST_GET_NEXT(trx_locks, lock), ++i) { - - /* No op */ - } - - return(lock); - } - - /** Set the ordinal value to 0 */ - void rewind() - { - m_index = 0; - } - - /** Increment the ordinal value. - @retun the current index value */ - ulint next() - { - return(++m_index); - } - -private: - /** Current iterator position */ - ulint m_index; -}; - -/** This iterates over both the RW and RO trx_sys lists. We need to keep -track where the iterator was up to and we do that using an ordinal value. */ - -class TrxListIterator { -public: - TrxListIterator() : m_index() - { - /* We iterate over the RW trx list first. */ - - m_trx_list = &trx_sys->rw_trx_list; - } - - /** Get the current transaction whose ordinality is m_index. - @return current transaction or 0 */ - - const trx_t* current() - { - return(reposition()); - } - - /** Advance the transaction current ordinal value and reset the - transaction lock ordinal value */ - - void next() - { - ++m_index; - m_lock_iter.rewind(); - } - - TrxLockIterator& lock_iter() - { - return(m_lock_iter); - } - -private: - /** Reposition the "cursor" on the current transaction. If it - is the first time then the "cursor" will be positioned on the - first transaction. - - @return transaction instance or 0 */ - const trx_t* reposition() const - { - ulint i; - trx_t* trx; - - /* Make the transaction at the ordinal value of m_index - the current transaction. ie. reposition/restore */ - - for (i = 0, trx = UT_LIST_GET_FIRST(*m_trx_list); - trx != NULL && (i < m_index); - trx = UT_LIST_GET_NEXT(trx_list, trx), ++i) { - - check_trx_state(trx); - } - - return(trx); - } - - /** Ordinal value of the transaction in the current transaction list */ - ulint m_index; - - /** Current transaction list */ - trx_ut_list_t* m_trx_list; - - /** For iterating over a transaction's locks */ - TrxLockIterator m_lock_iter; -}; - /** Prints transaction lock wait and MVCC state. @param[in,out] file file where to print @param[in] trx transaction */ @@ -5140,118 +5009,29 @@ lock_trx_print_wait_and_mvcc_state( } /*********************************************************************//** -Prints info of locks for a transaction. This function will release the -lock mutex and the trx_sys_t::mutex if the page was read from disk. -@return true if page was read from the tablespace */ +Prints info of locks for a transaction. */ static -bool -lock_rec_fetch_page( -/*================*/ - const lock_t* lock) /*!< in: record lock */ -{ - ut_ad(lock_get_type_low(lock) == LOCK_REC); - - ulint space_id = lock->un_member.rec_lock.space; - fil_space_t* space; - bool found; - const page_size_t& page_size = fil_space_get_page_size(space_id, - &found); - ulint page_no = lock->un_member.rec_lock.page_no; - - /* Check if the .ibd file exists. */ - if (found) { - mtr_t mtr; - - lock_mutex_exit(); - - mutex_exit(&trx_sys->mutex); - - DEBUG_SYNC_C("innodb_monitor_before_lock_page_read"); - - /* Check if the space is exists or not. only - when the space is valid, try to get the page. */ - space = fil_space_acquire(space_id); - if (space) { - dberr_t err = DB_SUCCESS; - mtr_start(&mtr); - buf_page_get_gen( - page_id_t(space_id, page_no), page_size, - RW_NO_LATCH, NULL, - BUF_GET_POSSIBLY_FREED, - __FILE__, __LINE__, &mtr, &err); - mtr_commit(&mtr); - fil_space_release(space); - } - - lock_mutex_enter(); - - mutex_enter(&trx_sys->mutex); - - return(true); - } - - return(false); -} - -/*********************************************************************//** -Prints info of locks for a transaction. -@return true if all printed, false if latches were released. */ -static -bool +void lock_trx_print_locks( /*=================*/ FILE* file, /*!< in/out: File to write */ - const trx_t* trx, /*!< in: current transaction */ - TrxLockIterator&iter, /*!< in: transaction lock iterator */ - bool load_block) /*!< in: if true then read block - from disk */ + const trx_t* trx) /*!< in: current transaction */ { - const lock_t* lock; - + uint32_t i= 0; /* Iterate over the transaction's locks. */ - while ((lock = iter.current(trx)) != 0) { - + for (lock_t *lock = UT_LIST_GET_FIRST(trx->lock.trx_locks); + lock != NULL; + lock = UT_LIST_GET_NEXT(trx_locks, lock)) { if (lock_get_type_low(lock) == LOCK_REC) { - if (load_block) { - - /* Note: lock_rec_fetch_page() will - release both the lock mutex and the - trx_sys_t::mutex if it does a read - from disk. */ - - if (lock_rec_fetch_page(lock)) { - /* We need to resync the - current transaction. */ - return(false); - } - - /* It is a single table tablespace - and the .ibd file is missing: - just print the lock without - attempting to load the page in the - buffer pool. */ - - fprintf(file, - "RECORD LOCKS on non-existing" - " space %u\n", - lock->un_member.rec_lock.space); - } - - /* Print all the record locks on the page from - the record lock bitmap */ - lock_rec_print(file, lock); - - load_block = true; - } else { ut_ad(lock_get_type_low(lock) & LOCK_TABLE); lock_table_print(file, lock); } - if (iter.next() >= 10) { + if (++i == 10) { fprintf(file, "10 LOCKS PRINTED FOR THIS TRX:" @@ -5260,10 +5040,48 @@ lock_trx_print_locks( break; } } - - return(true); } +/** Functor to display all transactions (except recovered ones) */ +struct lock_print_info +{ + lock_print_info(FILE* file) : file(file) {} + + void operator()(const trx_t* trx) const + { + ut_ad(mutex_own(&trx_sys->mutex)); + ut_ad(trx->in_mysql_trx_list); + lock_trx_print_wait_and_mvcc_state(file, trx); + + if (trx->will_lock && srv_print_innodb_lock_monitor) + lock_trx_print_locks(file, trx); + } + + FILE* const file; +}; + +/** Functor to display recovered read-write transactions */ +struct lock_print_info_rw_recovered +{ + lock_print_info_rw_recovered(FILE* file) : file(file) {} + + void operator()(const trx_t* trx) const + { + ut_ad(mutex_own(&trx_sys->mutex)); + ut_ad(trx->in_rw_trx_list); + if (trx->mysql_thd) + return; + ut_ad(!trx->in_mysql_trx_list); + + lock_trx_print_wait_and_mvcc_state(file, trx); + + if (trx->will_lock && srv_print_innodb_lock_monitor) + lock_trx_print_locks(file, trx); + } + + FILE* const file; +}; + /*********************************************************************//** Prints info of locks for each transaction. This function assumes that the caller holds the lock mutex and more importantly it will release the lock @@ -5278,84 +5096,10 @@ lock_print_info_all_transactions( fprintf(file, "LIST OF TRANSACTIONS FOR EACH SESSION:\n"); mutex_enter(&trx_sys->mutex); - - /* First print info on non-active transactions */ - - /* NOTE: information of auto-commit non-locking read-only - transactions will be omitted here. The information will be - available from INFORMATION_SCHEMA.INNODB_TRX. */ - - std::set not_printed_transactions; - for (const trx_t* trx = UT_LIST_GET_FIRST(trx_sys->mysql_trx_list); - trx; trx = UT_LIST_GET_NEXT(mysql_trx_list, trx)) { - print_not_started(trx, file, not_printed_transactions); - } - - const trx_t* trx; - TrxListIterator trx_iter; - const trx_t* prev_trx = 0; - - /* Control whether a block should be fetched from the buffer pool. */ - bool load_block = true; - bool monitor = srv_print_innodb_lock_monitor; - - while ((trx = trx_iter.current()) != 0) { - - check_trx_state(trx); - - not_printed_transactions.erase(trx); - - if (trx != prev_trx) { - lock_trx_print_wait_and_mvcc_state(file, trx); - prev_trx = trx; - - /* The transaction that read in the page is no - longer the one that read the page in. We need to - force a page read. */ - load_block = true; - } - - /* If we need to print the locked record contents then we - need to fetch the containing block from the buffer pool. */ - if (monitor) { - - /* Print the locks owned by the current transaction. */ - TrxLockIterator& lock_iter = trx_iter.lock_iter(); - - if (!lock_trx_print_locks( - file, trx, lock_iter, load_block)) { - - /* Resync trx_iter, the trx_sys->mutex and - the lock mutex were released. A page was - successfully read in. We need to print its - contents on the next call to - lock_trx_print_locks(). On the next call to - lock_trx_print_locks() we should simply print - the contents of the page just read in.*/ - load_block = false; - - continue; - } - } - - load_block = true; - - /* All record lock details were printed without fetching - a page from disk, or we didn't need to print the detail. */ - trx_iter.next(); - } - - for (std::set::const_iterator it - = not_printed_transactions.begin(), - end = not_printed_transactions.end(); - it != end; ++it) { - fputs("---", file); - trx_print_latched(file, *it, 600); - } - - lock_mutex_exit(); + ut_list_map(trx_sys->mysql_trx_list, lock_print_info(file)); + ut_list_map(trx_sys->rw_trx_list, lock_print_info_rw_recovered(file)); mutex_exit(&trx_sys->mutex); - + lock_mutex_exit(); ut_ad(lock_validate()); } From 8c8bee0a5635d7f8197a148f267c04c1452b47fc Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 30 Apr 2019 15:51:49 +0400 Subject: [PATCH 14/43] MDEV-10307 CAST(11068046444225730969 AS SIGNED) does not return a warning --- mysql-test/main/cast.result | 19 +++++++++++++++++++ mysql-test/main/cast.test | 6 ++++++ mysql-test/main/default.result | 2 ++ sql/item.cc | 9 +++++++++ sql/item.h | 7 +++++++ sql/sql_type.cc | 2 +- 6 files changed, 44 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/cast.result b/mysql-test/main/cast.result index ca314573581..1dc6bbbf9e7 100644 --- a/mysql-test/main/cast.result +++ b/mysql-test/main/cast.result @@ -9,6 +9,7 @@ CAST(CAST(1-2 AS UNSIGNED) AS SIGNED INTEGER) -1 Warnings: Note 1105 Cast to unsigned converted negative integer to it's positive complement +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement select CAST('10 ' as unsigned integer); CAST('10 ' as unsigned integer) 10 @@ -29,6 +30,8 @@ Note 1105 Cast to unsigned converted negative integer to it's positive complemen select ~5, cast(~5 as signed); ~5 cast(~5 as signed) 18446744073709551610 -6 +Warnings: +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement explain extended select ~5, cast(~5 as signed); id select_type table type possible_keys key key_len ref rows filtered Extra 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used @@ -37,6 +40,8 @@ Note 1003 select ~5 AS `~5`,cast(~5 as signed) AS `cast(~5 as signed)` select cast(18446744073709551615 as signed); cast(18446744073709551615 as signed) -1 +Warnings: +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement select cast(5 as unsigned) -6.0; cast(5 as unsigned) -6.0 -1.0 @@ -212,12 +217,16 @@ CAST(0xb3 as signed) select CAST(0x8fffffffffffffff as signed); CAST(0x8fffffffffffffff as signed) -8070450532247928833 +Warnings: +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement select CAST(0xffffffffffffffff as unsigned); CAST(0xffffffffffffffff as unsigned) 18446744073709551615 select CAST(0xfffffffffffffffe as signed); CAST(0xfffffffffffffffe as signed) -2 +Warnings: +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement select cast('-10a' as signed integer); cast('-10a' as signed integer) -10 @@ -554,6 +563,8 @@ cast(18446744073709551615 as unsigned) select cast(18446744073709551615 as signed); cast(18446744073709551615 as signed) -1 +Warnings: +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement select cast('18446744073709551615' as unsigned); cast('18446744073709551615' as unsigned) 18446744073709551615 @@ -1277,3 +1288,11 @@ END; $$ ERROR 22007: Truncated incorrect CHAR(1) value: '10:20:30' SET sql_mode=DEFAULT; +# +# MDEV-10307 CAST(11068046444225730969 AS SIGNED) does not return a warning +# +SELECT CAST(11068046444225730969 AS SIGNED); +CAST(11068046444225730969 AS SIGNED) +-7378697629483820647 +Warnings: +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement diff --git a/mysql-test/main/cast.test b/mysql-test/main/cast.test index b514dbb5b2d..f48d6d9f95f 100644 --- a/mysql-test/main/cast.test +++ b/mysql-test/main/cast.test @@ -724,3 +724,9 @@ $$ DELIMITER ;$$ SET sql_mode=DEFAULT; + +--echo # +--echo # MDEV-10307 CAST(11068046444225730969 AS SIGNED) does not return a warning +--echo # + +SELECT CAST(11068046444225730969 AS SIGNED); diff --git a/mysql-test/main/default.result b/mysql-test/main/default.result index 73417d0d64e..c214e529d72 100644 --- a/mysql-test/main/default.result +++ b/mysql-test/main/default.result @@ -2217,6 +2217,8 @@ t1 CREATE TABLE `t1` ( `b` bigint(20) DEFAULT (cast(`a` as signed)) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 INSERT INTO t1 (a) VALUES (0xFFFFFFFFFFFFFFFF); +Warnings: +Note 1105 Cast to signed converted positive out-of-range integer to it's negative complement SELECT * FROM t1; a b 18446744073709551615 -1 diff --git a/sql/item.cc b/sql/item.cc index faae5c5ad03..a9139ceb0b1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -333,6 +333,15 @@ longlong Item::val_int_unsigned_typecast_from_int() } +longlong Item::val_int_signed_typecast_from_int() +{ + longlong value= val_int(); + if (!null_value && unsigned_flag && value < 0) + push_note_converted_to_negative_complement(current_thd); + return value; +} + + String *Item::val_string_from_date(String *str) { MYSQL_TIME ltime; diff --git a/sql/item.h b/sql/item.h index c11a4fe56c0..4261ef64950 100644 --- a/sql/item.h +++ b/sql/item.h @@ -1057,6 +1057,13 @@ public: longlong val_int_unsigned_typecast_from_decimal(); longlong val_int_unsigned_typecast_from_int(); longlong val_int_unsigned_typecast_from_str(); + + /** + Get a value for CAST(x AS UNSIGNED). + Huge positive unsigned values are converted to negative complements. + */ + longlong val_int_signed_typecast_from_int(); + /* This is just a shortcut to avoid the cast. You should still use unsigned_flag to check the sign of the item. diff --git a/sql/sql_type.cc b/sql/sql_type.cc index c2c853efa23..a40172967a7 100644 --- a/sql/sql_type.cc +++ b/sql/sql_type.cc @@ -3380,7 +3380,7 @@ longlong Type_handler_real_result:: longlong Type_handler_int_result:: Item_val_int_signed_typecast(Item *item) const { - return item->val_int(); + return item->val_int_signed_typecast_from_int(); } longlong Type_handler_decimal_result:: From cb9fa1a08bd1f4f609324971e58b9b300a5cb55f Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Tue, 30 Apr 2019 21:05:50 +0530 Subject: [PATCH 15/43] MDEV-9959: A serious MariaDB server performance bug If a derived table has SELECT DISTINCT, provide index statistics for it so that the join optimizer in the upper select knows that ref access to the table will produce one row. --- mysql-test/main/cte_nonrecursive.result | 8 +-- mysql-test/main/derived.result | 54 +++++++++++++++++++ mysql-test/main/derived.test | 30 +++++++++++ mysql-test/main/derived_view.result | 2 +- mysql-test/main/subselect_extra.result | 2 +- .../main/subselect_extra_no_semijoin.result | 2 +- sql/sql_class.cc | 1 + sql/sql_lex.h | 1 + sql/sql_union.cc | 40 ++++++++++++++ sql/table.cc | 20 +++++++ 10 files changed, 153 insertions(+), 7 deletions(-) diff --git a/mysql-test/main/cte_nonrecursive.result b/mysql-test/main/cte_nonrecursive.result index b846ec2d8ac..d80d34ecc7f 100644 --- a/mysql-test/main/cte_nonrecursive.result +++ b/mysql-test/main/cte_nonrecursive.result @@ -244,7 +244,7 @@ with t as (select distinct a from t1 where b >= 'c') select * from t as r1, t as r2 where r1.a=r2.a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 8 Using where -1 PRIMARY ref key0 key0 5 r1.a 2 +1 PRIMARY ref key0 key0 5 r1.a 1 3 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary 2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary explain @@ -253,7 +253,7 @@ select * from (select distinct a from t1 where b >= 'c') as r1, where r1.a=r2.a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY ALL NULL NULL NULL NULL 8 Using where -1 PRIMARY ref key0 key0 5 r1.a 2 +1 PRIMARY ref key0 key0 5 r1.a 1 3 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary 2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where; Using temporary # two references to t specified by a query @@ -369,7 +369,7 @@ select c as a from t2 where c < 4) select * from t2,t where t2.c=t.a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where -1 PRIMARY ref key0 key0 5 test.t2.c 2 +1 PRIMARY ref key0 key0 5 test.t2.c 1 2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where 3 UNION t2 ALL NULL NULL NULL NULL 4 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL @@ -381,7 +381,7 @@ select c as a from t2 where c < 4) as t where t2.c=t.a; id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where -1 PRIMARY ref key0 key0 5 test.t2.c 2 +1 PRIMARY ref key0 key0 5 test.t2.c 1 2 DERIVED t1 ALL NULL NULL NULL NULL 8 Using where 3 UNION t2 ALL NULL NULL NULL NULL 4 Using where NULL UNION RESULT ALL NULL NULL NULL NULL NULL diff --git a/mysql-test/main/derived.result b/mysql-test/main/derived.result index f0d0289c1ce..857246d68b4 100644 --- a/mysql-test/main/derived.result +++ b/mysql-test/main/derived.result @@ -1195,3 +1195,57 @@ drop table t1,t2,t3; # # End of 10.2 tests # +# +# MDEV-9959: A serious MariaDB server performance bug +# +create table t1(a int); +insert into t1 values (1),(2),(3),(4),(5),(6); +create table t2(a int, b int,c int); +insert into t2(a,b,c) values (1,1,2),(2,2,3),(3,1,4),(4,2,2),(5,1,1),(6,2,5); +create table t3(a int, b int); +insert into t3(a,b) values (1,1),(2,2),(2,1),(1,2),(5,1),(9,2); +table "" should have type=ref and rows=1 +one select in derived table +with distinct +analyze select * from t1 , ((select distinct t2.a from t2 order by c))q where t1.a=q.a; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using where +1 PRIMARY ref key0 key0 5 test.t1.a 1 1.00 100.00 100.00 +2 DERIVED t2 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using temporary; Using filesort +analyze select * from t1 , ((select distinct t2.a, t2.b from t2 order by c))q where t1.a=q.a; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using where +1 PRIMARY ref key0 key0 5 test.t1.a 2 1.00 100.00 100.00 +2 DERIVED t2 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using temporary; Using filesort +# multiple selects in derived table +# NO UNION ALL +analyze select * from t1 , ( (select t2.a from t2 order by c) union (select t2.a from t2 order by c))q where t1.a=q.a; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using where +1 PRIMARY ref key0 key0 5 test.t1.a 1 1.00 100.00 100.00 +2 DERIVED t2 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 +3 UNION t2 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 +NULL UNION RESULT ALL NULL NULL NULL NULL NULL 6.00 NULL NULL +select * from t1 , ( (select t2.a from t2 order by c) union (select t2.a from t2 order by c))q where t1.a=q.a; +a a +1 1 +2 2 +3 3 +4 4 +5 5 +6 6 +# UNION ALL and EXCEPT +analyze select * from t1 , ( (select t2.a from t2 order by c) union all (select t2.a from t2 order by c) except(select t3.a from t3 order by b))q where t1.a=q.a; +id select_type table type possible_keys key key_len ref rows r_rows filtered r_filtered Extra +1 PRIMARY t1 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 Using where +1 PRIMARY ref key0 key0 5 test.t1.a 1 0.50 100.00 100.00 +2 DERIVED t2 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 +3 UNION t2 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 +4 EXCEPT t3 ALL NULL NULL NULL NULL 6 6.00 100.00 100.00 +NULL UNIT RESULT ALL NULL NULL NULL NULL NULL 3.00 NULL NULL +select * from t1 , ( (select t2.a from t2 order by c) union all (select t2.a from t2 order by c) except(select t3.a from t3 order by b))q where t1.a=q.a; +a a +3 3 +4 4 +6 6 +drop table t1,t2,t3; diff --git a/mysql-test/main/derived.test b/mysql-test/main/derived.test index 6c51f23c51e..990f955450a 100644 --- a/mysql-test/main/derived.test +++ b/mysql-test/main/derived.test @@ -1032,3 +1032,33 @@ drop table t1,t2,t3; --echo # --echo # End of 10.2 tests --echo # + +--echo # +--echo # MDEV-9959: A serious MariaDB server performance bug +--echo # + +create table t1(a int); +insert into t1 values (1),(2),(3),(4),(5),(6); +create table t2(a int, b int,c int); +insert into t2(a,b,c) values (1,1,2),(2,2,3),(3,1,4),(4,2,2),(5,1,1),(6,2,5); +create table t3(a int, b int); +insert into t3(a,b) values (1,1),(2,2),(2,1),(1,2),(5,1),(9,2); + +--echo table "" should have type=ref and rows=1 +--echo one select in derived table + +--echo with distinct +analyze select * from t1 , ((select distinct t2.a from t2 order by c))q where t1.a=q.a; +analyze select * from t1 , ((select distinct t2.a, t2.b from t2 order by c))q where t1.a=q.a; + +--echo # multiple selects in derived table +--echo # NO UNION ALL +analyze select * from t1 , ( (select t2.a from t2 order by c) union (select t2.a from t2 order by c))q where t1.a=q.a; +select * from t1 , ( (select t2.a from t2 order by c) union (select t2.a from t2 order by c))q where t1.a=q.a; + +--echo # UNION ALL and EXCEPT +analyze select * from t1 , ( (select t2.a from t2 order by c) union all (select t2.a from t2 order by c) except(select t3.a from t3 order by b))q where t1.a=q.a; + +select * from t1 , ( (select t2.a from t2 order by c) union all (select t2.a from t2 order by c) except(select t3.a from t3 order by b))q where t1.a=q.a; + +drop table t1,t2,t3; diff --git a/mysql-test/main/derived_view.result b/mysql-test/main/derived_view.result index 86dd73f5733..30831e75341 100644 --- a/mysql-test/main/derived_view.result +++ b/mysql-test/main/derived_view.result @@ -1525,7 +1525,7 @@ EXPLAIN SELECT a FROM t1 WHERE (a,b) IN (SELECT * FROM v2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY ref key0 key0 10 test.t1.a,test.t1.b 2 FirstMatch(t1) +1 PRIMARY ref key0 key0 10 test.t1.a,test.t1.b 1 FirstMatch(t1) 3 DERIVED t2 ALL NULL NULL NULL NULL 6 4 UNION t3 ALL NULL NULL NULL NULL 4 NULL UNION RESULT ALL NULL NULL NULL NULL NULL diff --git a/mysql-test/main/subselect_extra.result b/mysql-test/main/subselect_extra.result index a3a0f1f9a15..dbcf00268c2 100644 --- a/mysql-test/main/subselect_extra.result +++ b/mysql-test/main/subselect_extra.result @@ -409,7 +409,7 @@ EXPLAIN SELECT a FROM t1 WHERE (a,b) IN (SELECT * FROM v2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where -1 PRIMARY ref key0 key0 10 test.t1.a,test.t1.b 2 FirstMatch(t1) +1 PRIMARY ref key0 key0 10 test.t1.a,test.t1.b 1 FirstMatch(t1) 3 DERIVED t2 ALL NULL NULL NULL NULL 6 4 UNION t3 ALL NULL NULL NULL NULL 4 NULL UNION RESULT ALL NULL NULL NULL NULL NULL diff --git a/mysql-test/main/subselect_extra_no_semijoin.result b/mysql-test/main/subselect_extra_no_semijoin.result index ec9ddb0452e..49a1431eb9b 100644 --- a/mysql-test/main/subselect_extra_no_semijoin.result +++ b/mysql-test/main/subselect_extra_no_semijoin.result @@ -411,7 +411,7 @@ EXPLAIN SELECT a FROM t1 WHERE (a,b) IN (SELECT * FROM v2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t1 ALL NULL NULL NULL NULL 2 Using where -2 DEPENDENT SUBQUERY index_subquery key0 key0 10 func,func 2 Using where +2 DEPENDENT SUBQUERY index_subquery key0 key0 10 func,func 1 Using where 3 DERIVED t2 ALL NULL NULL NULL NULL 6 4 UNION t3 ALL NULL NULL NULL NULL 4 NULL UNION RESULT ALL NULL NULL NULL NULL NULL diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c26aaff10d8..d247c806a7f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -847,6 +847,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock) invoker.init(); prepare_derived_at_open= FALSE; create_tmp_table_for_derived= FALSE; + force_read_stats= FALSE; save_prep_leaf_list= FALSE; org_charset= 0; /* Restore THR_THD */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 72ca4ac0b43..4eaec7d062b 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -896,6 +896,7 @@ public: bool union_needs_tmp_table(); void set_unique_exclude(); + bool check_distinct_in_union(); friend struct LEX; friend int subselect_union_engine::exec(); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 87fbbebe4ba..3fb5552c77a 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -2049,3 +2049,43 @@ void st_select_lex_unit::set_unique_exclude() } } } + +/** + @brief + Check if the derived table is guaranteed to have distinct rows because of + UNION operations used to populate it. + + @detail + UNION operation removes duplicate rows from its output. That is, a query like + + select * from t1 UNION select * from t2 + + will not produce duplicate rows in its output, even if table t1 (and/or t2) + contain duplicate rows. EXCEPT and INTERSECT operations also have this + property. + + On the other hand, UNION ALL operation doesn't remove duplicates. (The SQL + standard also defines EXCEPT ALL and INTERSECT ALL, but we don't support + them). + + st_select_lex_unit computes its value left to right. That is, if there is + a st_select_lex_unit object describing + + (select #1) OP1 (select #2) OP2 (select #3) + + then ((select #1) OP1 (select #2)) is computed first, and OP2 is computed + second. + + How can one tell if st_select_lex_unit is guaranteed to have distinct + output rows? This depends on whether the last operation was duplicate- + removing or not: + - UNION ALL is not duplicate-removing + - all other operations are duplicate-removing +*/ + +bool st_select_lex_unit::check_distinct_in_union() +{ + if (union_distinct && !union_distinct->next_select()) + return true; + return false; +} diff --git a/sql/table.cc b/sql/table.cc index b4dcbaea6dc..7042959215d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -7270,6 +7270,26 @@ bool TABLE::add_tmp_key(uint key, uint key_parts, key_part_info++; } + /* + For the case when there is a derived table that would give distinct rows, + the index statistics are passed to the join optimizer to tell that a ref + access to all the fields of the derived table will produce only one row. + */ + + st_select_lex_unit* derived= pos_in_table_list ? + pos_in_table_list->derived: NULL; + if (derived) + { + st_select_lex* first= derived->first_select(); + uint select_list_items= first->get_item_list()->elements; + if (key_parts == select_list_items) + { + if ((!first->is_part_of_union() && (first->options & SELECT_DISTINCT)) || + derived->check_distinct_in_union()) + keyinfo->rec_per_key[key_parts - 1]= 1; + } + } + set_if_bigger(s->max_key_length, keyinfo->key_length); s->keys++; return FALSE; From dabef66e66a48f2d5f4ca5fdfd1f9d927e935471 Mon Sep 17 00:00:00 2001 From: Nikita Malyavin Date: Mon, 29 Apr 2019 20:32:36 +1000 Subject: [PATCH 16/43] MDEV-19188 Server Crash When Using a Trigger With A Number of Virtual Columns on INSERT/UPDATE use s->fields instead of s->stored_fields. extra_null_bitmap is allocated in Table_triggers_list::prepare_record_accessors with respect to virtual fields, so it will not overflow Closes #1292 --- mysql-test/r/trigger.result | 30 +++++++++++++++++++++++++----- mysql-test/t/trigger.test | 33 ++++++++++++++++++++++++++++----- sql/sql_trigger.h | 2 +- 3 files changed, 54 insertions(+), 11 deletions(-) diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index 901d132cd2c..00f16accb3e 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -1962,7 +1962,7 @@ ERROR HY000: Can't update table 't2' in stored function/trigger because it is al DROP TABLE t1; DROP TRIGGER t_insert; DROP TABLE t2; -End of 5.0 tests +# End of 5.0 tests drop table if exists table_25411_a; drop table if exists table_25411_b; create table table_25411_a(a int); @@ -2131,7 +2131,7 @@ b # Work around Bug#45235 DROP DATABASE db1; USE test; -End of 5.1 tests. +# End of 5.1 tests. create table t1 (i int); create table t2 (i int); flush tables; @@ -2150,7 +2150,7 @@ select * from t2; i 2 drop table t1,t2; -End of 5.2 tests. +# End of 5.2 tests. # # Bug#34453 Can't change size of file (Errcode: 1224) # @@ -2253,7 +2253,7 @@ c aaa DROP TABLE t1; -End of 5.5 tests. +# End of 5.5 tests. # # BUG #910083: materialized subquery in a trigger # @@ -2300,7 +2300,7 @@ b SET optimizer_switch=@save_optimizer_switch; DROP TRIGGER tr; DROP TABLE t1, t2; -End of 5.3 tests. +# End of 5.3 tests. set time_zone="+00:00"; SET TIMESTAMP=UNIX_TIMESTAMP('2001-01-01 10:20:30'); SET @@session.sql_mode = 'STRICT_ALL_TABLES,STRICT_TRANS_TABLES'; @@ -2407,3 +2407,23 @@ CREATE TRIGGER tr AFTER UPDATE ON t1 FOR EACH ROW SELECT (SELECT b FROM t2) INTO @x; # Running 20000 queries DROP TABLE t1,t2; +# +# MDEV-19188 Server Crash When Using a Trigger With A Number of Virtual Columns on INSERT/UPDATE +# +CREATE TABLE t1 ( +virt1 INT GENERATED ALWAYS AS (0) VIRTUAL, +virt2 INT GENERATED ALWAYS AS (0) VIRTUAL, +virt3 INT GENERATED ALWAYS AS (0) VIRTUAL, +virt4 INT GENERATED ALWAYS AS (0) VIRTUAL, +virt5 INT GENERATED ALWAYS AS (0) VIRTUAL, +virt6 INT GENERATED ALWAYS AS (0) VIRTUAL, +virt7 INT GENERATED ALWAYS AS (0) VIRTUAL, +virt8 INT GENERATED ALWAYS AS (0) VIRTUAL +); +INSERT INTO t1 () VALUES (); +CREATE TRIGGER t1_trigger BEFORE INSERT ON t1 FOR EACH ROW BEGIN END; +INSERT INTO t1 () VALUES (); +DROP TABLE t1; +# +# End of 10.2 tests +# diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index b9e908e9944..a4beeaf9161 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -2184,7 +2184,7 @@ DROP TABLE t1; DROP TRIGGER t_insert; DROP TABLE t2; ---echo End of 5.0 tests +--echo # End of 5.0 tests # # Bug#25411 (trigger code truncated) @@ -2406,7 +2406,7 @@ let $MYSQLD_DATADIR = `select @@datadir`; DROP DATABASE db1; USE test; ---echo End of 5.1 tests. +--echo # End of 5.1 tests. # # Test that using a trigger will not open mysql.proc @@ -2430,7 +2430,7 @@ select * from t1; select * from t2; drop table t1,t2; ---echo End of 5.2 tests. +--echo # End of 5.2 tests. --echo # --echo # Bug#34453 Can't change size of file (Errcode: 1224) @@ -2574,7 +2574,7 @@ SELECT c FROM t1; DROP TABLE t1; --echo ---echo End of 5.5 tests. +--echo # End of 5.5 tests. --echo # --echo # BUG #910083: materialized subquery in a trigger @@ -2613,7 +2613,7 @@ SET optimizer_switch=@save_optimizer_switch; DROP TRIGGER tr; DROP TABLE t1, t2; ---echo End of 5.3 tests. +--echo # End of 5.3 tests. # # MDEV-4829 BEFORE INSERT triggers dont issue 1406 error @@ -2737,3 +2737,26 @@ while ($n) --enable_query_log DROP TABLE t1,t2; + +--echo # +--echo # MDEV-19188 Server Crash When Using a Trigger With A Number of Virtual Columns on INSERT/UPDATE +--echo # + +CREATE TABLE t1 ( + virt1 INT GENERATED ALWAYS AS (0) VIRTUAL, + virt2 INT GENERATED ALWAYS AS (0) VIRTUAL, + virt3 INT GENERATED ALWAYS AS (0) VIRTUAL, + virt4 INT GENERATED ALWAYS AS (0) VIRTUAL, + virt5 INT GENERATED ALWAYS AS (0) VIRTUAL, + virt6 INT GENERATED ALWAYS AS (0) VIRTUAL, + virt7 INT GENERATED ALWAYS AS (0) VIRTUAL, + virt8 INT GENERATED ALWAYS AS (0) VIRTUAL +); +INSERT INTO t1 () VALUES (); +CREATE TRIGGER t1_trigger BEFORE INSERT ON t1 FOR EACH ROW BEGIN END; +INSERT INTO t1 () VALUES (); +DROP TABLE t1; + +--echo # +--echo # End of 10.2 tests +--echo # diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index 9d1c79cc7cf..6e94f348447 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -274,7 +274,7 @@ public: Field **nullable_fields() { return record0_field; } void reset_extra_null_bitmap() { - size_t null_bytes= (trigger_table->s->stored_fields - + size_t null_bytes= (trigger_table->s->fields - trigger_table->s->null_fields + 7)/8; bzero(extra_null_bitmap, null_bytes); } From b953bf7eb2cbebf74b1f8861f4c45a789d365f28 Mon Sep 17 00:00:00 2001 From: Sergei Golubchik Date: Wed, 1 May 2019 13:14:50 +0200 Subject: [PATCH 17/43] compilation fixes for VS 2019 --- sql/sql_analyze_stmt.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sql/sql_analyze_stmt.cc b/sql/sql_analyze_stmt.cc index 8e67267f6a0..9aed432c2b6 100644 --- a/sql/sql_analyze_stmt.cc +++ b/sql/sql_analyze_stmt.cc @@ -45,7 +45,7 @@ void Filesort_tracker::print_json_members(Json_writer *writer) else if (r_limit == 0) writer->add_str(varied_str); else - writer->add_ll((longlong) rint(r_limit)); + writer->add_ll(r_limit); } writer->add_member("r_used_priority_queue"); @@ -61,13 +61,13 @@ void Filesort_tracker::print_json_members(Json_writer *writer) if (!get_r_loops()) writer->add_member("r_output_rows").add_null(); else - writer->add_member("r_output_rows").add_ll((longlong) rint(r_output_rows / - get_r_loops())); + writer->add_member("r_output_rows").add_ll( + (longlong) rint((double)r_output_rows / get_r_loops())); if (sort_passes) { - writer->add_member("r_sort_passes").add_ll((longlong) rint(sort_passes / - get_r_loops())); + writer->add_member("r_sort_passes").add_ll( + (longlong) rint((double)sort_passes / get_r_loops())); } if (sort_buffer_size != 0) From dc8e15db7e170964699dec7b5214d20200b4b182 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 2 Jan 2018 12:00:55 +1100 Subject: [PATCH 18/43] MDEV-15051: signal handler - output information about the core generation The working directory, resource limits and core pattern will aid the user finding a core file in the case of failure. While the core file size is most relevant however other resource limits may give a clue as the the cause of the fatal signal so include them also. As signal handler functions are limited, proc filesystem reads/ readlink calls are used instead of the more obvious getcwd/getrlimits functions which aren't listed as signal safe. Results in output of the form: Writing a core file: working directory at /tmp/datadir Resource Limits: Limit Soft Limit Hard Limit Units Max cpu time unlimited unlimited seconds Max file size unlimited unlimited bytes Max data size unlimited unlimited bytes Max stack size 8388608 unlimited bytes Max core file size unlimited unlimited bytes Max resident set unlimited unlimited bytes Max processes 47194 47194 processes Max open files 1024 4096 files Max locked memory 65536 65536 bytes Max address space unlimited unlimited bytes Max file locks unlimited unlimited locks Max pending signals 47194 47194 signals Max msgqueue size 819200 819200 bytes Max nice priority 0 0 Max realtime priority 0 0 Max realtime timeout unlimited unlimited us Core pattern: |/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t %P %I Segmentation fault (core dumped) Closes #537 --- sql/signal_handler.cc | 46 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/sql/signal_handler.cc b/sql/signal_handler.cc index 68e801d5885..6c0220b1254 100644 --- a/sql/signal_handler.cc +++ b/sql/signal_handler.cc @@ -30,6 +30,10 @@ #define SIGNAL_FMT "signal %d" #endif +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + /* We are handling signals/exceptions in this file. Any global variables we read should be 'volatile sig_atomic_t' @@ -44,6 +48,43 @@ extern volatile sig_atomic_t ld_assume_kernel_is_set; extern const char *optimizer_switch_names[]; +static inline void output_core_info() +{ + /* proc is optional on some BSDs so it can't hurt to look */ +#ifdef HAVE_READLINK + char buff[PATH_MAX]; + ssize_t len; + int fd; + if ((len= readlink("/proc/self/cwd", buff, sizeof(buff))) >= 0) + { + my_safe_printf_stderr("Writing a core file...\nWorking directory at %.*s\n", + (int) len, buff); + } + if ((fd= my_open("/proc/self/limits", O_RDONLY, MYF(0))) >= 0) + { + my_safe_printf_stderr("Resource Limits:\n"); + while ((len= my_read(fd, (uchar*)buff, sizeof(buff), MYF(0))) > 0) + { + my_write_stderr(buff, len); + } + my_close(fd, MYF(0)); + } +#ifdef __linux__ + if ((fd= my_open("/proc/sys/kernel/core_pattern", O_RDONLY, MYF(0))) >= 0) + { + len= my_read(fd, (uchar*)buff, sizeof(buff), MYF(0)); + my_safe_printf_stderr("Core pattern: %.*s\n", (int) len, buff); + my_close(fd, MYF(0)); + } +#endif +#else + char buff[80]; + my_getwd(buff, sizeof(buff), 0); + my_safe_printf_stderr("Writing a core file at %s\n", buff); + fflush(stderr); +#endif +} + /** * Handler for fatal signals on POSIX, exception handler on Windows. * @@ -295,13 +336,10 @@ extern "C" sig_handler handle_fatal_signal(int sig) } #endif + output_core_info(); #ifdef HAVE_WRITE_CORE if (test_flags & TEST_CORE_ON_SIGNAL) { - char buff[80]; - my_getwd(buff, sizeof(buff), 0); - my_safe_printf_stderr("Writing a core file at %s\n", buff); - fflush(stderr); my_write_core(sig); } #endif From 2370eeb028b269243633b18f7661dca999089a41 Mon Sep 17 00:00:00 2001 From: Anel Husakovic Date: Fri, 9 Nov 2018 06:12:43 -0800 Subject: [PATCH 19/43] MDEV-17654 Incorrect syntax returned for column with CHECK constraint in the "SHOW CREATE TABLE ..." result Prepend COMMENT before CHECK constraint in SHOW CREATE Closes #924 --- mysql-test/r/constraints.result | 19 +++++++++++++++++++ mysql-test/t/constraints.test | 17 +++++++++++++++++ sql/sql_show.cc | 17 ++++++++++------- 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/constraints.result b/mysql-test/r/constraints.result index 3c061989fd3..df93b69cb9e 100644 --- a/mysql-test/r/constraints.result +++ b/mysql-test/r/constraints.result @@ -111,3 +111,22 @@ long_enough_name CREATE TABLE `long_enough_name` ( CONSTRAINT `constr` CHECK (`f6` >= 0) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 DROP TABLE long_enough_name; +CREATE TABLE test.t(t int COMMENT 't_comment' CHECK(t>0)); +SHOW CREATE TABLE test.t; +Table Create Table +t CREATE TABLE `t` ( + `t` int(11) DEFAULT NULL COMMENT 't_comment' CHECK (`t` > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP table test.t; +SET @OLD_SQL_MODE=@@SQL_MODE; +SET SQL_MODE='IGNORE_BAD_TABLE_OPTIONS'; +CREATE TABLE test.t (f int foo=bar check(f>0)); +Warnings: +Warning 1911 Unknown option 'foo' +SHOW CREATE TABLE t; +Table Create Table +t CREATE TABLE `t` ( + `f` int(11) DEFAULT NULL `foo`=bar CHECK (`f` > 0) +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +DROP table test.t; +SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/mysql-test/t/constraints.test b/mysql-test/t/constraints.test index fe51e5060dc..39b2eb52a9f 100644 --- a/mysql-test/t/constraints.test +++ b/mysql-test/t/constraints.test @@ -102,3 +102,20 @@ SELECT * FROM long_enough_name AS tbl; SHOW CREATE TABLE long_enough_name; DROP TABLE long_enough_name; + +# +# MDEV-17654 Incorrect syntax returned for column with CHECK constraint +# in the "SHOW CREATE TABLE ..." result +# + +CREATE TABLE test.t(t int COMMENT 't_comment' CHECK(t>0)); +SHOW CREATE TABLE test.t; +DROP table test.t; + +SET @OLD_SQL_MODE=@@SQL_MODE; +SET SQL_MODE='IGNORE_BAD_TABLE_OPTIONS'; + +CREATE TABLE test.t (f int foo=bar check(f>0)); +SHOW CREATE TABLE t; +DROP table test.t; +SET @@SQL_MODE=@OLD_SQL_MODE; diff --git a/sql/sql_show.cc b/sql/sql_show.cc index a29a6871b78..c84ac5f4977 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2065,6 +2065,16 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, !(sql_mode & MODE_NO_FIELD_OPTIONS)) packet->append(STRING_WITH_LEN(" AUTO_INCREMENT")); } + + if (field->comment.length) + { + packet->append(STRING_WITH_LEN(" COMMENT ")); + append_unescaped(packet, field->comment.str, field->comment.length); + } + + append_create_options(thd, packet, field->option_list, check_options, + hton->field_options); + if (field->check_constraint) { StringBuffer str(&my_charset_utf8mb4_general_ci); @@ -2074,13 +2084,6 @@ int show_create_table(THD *thd, TABLE_LIST *table_list, String *packet, packet->append(STRING_WITH_LEN(")")); } - if (field->comment.length) - { - packet->append(STRING_WITH_LEN(" COMMENT ")); - append_unescaped(packet, field->comment.str, field->comment.length); - } - append_create_options(thd, packet, field->option_list, check_options, - hton->field_options); } key_info= table->key_info; From 0fd5ecb03cb3161b9dcd90d018a419bb6ac14c34 Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Thu, 2 May 2019 10:12:35 +0530 Subject: [PATCH 20/43] Adjust the result for join_cache.test --- mysql-test/main/join_cache.result | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/main/join_cache.result b/mysql-test/main/join_cache.result index fde6e0fec6b..23396d22876 100644 --- a/mysql-test/main/join_cache.result +++ b/mysql-test/main/join_cache.result @@ -5197,7 +5197,7 @@ SELECT * FROM (SELECT DISTINCT * FROM t1) t WHERE t.a IN (SELECT t2.a FROM t2); id select_type table type possible_keys key key_len ref rows Extra 1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Start temporary -1 PRIMARY ref key0 key0 5 test.t2.a 2 End temporary +1 PRIMARY ref key0 key0 5 test.t2.a 1 End temporary 2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary SELECT * FROM (SELECT DISTINCT * FROM t1) t WHERE t.a IN (SELECT t2.a FROM t2); @@ -5208,8 +5208,8 @@ EXPLAIN SELECT * FROM (SELECT DISTINCT * FROM t1) t WHERE t.a IN (SELECT t2.a FROM t2); id select_type table type possible_keys key key_len ref rows Extra -1 PRIMARY ALL NULL NULL NULL NULL 3 -1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Start temporary; End temporary; Using join buffer (flat, BNL join) +1 PRIMARY t2 ALL NULL NULL NULL NULL 4 Using where; Start temporary +1 PRIMARY ref key0 key0 5 test.t2.a 1 End temporary 2 DERIVED t1 ALL NULL NULL NULL NULL 3 Using temporary SELECT * FROM (SELECT DISTINCT * FROM t1) t WHERE t.a IN (SELECT t2.a FROM t2); From d46ffaf6afdcfc5b9241d22b176000e9e9936477 Mon Sep 17 00:00:00 2001 From: Aleksey Midenkov Date: Wed, 19 Dec 2018 16:48:07 +0300 Subject: [PATCH 21/43] MDEV-17655 Inconsistent grant-name usage between grant-statement and privilege tables Closes #1044 --- mysql-test/main/events_grant.result | 2 +- mysql-test/main/grant.result | 10 ++++----- mysql-test/main/information_schema.result | 2 +- .../suite/funcs_1/r/innodb_trig_03.result | 22 +++++++++---------- .../suite/funcs_1/r/innodb_trig_03e.result | 6 ++--- .../funcs_1/r/is_column_privileges.result | 2 +- .../funcs_1/r/is_schema_privileges.result | 4 ++-- .../is_schema_privileges_is_mysql_test.result | 2 +- .../funcs_1/r/is_table_privileges.result | 8 +++---- mysql-test/suite/funcs_1/r/is_triggers.result | 2 +- .../suite/funcs_1/r/memory_trig_03.result | 22 +++++++++---------- .../suite/funcs_1/r/memory_trig_03e.result | 6 ++--- .../suite/funcs_1/r/myisam_trig_03.result | 22 +++++++++---------- .../suite/funcs_1/r/myisam_trig_03e.result | 6 ++--- .../versioning/r/truncate_privilege.result | 10 ++++----- sql/sql_acl.cc | 4 ++-- 16 files changed, 65 insertions(+), 65 deletions(-) diff --git a/mysql-test/main/events_grant.result b/mysql-test/main/events_grant.result index 51b80742737..cc7796975a6 100644 --- a/mysql-test/main/events_grant.result +++ b/mysql-test/main/events_grant.result @@ -23,7 +23,7 @@ SHOW GRANTS; Grants for ev_test@localhost GRANT USAGE ON *.* TO 'ev_test'@'localhost' GRANT ALL PRIVILEGES ON `events_test`.* TO 'ev_test'@'localhost' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER, DELETE VERSIONING ROWS ON `events_test2`.* TO 'ev_test'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER, DELETE HISTORY ON `events_test2`.* TO 'ev_test'@'localhost' "Here comes an error:"; SHOW EVENTS; ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2' diff --git a/mysql-test/main/grant.result b/mysql-test/main/grant.result index b2f6bafd291..31ea932445d 100644 --- a/mysql-test/main/grant.result +++ b/mysql-test/main/grant.result @@ -226,7 +226,7 @@ revoke LOCK TABLES, ALTER on mysqltest.* from mysqltest_1@localhost; show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TEMPORARY TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION revoke all privileges on mysqltest.* from mysqltest_1@localhost; delete from mysql.user where user='mysqltest_1'; flush privileges; @@ -668,8 +668,8 @@ SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE = '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; TABLE_SCHEMA TABLE_NAME PRIVILEGES -mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE -mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DELETE HISTORY, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DELETE HISTORY, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE FLUSH PRIVILEGES; SHOW GRANTS FOR dummy@localhost; Grants for dummy@localhost @@ -680,8 +680,8 @@ SELECT TABLE_SCHEMA, TABLE_NAME, GROUP_CONCAT(PRIVILEGE_TYPE ORDER BY PRIVILEGE_TYPE SEPARATOR ', ') AS PRIVILEGES FROM TABLE_PRIVILEGES WHERE GRANTEE = '\'dummy\'@\'localhost\'' GROUP BY TABLE_SCHEMA, TABLE_NAME; TABLE_SCHEMA TABLE_NAME PRIVILEGES -mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE -mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DELETE VERSIONING ROWS, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummytable ALTER, CREATE, CREATE VIEW, DELETE, DELETE HISTORY, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE +mysqltest dummyview ALTER, CREATE, CREATE VIEW, DELETE, DELETE HISTORY, DROP, INDEX, INSERT, REFERENCES, SELECT, SHOW VIEW, TRIGGER, UPDATE SHOW FIELDS FROM mysql.tables_priv; Field Type Null Key Default Extra Host char(60) NO PRI diff --git a/mysql-test/main/information_schema.result b/mysql-test/main/information_schema.result index 83f987b78db..bca22b4885e 100644 --- a/mysql-test/main/information_schema.result +++ b/mysql-test/main/information_schema.result @@ -492,7 +492,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE 'mysqltest_1'@'localhost' def test ALTER ROUTINE YES 'mysqltest_1'@'localhost' def test EVENT YES 'mysqltest_1'@'localhost' def test TRIGGER YES -'mysqltest_1'@'localhost' def test DELETE VERSIONING ROWS YES +'mysqltest_1'@'localhost' def test DELETE HISTORY YES select * from information_schema.TABLE_PRIVILEGES where grantee like '%mysqltest_1%'; GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'mysqltest_1'@'localhost' def test t1 SELECT NO diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_03.result b/mysql-test/suite/funcs_1/r/innodb_trig_03.result index 7666b86bc94..be235c2d4ae 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_03.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_03.result @@ -78,7 +78,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke TRIGGER on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -168,7 +168,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke UPDATE on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, UPDATE on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -183,7 +183,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' select f1 from t1 order by f1; f1 insert 3.5.3.2-no @@ -248,7 +248,7 @@ connection no_privs_424b; show grants; Grants for test_noprivs@localhost GRANT USAGE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4b_1 before UPDATE on t1 for each row set new.f1 = 'trig 3.5.3.7-1b'; @@ -329,7 +329,7 @@ connection no_privs_424c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4c_1 before INSERT on t1 for each row set new.f1 = 'trig 3.5.3.7-1c'; @@ -441,7 +441,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke SELECT on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, SELECT on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -457,7 +457,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' create trigger trg5a_1 before INSERT on t1 for each row set @test_var = new.f1; connection default; @@ -503,7 +503,7 @@ revoke SELECT on priv_db.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.* to test_yesprivs@localhost; @@ -518,7 +518,7 @@ connection no_privs_425b; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5b_1 before UPDATE on t1 for each row set @test_var= new.f1; @@ -565,7 +565,7 @@ revoke SELECT on priv_db.t1 from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -580,7 +580,7 @@ connection no_privs_425c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5c_1 before INSERT on t1 for each row set @test_var= new.f1; diff --git a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result index 90dabe044e8..aea34df6356 100644 --- a/mysql-test/suite/funcs_1/r/innodb_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/innodb_trig_03e.result @@ -603,7 +603,7 @@ trig 1_1-yes revoke TRIGGER on *.* from test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' disconnect yes_privs; connect yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK; select current_user; @@ -656,7 +656,7 @@ root@localhost grant TRIGGER on priv_db.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' GRANT TRIGGER ON `priv_db`.* TO 'test_yesprivs'@'localhost' trigger privilege on db level for create: @@ -929,7 +929,7 @@ grant TRIGGER on priv1_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost GRANT USAGE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE VERSIONING ROWS ON `priv1_db`.* TO 'test_yesprivs'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE HISTORY ON `priv1_db`.* TO 'test_yesprivs'@'localhost' GRANT SELECT, UPDATE ON `priv2_db`.* TO 'test_yesprivs'@'localhost' GRANT TRIGGER ON `priv1_db`.`t1` TO 'test_yesprivs'@'localhost' diff --git a/mysql-test/suite/funcs_1/r/is_column_privileges.result b/mysql-test/suite/funcs_1/r/is_column_privileges.result index 033fb64f689..c835864e738 100644 --- a/mysql-test/suite/funcs_1/r/is_column_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_column_privileges.result @@ -140,7 +140,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE 'testuser3'@'localhost' def db_datadict CREATE TEMPORARY TABLES NO 'testuser3'@'localhost' def db_datadict CREATE VIEW NO 'testuser3'@'localhost' def db_datadict DELETE NO -'testuser3'@'localhost' def db_datadict DELETE VERSIONING ROWS NO +'testuser3'@'localhost' def db_datadict DELETE HISTORY NO 'testuser3'@'localhost' def db_datadict DROP NO 'testuser3'@'localhost' def db_datadict EVENT NO 'testuser3'@'localhost' def db_datadict EXECUTE NO diff --git a/mysql-test/suite/funcs_1/r/is_schema_privileges.result b/mysql-test/suite/funcs_1/r/is_schema_privileges.result index 1339639106f..3daac8b2c5f 100644 --- a/mysql-test/suite/funcs_1/r/is_schema_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_schema_privileges.result @@ -68,7 +68,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE ''@'%' def test CREATE ROUTINE ''@'%' def test EVENT ''@'%' def test TRIGGER -''@'%' def test DELETE VERSIONING ROWS +''@'%' def test DELETE HISTORY ''@'%' def test\_% SELECT ''@'%' def test\_% INSERT ''@'%' def test\_% UPDATE @@ -85,7 +85,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE ''@'%' def test\_% CREATE ROUTINE ''@'%' def test\_% EVENT ''@'%' def test\_% TRIGGER -''@'%' def test\_% DELETE VERSIONING ROWS +''@'%' def test\_% DELETE HISTORY ############################################################################### # Testcase 3.2.15.2-3.2.15.4 INFORMATION_SCHEMA.SCHEMA_PRIVILEGES accessibility ############################################################################### diff --git a/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result b/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result index 528a770e0eb..2b285395cff 100644 --- a/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result +++ b/mysql-test/suite/funcs_1/r/is_schema_privileges_is_mysql_test.result @@ -16,7 +16,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA PRIVILEGE_TYPE IS_GRANTABLE ''@'%' def test CREATE TEMPORARY TABLES NO ''@'%' def test CREATE VIEW NO ''@'%' def test DELETE NO -''@'%' def test DELETE VERSIONING ROWS NO +''@'%' def test DELETE HISTORY NO ''@'%' def test DROP NO ''@'%' def test EVENT NO ''@'%' def test INDEX NO diff --git a/mysql-test/suite/funcs_1/r/is_table_privileges.result b/mysql-test/suite/funcs_1/r/is_table_privileges.result index c448241e14e..1d54ef75297 100644 --- a/mysql-test/suite/funcs_1/r/is_table_privileges.result +++ b/mysql-test/suite/funcs_1/r/is_table_privileges.result @@ -96,7 +96,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser2'@'localhost' def db_datadict tb1 CREATE YES 'testuser2'@'localhost' def db_datadict tb1 CREATE VIEW YES 'testuser2'@'localhost' def db_datadict tb1 DELETE YES -'testuser2'@'localhost' def db_datadict tb1 DELETE VERSIONING ROWS YES +'testuser2'@'localhost' def db_datadict tb1 DELETE HISTORY YES 'testuser2'@'localhost' def db_datadict tb1 DROP YES 'testuser2'@'localhost' def db_datadict tb1 INDEX YES 'testuser2'@'localhost' def db_datadict tb1 INSERT YES @@ -132,7 +132,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser2'@'localhost' def db_datadict tb1 CREATE YES 'testuser2'@'localhost' def db_datadict tb1 CREATE VIEW YES 'testuser2'@'localhost' def db_datadict tb1 DELETE YES -'testuser2'@'localhost' def db_datadict tb1 DELETE VERSIONING ROWS YES +'testuser2'@'localhost' def db_datadict tb1 DELETE HISTORY YES 'testuser2'@'localhost' def db_datadict tb1 DROP YES 'testuser2'@'localhost' def db_datadict tb1 INDEX YES 'testuser2'@'localhost' def db_datadict tb1 INSERT YES @@ -186,7 +186,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser1'@'localhost' def test t1_table CREATE NO 'testuser1'@'localhost' def test t1_table CREATE VIEW NO 'testuser1'@'localhost' def test t1_table DELETE NO -'testuser1'@'localhost' def test t1_table DELETE VERSIONING ROWS NO +'testuser1'@'localhost' def test t1_table DELETE HISTORY NO 'testuser1'@'localhost' def test t1_table DROP NO 'testuser1'@'localhost' def test t1_table INDEX NO 'testuser1'@'localhost' def test t1_table INSERT NO @@ -199,7 +199,7 @@ GRANTEE TABLE_CATALOG TABLE_SCHEMA TABLE_NAME PRIVILEGE_TYPE IS_GRANTABLE 'testuser1'@'localhost' def test t1_view CREATE NO 'testuser1'@'localhost' def test t1_view CREATE VIEW NO 'testuser1'@'localhost' def test t1_view DELETE NO -'testuser1'@'localhost' def test t1_view DELETE VERSIONING ROWS NO +'testuser1'@'localhost' def test t1_view DELETE HISTORY NO 'testuser1'@'localhost' def test t1_view DROP NO 'testuser1'@'localhost' def test t1_view INDEX NO 'testuser1'@'localhost' def test t1_view INSERT NO diff --git a/mysql-test/suite/funcs_1/r/is_triggers.result b/mysql-test/suite/funcs_1/r/is_triggers.result index 1ea7263eb8f..e9b6b31451a 100644 --- a/mysql-test/suite/funcs_1/r/is_triggers.result +++ b/mysql-test/suite/funcs_1/r/is_triggers.result @@ -145,7 +145,7 @@ connect testuser2, localhost, testuser2, , db_datadict; SHOW GRANTS FOR 'testuser2'@'localhost'; Grants for testuser2@localhost GRANT USAGE ON *.* TO 'testuser2'@'localhost' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, DELETE VERSIONING ROWS ON `db_datadict`.`t1` TO 'testuser2'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, DELETE HISTORY ON `db_datadict`.`t1` TO 'testuser2'@'localhost' # No TRIGGER Privilege --> no result for query SELECT * FROM information_schema.triggers WHERE trigger_name = 'trg1'; diff --git a/mysql-test/suite/funcs_1/r/memory_trig_03.result b/mysql-test/suite/funcs_1/r/memory_trig_03.result index b86315a1a7d..acab98b0cdc 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_03.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_03.result @@ -78,7 +78,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke TRIGGER on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -168,7 +168,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke UPDATE on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, UPDATE on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -183,7 +183,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' select f1 from t1 order by f1; f1 insert 3.5.3.2-no @@ -248,7 +248,7 @@ connection no_privs_424b; show grants; Grants for test_noprivs@localhost GRANT USAGE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4b_1 before UPDATE on t1 for each row set new.f1 = 'trig 3.5.3.7-1b'; @@ -329,7 +329,7 @@ connection no_privs_424c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4c_1 before INSERT on t1 for each row set new.f1 = 'trig 3.5.3.7-1c'; @@ -441,7 +441,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke SELECT on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, SELECT on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -457,7 +457,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' create trigger trg5a_1 before INSERT on t1 for each row set @test_var = new.f1; connection default; @@ -503,7 +503,7 @@ revoke SELECT on priv_db.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.* to test_yesprivs@localhost; @@ -518,7 +518,7 @@ connection no_privs_425b; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5b_1 before UPDATE on t1 for each row set @test_var= new.f1; @@ -565,7 +565,7 @@ revoke SELECT on priv_db.t1 from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -580,7 +580,7 @@ connection no_privs_425c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5c_1 before INSERT on t1 for each row set @test_var= new.f1; diff --git a/mysql-test/suite/funcs_1/r/memory_trig_03e.result b/mysql-test/suite/funcs_1/r/memory_trig_03e.result index ea0aaf0c86f..b1c017d368b 100644 --- a/mysql-test/suite/funcs_1/r/memory_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/memory_trig_03e.result @@ -604,7 +604,7 @@ trig 1_1-yes revoke TRIGGER on *.* from test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' disconnect yes_privs; connect yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK; select current_user; @@ -657,7 +657,7 @@ root@localhost grant TRIGGER on priv_db.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' GRANT TRIGGER ON `priv_db`.* TO 'test_yesprivs'@'localhost' trigger privilege on db level for create: @@ -930,7 +930,7 @@ grant TRIGGER on priv1_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost GRANT USAGE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE VERSIONING ROWS ON `priv1_db`.* TO 'test_yesprivs'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE HISTORY ON `priv1_db`.* TO 'test_yesprivs'@'localhost' GRANT SELECT, UPDATE ON `priv2_db`.* TO 'test_yesprivs'@'localhost' GRANT TRIGGER ON `priv1_db`.`t1` TO 'test_yesprivs'@'localhost' diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_03.result b/mysql-test/suite/funcs_1/r/myisam_trig_03.result index b86315a1a7d..acab98b0cdc 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_03.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_03.result @@ -78,7 +78,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke TRIGGER on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -168,7 +168,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke UPDATE on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, UPDATE on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -183,7 +183,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' select f1 from t1 order by f1; f1 insert 3.5.3.2-no @@ -248,7 +248,7 @@ connection no_privs_424b; show grants; Grants for test_noprivs@localhost GRANT USAGE ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4b_1 before UPDATE on t1 for each row set new.f1 = 'trig 3.5.3.7-1b'; @@ -329,7 +329,7 @@ connection no_privs_424c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT SELECT, INSERT, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg4c_1 before INSERT on t1 for each row set new.f1 = 'trig 3.5.3.7-1c'; @@ -441,7 +441,7 @@ grant ALL on *.* to test_noprivs@localhost; revoke SELECT on *.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER, SELECT on *.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; @@ -457,7 +457,7 @@ test_noprivs@localhost use priv_db; show grants; Grants for test_noprivs@localhost -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' create trigger trg5a_1 before INSERT on t1 for each row set @test_var = new.f1; connection default; @@ -503,7 +503,7 @@ revoke SELECT on priv_db.* from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.* to test_yesprivs@localhost; @@ -518,7 +518,7 @@ connection no_privs_425b; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.* TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, TRIGGER, DELETE HISTORY ON `priv_db`.* TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5b_1 before UPDATE on t1 for each row set @test_var= new.f1; @@ -565,7 +565,7 @@ revoke SELECT on priv_db.t1 from test_noprivs@localhost; show grants for test_noprivs@localhost; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' revoke ALL PRIVILEGES, GRANT OPTION FROM test_yesprivs@localhost; grant TRIGGER on *.* to test_yesprivs@localhost; grant SELECT on priv_db.t1 to test_yesprivs@localhost; @@ -580,7 +580,7 @@ connection no_privs_425c; show grants; Grants for test_noprivs@localhost GRANT TRIGGER ON *.* TO 'test_noprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE VERSIONING ROWS ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' +GRANT INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE VIEW, SHOW VIEW, TRIGGER, DELETE HISTORY ON `priv_db`.`t1` TO 'test_noprivs'@'localhost' use priv_db; create trigger trg5c_1 before INSERT on t1 for each row set @test_var= new.f1; diff --git a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result index 60e6031f0e2..8a42a54b1be 100644 --- a/mysql-test/suite/funcs_1/r/myisam_trig_03e.result +++ b/mysql-test/suite/funcs_1/r/myisam_trig_03e.result @@ -604,7 +604,7 @@ trig 1_1-yes revoke TRIGGER on *.* from test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' disconnect yes_privs; connect yes_privs,localhost,test_yesprivs,PWD,test,$MASTER_MYPORT,$MASTER_MYSOCK; select current_user; @@ -657,7 +657,7 @@ root@localhost grant TRIGGER on priv_db.* to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE VERSIONING ROWS ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, SHUTDOWN, PROCESS, FILE, REFERENCES, INDEX, ALTER, SHOW DATABASES, SUPER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, CREATE TABLESPACE, DELETE HISTORY ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' GRANT TRIGGER ON `priv_db`.* TO 'test_yesprivs'@'localhost' trigger privilege on db level for create: @@ -930,7 +930,7 @@ grant TRIGGER on priv1_db.t1 to test_yesprivs@localhost; show grants for test_yesprivs@localhost; Grants for test_yesprivs@localhost GRANT USAGE ON *.* TO 'test_yesprivs'@'localhost' IDENTIFIED BY PASSWORD '*C49735D016A099C0CF104EF9183F374A54CA2576' -GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE VERSIONING ROWS ON `priv1_db`.* TO 'test_yesprivs'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, EVENT, DELETE HISTORY ON `priv1_db`.* TO 'test_yesprivs'@'localhost' GRANT SELECT, UPDATE ON `priv2_db`.* TO 'test_yesprivs'@'localhost' GRANT TRIGGER ON `priv1_db`.`t1` TO 'test_yesprivs'@'localhost' diff --git a/mysql-test/suite/versioning/r/truncate_privilege.result b/mysql-test/suite/versioning/r/truncate_privilege.result index e378407afde..3242c4557c5 100644 --- a/mysql-test/suite/versioning/r/truncate_privilege.result +++ b/mysql-test/suite/versioning/r/truncate_privilege.result @@ -11,7 +11,7 @@ show grants; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' delete history from mysqltest.t before system_time now(); -ERROR 42000: DELETE VERSIONING ROWS command denied to user 'mysqltest_1'@'localhost' for table 't' +ERROR 42000: DELETE HISTORY command denied to user 'mysqltest_1'@'localhost' for table 't' connection root; grant delete history on mysqltest.* to mysqltest_1@localhost; grant delete history on mysqltest.t to mysqltest_1@localhost; @@ -19,15 +19,15 @@ connection user1; show grants; Grants for mysqltest_1@localhost GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost' -GRANT DELETE VERSIONING ROWS ON `mysqltest`.* TO 'mysqltest_1'@'localhost' -GRANT DELETE VERSIONING ROWS ON `mysqltest`.`t` TO 'mysqltest_1'@'localhost' +GRANT DELETE HISTORY ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +GRANT DELETE HISTORY ON `mysqltest`.`t` TO 'mysqltest_1'@'localhost' delete history from mysqltest.t before system_time now(); connection root; grant all on *.* to mysqltest_1@localhost; show grants for mysqltest_1@localhost; Grants for mysqltest_1@localhost GRANT ALL PRIVILEGES ON *.* TO 'mysqltest_1'@'localhost' -GRANT DELETE VERSIONING ROWS ON `mysqltest`.* TO 'mysqltest_1'@'localhost' -GRANT DELETE VERSIONING ROWS ON `mysqltest`.`t` TO 'mysqltest_1'@'localhost' +GRANT DELETE HISTORY ON `mysqltest`.* TO 'mysqltest_1'@'localhost' +GRANT DELETE HISTORY ON `mysqltest`.`t` TO 'mysqltest_1'@'localhost' drop user mysqltest_1@localhost; drop database mysqltest; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 4ffb2c8b8f1..ed200bba763 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8437,13 +8437,13 @@ static const char *command_array[]= "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT", "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE", "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE", - "DELETE VERSIONING ROWS" + "DELETE HISTORY" }; static uint command_lengths[]= { 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9, - 14, 13, 11, 5, 7, 17, 22, + 14, 13, 11, 5, 7, 17, 14, }; From ada1074bb10359342ee00e220fe9c172574265fb Mon Sep 17 00:00:00 2001 From: Thirunarayanan Balathandayuthapani Date: Wed, 1 May 2019 17:24:58 +0530 Subject: [PATCH 22/43] MDEV-14398 innodb_encryption_rotate_key_age=0 causes innodb_encrypt_tables to be ignored MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The statement SET GLOBAL innodb_encryption_rotate_key_age=0; would have the unwanted side effect that ENCRYPTION=DEFAULT tablespaces would no longer be encrypted or decrypted according to the setting of innodb_encrypt_tables. We implement a trigger, so that whenever one of the following is executed: SET GLOBAL innodb_encrypt_tables=OFF; SET GLOBAL innodb_encrypt_tables=ON; SET GLOBAL innodb_encrypt_tables=FORCE; all wrong-state ENCRYPTION=DEFAULT tablespaces will be added to fil_system_t::rotation_list, so that the encryption will be added or removed. Note: This will *NOT* happen automatically after a server restart. Before reading the first page of a data file, InnoDB cannot know the encryption status of the data file. The statement SET GLOBAL innodb_encrypt_tables will have the side effect that all not-yet-read InnoDB data files will be accessed in order to determine the encryption status. innodb_encrypt_tables_validate(): Stop disallowing SET GLOBAL innodb_encrypt_tables when innodb_encryption_rotate_key_age=0. This reverts part of commit 50eb40a2a8aa3af6cc271f6028f4d6d74301d030 that addressed MDEV-11738 and MDEV-11581. fil_system_t::read_page0(): Trigger a call to fil_node_t::read_page0(). Refactored from fil_space_get_space(). fil_crypt_rotation_list_fill(): If innodb_encryption_rotate_key_age=0, initialize fil_system->rotation_list. This is invoked both on SET GLOBAL innodb_encrypt_tables and on SET GLOBAL innodb_encryption_rotate_key_age=0. fil_space_set_crypt_data(): Remove. fil_parse_write_crypt_data(): Simplify the logic. This is joint work with Marko Mäkelä. --- .../r/innodb-key-rotation-disable.result | 4 - .../r/innodb_encrypt_key_rotation_age.result | 75 ++++++++ .../t/innodb-key-rotation-disable.test | 5 - .../t/innodb_encrypt_key_rotation_age.opt | 2 + .../t/innodb_encrypt_key_rotation_age.test | 82 +++++++++ storage/innobase/fil/fil0crypt.cc | 164 +++++++++++------- storage/innobase/fil/fil0fil.cc | 84 ++++----- storage/innobase/handler/ha_innodb.cc | 10 -- storage/innobase/include/fil0fil.h | 6 + 9 files changed, 314 insertions(+), 118 deletions(-) create mode 100644 mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age.result create mode 100644 mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.opt create mode 100644 mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test diff --git a/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result b/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result index 680db692c17..a662f5e6343 100644 --- a/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result +++ b/mysql-test/suite/encryption/r/innodb-key-rotation-disable.result @@ -37,10 +37,6 @@ NAME ENCRYPTION_SCHEME CURRENT_KEY_ID enctests/t7 0 1 enctests/t8 0 1 enctests/t9 0 1 -SET GLOBAL innodb_encrypt_tables=OFF; -ERROR 42000: Variable 'innodb_encrypt_tables' can't be set to the value of 'OFF' -SET GLOBAL innodb_encrypt_tables=ON; -ERROR 42000: Variable 'innodb_encrypt_tables' can't be set to the value of 'ON' # t1 default on expecting NOT FOUND NOT FOUND /secred/ in t1.ibd # t2 default on expecting NOT FOUND diff --git a/mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age.result b/mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age.result new file mode 100644 index 00000000000..137ce01e14c --- /dev/null +++ b/mysql-test/suite/encryption/r/innodb_encrypt_key_rotation_age.result @@ -0,0 +1,75 @@ +CREATE TABLE t1 (f1 INT, f2 VARCHAR(256))engine=innodb; +INSERT INTO t1 VALUES(1, 'MariaDB'), (2, 'Robot'), (3, 'Science'); +INSERT INTO t1 SELECT * FROM t1; +CREATE TABLE t2(f1 INT, f2 VARCHAR(256))engine=innodb; +INSERT INTO t2 SELECT * FROM t1; +CREATE TABLE t3(f1 INT, f2 VARCHAR(256))engine=innodb encrypted=yes; +INSERT INTO t3 SELECT * FROM t1; +# Restart the server with encryption +# Wait until encryption threads have encrypted all tablespaces +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +NAME +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +NAME +innodb_system +mysql/innodb_index_stats +mysql/innodb_table_stats +test/t1 +test/t2 +test/t3 +# Restart the server with innodb_encryption_rotate_key_age= 0 +create table t4 (f1 int not null)engine=innodb encrypted=NO; +# Wait until encryption threads have encrypted all tablespaces +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +NAME +test/t4 +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +NAME +innodb_system +mysql/innodb_index_stats +mysql/innodb_table_stats +test/t1 +test/t2 +test/t3 +# Disable encryption when innodb_encryption_rotate_key_age is 0 +set global innodb_encrypt_tables = OFF; +# Wait until encryption threads to decrypt all unencrypted tablespaces +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +NAME +innodb_system +mysql/innodb_index_stats +mysql/innodb_table_stats +test/t1 +test/t2 +test/t4 +# Display only encrypted create tables (t3) +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +NAME +test/t3 +# Enable encryption when innodb_encryption_rotate_key_age is 0 +set global innodb_encrypt_tables = ON; +# Wait until encryption threads to encrypt all unencrypted tablespaces +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +NAME +test/t4 +# Display only unencrypted create tables (t4) +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +NAME +innodb_system +mysql/innodb_index_stats +mysql/innodb_table_stats +test/t1 +test/t2 +test/t3 +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +NAME +test/t4 +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +NAME +innodb_system +mysql/innodb_index_stats +mysql/innodb_table_stats +test/t1 +test/t2 +test/t3 +DROP TABLE t4, t3, t2, t1; diff --git a/mysql-test/suite/encryption/t/innodb-key-rotation-disable.test b/mysql-test/suite/encryption/t/innodb-key-rotation-disable.test index 574e0c3becc..2e5d877f7c0 100644 --- a/mysql-test/suite/encryption/t/innodb-key-rotation-disable.test +++ b/mysql-test/suite/encryption/t/innodb-key-rotation-disable.test @@ -43,11 +43,6 @@ SELECT NAME,ENCRYPTION_SCHEME,CURRENT_KEY_ID FROM INFORMATION_SCHEMA.INNODB_TABL --echo # should list tables t7-t9 SELECT NAME,ENCRYPTION_SCHEME,CURRENT_KEY_ID FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 and NAME LIKE 'enctests%'; ---error ER_WRONG_VALUE_FOR_VAR -SET GLOBAL innodb_encrypt_tables=OFF; ---error ER_WRONG_VALUE_FOR_VAR -SET GLOBAL innodb_encrypt_tables=ON; - --let $MYSQLD_DATADIR=`select @@datadir` -- source include/shutdown_mysqld.inc diff --git a/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.opt b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.opt new file mode 100644 index 00000000000..6fa06402377 --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.opt @@ -0,0 +1,2 @@ +--innodb-tablespaces-encryption +--innodb_encrypt_tables=ON diff --git a/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test new file mode 100644 index 00000000000..c3fafb0751b --- /dev/null +++ b/mysql-test/suite/encryption/t/innodb_encrypt_key_rotation_age.test @@ -0,0 +1,82 @@ +-- source include/have_innodb.inc +-- source include/not_embedded.inc +-- source include/have_example_key_management_plugin.inc + +CREATE TABLE t1 (f1 INT, f2 VARCHAR(256))engine=innodb; +INSERT INTO t1 VALUES(1, 'MariaDB'), (2, 'Robot'), (3, 'Science'); +INSERT INTO t1 SELECT * FROM t1; + +CREATE TABLE t2(f1 INT, f2 VARCHAR(256))engine=innodb; +INSERT INTO t2 SELECT * FROM t1; + +CREATE TABLE t3(f1 INT, f2 VARCHAR(256))engine=innodb encrypted=yes; +INSERT INTO t3 SELECT * FROM t1; + +--echo # Restart the server with encryption + +let $restart_parameters= --innodb_encryption_threads=5 --innodb_encryption_rotate_key_age=16384; +--source include/restart_mysqld.inc + +--echo # Wait until encryption threads have encrypted all tablespaces + +--let $tables_count= `select count(*) + 1 from information_schema.tables where engine = 'InnoDB'` +--let $wait_timeout= 600 +--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--source include/wait_condition.inc + +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + +--echo # Restart the server with innodb_encryption_rotate_key_age= 0 + +let $restart_parameters= --innodb_encryption_threads=1 --innodb_encryption_rotate_key_age=0; + +--source include/restart_mysqld.inc + +create table t4 (f1 int not null)engine=innodb encrypted=NO; + +--echo # Wait until encryption threads have encrypted all tablespaces + +--let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $wait_timeout= 600 +--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--source include/wait_condition.inc + +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; + +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + +--echo # Disable encryption when innodb_encryption_rotate_key_age is 0 +set global innodb_encrypt_tables = OFF; + +--echo # Wait until encryption threads to decrypt all unencrypted tablespaces + +--let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $wait_timeout= 600 +--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0 AND ROTATING_OR_FLUSHING = 0; +--source include/wait_condition.inc + +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--echo # Display only encrypted create tables (t3) +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + +--echo # Enable encryption when innodb_encryption_rotate_key_age is 0 +set global innodb_encrypt_tables = ON; + +--echo # Wait until encryption threads to encrypt all unencrypted tablespaces + +--let $tables_count= `select count(*) from information_schema.tables where engine = 'InnoDB'` +--let $wait_timeout= 600 +--let $wait_condition=SELECT COUNT(*) >= $tables_count FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +--source include/wait_condition.inc + +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +--echo # Display only unencrypted create tables (t4) +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; + +--let $restart_parameters= +-- source include/restart_mysqld.inc + +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION = 0; +SELECT NAME FROM INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION WHERE MIN_KEY_VERSION <> 0; +DROP TABLE t4, t3, t2, t1; diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc index 32fd844ec17..5a53355a279 100644 --- a/storage/innobase/fil/fil0crypt.cc +++ b/storage/innobase/fil/fil0crypt.cc @@ -1,6 +1,6 @@ /***************************************************************************** Copyright (C) 2013, 2015, Google Inc. All Rights Reserved. -Copyright (c) 2014, 2018, MariaDB Corporation. All Rights Reserved. +Copyright (c) 2014, 2019, 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 @@ -418,45 +418,6 @@ fil_space_crypt_t::write_page0( } } -/****************************************************************** -Set crypt data for a tablespace -@param[in,out] space Tablespace -@param[in,out] crypt_data Crypt data to be set -@return crypt_data in tablespace */ -static -fil_space_crypt_t* -fil_space_set_crypt_data( - fil_space_t* space, - fil_space_crypt_t* crypt_data) -{ - fil_space_crypt_t* free_crypt_data = NULL; - fil_space_crypt_t* ret_crypt_data = NULL; - - /* Provided space is protected using fil_space_acquire() - from concurrent operations. */ - if (space->crypt_data != NULL) { - /* There is already crypt data present, - merge new crypt_data */ - fil_space_merge_crypt_data(space->crypt_data, - crypt_data); - ret_crypt_data = space->crypt_data; - free_crypt_data = crypt_data; - } else { - space->crypt_data = crypt_data; - ret_crypt_data = space->crypt_data; - } - - if (free_crypt_data != NULL) { - /* there was already crypt data present and the new crypt - * data provided as argument to this function has been merged - * into that => free new crypt data - */ - fil_space_destroy_crypt_data(&free_crypt_data); - } - - return ret_crypt_data; -} - /****************************************************************** Parse a MLOG_FILE_WRITE_CRYPT_DATA log entry @param[in] ptr Log entry start @@ -515,26 +476,36 @@ fil_parse_write_crypt_data( return NULL; } - fil_space_crypt_t* crypt_data = fil_space_create_crypt_data(encryption, key_id); - /* Need to overwrite these as above will initialize fields. */ + mutex_enter(&fil_system->mutex); + + fil_space_t* space = fil_space_get_by_id(space_id); + + if (!space) { + mutex_exit(&fil_system->mutex); + return ptr + len; + } + + fil_space_crypt_t* crypt_data = fil_space_create_crypt_data( + encryption, key_id); + crypt_data->page0_offset = offset; crypt_data->min_key_version = min_key_version; - crypt_data->encryption = encryption; crypt_data->type = type; memcpy(crypt_data->iv, ptr, len); ptr += len; - /* update fil_space memory cache with crypt_data */ - if (fil_space_t* space = fil_space_acquire_silent(space_id)) { - crypt_data = fil_space_set_crypt_data(space, crypt_data); - fil_space_release(space); - /* Check is used key found from encryption plugin */ - if (crypt_data->should_encrypt() - && !crypt_data->is_key_found()) { - *err = DB_DECRYPTION_FAILED; - } - } else { + if (space->crypt_data) { + fil_space_merge_crypt_data(space->crypt_data, crypt_data); fil_space_destroy_crypt_data(&crypt_data); + crypt_data = space->crypt_data; + } else { + space->crypt_data = crypt_data; + } + + mutex_exit(&fil_system->mutex); + + if (crypt_data->should_encrypt() && !crypt_data->is_key_found()) { + *err = DB_DECRYPTION_FAILED; } return ptr; @@ -919,11 +890,15 @@ fil_crypt_needs_rotation( if (crypt_data->encryption == FIL_ENCRYPTION_DEFAULT && crypt_data->type == CRYPT_SCHEME_1 - && srv_encrypt_tables == 0 ) { + && !srv_encrypt_tables) { /* This is rotation encrypted => unencrypted */ return true; } + if (rotate_key_age == 0) { + return false; + } + /* this is rotation encrypted => encrypted, * only reencrypt if key is sufficiently old */ if (key_version + rotate_key_age < latest_key_version) { @@ -1006,7 +981,8 @@ fil_crypt_start_encrypting_space( * crypt data in page 0 */ /* 1 - create crypt data */ - crypt_data = fil_space_create_crypt_data(FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); + crypt_data = fil_space_create_crypt_data( + FIL_ENCRYPTION_DEFAULT, FIL_DEFAULT_ENCRYPTION_KEY); if (crypt_data == NULL) { mutex_exit(&fil_crypt_threads_mutex); @@ -1019,9 +995,9 @@ fil_crypt_start_encrypting_space( crypt_data->rotate_state.starting = true; crypt_data->rotate_state.active_threads = 1; - mutex_enter(&crypt_data->mutex); - crypt_data = fil_space_set_crypt_data(space, crypt_data); - mutex_exit(&crypt_data->mutex); + mutex_enter(&fil_system->mutex); + space->crypt_data = crypt_data; + mutex_exit(&fil_system->mutex); fil_crypt_start_converting = true; mutex_exit(&fil_crypt_threads_mutex); @@ -2292,6 +2268,64 @@ fil_crypt_set_thread_cnt( } } +/** Initialize the tablespace rotation_list +if innodb_encryption_rotate_key_age=0. */ +static void fil_crypt_rotation_list_fill() +{ + ut_ad(mutex_own(&fil_system->mutex)); + + for (fil_space_t* space = UT_LIST_GET_FIRST(fil_system->space_list); + space != NULL; + space = UT_LIST_GET_NEXT(space_list, space)) { + if (space->purpose != FIL_TYPE_TABLESPACE + || space->is_in_rotation_list() + || space->is_stopping() + || UT_LIST_GET_LEN(space->chain) == 0) { + continue; + } + + /* Ensure that crypt_data has been initialized. */ + if (!space->size) { + /* Protect the tablespace while we may + release fil_system->mutex. */ + space->n_pending_ops++; + fil_space_t* s= fil_system->read_page0( + space->id); + ut_ad(!s || s == space); + space->n_pending_ops--; + if (!space->size) { + /* Page 0 was not loaded. + Skip this tablespace. */ + continue; + } + } + + /* Skip ENCRYPTION!=DEFAULT tablespaces. */ + if (space->crypt_data + && !space->crypt_data->is_default_encryption()) { + continue; + } + + if (srv_encrypt_tables) { + /* Skip encrypted tablespaces if + innodb_encrypt_tables!=OFF */ + if (space->crypt_data + && space->crypt_data->min_key_version) { + continue; + } + } else { + /* Skip unencrypted tablespaces if + innodb_encrypt_tables=OFF */ + if (!space->crypt_data + || !space->crypt_data->min_key_version) { + continue; + } + } + + UT_LIST_ADD_LAST(fil_system->rotation_list, space); + } +} + /********************************************************************* Adjust max key age @param[in] val New max key age */ @@ -2300,7 +2334,12 @@ void fil_crypt_set_rotate_key_age( uint val) { + mutex_enter(&fil_system->mutex); srv_fil_crypt_rotate_key_age = val; + if (val == 0) { + fil_crypt_rotation_list_fill(); + } + mutex_exit(&fil_system->mutex); os_event_set(fil_crypt_threads_event); } @@ -2324,7 +2363,16 @@ void fil_crypt_set_encrypt_tables( uint val) { + mutex_enter(&fil_system->mutex); + srv_encrypt_tables = val; + + if (srv_fil_crypt_rotate_key_age == 0) { + fil_crypt_rotation_list_fill(); + } + + mutex_exit(&fil_system->mutex); + os_event_set(fil_crypt_threads_event); } diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc index 2de94fe3e40..102d7e178b5 100644 --- a/storage/innobase/fil/fil0fil.cc +++ b/storage/innobase/fil/fil0fil.cc @@ -1525,6 +1525,47 @@ fil_assign_new_space_id( return(success); } +/** Trigger a call to fil_node_t::read_page0() +@param[in] id tablespace identifier +@return tablespace +@retval NULL if the tablespace does not exist or cannot be read */ +fil_space_t* fil_system_t::read_page0(ulint id) +{ + mutex_exit(&mutex); + + ut_ad(id != 0); + + /* It is possible that the tablespace is dropped while we are + not holding the mutex. */ + fil_mutex_enter_and_prepare_for_io(id); + + fil_space_t* space = fil_space_get_by_id(id); + + if (space == NULL || UT_LIST_GET_LEN(space->chain) == 0) { + return(NULL); + } + + /* The following code must change when InnoDB supports + multiple datafiles per tablespace. */ + ut_a(1 == UT_LIST_GET_LEN(space->chain)); + + fil_node_t* node = UT_LIST_GET_FIRST(space->chain); + + /* It must be a single-table tablespace and we have not opened + the file yet; the following calls will open it and update the + size fields */ + + if (!fil_node_prepare_for_io(node, fil_system, space)) { + /* The single-table tablespace can't be opened, + because the ibd file is missing. */ + return(NULL); + } + + fil_node_complete_io(node, IORequestRead); + + return space; +} + /*******************************************************************//** Returns a pointer to the fil_space_t that is in the memory cache associated with a space id. The caller must lock fil_system->mutex. @@ -1535,12 +1576,7 @@ fil_space_get_space( /*================*/ ulint id) /*!< in: space id */ { - fil_space_t* space; - fil_node_t* node; - - ut_ad(fil_system); - - space = fil_space_get_by_id(id); + fil_space_t* space = fil_space_get_by_id(id); if (space == NULL || space->size != 0) { return(space); } @@ -1551,41 +1587,7 @@ fil_space_get_space( case FIL_TYPE_TEMPORARY: case FIL_TYPE_TABLESPACE: case FIL_TYPE_IMPORT: - ut_a(id != 0); - - mutex_exit(&fil_system->mutex); - - /* It is possible that the space gets evicted at this point - before the fil_mutex_enter_and_prepare_for_io() acquires - the fil_system->mutex. Check for this after completing the - call to fil_mutex_enter_and_prepare_for_io(). */ - fil_mutex_enter_and_prepare_for_io(id); - - /* We are still holding the fil_system->mutex. Check if - the space is still in memory cache. */ - space = fil_space_get_by_id(id); - - if (space == NULL || UT_LIST_GET_LEN(space->chain) == 0) { - return(NULL); - } - - /* The following code must change when InnoDB supports - multiple datafiles per tablespace. */ - ut_a(1 == UT_LIST_GET_LEN(space->chain)); - - node = UT_LIST_GET_FIRST(space->chain); - - /* It must be a single-table tablespace and we have not opened - the file yet; the following calls will open it and update the - size fields */ - - if (!fil_node_prepare_for_io(node, fil_system, space)) { - /* The single-table tablespace can't be opened, - because the ibd file is missing. */ - return(NULL); - } - - fil_node_complete_io(node, IORequestRead); + space = fil_system->read_page0(id); } return(space); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 64559b1dae2..ecf85a81638 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -22404,16 +22404,6 @@ innodb_encrypt_tables_validate( return 1; } - if (!srv_fil_crypt_rotate_key_age) { - const char *msg = (encrypt_tables ? "enable" : "disable"); - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - HA_ERR_UNSUPPORTED, - "InnoDB: cannot %s encryption, " - "innodb_encryption_rotate_key_age=0" - " i.e. key rotation disabled", msg); - return 1; - } - return 0; } diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h index 1a37dde4452..0ef5e7a3364 100644 --- a/storage/innobase/include/fil0fil.h +++ b/storage/innobase/include/fil0fil.h @@ -532,6 +532,12 @@ struct fil_system_t { /* !< TRUE if fil_space_create() has issued a warning about potential space_id reuse */ + + /** Trigger a call to fil_node_t::read_page0() + @param[in] id tablespace identifier + @return tablespace + @retval NULL if the tablespace does not exist or cannot be read */ + fil_space_t* read_page0(ulint id); }; /** The tablespace memory cache. This variable is NULL before the module is From 4b0f010b884cb298a33ed438c2b3688c472dbbf7 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 2 May 2019 14:25:24 +0100 Subject: [PATCH 23/43] MDEV-18544 "missing required privilege PROCESS on *.*" using mariabackup for SST If required privilege is missing, dump the output from "SHOW GRANTS" into mariabackup log. This will help troubleshooting, and make the bug reproducible. --- extra/mariabackup/xtrabackup.cc | 7 +++++++ mysql-test/suite/mariabackup/backup_grants.result | 1 + mysql-test/suite/mariabackup/backup_grants.test | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/extra/mariabackup/xtrabackup.cc b/extra/mariabackup/xtrabackup.cc index eae55ddb02e..538d00f0fdb 100644 --- a/extra/mariabackup/xtrabackup.cc +++ b/extra/mariabackup/xtrabackup.cc @@ -5820,6 +5820,13 @@ check_all_privileges() if (check_result & PRIVILEGE_ERROR) { mysql_close(mysql_connection); + msg("Current privileges, as reported by 'SHOW GRANTS': "); + int n=1; + for (std::list::const_iterator it = granted_privileges.begin(); + it != granted_privileges.end(); + it++,n++) { + msg(" %d.%s", n, it->c_str()); + } die("Insufficient privileges"); } } diff --git a/mysql-test/suite/mariabackup/backup_grants.result b/mysql-test/suite/mariabackup/backup_grants.result index d8869b7ac82..ed793e7ff1a 100644 --- a/mysql-test/suite/mariabackup/backup_grants.result +++ b/mysql-test/suite/mariabackup/backup_grants.result @@ -1,5 +1,6 @@ CREATE user backup@localhost; FOUND 1 /missing required privilege RELOAD/ in backup.log FOUND 1 /missing required privilege PROCESS/ in backup.log +FOUND 1 /GRANT USAGE ON/ in backup.log GRANT RELOAD, PROCESS on *.* to backup@localhost; DROP USER backup@localhost; diff --git a/mysql-test/suite/mariabackup/backup_grants.test b/mysql-test/suite/mariabackup/backup_grants.test index 1c0c3f89346..eadeedd9b5f 100644 --- a/mysql-test/suite/mariabackup/backup_grants.test +++ b/mysql-test/suite/mariabackup/backup_grants.test @@ -18,7 +18,8 @@ let SEARCH_FILE=$MYSQLTEST_VARDIR/tmp/backup.log; --source include/search_pattern_in_file.inc --let SEARCH_PATTERN= missing required privilege PROCESS --source include/search_pattern_in_file.inc - +--let SEARCH_PATTERN= GRANT USAGE ON +--source include/search_pattern_in_file.inc # backup succeeds with RELOAD privilege GRANT RELOAD, PROCESS on *.* to backup@localhost; --disable_result_log From 0d6fb43e6d6ca1eb9060d7369efcbabcda324f1e Mon Sep 17 00:00:00 2001 From: Monty Date: Thu, 2 May 2019 16:49:47 +0300 Subject: [PATCH 24/43] Fixed some compilation warnings/errors --- sql/item_sum.cc | 2 +- sql/mysqld.cc | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/sql/item_sum.cc b/sql/item_sum.cc index eb6d71cf99b..4e449198fe0 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2046,7 +2046,7 @@ double Item_sum_std::val_real() { DBUG_ASSERT(fixed == 1); double nr= Item_sum_variance::val_real(); - if (isnan(nr)) + if (std::isnan(nr)) { /* variance_fp_recurrence_next() can overflow in some cases and return "nan": diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 212ab8e2a13..f0ffa7eae8c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -3043,9 +3043,8 @@ static bool cache_thread(THD *thd) Create new instrumentation for the new THD job, and attach it to this running pthread. */ - PSI_thread *psi= PSI_CALL_new_thread(key_thread_one_connection, - thd, thd->thread_id); - PSI_CALL_set_thread(psi); + PSI_CALL_set_thread(PSI_CALL_new_thread(key_thread_one_connection, + thd, thd->thread_id)); /* reset abort flag for the thread */ thd->mysys_var->abort= 0; From 13d7c721a54ea777898cd0db9dce8ebc516a8af8 Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Thu, 2 May 2019 19:44:36 +0100 Subject: [PATCH 25/43] MDEV-17008 prepare with datadir, on Windows, does not set ACL on tablespace files Fix is to always add Full Control for NetworkService account, for every file that copyback/moveback copies around. --- extra/mariabackup/backup_copy.cc | 68 +++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/extra/mariabackup/backup_copy.cc b/extra/mariabackup/backup_copy.cc index fa665a798ac..ee7f55e304c 100644 --- a/extra/mariabackup/backup_copy.cc +++ b/extra/mariabackup/backup_copy.cc @@ -989,6 +989,65 @@ run_data_threads(datadir_iter_t *it, os_thread_func_t func, uint n) return(ret); } +#ifdef _WIN32 +#include +#include +#include +/* + On Windows, fix permission of the file after "copyback" + We assume that after copyback, mysqld will run as service as NetworkService + user, thus well give full permission on given file to that user. +*/ + +static int fix_win_file_permissions(const char *file) +{ + struct { + TOKEN_USER tokenUser; + BYTE buffer[SECURITY_MAX_SID_SIZE]; + } tokenInfoBuffer; + HANDLE hFile = CreateFile(file, READ_CONTROL | WRITE_DAC, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hFile == INVALID_HANDLE_VALUE) + return -1; + ACL* pOldDACL; + SECURITY_DESCRIPTOR* pSD = NULL; + EXPLICIT_ACCESS ea = { 0 }; + BOOL isWellKnownSID = FALSE; + PSID pSid = NULL; + + GetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, + &pOldDACL, NULL, (void**)&pSD); + DWORD size = SECURITY_MAX_SID_SIZE; + pSid = (PSID)tokenInfoBuffer.buffer; + if (!CreateWellKnownSid(WinNetworkServiceSid, NULL, pSid, + &size)) + { + return 1; + } + ea.Trustee.TrusteeForm = TRUSTEE_IS_SID; + ea.Trustee.ptstrName = (LPTSTR)pSid; + + ea.grfAccessMode = GRANT_ACCESS; + ea.grfAccessPermissions = GENERIC_ALL; + ea.grfInheritance = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE; + ea.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN; + ACL* pNewDACL = 0; + DWORD err = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL); + if (pNewDACL) + { + SetSecurityInfo(hFile, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, + pNewDACL, NULL); + } + if (pSD != NULL) + LocalFree((HLOCAL)pSD); + if (pNewDACL != NULL) + LocalFree((HLOCAL)pNewDACL); + CloseHandle(hFile); + return 0; +} + +#endif + /************************************************************************ Copy file for backup/restore. @@ -1037,6 +1096,10 @@ copy_file(ds_ctxt_t *datasink, /* close */ msg(thread_n," ...done"); datafile_close(&cursor); +#ifdef _WIN32 + if (xtrabackup_copy_back || xtrabackup_move_back) + ut_a(!fix_win_file_permissions(dstfile->path)); +#endif if (ds_close(dstfile)) { goto error_close; } @@ -1107,7 +1170,10 @@ move_file(ds_ctxt_t *datasink, errbuf); return(false); } - +#ifdef _WIN32 + if (xtrabackup_copy_back || xtrabackup_move_back) + ut_a(!fix_win_file_permissions(dst_file_path_abs)); +#endif msg(thread_n," ...done"); return(true); From 879878e43d5ffd2bf4d18ffe4d0186f8926e58ca Mon Sep 17 00:00:00 2001 From: Varun Gupta Date: Thu, 2 May 2019 14:38:43 +0530 Subject: [PATCH 26/43] MDEV-18943: Group Concat with limit not working with views Adjusted the Item_func_group_concat::print function to take into account limit if present with GROUP_CONCAT --- mysql-test/main/func_gconcat.result | 14 ++++++++++++++ mysql-test/main/func_gconcat.test | 12 ++++++++++++ sql/item_sum.cc | 14 +++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/func_gconcat.result b/mysql-test/main/func_gconcat.result index 723a1952d79..1701bb364e8 100644 --- a/mysql-test/main/func_gconcat.result +++ b/mysql-test/main/func_gconcat.result @@ -1378,5 +1378,19 @@ group_concat(a,b limit ?) 1a,1b,2x,2y drop table t2; # +# MDEV-18943: Group Concat with limit not working with views +# +create table t1 (a int, b varchar(10)); +insert into t1 values(1,'a'),(1,'b'),(NULL,'c'),(2,'x'),(2,'y'); +select group_concat(a,b limit 2) from t1; +group_concat(a,b limit 2) +1a,1b +create view v1 as select group_concat(a,b limit 2) from t1; +select * from v1; +group_concat(a,b limit 2) +1a,1b +drop view v1; +drop table t1; +# # End of 10.3 tests # diff --git a/mysql-test/main/func_gconcat.test b/mysql-test/main/func_gconcat.test index 5cbc6969e02..b8ab96bdea4 100644 --- a/mysql-test/main/func_gconcat.test +++ b/mysql-test/main/func_gconcat.test @@ -985,6 +985,18 @@ prepare STMT from 'select group_concat(a,b limit ?) from t2'; execute STMT using @x; drop table t2; +--echo # +--echo # MDEV-18943: Group Concat with limit not working with views +--echo # + +create table t1 (a int, b varchar(10)); +insert into t1 values(1,'a'),(1,'b'),(NULL,'c'),(2,'x'),(2,'y'); +select group_concat(a,b limit 2) from t1; +create view v1 as select group_concat(a,b limit 2) from t1; +select * from v1; +drop view v1; +drop table t1; + --echo # --echo # End of 10.3 tests --echo # diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 4e449198fe0..ce0c9d3e944 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -4172,7 +4172,19 @@ void Item_func_group_concat::print(String *str, enum_query_type query_type) } str->append(STRING_WITH_LEN(" separator \'")); str->append_for_single_quote(separator->ptr(), separator->length()); - str->append(STRING_WITH_LEN("\')")); + str->append(STRING_WITH_LEN("\'")); + + if (limit_clause) + { + str->append(STRING_WITH_LEN(" limit ")); + if (offset_limit) + { + offset_limit->print(str, query_type); + str->append(','); + } + row_limit->print(str, query_type); + } + str->append(STRING_WITH_LEN(")")); } From 0e91e0c377f38c31cd5ad766b9a6faceacb7ce18 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 13 Mar 2019 14:41:52 +0400 Subject: [PATCH 27/43] A proper State_tracker::m_changed enacpsulation Note: preserved original behaviour, where remaining trackers are not reset on error from store(). This effectively means subsequent statements will start tracking from unclean state. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 91 ++++++------------------------------------ sql/session_tracker.h | 5 ++- 2 files changed, 15 insertions(+), 81 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index b59475645fa..c049e1bab33 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -209,7 +209,6 @@ public: return result; } - void reset(); bool enable(THD *thd); bool check_str(THD *thd, LEX_STRING *val); bool update(THD *thd, set_var *var); @@ -241,7 +240,6 @@ class Current_schema_tracker : public State_tracker { private: bool schema_track_inited; - void reset(); public: @@ -272,17 +270,11 @@ public: class Session_state_change_tracker : public State_tracker { -private: - - void reset(); - public: - Session_state_change_tracker(); bool enable(THD *thd) { return update(thd, NULL); }; bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); - bool is_state_changed(THD*); }; @@ -829,7 +821,7 @@ bool Session_sysvars_tracker::store(THD *thd, String *buf) if (orig_list->store(thd, buf)) return true; - reset(); + orig_list->reset(); return false; } @@ -892,17 +884,6 @@ void Session_sysvars_tracker::vars_list::reset() my_hash_iterate(&m_registered_sysvars, &reset_variable, NULL); } -/** - Prepare/reset the m_registered_sysvars hash for next statement. -*/ - -void Session_sysvars_tracker::reset() -{ - - orig_list->reset(); - m_changed= false; -} - static Session_sysvars_tracker* sysvar_tracker(THD *thd) { return (Session_sysvars_tracker*) @@ -991,24 +972,10 @@ bool Current_schema_tracker::store(THD *thd, String *buf) /* Length and current schema name */ buf->q_net_store_data((const uchar *)thd->db.str, thd->db.length); - reset(); - return false; } -/** - Reset the m_changed flag for next statement. - - @return void -*/ - -void Current_schema_tracker::reset() -{ - m_changed= false; -} - - /////////////////////////////////////////////////////////////////////////////// @@ -1331,24 +1298,13 @@ bool Transaction_state_tracker::store(THD *thd, String *buf) } } - reset(); + tx_reported_state= tx_curr_state; + tx_changed= TX_CHG_NONE; return false; } -/** - Reset the m_changed flag for next statement. -*/ - -void Transaction_state_tracker::reset() -{ - m_changed= false; - tx_reported_state= tx_curr_state; - tx_changed= TX_CHG_NONE; -} - - /** Helper function: turn table info into table access flag. Accepts table lock type and engine type flag (transactional/ @@ -1518,11 +1474,6 @@ void Transaction_state_tracker::set_isol_level(THD *thd, /////////////////////////////////////////////////////////////////////////////// -Session_state_change_tracker::Session_state_change_tracker() -{ - m_changed= false; -} - /** @Enable/disable the tracker based on @@session_track_state_change value. @@ -1560,34 +1511,12 @@ bool Session_state_change_tracker::store(THD *thd, String *buf) /* Length of the overall entity (1 byte) */ buf->q_append('\1'); - DBUG_ASSERT(is_state_changed(thd)); + DBUG_ASSERT(is_changed()); buf->q_append('1'); - reset(); - return false; } - -/** - Reset the m_changed flag for next statement. -*/ - -void Session_state_change_tracker::reset() -{ - m_changed= false; -} - - -/** - Find if there is a session state change. -*/ - -bool Session_state_change_tracker::is_state_changed(THD *) -{ - return m_changed; -} - /////////////////////////////////////////////////////////////////////////////// /** @@ -1682,11 +1611,15 @@ void Session_tracker::store(THD *thd, String *buf) /* Get total length. */ for (int i= 0; i < SESSION_TRACKER_END; i++) { - if (m_trackers[i]->is_changed() && - m_trackers[i]->store(thd, buf)) + if (m_trackers[i]->is_changed()) { - buf->length(start); // it is safer to have 0-length block in case of error - return; + if (m_trackers[i]->store(thd, buf)) + { + // it is safer to have 0-length block in case of error + buf->length(start); + return; + } + m_trackers[i]->reset_changed(); } } diff --git a/sql/session_tracker.h b/sql/session_tracker.h index 684692aae0c..2452183acd4 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -67,6 +67,7 @@ protected: */ bool m_enabled; +private: /** Has the session state type changed ? */ bool m_changed; @@ -86,6 +87,8 @@ public: bool is_changed() const { return m_changed; } + void reset_changed() { m_changed= false; } + /** Called in the constructor of THD*/ virtual bool enable(THD *thd)= 0; @@ -276,8 +279,6 @@ private: /** isolation level */ enum enum_tx_isol_level tx_isol_level; - void reset(); - inline void update_change_flags(THD *thd) { tx_changed &= uint(~TX_CHG_STATE); From 8f594b3384f5c68f530730a037a7e74fa215b67d Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Mon, 18 Mar 2019 14:43:14 +0400 Subject: [PATCH 28/43] Session_sysvars_tracker::vars_list cleanups - return proper type - removed useless node argument - removed useless mem_flag - classes are "private" by default - simplified iterators Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 142 +++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 92 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index c049e1bab33..04a8b783837 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -70,7 +70,6 @@ private: class vars_list { - private: /** Registered system variables. (@@session_track_system_variables) A hash to store the name of all the system variables specified by the @@ -101,12 +100,20 @@ private: } } - uchar* search(const sys_var *svar) + sysvar_node_st *search(const sys_var *svar) { - return (my_hash_search(&m_registered_sysvars, (const uchar *)&svar, - sizeof(sys_var *))); + return reinterpret_cast( + my_hash_search(&m_registered_sysvars, + reinterpret_cast(&svar), + sizeof(sys_var*))); } + sysvar_node_st *at(ulong i) + { + DBUG_ASSERT(i < m_registered_sysvars.records); + return reinterpret_cast( + my_hash_element(&m_registered_sysvars, i)); + } public: vars_list() : buffer_length(0) @@ -129,22 +136,21 @@ private: } } - uchar* insert_or_search(sysvar_node_st *node, const sys_var *svar) + sysvar_node_st *insert_or_search(const sys_var *svar) { - uchar *res; - res= search(svar); + sysvar_node_st *res= search(svar); if (!res) { if (track_all) { - insert(node, svar, m_mem_flag); + insert(svar); return search(svar); } } return res; } - bool insert(sysvar_node_st *node, const sys_var *svar, myf mem_flag); + bool insert(const sys_var *svar); void reinit(); void reset(); inline bool is_enabled() @@ -218,11 +224,6 @@ public: static uchar *sysvars_get_key(const char *entry, size_t *length, my_bool not_used __attribute__((unused))); - // hash iterators - static my_bool name_array_filler(void *ptr, void *data_ptr); - static my_bool store_variable(void *ptr, void *data_ptr); - static my_bool reset_variable(void *ptr, void *data_ptr); - static bool check_var_list(THD *thd, LEX_STRING var_list, bool throw_error, CHARSET_INFO *char_set, bool take_mutex); }; @@ -313,25 +314,20 @@ void Session_sysvars_tracker::vars_list::copy(vars_list* from, THD *thd) /** Inserts the variable to be tracked into m_registered_sysvars hash. - @param node Node to be inserted. @param svar address of the system variable @retval false success @retval true error */ -bool Session_sysvars_tracker::vars_list::insert(sysvar_node_st *node, - const sys_var *svar, - myf mem_flag) +bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) { - if (!node) + sysvar_node_st *node; + if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st), + MYF(MY_WME | m_mem_flag)))) { - if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st), - MYF(MY_WME | mem_flag)))) - { - reinit(); - return true; - } + reinit(); + return true; } node->m_svar= (sys_var *)svar; @@ -433,7 +429,7 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, else if ((svar= find_sys_var_ex(thd, var.str, var.length, throw_error, true))) { - if (insert(NULL, svar, m_mem_flag) == TRUE) + if (insert(svar) == TRUE) goto error; } else if (throw_error && thd) @@ -536,24 +532,6 @@ bool Session_sysvars_tracker::check_var_list(THD *thd, return false; } -struct name_array_filler_data -{ - LEX_CSTRING **names; - uint idx; - -}; - -/** Collects variable references into array */ -my_bool Session_sysvars_tracker::name_array_filler(void *ptr, - void *data_ptr) -{ - Session_sysvars_tracker::sysvar_node_st *node= - (Session_sysvars_tracker::sysvar_node_st *)ptr; - name_array_filler_data *data= (struct name_array_filler_data *)data_ptr; - if (*node->test_load) - data->names[data->idx++]= &node->m_svar->name; - return FALSE; -} /* Sorts variable references array */ static int name_array_sorter(const void *a, const void *b) @@ -573,7 +551,8 @@ static int name_array_sorter(const void *a, const void *b) bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, size_t buf_len) { - struct name_array_filler_data data; + LEX_CSTRING **names; + uint idx; size_t left= buf_len; size_t names_size= m_registered_sysvars.records * sizeof(LEX_CSTRING *); const char separator= ','; @@ -596,16 +575,19 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, return false; } - data.names= (LEX_CSTRING**)my_safe_alloca(names_size); - - if (unlikely(!data.names)) + if (unlikely(!(names= (LEX_CSTRING**) my_safe_alloca(names_size)))) return true; - data.idx= 0; + idx= 0; mysql_mutex_lock(&LOCK_plugin); - my_hash_iterate(&m_registered_sysvars, &name_array_filler, &data); - DBUG_ASSERT(data.idx <= m_registered_sysvars.records); + for (ulong i= 0; i < m_registered_sysvars.records; i++) + { + sysvar_node_st *node= at(i); + if (*node->test_load) + names[idx++]= &node->m_svar->name; + } + DBUG_ASSERT(idx <= m_registered_sysvars.records); /* We check number of records again here because number of variables @@ -618,17 +600,16 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, return false; } - my_qsort(data.names, data.idx, sizeof(LEX_CSTRING *), - &name_array_sorter); + my_qsort(names, idx, sizeof(LEX_CSTRING*), &name_array_sorter); - for(uint i= 0; i < data.idx; i++) + for(uint i= 0; i < idx; i++) { - LEX_CSTRING *nm= data.names[i]; + LEX_CSTRING *nm= names[i]; size_t ln= nm->length + 1; if (ln > left) { mysql_mutex_unlock(&LOCK_plugin); - my_safe_afree(data.names, names_size); + my_safe_afree(names, names_size); return true; } memcpy(buf, nm->str, nm->length); @@ -639,7 +620,7 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, mysql_mutex_unlock(&LOCK_plugin); buf--; buf[0]= '\0'; - my_safe_afree(data.names, names_size); + my_safe_afree(names, names_size); return false; } @@ -724,24 +705,15 @@ bool Session_sysvars_tracker::update(THD *thd, set_var *var) } -/* - Function and structure to support storing variables from hash to the buffer. -*/ - -struct st_store_variable_param +bool Session_sysvars_tracker::vars_list::store(THD *thd, String *buf) { - THD *thd; - String *buf; -}; - -my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr) -{ - Session_sysvars_tracker::sysvar_node_st *node= - (Session_sysvars_tracker::sysvar_node_st *)ptr; - if (node->m_changed) + for (ulong i= 0; i < m_registered_sysvars.records; i++) { - THD *thd= ((st_store_variable_param *)data_ptr)->thd; - String *buf= ((st_store_variable_param *)data_ptr)->buf; + sysvar_node_st *node= at(i); + + if (!node->m_changed) + continue; + char val_buf[SHOW_VAR_FUNC_BUFF_SIZE]; SHOW_VAR show; CHARSET_INFO *charset; @@ -750,7 +722,7 @@ my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr) if (!*node->test_load) { mysql_mutex_unlock(&LOCK_plugin); - return false; + continue; } sys_var *svar= node->m_svar; bool is_plugin= svar->cast_pluginvar(); @@ -795,11 +767,6 @@ my_bool Session_sysvars_tracker::store_variable(void *ptr, void *data_ptr) return false; } -bool Session_sysvars_tracker::vars_list::store(THD *thd, String *buf) -{ - st_store_variable_param data= {thd, buf}; - return my_hash_iterate(&m_registered_sysvars, &store_variable, &data); -} /** Store the data for changed system variables in the specified buffer. @@ -836,14 +803,13 @@ bool Session_sysvars_tracker::store(THD *thd, String *buf) void Session_sysvars_tracker::mark_as_changed(THD *thd, LEX_CSTRING *var) { - sysvar_node_st *node= NULL; + sysvar_node_st *node; sys_var *svar= (sys_var *)var; /* Check if the specified system variable is being tracked, if so mark it as changed and also set the class's m_changed flag. */ - if (orig_list->is_enabled() && - (node= (sysvar_node_st *) (orig_list->insert_or_search(node, svar)))) + if (orig_list->is_enabled() && (node= orig_list->insert_or_search(svar))) { node->m_changed= true; State_tracker::mark_as_changed(thd, var); @@ -870,18 +836,10 @@ uchar *Session_sysvars_tracker::sysvars_get_key(const char *entry, } -/* Function to support resetting hash nodes for the variables */ - -my_bool Session_sysvars_tracker::reset_variable(void *ptr, - void *data_ptr) -{ - ((Session_sysvars_tracker::sysvar_node_st *)ptr)->m_changed= false; - return false; -} - void Session_sysvars_tracker::vars_list::reset() { - my_hash_iterate(&m_registered_sysvars, &reset_variable, NULL); + for (ulong i= 0; i < m_registered_sysvars.records; i++) + at(i)->m_changed= false; } static Session_sysvars_tracker* sysvar_tracker(THD *thd) From 19d5ddccfde04c6b336bb4974407ecde4fb6fbc6 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 13 Mar 2019 14:16:49 +0400 Subject: [PATCH 29/43] Cleanup session tracker redundancy - m_enabled is initialised by the base class constructor - removed unused schema_track_inited - moved Transaction_state_tracker constructor to declaration - common enable() - removed unused Session_sysvars_tracker::check_str() - classes are "private" by default - don't even try to compile for embedded Part of MDEV-14984 - regression in connect performance --- libmysqld/CMakeLists.txt | 1 - sql/session_tracker.cc | 51 ---------------------------------------- sql/session_tracker.h | 13 +++++----- 3 files changed, 7 insertions(+), 58 deletions(-) diff --git a/libmysqld/CMakeLists.txt b/libmysqld/CMakeLists.txt index 537f40cbbbf..98d5860d45e 100644 --- a/libmysqld/CMakeLists.txt +++ b/libmysqld/CMakeLists.txt @@ -117,7 +117,6 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc ../sql/sql_sequence.cc ../sql/sql_sequence.h ../sql/ha_sequence.cc ../sql/ha_sequence.h ../sql/temporary_tables.cc - ../sql/session_tracker.cc ../sql/proxy_protocol.cc ../sql/sql_tvc.cc ../sql/sql_tvc.h ../sql/opt_split.cc diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 04a8b783837..14fc43e09e7 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -15,7 +15,6 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef EMBEDDED_LIBRARY #include "sql_plugin.h" #include "session_tracker.h" @@ -60,8 +59,6 @@ public: class Session_sysvars_tracker : public State_tracker { -private: - struct sysvar_node_st { sys_var *m_svar; bool *test_load; @@ -216,7 +213,6 @@ public: } bool enable(THD *thd); - bool check_str(THD *thd, LEX_STRING *val); bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name); @@ -239,18 +235,7 @@ public: class Current_schema_tracker : public State_tracker { -private: - bool schema_track_inited; - public: - - Current_schema_tracker() - { - schema_track_inited= false; - } - - bool enable(THD *thd) - { return update(thd, NULL); } bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); }; @@ -272,8 +257,6 @@ public: class Session_state_change_tracker : public State_tracker { public: - bool enable(THD *thd) - { return update(thd, NULL); }; bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); }; @@ -654,27 +637,6 @@ bool Session_sysvars_tracker::enable(THD *thd) } -/** - Check system variable name(s). - - @note This function is called from the ON_CHECK() function of the - session_track_system_variables' sys_var class. - - @param thd [IN] The thd handle. - @param var [IN] A pointer to set_var holding the specified list of - system variable names. - - @retval true Error - @retval false Success -*/ - -inline bool Session_sysvars_tracker::check_str(THD *thd, LEX_STRING *val) -{ - return Session_sysvars_tracker::check_var_list(thd, *val, true, - thd->charset(), true); -} - - /** Once the value of the @@session_track_system_variables has been successfully updated, this function calls @@ -936,17 +898,6 @@ bool Current_schema_tracker::store(THD *thd, String *buf) /////////////////////////////////////////////////////////////////////////////// - -Transaction_state_tracker::Transaction_state_tracker() -{ - m_enabled = false; - tx_changed = TX_CHG_NONE; - tx_curr_state = - tx_reported_state= TX_EMPTY; - tx_read_flags = TX_READ_INHERIT; - tx_isol_level = TX_ISOL_INHERIT; -} - /** Enable/disable the tracker based on @@session_track_transaction_info. @@ -1597,5 +1548,3 @@ void Session_tracker::store(THD *thd, String *buf) net_store_length(data - 1, length); } - -#endif //EMBEDDED_LIBRARY diff --git a/sql/session_tracker.h b/sql/session_tracker.h index 2452183acd4..1d0f55c252a 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -90,7 +90,7 @@ public: void reset_changed() { m_changed= false; } /** Called in the constructor of THD*/ - virtual bool enable(THD *thd)= 0; + virtual bool enable(THD *thd) { return update(thd, 0); } /** To be invoked when the tracker's system variable is updated (ON_UPDATE).*/ virtual bool update(THD *thd, set_var *var)= 0; @@ -119,7 +119,6 @@ bool sysvartrack_value_construct(THD *thd, char *val, size_t len); class Session_tracker { -private: State_tracker *m_trackers[SESSION_TRACKER_END]; /* The following two functions are private to disable copying. */ @@ -234,14 +233,16 @@ enum enum_session_track_transaction_info { class Transaction_state_tracker : public State_tracker { -private: /** Helper function: turn table info into table access flag */ enum_tx_state calc_trx_state(THD *thd, thr_lock_type l, bool has_trx); public: /** Constructor */ - Transaction_state_tracker(); - bool enable(THD *thd) - { return update(thd, NULL); } + Transaction_state_tracker(): tx_changed(TX_CHG_NONE), + tx_curr_state(TX_EMPTY), + tx_reported_state(TX_EMPTY), + tx_read_flags(TX_READ_INHERIT), + tx_isol_level(TX_ISOL_INHERIT) {} + bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); From 2be28a91b15010c5e6146e78e78fbe10a9b86153 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Fri, 15 Mar 2019 11:52:26 +0400 Subject: [PATCH 30/43] Cleanup session tracker API - Session_sysvars_tracker::server_init_check() -> sysvartrack_validate_value() - Session_sysvars_tracker::check_var_list() -> sysvartrack_validate_value() - Session_sysvars_tracker::server_init_process() -> sysvartrack_global_update() - sysvartrack_reprint_value() -> sysvartrack_global_update() - sysvartrack_value_len() -> sysvartrack_session_value_ptr() - sysvartrack_value_construct() -> sysvartrack_session_value_ptr() - sysvartrack_update() -> Session_sysvars_tracker::update() - Session_tracker::server_boot_verify() -> session_tracker_init() - sysvar_tracker() -> /dev/null Part of MDEV-14984 - regression in connect performance --- sql/mysqld.cc | 10 +-- sql/session_tracker.cc | 136 ++++++++++++++--------------------------- sql/session_tracker.h | 9 ++- sql/sys_vars.ic | 18 ++---- 4 files changed, 56 insertions(+), 117 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index f0ffa7eae8c..73dd7ce36af 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5420,14 +5420,8 @@ static int init_server_components() #endif #ifndef EMBEDDED_LIBRARY - { - if (Session_tracker::server_boot_verify(system_charset_info)) - { - sql_print_error("The variable session_track_system_variables has " - "invalid values."); - unireg_abort(1); - } - } + if (session_tracker_init()) + return 1; #endif //EMBEDDED_LIBRARY /* we do want to exit if there are any other unknown options */ diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 14fc43e09e7..7908c083446 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -190,28 +190,6 @@ public: return orig_list->construct_var_list(buf, buf_len); } - /** - Method used to check the validity of string provided - for session_track_system_variables during the server - startup. - */ - static bool server_init_check(THD *thd, CHARSET_INFO *char_set, - LEX_STRING var_list) - { - return check_var_list(thd, var_list, false, char_set, false); - } - - static bool server_init_process(THD *thd, CHARSET_INFO *char_set, - LEX_STRING var_list) - { - vars_list dummy; - bool result; - result= dummy.parse_var_list(thd, var_list, false, char_set, false); - if (!result) - dummy.construct_var_list(var_list.str, var_list.length + 1); - return result; - } - bool enable(THD *thd); bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); @@ -220,8 +198,7 @@ public: static uchar *sysvars_get_key(const char *entry, size_t *length, my_bool not_used __attribute__((unused))); - static bool check_var_list(THD *thd, LEX_STRING var_list, bool throw_error, - CHARSET_INFO *char_set, bool take_mutex); + friend bool sysvartrack_global_update(THD *thd, char *str, size_t len); }; @@ -442,12 +419,9 @@ error: } -bool Session_sysvars_tracker::check_var_list(THD *thd, - LEX_STRING var_list, - bool throw_error, - CHARSET_INFO *char_set, - bool take_mutex) +bool sysvartrack_validate_value(THD *thd, const char *str, size_t len) { + LEX_STRING var_list= { (char *) str, len }; const char separator= ','; char *token, *lasts= NULL; size_t rest= var_list.length; @@ -466,7 +440,7 @@ bool Session_sysvars_tracker::check_var_list(THD *thd, token value. Hence the mutex is handled here to avoid a performance overhead. */ - if (!thd || take_mutex) + if (!thd) mysql_mutex_lock(&LOCK_plugin); for (;;) { @@ -484,24 +458,14 @@ bool Session_sysvars_tracker::check_var_list(THD *thd, var.length= rest; /* Remove leading/trailing whitespace. */ - trim_whitespace(char_set, &var); + trim_whitespace(system_charset_info, &var); if(!strcmp(var.str, "*") && - !find_sys_var_ex(thd, var.str, var.length, throw_error, true)) + !find_sys_var_ex(thd, var.str, var.length, false, true)) { - if (throw_error && take_mutex && thd) - { - push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN, - ER_WRONG_VALUE_FOR_VAR, - "%.*s is not a valid system variable and will" - "be ignored.", (int)var.length, token); - } - else - { - if (!thd || take_mutex) - mysql_mutex_unlock(&LOCK_plugin); - return true; - } + if (!thd) + mysql_mutex_unlock(&LOCK_plugin); + return true; } if (lasts) @@ -509,7 +473,7 @@ bool Session_sysvars_tracker::check_var_list(THD *thd, else break; } - if (!thd || take_mutex) + if (!thd) mysql_mutex_unlock(&LOCK_plugin); return false; @@ -804,38 +768,50 @@ void Session_sysvars_tracker::vars_list::reset() at(i)->m_changed= false; } -static Session_sysvars_tracker* sysvar_tracker(THD *thd) + +bool sysvartrack_global_update(THD *thd, char *str, size_t len) { - return (Session_sysvars_tracker*) - thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER); + LEX_STRING tmp= { str, len }; + Session_sysvars_tracker::vars_list dummy; + if (!dummy.parse_var_list(thd, tmp, false, system_charset_info, false)) + { + dummy.construct_var_list(str, len + 1); + return false; + } + return true; } -bool sysvartrack_validate_value(THD *thd, const char *str, size_t len) + +uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base) { - LEX_STRING tmp= {(char *)str, len}; - return Session_sysvars_tracker::server_init_check(thd, system_charset_info, - tmp); + Session_sysvars_tracker *tracker= static_cast + (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)); + size_t len= tracker->get_buffer_length(); + char *res= (char*) thd->alloc(len + sizeof(char*)); + if (res) + { + char *buf= res + sizeof(char*); + *((char**) res)= buf; + tracker->construct_var_list(buf, len); + } + return (uchar*) res; } -bool sysvartrack_reprint_value(THD *thd, char *str, size_t len) + + +int session_tracker_init() { - LEX_STRING tmp= {str, len}; - return Session_sysvars_tracker::server_init_process(thd, - system_charset_info, - tmp); -} -bool sysvartrack_update(THD *thd, set_var *var) -{ - return sysvar_tracker(thd)->update(thd, var); -} -size_t sysvartrack_value_len(THD *thd) -{ - return sysvar_tracker(thd)->get_buffer_length(); -} -bool sysvartrack_value_construct(THD *thd, char *val, size_t len) -{ - return sysvar_tracker(thd)->construct_var_list(val, len); + if (sysvartrack_validate_value(0, + global_system_variables.session_track_system_variables, + safe_strlen(global_system_variables.session_track_system_variables))) + { + sql_print_error("The variable session_track_system_variables has " + "invalid values."); + return 1; + } + return 0; } + /////////////////////////////////////////////////////////////////////////////// /** @@ -1477,26 +1453,6 @@ void Session_tracker::enable(THD *thd) } -/** - Method called during the server startup to verify the contents - of @@session_track_system_variables. - - @retval false Success - @retval true Failure -*/ - -bool Session_tracker::server_boot_verify(CHARSET_INFO *char_set) -{ - bool result; - LEX_STRING tmp; - tmp.str= global_system_variables.session_track_system_variables; - tmp.length= safe_strlen(tmp.str); - result= - Session_sysvars_tracker::server_init_check(NULL, char_set, tmp); - return result; -} - - /** @brief Store all change information in the specified buffer. diff --git a/sql/session_tracker.h b/sql/session_tracker.h index 1d0f55c252a..8edc3ce2a39 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -103,10 +103,8 @@ public: }; bool sysvartrack_validate_value(THD *thd, const char *str, size_t len); -bool sysvartrack_reprint_value(THD *thd, char *str, size_t len); -bool sysvartrack_update(THD *thd, set_var *var); -size_t sysvartrack_value_len(THD *thd); -bool sysvartrack_value_construct(THD *thd, char *val, size_t len); +bool sysvartrack_global_update(THD *thd, char *str, size_t len); +uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base); /** @@ -152,7 +150,6 @@ public: } void enable(THD *thd); - static bool server_boot_verify(CHARSET_INFO *char_set); /** Returns the pointer to the tracker object for the specified tracker. */ inline State_tracker *get_tracker(enum_session_tracker tracker) const @@ -296,6 +293,8 @@ private: ->X; } } while(0) #define SESSION_TRACKER_CHANGED(A,B,C) \ thd->session_tracker.mark_as_changed(A,B,C) + +int session_tracker_init(); #else #define TRANSACT_TRACKER(X) do{}while(0) diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 373df354268..7c375f16cdd 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -615,7 +615,7 @@ public: char *new_val= global_update_prepare(thd, var); if (new_val) { - if (sysvartrack_reprint_value(thd, new_val, + if (sysvartrack_global_update(thd, new_val, var->save_result.string_value.length)) new_val= 0; } @@ -624,7 +624,8 @@ public: } bool session_update(THD *thd, set_var *var) { - return sysvartrack_update(thd, var); + return thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> + update(thd, var); } void session_save_default(THD *thd, set_var *var) { @@ -644,18 +645,7 @@ public: } } uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) - { - DBUG_ASSERT(thd != NULL); - size_t len= sysvartrack_value_len(thd); - char *res= (char *)thd->alloc(len + sizeof(char *)); - if (res) - { - char *buf= res + sizeof(char *); - *((char**) res)= buf; - sysvartrack_value_construct(thd, buf, len); - } - return (uchar *)res; - } + { return sysvartrack_session_value_ptr(thd, base); } }; #endif //EMBEDDED_LIBRARY From 55bdd7f7b4a0898dca2a2e7d457b06cb81df7d6a Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 13 Mar 2019 12:20:11 +0400 Subject: [PATCH 31/43] Get rid of not implemented SESSION_GTIDS_TRACKER One less new/delete per connection. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 16 ---------------- sql/session_tracker.h | 1 - 2 files changed, 17 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 7908c083446..13da65b417e 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -34,20 +34,6 @@ void State_tracker::mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name) } -class Not_implemented_tracker : public State_tracker -{ -public: - bool enable(THD *thd) - { return false; } - bool update(THD *, set_var *) - { return false; } - bool store(THD *, String *) - { return false; } - void mark_as_changed(THD *, LEX_CSTRING *tracked_item_name) - {} - -}; - /** Session_sysvars_tracker @@ -1443,8 +1429,6 @@ void Session_tracker::enable(THD *thd) new (std::nothrow) Current_schema_tracker; m_trackers[SESSION_STATE_CHANGE_TRACKER]= new (std::nothrow) Session_state_change_tracker; - m_trackers[SESSION_GTIDS_TRACKER]= - new (std::nothrow) Not_implemented_tracker; m_trackers[TRANSACTION_INFO_TRACKER]= new (std::nothrow) Transaction_state_tracker; diff --git a/sql/session_tracker.h b/sql/session_tracker.h index 8edc3ce2a39..8265e638f1b 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -32,7 +32,6 @@ enum enum_session_tracker SESSION_SYSVARS_TRACKER, /* Session system variables */ CURRENT_SCHEMA_TRACKER, /* Current schema */ SESSION_STATE_CHANGE_TRACKER, - SESSION_GTIDS_TRACKER, /* Tracks GTIDs */ TRANSACTION_INFO_TRACKER, /* Transaction state */ SESSION_TRACKER_END /* must be the last */ }; From 01e8f3c52b349a0374c04f0765a625b5ac03a652 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 13 Mar 2019 13:41:18 +0400 Subject: [PATCH 32/43] Allocate orig_list statically tool_list is a temporary list needed only for SET SESSION session_track_system_variables, so allocate it on stack instead. Sane reinit() calls. Saves 2 new/delete per connection. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 57 +++++++++++++----------------------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 13da65b417e..1af1c8de05a 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -98,8 +98,7 @@ class Session_sysvars_tracker : public State_tracker my_hash_element(&m_registered_sysvars, i)); } public: - vars_list() : - buffer_length(0) + vars_list(): buffer_length(0), track_all(false) { m_mem_flag= current_thd ? MY_THREAD_SPECIFIC : 0; init(); @@ -150,30 +149,16 @@ class Session_sysvars_tracker : public State_tracker Two objects of vars_list type are maintained to manage various operations. */ - vars_list *orig_list, *tool_list; + vars_list orig_list; public: - Session_sysvars_tracker() - { - orig_list= new (std::nothrow) vars_list(); - tool_list= new (std::nothrow) vars_list(); - } - - ~Session_sysvars_tracker() - { - if (orig_list) - delete orig_list; - if (tool_list) - delete tool_list; - } - size_t get_buffer_length() { - return orig_list->get_buffer_length(); + return orig_list.get_buffer_length(); } bool construct_var_list(char *buf, size_t buf_len) { - return orig_list->construct_var_list(buf, buf_len); + return orig_list.construct_var_list(buf, buf_len); } bool enable(THD *thd); @@ -249,7 +234,6 @@ void Session_sysvars_tracker::vars_list::reinit() void Session_sysvars_tracker::vars_list::copy(vars_list* from, THD *thd) { - reinit(); track_all= from->track_all; free_hash(); buffer_length= from->buffer_length; @@ -271,10 +255,7 @@ bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) sysvar_node_st *node; if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st), MYF(MY_WME | m_mem_flag)))) - { - reinit(); return true; - } node->m_svar= (sys_var *)svar; node->test_load= node->m_svar->test_load; @@ -285,7 +266,6 @@ bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) if (!search((sys_var *)svar)) { //EOF (error is already reported) - reinit(); return true; } } @@ -322,7 +302,6 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, const char separator= ','; char *token, *lasts= NULL; size_t rest= var_list.length; - reinit(); if (!var_list.str || var_list.length == 0) { @@ -573,14 +552,13 @@ bool Session_sysvars_tracker::enable(THD *thd) LEX_STRING tmp; tmp.str= global_system_variables.session_track_system_variables; tmp.length= safe_strlen(tmp.str); - if (tool_list->parse_var_list(thd, tmp, - true, thd->charset(), false) == true) + if (orig_list.parse_var_list(thd, tmp, true, thd->charset(), false) == true) { mysql_mutex_unlock(&LOCK_plugin); + orig_list.reinit(); return true; } mysql_mutex_unlock(&LOCK_plugin); - orig_list->copy(tool_list, thd); m_enabled= true; return false; @@ -593,6 +571,9 @@ bool Session_sysvars_tracker::enable(THD *thd) Session_sysvars_tracker::vars_list::copy updating the hash in orig_list which represents the system variables to be tracked. + We are doing via tool list because there possible errors with memory + in this case value will be unchanged. + @note This function is called from the ON_UPDATE() function of the session_track_system_variables' sys_var class. @@ -604,15 +585,11 @@ bool Session_sysvars_tracker::enable(THD *thd) bool Session_sysvars_tracker::update(THD *thd, set_var *var) { - /* - We are doing via tool list because there possible errors with memory - in this case value will be unchanged. - */ - tool_list->reinit(); - if (tool_list->parse_var_list(thd, var->save_result.string_value, true, - thd->charset(), true)) + vars_list tool_list; + if (tool_list.parse_var_list(thd, var->save_result.string_value, true, + thd->charset(), true)) return true; - orig_list->copy(tool_list, thd); + orig_list.copy(&tool_list, thd); return false; } @@ -694,13 +671,13 @@ bool Session_sysvars_tracker::vars_list::store(THD *thd, String *buf) bool Session_sysvars_tracker::store(THD *thd, String *buf) { - if (!orig_list->is_enabled()) + if (!orig_list.is_enabled()) return false; - if (orig_list->store(thd, buf)) + if (orig_list.store(thd, buf)) return true; - orig_list->reset(); + orig_list.reset(); return false; } @@ -721,7 +698,7 @@ void Session_sysvars_tracker::mark_as_changed(THD *thd, Check if the specified system variable is being tracked, if so mark it as changed and also set the class's m_changed flag. */ - if (orig_list->is_enabled() && (node= orig_list->insert_or_search(svar))) + if (orig_list.is_enabled() && (node= orig_list.insert_or_search(svar))) { node->m_changed= true; State_tracker::mark_as_changed(thd, var); From 47bd06d55ec211bc4d05d616a0833629504c7edf Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Mon, 18 Mar 2019 17:13:00 +0400 Subject: [PATCH 33/43] Static current schema and state change trackers Saves 2 new/delete per connection. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 47 +++------------------------- sql/session_tracker.h | 69 ++++++++++++++++++++++++++++++++++-------- sql/sys_vars.cc | 6 ++-- 3 files changed, 63 insertions(+), 59 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 1af1c8de05a..868e8295294 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -173,43 +173,6 @@ public: }; - -/** - Current_schema_tracker, - - This is a tracker class that enables & manages the tracking of current - schema for a particular connection. -*/ - -class Current_schema_tracker : public State_tracker -{ -public: - bool update(THD *thd, set_var *var); - bool store(THD *thd, String *buf); -}; - -/* - Session_state_change_tracker - - This is a boolean tracker class that will monitor any change that contributes - to a session state change. - Attributes that contribute to session state change include: - - Successful change to System variables - - User defined variables assignments - - temporary tables created, altered or deleted - - prepared statements added or removed - - change in current database - - change of current role -*/ - -class Session_state_change_tracker : public State_tracker -{ -public: - bool update(THD *thd, set_var *var); - bool store(THD *thd, String *buf); -}; - - /* To be used in expanding the buffer. */ static const unsigned int EXTRA_ALLOC= 1024; @@ -1379,8 +1342,10 @@ Session_tracker::Session_tracker() compile_time_assert((uint)SESSION_TRACK_always_at_the_end >= (uint)SESSION_TRACKER_END); - for (int i= 0; i < SESSION_TRACKER_END; i++) - m_trackers[i]= NULL; + m_trackers[SESSION_SYSVARS_TRACKER]= 0; + m_trackers[CURRENT_SCHEMA_TRACKER]= ¤t_schema; + m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change; + m_trackers[TRANSACTION_INFO_TRACKER]= 0; } @@ -1402,10 +1367,6 @@ void Session_tracker::enable(THD *thd) deinit(); m_trackers[SESSION_SYSVARS_TRACKER]= new (std::nothrow) Session_sysvars_tracker(); - m_trackers[CURRENT_SCHEMA_TRACKER]= - new (std::nothrow) Current_schema_tracker; - m_trackers[SESSION_STATE_CHANGE_TRACKER]= - new (std::nothrow) Session_state_change_tracker; m_trackers[TRANSACTION_INFO_TRACKER]= new (std::nothrow) Transaction_state_tracker; diff --git a/sql/session_tracker.h b/sql/session_tracker.h index 8265e638f1b..ec6d21bd344 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -88,8 +88,18 @@ public: void reset_changed() { m_changed= false; } - /** Called in the constructor of THD*/ - virtual bool enable(THD *thd) { return update(thd, 0); } + /** + Called by THD::init() when new connection is being created + + We may inherit m_changed from previous connection served by this THD if + connection was broken or client didn't have session tracking capability. + Thus we have to reset it here. + */ + virtual bool enable(THD *thd) + { + reset_changed(); + return update(thd, 0); + } /** To be invoked when the tracker's system variable is updated (ON_UPDATE).*/ virtual bool update(THD *thd, set_var *var)= 0; @@ -101,11 +111,49 @@ public: virtual void mark_as_changed(THD *thd, LEX_CSTRING *name); }; + bool sysvartrack_validate_value(THD *thd, const char *str, size_t len); bool sysvartrack_global_update(THD *thd, char *str, size_t len); uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base); +/** + Current_schema_tracker, + + This is a tracker class that enables & manages the tracking of current + schema for a particular connection. +*/ + +class Current_schema_tracker: public State_tracker +{ +public: + bool update(THD *thd, set_var *var); + bool store(THD *thd, String *buf); +}; + + +/* + Session_state_change_tracker + + This is a boolean tracker class that will monitor any change that contributes + to a session state change. + Attributes that contribute to session state change include: + - Successful change to System variables + - User defined variables assignments + - temporary tables created, altered or deleted + - prepared statements added or removed + - change in current database + - change of current role +*/ + +class Session_state_change_tracker: public State_tracker +{ +public: + bool update(THD *thd, set_var *var); + bool store(THD *thd, String *buf); +}; + + /** Session_tracker @@ -130,22 +178,19 @@ class Session_tracker } public: + Current_schema_tracker current_schema; + Session_state_change_tracker state_change; Session_tracker(); - ~Session_tracker() - { - deinit(); - } + ~Session_tracker() { deinit(); } /* trick to make happy memory accounting system */ void deinit() { - for (int i= 0; i < SESSION_TRACKER_END; i++) - { - if (m_trackers[i]) - delete m_trackers[i]; - m_trackers[i]= NULL; - } + delete m_trackers[SESSION_SYSVARS_TRACKER]; + m_trackers[SESSION_SYSVARS_TRACKER]= 0; + delete m_trackers[TRANSACTION_INFO_TRACKER]; + m_trackers[TRANSACTION_INFO_TRACKER]= 0; } void enable(THD *thd); diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index ac245d1ee54..bea46578148 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -6128,8 +6128,7 @@ static bool update_session_track_schema(sys_var *self, THD *thd, enum_var_type type) { DBUG_ENTER("update_session_track_schema"); - DBUG_RETURN(thd->session_tracker.get_tracker(CURRENT_SCHEMA_TRACKER)-> - update(thd, NULL)); + DBUG_RETURN(thd->session_tracker.current_schema.update(thd, NULL)); } static Sys_var_mybool Sys_session_track_schema( @@ -6172,8 +6171,7 @@ static bool update_session_track_state_change(sys_var *self, THD *thd, enum_var_type type) { DBUG_ENTER("update_session_track_state_change"); - DBUG_RETURN(thd->session_tracker.get_tracker(SESSION_STATE_CHANGE_TRACKER)-> - update(thd, NULL)); + DBUG_RETURN(thd->session_tracker.state_change.update(thd, NULL)); } static Sys_var_mybool Sys_session_track_state_change( From a7adc2ce1680f00635b8241202066fd5542d286f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Mon, 18 Mar 2019 19:18:54 +0400 Subject: [PATCH 34/43] Allocate Transaction_state_tracker statically One less new/delete per connection. Part of MDEV-14984 - regression in connect performance --- sql/lock.cc | 11 +--- sql/session_tracker.cc | 4 +- sql/session_tracker.h | 139 +++++++++++++++++++++-------------------- sql/sys_vars.cc | 11 ++-- sql/sys_vars.ic | 18 ++---- sql/transaction.cc | 37 ++++------- 6 files changed, 94 insertions(+), 126 deletions(-) diff --git a/sql/lock.cc b/sql/lock.cc index 5420e9f42b5..aeba6cc7504 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -252,16 +252,11 @@ static void track_table_access(THD *thd, TABLE **tables, size_t count) { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) { - Transaction_state_tracker *tst= (Transaction_state_tracker *) - thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER); - while (count--) { - TABLE *t= tables[count]; - - if (t) - tst->add_trx_state(thd, t->reginfo.lock_type, - t->file->has_transaction_manager()); + if (TABLE *t= tables[count]) + thd->session_tracker.transaction_info.add_trx_state(thd, + t->reginfo.lock_type, t->file->has_transaction_manager()); } } } diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 868e8295294..2f72b7198f9 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -1345,7 +1345,7 @@ Session_tracker::Session_tracker() m_trackers[SESSION_SYSVARS_TRACKER]= 0; m_trackers[CURRENT_SCHEMA_TRACKER]= ¤t_schema; m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change; - m_trackers[TRANSACTION_INFO_TRACKER]= 0; + m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info; } @@ -1367,8 +1367,6 @@ void Session_tracker::enable(THD *thd) deinit(); m_trackers[SESSION_SYSVARS_TRACKER]= new (std::nothrow) Session_sysvars_tracker(); - m_trackers[TRANSACTION_INFO_TRACKER]= - new (std::nothrow) Transaction_state_tracker; for (int i= 0; i < SESSION_TRACKER_END; i++) m_trackers[i]->enable(thd); diff --git a/sql/session_tracker.h b/sql/session_tracker.h index ec6d21bd344..faa34e88c74 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -154,65 +154,6 @@ public: }; -/** - Session_tracker - - This class holds an object each for all tracker classes and provides - methods necessary for systematic detection and generation of session - state change information. -*/ - -class Session_tracker -{ - State_tracker *m_trackers[SESSION_TRACKER_END]; - - /* The following two functions are private to disable copying. */ - Session_tracker(Session_tracker const &other) - { - DBUG_ASSERT(FALSE); - } - Session_tracker& operator= (Session_tracker const &rhs) - { - DBUG_ASSERT(FALSE); - return *this; - } - -public: - Current_schema_tracker current_schema; - Session_state_change_tracker state_change; - - Session_tracker(); - ~Session_tracker() { deinit(); } - - /* trick to make happy memory accounting system */ - void deinit() - { - delete m_trackers[SESSION_SYSVARS_TRACKER]; - m_trackers[SESSION_SYSVARS_TRACKER]= 0; - delete m_trackers[TRANSACTION_INFO_TRACKER]; - m_trackers[TRANSACTION_INFO_TRACKER]= 0; - } - - void enable(THD *thd); - - /** Returns the pointer to the tracker object for the specified tracker. */ - inline State_tracker *get_tracker(enum_session_tracker tracker) const - { - return m_trackers[tracker]; - } - - inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker, - LEX_CSTRING *data) - { - if (m_trackers[tracker]->is_enabled()) - m_trackers[tracker]->mark_as_changed(thd, data); - } - - - void store(THD *thd, String *main_buf); -}; - - /* Transaction_state_tracker */ @@ -277,12 +218,17 @@ class Transaction_state_tracker : public State_tracker /** Helper function: turn table info into table access flag */ enum_tx_state calc_trx_state(THD *thd, thr_lock_type l, bool has_trx); public: - /** Constructor */ - Transaction_state_tracker(): tx_changed(TX_CHG_NONE), - tx_curr_state(TX_EMPTY), - tx_reported_state(TX_EMPTY), - tx_read_flags(TX_READ_INHERIT), - tx_isol_level(TX_ISOL_INHERIT) {} + + bool enable(THD *thd) + { + m_enabled= false; + tx_changed= TX_CHG_NONE; + tx_curr_state= TX_EMPTY; + tx_reported_state= TX_EMPTY; + tx_read_flags= TX_READ_INHERIT; + tx_isol_level= TX_ISOL_INHERIT; + return State_tracker::enable(thd); + } bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); @@ -332,12 +278,69 @@ private: #define TRANSACT_TRACKER(X) \ do { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) \ - {((Transaction_state_tracker *) \ - thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER)) \ - ->X; } } while(0) + thd->session_tracker.transaction_info.X; } while(0) #define SESSION_TRACKER_CHANGED(A,B,C) \ thd->session_tracker.mark_as_changed(A,B,C) + +/** + Session_tracker + + This class holds an object each for all tracker classes and provides + methods necessary for systematic detection and generation of session + state change information. +*/ + +class Session_tracker +{ + State_tracker *m_trackers[SESSION_TRACKER_END]; + + /* The following two functions are private to disable copying. */ + Session_tracker(Session_tracker const &other) + { + DBUG_ASSERT(FALSE); + } + Session_tracker& operator= (Session_tracker const &rhs) + { + DBUG_ASSERT(FALSE); + return *this; + } + +public: + Current_schema_tracker current_schema; + Session_state_change_tracker state_change; + Transaction_state_tracker transaction_info; + + Session_tracker(); + ~Session_tracker() { deinit(); } + + /* trick to make happy memory accounting system */ + void deinit() + { + delete m_trackers[SESSION_SYSVARS_TRACKER]; + m_trackers[SESSION_SYSVARS_TRACKER]= 0; + } + + void enable(THD *thd); + + /** Returns the pointer to the tracker object for the specified tracker. */ + inline State_tracker *get_tracker(enum_session_tracker tracker) const + { + return m_trackers[tracker]; + } + + inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker, + LEX_CSTRING *data) + { + if (m_trackers[tracker]->is_enabled()) + m_trackers[tracker]->mark_as_changed(thd, data); + } + + + void store(THD *thd, String *main_buf); +}; + + int session_tracker_init(); #else diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index bea46578148..004fd4baecb 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3743,14 +3743,12 @@ bool Sys_var_tx_read_only::session_update(THD *thd, set_var *var) #ifndef EMBEDDED_LIBRARY if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) { - Transaction_state_tracker *tst= (Transaction_state_tracker *) - thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER); - if (var->type == OPT_DEFAULT) - tst->set_read_flags(thd, + thd->session_tracker.transaction_info.set_read_flags(thd, thd->tx_read_only ? TX_READ_ONLY : TX_READ_WRITE); else - tst->set_read_flags(thd, TX_READ_INHERIT); + thd->session_tracker.transaction_info.set_read_flags(thd, + TX_READ_INHERIT); } #endif //EMBEDDED_LIBRARY } @@ -6145,8 +6143,7 @@ static bool update_session_track_tx_info(sys_var *self, THD *thd, enum_var_type type) { DBUG_ENTER("update_session_track_tx_info"); - DBUG_RETURN(thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER)-> - update(thd, NULL)); + DBUG_RETURN(thd->session_tracker.transaction_info.update(thd, NULL)); } static const char *session_track_transaction_info_names[]= diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 7c375f16cdd..042b7c75da7 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -2219,14 +2219,6 @@ public: return TRUE; if (var->type == OPT_DEFAULT || !thd->in_active_multi_stmt_transaction()) { -#ifndef EMBEDDED_LIBRARY - Transaction_state_tracker *tst= NULL; - - if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) - tst= (Transaction_state_tracker *) - thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER); -#endif //EMBEDDED_LIBRARY - thd->tx_isolation= (enum_tx_isolation) var->save_result.ulonglong_value; #ifndef EMBEDDED_LIBRARY @@ -2250,13 +2242,11 @@ public: DBUG_ASSERT(0); return TRUE; } - if (tst) - tst->set_isol_level(thd, l); - } - else if (tst) - { - tst->set_isol_level(thd, TX_ISOL_INHERIT); + if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) + thd->session_tracker.transaction_info.set_isol_level(thd, l); } + else if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) + thd->session_tracker.transaction_info.set_isol_level(thd, TX_ISOL_INHERIT); #endif //EMBEDDED_LIBRARY } return FALSE; diff --git a/sql/transaction.cc b/sql/transaction.cc index 1c2820200d1..74f4eda881b 100644 --- a/sql/transaction.cc +++ b/sql/transaction.cc @@ -32,10 +32,7 @@ static void trans_track_end_trx(THD *thd) { if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) - { - ((Transaction_state_tracker *) - thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER))->end_trx(thd); - } + thd->session_tracker.transaction_info.end_trx(thd); } #else #define trans_track_end_trx(A) do{}while(0) @@ -51,11 +48,8 @@ void trans_reset_one_shot_chistics(THD *thd) #ifndef EMBEDDED_LIBRARY if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) { - Transaction_state_tracker *tst= (Transaction_state_tracker *) - thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER); - - tst->set_read_flags(thd, TX_READ_INHERIT); - tst->set_isol_level(thd, TX_ISOL_INHERIT); + thd->session_tracker.transaction_info.set_read_flags(thd, TX_READ_INHERIT); + thd->session_tracker.transaction_info.set_isol_level(thd, TX_ISOL_INHERIT); } #endif //EMBEDDED_LIBRARY thd->tx_isolation= (enum_tx_isolation) thd->variables.tx_isolation; @@ -162,20 +156,11 @@ static bool xa_trans_force_rollback(THD *thd) bool trans_begin(THD *thd, uint flags) { int res= FALSE; -#ifndef EMBEDDED_LIBRARY - Transaction_state_tracker *tst= NULL; -#endif //EMBEDDED_LIBRARY DBUG_ENTER("trans_begin"); if (trans_check(thd)) DBUG_RETURN(TRUE); -#ifndef EMBEDDED_LIBRARY - if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) - tst= (Transaction_state_tracker *) - thd->session_tracker.get_tracker(TRANSACTION_INFO_TRACKER); -#endif //EMBEDDED_LIBRARY - thd->locked_tables_list.unlock_locked_tables(thd); DBUG_ASSERT(!thd->locked_tables_mode); @@ -221,8 +206,8 @@ bool trans_begin(THD *thd, uint flags) { thd->tx_read_only= true; #ifndef EMBEDDED_LIBRARY - if (tst) - tst->set_read_flags(thd, TX_READ_ONLY); + if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) + thd->session_tracker.transaction_info.set_read_flags(thd, TX_READ_ONLY); #endif //EMBEDDED_LIBRARY } else if (flags & MYSQL_START_TRANS_OPT_READ_WRITE) @@ -246,8 +231,8 @@ bool trans_begin(THD *thd, uint flags) just from the session's default. */ #ifndef EMBEDDED_LIBRARY - if (tst) - tst->set_read_flags(thd, TX_READ_WRITE); + if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) + thd->session_tracker.transaction_info.set_read_flags(thd, TX_READ_WRITE); #endif //EMBEDDED_LIBRARY } @@ -264,16 +249,16 @@ bool trans_begin(THD *thd, uint flags) DBUG_PRINT("info", ("setting SERVER_STATUS_IN_TRANS")); #ifndef EMBEDDED_LIBRARY - if (tst) - tst->add_trx_state(thd, TX_EXPLICIT); + if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) + thd->session_tracker.transaction_info.add_trx_state(thd, TX_EXPLICIT); #endif //EMBEDDED_LIBRARY /* ha_start_consistent_snapshot() relies on OPTION_BEGIN flag set. */ if (flags & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) { #ifndef EMBEDDED_LIBRARY - if (tst) - tst->add_trx_state(thd, TX_WITH_SNAPSHOT); + if (thd->variables.session_track_transaction_info > TX_TRACK_NONE) + thd->session_tracker.transaction_info.add_trx_state(thd, TX_WITH_SNAPSHOT); #endif //EMBEDDED_LIBRARY res= ha_start_consistent_snapshot(thd); } From 554ac6f393941040cea6d45d57a298e900bff193 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 19 Mar 2019 00:40:26 +0400 Subject: [PATCH 35/43] Allocate Session_sysvars_tracker statically One less new/delete per connection. Removed m_mem_flag since most allocs are thread specific. The only exception are allocs performed during initialization. Removed State_tracker and Session_tracker constructors as they don't make sense anymore. No reason to access session_sysvars_tracker via get_tracker(), so access it directly instead. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 196 +++-------------------------------------- sql/session_tracker.h | 151 +++++++++++++++++++++++++++---- sql/set_var.cc | 8 +- sql/sql_class.cc | 9 +- sql/sys_vars.ic | 5 +- 5 files changed, 156 insertions(+), 213 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 2f72b7198f9..81da43a0946 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -16,8 +16,6 @@ #include "sql_plugin.h" -#include "session_tracker.h" - #include "hash.h" #include "table.h" #include "rpl_gtid.h" @@ -34,145 +32,6 @@ void State_tracker::mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name) } -/** - Session_sysvars_tracker - - This is a tracker class that enables & manages the tracking of session - system variables. It internally maintains a hash of user supplied variable - references and a boolean field to store if the variable was changed by the - last statement. -*/ - -class Session_sysvars_tracker : public State_tracker -{ - struct sysvar_node_st { - sys_var *m_svar; - bool *test_load; - bool m_changed; - }; - - class vars_list - { - /** - Registered system variables. (@@session_track_system_variables) - A hash to store the name of all the system variables specified by the - user. - */ - HASH m_registered_sysvars; - /** Size of buffer for string representation */ - size_t buffer_length; - myf m_mem_flag; - /** - If TRUE then we want to check all session variable. - */ - bool track_all; - void init() - { - my_hash_init(&m_registered_sysvars, - &my_charset_bin, - 4, 0, 0, (my_hash_get_key) sysvars_get_key, - my_free, MYF(HASH_UNIQUE | - ((m_mem_flag & MY_THREAD_SPECIFIC) ? - HASH_THREAD_SPECIFIC : 0))); - } - void free_hash() - { - if (my_hash_inited(&m_registered_sysvars)) - { - my_hash_free(&m_registered_sysvars); - } - } - - sysvar_node_st *search(const sys_var *svar) - { - return reinterpret_cast( - my_hash_search(&m_registered_sysvars, - reinterpret_cast(&svar), - sizeof(sys_var*))); - } - - sysvar_node_st *at(ulong i) - { - DBUG_ASSERT(i < m_registered_sysvars.records); - return reinterpret_cast( - my_hash_element(&m_registered_sysvars, i)); - } - public: - vars_list(): buffer_length(0), track_all(false) - { - m_mem_flag= current_thd ? MY_THREAD_SPECIFIC : 0; - init(); - } - - size_t get_buffer_length() - { - DBUG_ASSERT(buffer_length != 0); // asked earlier then should - return buffer_length; - } - ~vars_list() - { - /* free the allocated hash. */ - if (my_hash_inited(&m_registered_sysvars)) - { - my_hash_free(&m_registered_sysvars); - } - } - - sysvar_node_st *insert_or_search(const sys_var *svar) - { - sysvar_node_st *res= search(svar); - if (!res) - { - if (track_all) - { - insert(svar); - return search(svar); - } - } - return res; - } - - bool insert(const sys_var *svar); - void reinit(); - void reset(); - inline bool is_enabled() - { - return track_all || m_registered_sysvars.records; - } - void copy(vars_list* from, THD *thd); - bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error, - CHARSET_INFO *char_set, bool take_mutex); - bool construct_var_list(char *buf, size_t buf_len); - bool store(THD *thd, String *buf); - }; - /** - Two objects of vars_list type are maintained to manage - various operations. - */ - vars_list orig_list; - -public: - size_t get_buffer_length() - { - return orig_list.get_buffer_length(); - } - bool construct_var_list(char *buf, size_t buf_len) - { - return orig_list.construct_var_list(buf, buf_len); - } - - bool enable(THD *thd); - bool update(THD *thd, set_var *var); - bool store(THD *thd, String *buf); - void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name); - /* callback */ - static uchar *sysvars_get_key(const char *entry, size_t *length, - my_bool not_used __attribute__((unused))); - - friend bool sysvartrack_global_update(THD *thd, char *str, size_t len); -}; - - /* To be used in expanding the buffer. */ static const unsigned int EXTRA_ALLOC= 1024; @@ -217,7 +76,9 @@ bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) { sysvar_node_st *node; if (!(node= (sysvar_node_st *) my_malloc(sizeof(sysvar_node_st), - MYF(MY_WME | m_mem_flag)))) + MYF(MY_WME | + (mysqld_server_initialized ? + MY_THREAD_SPECIFIC : 0))))) return true; node->m_svar= (sys_var *)svar; @@ -511,6 +372,7 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, bool Session_sysvars_tracker::enable(THD *thd) { + orig_list.reinit(); mysql_mutex_lock(&LOCK_plugin); LEX_STRING tmp; tmp.str= global_system_variables.session_track_system_variables; @@ -519,6 +381,7 @@ bool Session_sysvars_tracker::enable(THD *thd) { mysql_mutex_unlock(&LOCK_plugin); orig_list.reinit(); + m_enabled= false; return true; } mysql_mutex_unlock(&LOCK_plugin); @@ -1330,49 +1193,6 @@ bool Session_state_change_tracker::store(THD *thd, String *buf) /////////////////////////////////////////////////////////////////////////////// -/** - @brief Initialize session tracker objects. -*/ - -Session_tracker::Session_tracker() -{ - /* track data ID fit into one byte in net coding */ - compile_time_assert(SESSION_TRACK_always_at_the_end < 251); - /* one tracker could serv several tracking data */ - compile_time_assert((uint)SESSION_TRACK_always_at_the_end >= - (uint)SESSION_TRACKER_END); - - m_trackers[SESSION_SYSVARS_TRACKER]= 0; - m_trackers[CURRENT_SCHEMA_TRACKER]= ¤t_schema; - m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change; - m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info; -} - - -/** - @brief Enables the tracker objects. - - @param thd [IN] The thread handle. - - @return void -*/ - -void Session_tracker::enable(THD *thd) -{ - /* - Originally and correctly this allocation was in the constructor and - deallocation in the destructor, but in this case memory counting - system works incorrectly (for example in INSERT DELAYED thread) - */ - deinit(); - m_trackers[SESSION_SYSVARS_TRACKER]= - new (std::nothrow) Session_sysvars_tracker(); - - for (int i= 0; i < SESSION_TRACKER_END; i++) - m_trackers[i]->enable(thd); -} - - /** @brief Store all change information in the specified buffer. @@ -1385,6 +1205,12 @@ void Session_tracker::store(THD *thd, String *buf) { size_t start; + /* track data ID fit into one byte in net coding */ + compile_time_assert(SESSION_TRACK_always_at_the_end < 251); + /* one tracker could serv several tracking data */ + compile_time_assert((uint) SESSION_TRACK_always_at_the_end >= + (uint) SESSION_TRACKER_END); + /* Probably most track result will fit in 251 byte so lets made it at least efficient. We allocate 1 byte for length and then will move diff --git a/sql/session_tracker.h b/sql/session_tracker.h index faa34e88c74..51e32dde639 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -71,13 +71,7 @@ private: bool m_changed; public: - /** Constructor */ - State_tracker() : m_enabled(false), m_changed(false) - {} - - /** Destructor */ - virtual ~State_tracker() - {} + virtual ~State_tracker() {} /** Getters */ bool is_enabled() const @@ -112,6 +106,130 @@ public: }; +/** + Session_sysvars_tracker + + This is a tracker class that enables & manages the tracking of session + system variables. It internally maintains a hash of user supplied variable + references and a boolean field to store if the variable was changed by the + last statement. +*/ + +class Session_sysvars_tracker: public State_tracker +{ + struct sysvar_node_st { + sys_var *m_svar; + bool *test_load; + bool m_changed; + }; + + class vars_list + { + /** + Registered system variables. (@@session_track_system_variables) + A hash to store the name of all the system variables specified by the + user. + */ + HASH m_registered_sysvars; + /** Size of buffer for string representation */ + size_t buffer_length; + /** + If TRUE then we want to check all session variable. + */ + bool track_all; + void init() + { + my_hash_init(&m_registered_sysvars, &my_charset_bin, 0, 0, 0, + (my_hash_get_key) sysvars_get_key, my_free, + HASH_UNIQUE | (mysqld_server_initialized ? + HASH_THREAD_SPECIFIC : 0)); + } + void free_hash() + { + DBUG_ASSERT(my_hash_inited(&m_registered_sysvars)); + my_hash_free(&m_registered_sysvars); + } + + sysvar_node_st *search(const sys_var *svar) + { + return reinterpret_cast( + my_hash_search(&m_registered_sysvars, + reinterpret_cast(&svar), + sizeof(sys_var*))); + } + + sysvar_node_st *at(ulong i) + { + DBUG_ASSERT(i < m_registered_sysvars.records); + return reinterpret_cast( + my_hash_element(&m_registered_sysvars, i)); + } + public: + vars_list(): buffer_length(0), track_all(false) { init(); } + void deinit() { free_hash(); } + + size_t get_buffer_length() + { + DBUG_ASSERT(buffer_length != 0); // asked earlier then should + return buffer_length; + } + + sysvar_node_st *insert_or_search(const sys_var *svar) + { + sysvar_node_st *res= search(svar); + if (!res) + { + if (track_all) + { + insert(svar); + return search(svar); + } + } + return res; + } + + bool insert(const sys_var *svar); + void reinit(); + void reset(); + inline bool is_enabled() + { + return track_all || m_registered_sysvars.records; + } + void copy(vars_list* from, THD *thd); + bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error, + CHARSET_INFO *char_set, bool take_mutex); + bool construct_var_list(char *buf, size_t buf_len); + bool store(THD *thd, String *buf); + }; + /** + Two objects of vars_list type are maintained to manage + various operations. + */ + vars_list orig_list; + +public: + size_t get_buffer_length() + { + return orig_list.get_buffer_length(); + } + bool construct_var_list(char *buf, size_t buf_len) + { + return orig_list.construct_var_list(buf, buf_len); + } + + bool enable(THD *thd); + bool update(THD *thd, set_var *var); + bool store(THD *thd, String *buf); + void mark_as_changed(THD *thd, LEX_CSTRING *tracked_item_name); + void deinit() { orig_list.deinit(); } + /* callback */ + static uchar *sysvars_get_key(const char *entry, size_t *length, + my_bool not_used __attribute__((unused))); + + friend bool sysvartrack_global_update(THD *thd, char *str, size_t len); +}; + + bool sysvartrack_validate_value(THD *thd, const char *str, size_t len); bool sysvartrack_global_update(THD *thd, char *str, size_t len); uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base); @@ -310,18 +428,21 @@ public: Current_schema_tracker current_schema; Session_state_change_tracker state_change; Transaction_state_tracker transaction_info; + Session_sysvars_tracker sysvars; - Session_tracker(); - ~Session_tracker() { deinit(); } - - /* trick to make happy memory accounting system */ - void deinit() + Session_tracker() { - delete m_trackers[SESSION_SYSVARS_TRACKER]; - m_trackers[SESSION_SYSVARS_TRACKER]= 0; + m_trackers[SESSION_SYSVARS_TRACKER]= &sysvars; + m_trackers[CURRENT_SCHEMA_TRACKER]= ¤t_schema; + m_trackers[SESSION_STATE_CHANGE_TRACKER]= &state_change; + m_trackers[TRANSACTION_INFO_TRACKER]= &transaction_info; } - void enable(THD *thd); + void enable(THD *thd) + { + for (int i= 0; i < SESSION_TRACKER_END; i++) + m_trackers[i]->enable(thd); + } /** Returns the pointer to the tracker object for the specified tracker. */ inline State_tracker *get_tracker(enum_session_tracker tracker) const diff --git a/sql/set_var.cc b/sql/set_var.cc index 8ab892068b3..ddaf747908c 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -1016,13 +1016,13 @@ int set_var_collation_client::update(THD *thd) /* Mark client collation variables as changed */ #ifndef EMBEDDED_LIBRARY - if (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled()) + if (thd->session_tracker.sysvars.is_enabled()) { - thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> + thd->session_tracker.sysvars. mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_client_ptr); - thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> + thd->session_tracker.sysvars. mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_results_ptr); - thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> + thd->session_tracker.sysvars. mark_as_changed(thd, (LEX_CSTRING*)Sys_character_set_connection_ptr); } thd->session_tracker.mark_as_changed(thd, SESSION_STATE_CHANGE_TRACKER, NULL); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d247c806a7f..97233895fd5 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1661,7 +1661,7 @@ THD::~THD() /* trick to make happy memory accounting system */ #ifndef EMBEDDED_LIBRARY - session_tracker.deinit(); + session_tracker.sysvars.deinit(); #endif //EMBEDDED_LIBRARY if (status_var.local_memory_used != 0) @@ -7302,12 +7302,11 @@ void THD::set_last_commit_gtid(rpl_gtid >id) #endif m_last_commit_gtid= gtid; #ifndef EMBEDDED_LIBRARY - if (changed_gtid && - session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)->is_enabled()) + if (changed_gtid && session_tracker.sysvars.is_enabled()) { - session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> + session_tracker.sysvars. mark_as_changed(this, (LEX_CSTRING*)Sys_last_gtid_ptr); - } + } #endif } diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 042b7c75da7..24fdc2d04a4 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -623,10 +623,7 @@ public: return (new_val == 0 && var->save_result.string_value.str != 0); } bool session_update(THD *thd, set_var *var) - { - return thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)-> - update(thd, var); - } + { return thd->session_tracker.sysvars.update(thd, var); } void session_save_default(THD *thd, set_var *var) { var->save_result.string_value.str= global_var(char*); From 1b5cf2f7e7995f8ee17da76eb28633f652852d8f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Tue, 19 Mar 2019 20:04:10 +0400 Subject: [PATCH 36/43] Safe session_track_system_variables snapshot When enabling system variables tracker, make a copy of global_system_variables.session_track_system_variables under LOCK_global_system_variables. This protects from concurrent variable updates and potential freed memory access, as well as from variable reconstruction (which was previously protected by LOCK_plugin). We can also use this copy as a session variable pointer, so that we don't have to allocate memory and reconstruct it every time it is referenced. For this very reason we don't need buffer_length stuff anymore. As well as don't we need to take LOCK_plugin early in ::enable(). Unified ::parse_var_list() to acquire LOCK_plugin unconditionally. For no apparent reason it wasn't previously acquired for global variable update. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 93 ++++++++++++++++++++++-------------------- sql/session_tracker.h | 30 ++------------ sql/sql_plugin.cc | 12 ++++++ sql/sys_vars.ic | 2 - 4 files changed, 65 insertions(+), 72 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 81da43a0946..8b0e247767c 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -38,7 +38,6 @@ static const unsigned int EXTRA_ALLOC= 1024; void Session_sysvars_tracker::vars_list::reinit() { - buffer_length= 0; track_all= 0; if (m_registered_sysvars.records) my_hash_reset(&m_registered_sysvars); @@ -58,7 +57,6 @@ void Session_sysvars_tracker::vars_list::copy(vars_list* from, THD *thd) { track_all= from->track_all; free_hash(); - buffer_length= from->buffer_length; m_registered_sysvars= from->m_registered_sysvars; from->init(); } @@ -111,7 +109,6 @@ bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) in case of invalid/duplicate values. @param char_set [IN] charecter set information used for string manipulations. - @param take_mutex [IN] take LOCK_plugin @return true Error @@ -120,27 +117,21 @@ bool Session_sysvars_tracker::vars_list::insert(const sys_var *svar) bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error, - CHARSET_INFO *char_set, - bool take_mutex) + CHARSET_INFO *char_set) { const char separator= ','; char *token, *lasts= NULL; size_t rest= var_list.length; if (!var_list.str || var_list.length == 0) - { - buffer_length= 1; return false; - } if(!strcmp(var_list.str, "*")) { track_all= true; - buffer_length= 2; return false; } - buffer_length= var_list.length + 1; token= var_list.str; track_all= false; @@ -150,8 +141,7 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, token value. Hence the mutex is handled here to avoid a performance overhead. */ - if (!thd || take_mutex) - mysql_mutex_lock(&LOCK_plugin); + mysql_mutex_lock(&LOCK_plugin); for (;;) { sys_var *svar; @@ -196,14 +186,12 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, else break; } - if (!thd || take_mutex) - mysql_mutex_unlock(&LOCK_plugin); + mysql_mutex_unlock(&LOCK_plugin); return false; error: - if (!thd || take_mutex) - mysql_mutex_unlock(&LOCK_plugin); + mysql_mutex_unlock(&LOCK_plugin); return true; } @@ -361,6 +349,25 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, return false; } + +void Session_sysvars_tracker::init(THD *thd) +{ + DBUG_ASSERT(thd->variables.session_track_system_variables == + global_system_variables.session_track_system_variables); + DBUG_ASSERT(global_system_variables.session_track_system_variables); + thd->variables.session_track_system_variables= + my_strdup(global_system_variables.session_track_system_variables, + MYF(MY_WME | MY_THREAD_SPECIFIC)); +} + + +void Session_sysvars_tracker::deinit(THD *thd) +{ + my_free(thd->variables.session_track_system_variables); + thd->variables.session_track_system_variables= 0; +} + + /** Enable session tracker by parsing global value of tracked variables. @@ -372,21 +379,16 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, bool Session_sysvars_tracker::enable(THD *thd) { + LEX_STRING tmp= { thd->variables.session_track_system_variables, + safe_strlen(thd->variables.session_track_system_variables) }; orig_list.reinit(); - mysql_mutex_lock(&LOCK_plugin); - LEX_STRING tmp; - tmp.str= global_system_variables.session_track_system_variables; - tmp.length= safe_strlen(tmp.str); - if (orig_list.parse_var_list(thd, tmp, true, thd->charset(), false) == true) + if (orig_list.parse_var_list(thd, tmp, true, thd->charset()) == true) { - mysql_mutex_unlock(&LOCK_plugin); orig_list.reinit(); m_enabled= false; return true; } - mysql_mutex_unlock(&LOCK_plugin); m_enabled= true; - return false; } @@ -412,10 +414,28 @@ bool Session_sysvars_tracker::enable(THD *thd) bool Session_sysvars_tracker::update(THD *thd, set_var *var) { vars_list tool_list; - if (tool_list.parse_var_list(thd, var->save_result.string_value, true, - thd->charset(), true)) + void *copy= var->save_result.string_value.str ? + my_memdup(var->save_result.string_value.str, + var->save_result.string_value.length + 1, + MYF(MY_WME | MY_THREAD_SPECIFIC)) : + my_strdup("", MYF(MY_WME | MY_THREAD_SPECIFIC)); + + if (!copy) return true; + + if (tool_list.parse_var_list(thd, var->save_result.string_value, true, + thd->charset())) + { + my_free(copy); + return true; + } + + my_free(thd->variables.session_track_system_variables); + thd->variables.session_track_system_variables= static_cast(copy); + orig_list.copy(&tool_list, thd); + orig_list.construct_var_list(thd->variables.session_track_system_variables, + var->save_result.string_value.length + 1); return false; } @@ -562,7 +582,7 @@ bool sysvartrack_global_update(THD *thd, char *str, size_t len) { LEX_STRING tmp= { str, len }; Session_sysvars_tracker::vars_list dummy; - if (!dummy.parse_var_list(thd, tmp, false, system_charset_info, false)) + if (!dummy.parse_var_list(thd, tmp, false, system_charset_info)) { dummy.construct_var_list(str, len + 1); return false; @@ -571,27 +591,12 @@ bool sysvartrack_global_update(THD *thd, char *str, size_t len) } -uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base) -{ - Session_sysvars_tracker *tracker= static_cast - (thd->session_tracker.get_tracker(SESSION_SYSVARS_TRACKER)); - size_t len= tracker->get_buffer_length(); - char *res= (char*) thd->alloc(len + sizeof(char*)); - if (res) - { - char *buf= res + sizeof(char*); - *((char**) res)= buf; - tracker->construct_var_list(buf, len); - } - return (uchar*) res; -} - - int session_tracker_init() { + DBUG_ASSERT(global_system_variables.session_track_system_variables); if (sysvartrack_validate_value(0, global_system_variables.session_track_system_variables, - safe_strlen(global_system_variables.session_track_system_variables))) + strlen(global_system_variables.session_track_system_variables))) { sql_print_error("The variable session_track_system_variables has " "invalid values."); diff --git a/sql/session_tracker.h b/sql/session_tracker.h index 51e32dde639..55c78a75978 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -131,8 +131,6 @@ class Session_sysvars_tracker: public State_tracker user. */ HASH m_registered_sysvars; - /** Size of buffer for string representation */ - size_t buffer_length; /** If TRUE then we want to check all session variable. */ @@ -165,15 +163,9 @@ class Session_sysvars_tracker: public State_tracker my_hash_element(&m_registered_sysvars, i)); } public: - vars_list(): buffer_length(0), track_all(false) { init(); } + vars_list(): track_all(false) { init(); } void deinit() { free_hash(); } - size_t get_buffer_length() - { - DBUG_ASSERT(buffer_length != 0); // asked earlier then should - return buffer_length; - } - sysvar_node_st *insert_or_search(const sys_var *svar) { sysvar_node_st *res= search(svar); @@ -197,7 +189,7 @@ class Session_sysvars_tracker: public State_tracker } void copy(vars_list* from, THD *thd); bool parse_var_list(THD *thd, LEX_STRING var_list, bool throw_error, - CHARSET_INFO *char_set, bool take_mutex); + CHARSET_INFO *char_set); bool construct_var_list(char *buf, size_t buf_len); bool store(THD *thd, String *buf); }; @@ -208,15 +200,8 @@ class Session_sysvars_tracker: public State_tracker vars_list orig_list; public: - size_t get_buffer_length() - { - return orig_list.get_buffer_length(); - } - bool construct_var_list(char *buf, size_t buf_len) - { - return orig_list.construct_var_list(buf, buf_len); - } - + void init(THD *thd); + void deinit(THD *thd); bool enable(THD *thd); bool update(THD *thd, set_var *var); bool store(THD *thd, String *buf); @@ -232,7 +217,6 @@ public: bool sysvartrack_validate_value(THD *thd, const char *str, size_t len); bool sysvartrack_global_update(THD *thd, char *str, size_t len); -uchar *sysvartrack_session_value_ptr(THD *thd, const LEX_CSTRING *base); /** @@ -444,12 +428,6 @@ public: m_trackers[i]->enable(thd); } - /** Returns the pointer to the tracker object for the specified tracker. */ - inline State_tracker *get_tracker(enum_session_tracker tracker) const - { - return m_trackers[tracker]; - } - inline void mark_as_changed(THD *thd, enum enum_session_tracker tracker, LEX_CSTRING *data) { diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index b2ceb1627a1..d0682ecb151 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -3149,6 +3149,11 @@ void plugin_thdvar_init(THD *thd) thd->variables.enforced_table_plugin= NULL; cleanup_variables(&thd->variables); + /* This and all other variable cleanups are here for COM_CHANGE_USER :( */ +#ifndef EMBEDDED_LIBRARY + thd->session_tracker.sysvars.deinit(thd); +#endif + thd->variables= global_system_variables; /* we are going to allocate these lazily */ @@ -3170,6 +3175,9 @@ void plugin_thdvar_init(THD *thd) intern_plugin_unlock(NULL, old_enforced_table_plugin); mysql_mutex_unlock(&LOCK_plugin); +#ifndef EMBEDDED_LIBRARY + thd->session_tracker.sysvars.init(thd); +#endif DBUG_VOID_RETURN; } @@ -3235,6 +3243,10 @@ void plugin_thdvar_cleanup(THD *thd) plugin_ref *list; DBUG_ENTER("plugin_thdvar_cleanup"); +#ifndef EMBEDDED_LIBRARY + thd->session_tracker.sysvars.deinit(thd); +#endif + mysql_mutex_lock(&LOCK_plugin); unlock_variables(thd, &thd->variables); diff --git a/sql/sys_vars.ic b/sql/sys_vars.ic index 24fdc2d04a4..d8d95046cc2 100644 --- a/sql/sys_vars.ic +++ b/sql/sys_vars.ic @@ -641,8 +641,6 @@ public: DBUG_ASSERT(res == 0); } } - uchar *session_value_ptr(THD *thd, const LEX_CSTRING *base) - { return sysvartrack_session_value_ptr(thd, base); } }; #endif //EMBEDDED_LIBRARY From 53671a1fff8d4aa0978be2fb916f8e053c09424a Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 20 Mar 2019 01:32:10 +0400 Subject: [PATCH 37/43] Make connect speed great again Rather than parsing session_track_system_variables when thread starts, do it when first trackable event occurs. Benchmarked on a 2socket/20core/40threads Broadwell system using sysbench connect brencmark @40 threads (with select 1 disabled): 101379.77 -> 143016.68 CPS, whereas 10.2 is currently at 137766.31 CPS. Part of MDEV-14984 - regression in connect performance --- sql/log.cc | 2 ++ sql/session_tracker.cc | 27 ++++++++++++++++++--------- sql/session_tracker.h | 1 + sql/sql_class.cc | 1 + 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/sql/log.cc b/sql/log.cc index 92b2061d4bf..ac885746c62 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -7903,6 +7903,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) */ for (current= queue; current != NULL; current= current->next) { + set_current_thd(current->thd); binlog_cache_mngr *cache_mngr= current->cache_mngr; /* @@ -7938,6 +7939,7 @@ MYSQL_BIN_LOG::trx_group_commit_leader(group_commit_entry *leader) cache_mngr->delayed_error= false; } } + set_current_thd(leader->thd); bool synced= 0; if (unlikely(flush_and_sync(&synced))) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 8b0e247767c..db82b7dffe9 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -379,16 +379,10 @@ void Session_sysvars_tracker::deinit(THD *thd) bool Session_sysvars_tracker::enable(THD *thd) { - LEX_STRING tmp= { thd->variables.session_track_system_variables, - safe_strlen(thd->variables.session_track_system_variables) }; orig_list.reinit(); - if (orig_list.parse_var_list(thd, tmp, true, thd->charset()) == true) - { - orig_list.reinit(); - m_enabled= false; - return true; - } - m_enabled= true; + m_parsed= false; + m_enabled= thd->variables.session_track_system_variables && + *thd->variables.session_track_system_variables; return false; } @@ -433,6 +427,7 @@ bool Session_sysvars_tracker::update(THD *thd, set_var *var) my_free(thd->variables.session_track_system_variables); thd->variables.session_track_system_variables= static_cast(copy); + m_parsed= true; orig_list.copy(&tool_list, thd); orig_list.construct_var_list(thd->variables.session_track_system_variables, var->save_result.string_value.length + 1); @@ -540,6 +535,20 @@ void Session_sysvars_tracker::mark_as_changed(THD *thd, { sysvar_node_st *node; sys_var *svar= (sys_var *)var; + + if (!m_parsed) + { + DBUG_ASSERT(thd->variables.session_track_system_variables); + LEX_STRING tmp= { thd->variables.session_track_system_variables, + strlen(thd->variables.session_track_system_variables) }; + if (orig_list.parse_var_list(thd, tmp, true, thd->charset())) + { + orig_list.reinit(); + return; + } + m_parsed= true; + } + /* Check if the specified system variable is being tracked, if so mark it as changed and also set the class's m_changed flag. diff --git a/sql/session_tracker.h b/sql/session_tracker.h index 55c78a75978..b6694970c38 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -198,6 +198,7 @@ class Session_sysvars_tracker: public State_tracker various operations. */ vars_list orig_list; + bool m_parsed; public: void init(THD *thd); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 97233895fd5..da04ddad49c 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -7304,6 +7304,7 @@ void THD::set_last_commit_gtid(rpl_gtid >id) #ifndef EMBEDDED_LIBRARY if (changed_gtid && session_tracker.sysvars.is_enabled()) { + DBUG_ASSERT(current_thd == this); session_tracker.sysvars. mark_as_changed(this, (LEX_CSTRING*)Sys_last_gtid_ptr); } From 894df7edb67b888c41eae5ffbe654ceba97c6b8f Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Thu, 21 Mar 2019 00:42:48 +0400 Subject: [PATCH 38/43] Adieu find_sys_var_ex() Only take LOCK_plugin for plugin system variables. Reverted optimisation that was originally done for session tracker: it makes much less sense now. Specifically only if connections would want to track plugin session variables changes and these changes would actually happen frequently. If this ever becomes an issue, there're much better ways to optimise this workload. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.cc | 38 ++++---------------------------------- sql/set_var.h | 3 ++- sql/sql_lex.cc | 5 ++--- sql/sql_plugin.cc | 35 +++++++++-------------------------- sql/sql_plugin.h | 3 --- 5 files changed, 17 insertions(+), 67 deletions(-) diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index db82b7dffe9..63a6770f7d1 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -135,13 +135,6 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, token= var_list.str; track_all= false; - /* - If Lock to the plugin mutex is not acquired here itself, it results - in having to acquire it multiple times in find_sys_var_ex for each - token value. Hence the mutex is handled here to avoid a performance - overhead. - */ - mysql_mutex_lock(&LOCK_plugin); for (;;) { sys_var *svar; @@ -165,11 +158,10 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, { track_all= true; } - else if ((svar= - find_sys_var_ex(thd, var.str, var.length, throw_error, true))) + else if ((svar= find_sys_var(thd, var.str, var.length, throw_error))) { if (insert(svar) == TRUE) - goto error; + return true; } else if (throw_error && thd) { @@ -179,20 +171,14 @@ bool Session_sysvars_tracker::vars_list::parse_var_list(THD *thd, "be ignored.", (int)var.length, token); } else - goto error; + return true; if (lasts) token= lasts + 1; else break; } - mysql_mutex_unlock(&LOCK_plugin); - return false; - -error: - mysql_mutex_unlock(&LOCK_plugin); - return true; } @@ -211,14 +197,6 @@ bool sysvartrack_validate_value(THD *thd, const char *str, size_t len) token= var_list.str; - /* - If Lock to the plugin mutex is not acquired here itself, it results - in having to acquire it multiple times in find_sys_var_ex for each - token value. Hence the mutex is handled here to avoid a performance - overhead. - */ - if (!thd) - mysql_mutex_lock(&LOCK_plugin); for (;;) { LEX_CSTRING var; @@ -237,22 +215,14 @@ bool sysvartrack_validate_value(THD *thd, const char *str, size_t len) /* Remove leading/trailing whitespace. */ trim_whitespace(system_charset_info, &var); - if(!strcmp(var.str, "*") && - !find_sys_var_ex(thd, var.str, var.length, false, true)) - { - if (!thd) - mysql_mutex_unlock(&LOCK_plugin); + if (!strcmp(var.str, "*") && !find_sys_var(thd, var.str, var.length)) return true; - } if (lasts) token= lasts + 1; else break; } - if (!thd) - mysql_mutex_unlock(&LOCK_plugin); - return false; } diff --git a/sql/set_var.h b/sql/set_var.h index 6097b28e76f..6e673cffefb 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -398,7 +398,8 @@ extern SHOW_COMP_OPTION have_openssl; SHOW_VAR* enumerate_sys_vars(THD *thd, bool sorted, enum enum_var_type type); int fill_sysvars(THD *thd, TABLE_LIST *tables, COND *cond); -sys_var *find_sys_var(THD *thd, const char *str, size_t length=0); +sys_var *find_sys_var(THD *thd, const char *str, size_t length= 0, + bool throw_error= false); int sql_set_variables(THD *thd, List *var_list, bool free); #define SYSVAR_AUTOSIZE(VAR,VAL) \ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index b5ff060ecc6..6ce778d03cf 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -7254,8 +7254,7 @@ bool LEX::set_system_variable(THD *thd, enum_var_type var_type, { sys_var *tmp; if (unlikely(check_reserved_words(name1)) || - unlikely(!(tmp= find_sys_var_ex(thd, name2->str, name2->length, true, - false)))) + unlikely(!(tmp= find_sys_var(thd, name2->str, name2->length, true)))) { my_error(ER_UNKNOWN_STRUCTURED_VARIABLE, MYF(0), (int) name1->length, name1->str); @@ -7649,7 +7648,7 @@ int set_statement_var_if_exists(THD *thd, const char *var_name, my_error(ER_SP_BADSTATEMENT, MYF(0), "[NO]WAIT"); return 1; } - if ((sysvar= find_sys_var_ex(thd, var_name, var_name_length, true, false))) + if ((sysvar= find_sys_var(thd, var_name, var_name_length, true))) { Item *item= new (thd->mem_root) Item_uint(thd, value); set_var *var= new (thd->mem_root) set_var(thd, OPT_SESSION, sysvar, diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index d0682ecb151..b8aff064aca 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -2822,37 +2822,25 @@ static void update_func_double(THD *thd, struct st_mysql_sys_var *var, System Variables support ****************************************************************************/ -sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length, - bool throw_error, bool locked) +sys_var *find_sys_var(THD *thd, const char *str, size_t length, + bool throw_error) { sys_var *var; - sys_var_pluginvar *pi= NULL; - plugin_ref plugin; - DBUG_ENTER("find_sys_var_ex"); + sys_var_pluginvar *pi; + DBUG_ENTER("find_sys_var"); DBUG_PRINT("enter", ("var '%.*s'", (int)length, str)); - if (!locked) - mysql_mutex_lock(&LOCK_plugin); mysql_prlock_rdlock(&LOCK_system_variables_hash); if ((var= intern_find_sys_var(str, length)) && (pi= var->cast_pluginvar())) { - mysql_prlock_unlock(&LOCK_system_variables_hash); - LEX *lex= thd ? thd->lex : 0; - if (!(plugin= intern_plugin_lock(lex, plugin_int_to_ref(pi->plugin)))) + mysql_mutex_lock(&LOCK_plugin); + if (!intern_plugin_lock(thd ? thd->lex : 0, plugin_int_to_ref(pi->plugin), + PLUGIN_IS_READY)) var= NULL; /* failed to lock it, it must be uninstalling */ - else - if (!(plugin_state(plugin) & PLUGIN_IS_READY)) - { - /* initialization not completed */ - var= NULL; - intern_plugin_unlock(lex, plugin); - } - } - else - mysql_prlock_unlock(&LOCK_system_variables_hash); - if (!locked) mysql_mutex_unlock(&LOCK_plugin); + } + mysql_prlock_unlock(&LOCK_system_variables_hash); if (unlikely(!throw_error && !var)) my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), @@ -2861,11 +2849,6 @@ sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length, } -sys_var *find_sys_var(THD *thd, const char *str, size_t length) -{ - return find_sys_var_ex(thd, str, length, false, false); -} - /* called by register_var, construct_options and test_plugin_options. Returns the 'bookmark' for the named variable. diff --git a/sql/sql_plugin.h b/sql/sql_plugin.h index 4e899e18f9b..01ec0563050 100644 --- a/sql/sql_plugin.h +++ b/sql/sql_plugin.h @@ -196,9 +196,6 @@ extern void sync_dynamic_session_variables(THD* thd, bool global_lock); extern bool plugin_dl_foreach(THD *thd, const LEX_CSTRING *dl, plugin_foreach_func *func, void *arg); -sys_var *find_sys_var_ex(THD *thd, const char *str, size_t length, - bool throw_error, bool locked); - extern void sync_dynamic_session_variables(THD* thd, bool global_lock); #endif From 779fb636daf4c127dbb90f75bab004ac1bbe12df Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Wed, 20 Mar 2019 18:35:20 +0400 Subject: [PATCH 39/43] Revert THD::THD(skip_global_sys_var_lock) argument Originally introduced by e972125f1 to avoid harmless wait for LOCK_global_system_variables in a newly created thread, which creation was initiated by system variable update. At the same time it opens dangerous hole, when system variable update thread already released LOCK_global_system_variables and ack_receiver thread haven't yet completed new THD construction. In this case THD constructor goes completely unprotected. Since ack_receiver.stop() waits for the thread to go down, we have to temporarily release LOCK_global_system_variables so that it doesn't deadlock with ack_receiver.run(). Unfortunately it breaks atomicity of rpl_semi_sync_master_enabled updates and makes them not serialized. LOCK_rpl_semi_sync_master_enabled was introduced to workaround the above. TODO: move ack_receiver start/stop into repl_semisync_master enable_master/disable_master under LOCK_binlog protection? Part of MDEV-14984 - regression in connect performance --- sql/mysqld.cc | 2 ++ sql/semisync_master.cc | 11 ++++++----- sql/semisync_master.h | 8 +++++--- sql/semisync_master_ack_receiver.cc | 3 +-- sql/session_tracker.cc | 1 + sql/sql_class.cc | 12 +++++------- sql/sql_class.h | 11 +++-------- sql/sys_vars.cc | 10 ++++++---- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 73dd7ce36af..4f5026fd3b5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -941,6 +941,7 @@ PSI_mutex_key key_LOCK_relaylog_end_pos; PSI_mutex_key key_LOCK_thread_id; PSI_mutex_key key_LOCK_slave_state, key_LOCK_binlog_state, key_LOCK_rpl_thread, key_LOCK_rpl_thread_pool, key_LOCK_parallel_entry; +PSI_mutex_key key_LOCK_rpl_semi_sync_master_enabled; PSI_mutex_key key_LOCK_binlog; PSI_mutex_key key_LOCK_stats, @@ -1038,6 +1039,7 @@ static PSI_mutex_info all_server_mutexes[]= { &key_LOCK_rpl_thread_pool, "LOCK_rpl_thread_pool", 0}, { &key_LOCK_parallel_entry, "LOCK_parallel_entry", 0}, { &key_LOCK_ack_receiver, "Ack_receiver::mutex", 0}, + { &key_LOCK_rpl_semi_sync_master_enabled, "LOCK_rpl_semi_sync_master_enabled", 0}, { &key_LOCK_binlog, "LOCK_binlog", 0} }; diff --git a/sql/semisync_master.cc b/sql/semisync_master.cc index 4e37e3af58d..f9fb4d9147d 100644 --- a/sql/semisync_master.cc +++ b/sql/semisync_master.cc @@ -352,7 +352,7 @@ Repl_semi_sync_master::Repl_semi_sync_master() int Repl_semi_sync_master::init_object() { - int result; + int result= 0; m_init_done = true; @@ -362,6 +362,8 @@ int Repl_semi_sync_master::init_object() set_wait_point(rpl_semi_sync_master_wait_point); /* Mutex initialization can only be done after MY_INIT(). */ + mysql_mutex_init(key_LOCK_rpl_semi_sync_master_enabled, + &LOCK_rpl_semi_sync_master_enabled, MY_MUTEX_INIT_FAST); mysql_mutex_init(key_LOCK_binlog, &LOCK_binlog, MY_MUTEX_INIT_FAST); mysql_cond_init(key_COND_binlog_send, @@ -383,7 +385,7 @@ int Repl_semi_sync_master::init_object() } else { - result = disable_master(); + disable_master(); } return result; @@ -421,7 +423,7 @@ int Repl_semi_sync_master::enable_master() return result; } -int Repl_semi_sync_master::disable_master() +void Repl_semi_sync_master::disable_master() { /* Must have the lock when we do enable of disable. */ lock(); @@ -446,14 +448,13 @@ int Repl_semi_sync_master::disable_master() } unlock(); - - return 0; } void Repl_semi_sync_master::cleanup() { if (m_init_done) { + mysql_mutex_destroy(&LOCK_rpl_semi_sync_master_enabled); mysql_mutex_destroy(&LOCK_binlog); mysql_cond_destroy(&COND_binlog_send); m_init_done= 0; diff --git a/sql/semisync_master.h b/sql/semisync_master.h index de5e3240802..517175b5b06 100644 --- a/sql/semisync_master.h +++ b/sql/semisync_master.h @@ -23,6 +23,7 @@ #include "semisync_master_ack_receiver.h" #ifdef HAVE_PSI_INTERFACE +extern PSI_mutex_key key_LOCK_rpl_semi_sync_master_enabled; extern PSI_mutex_key key_LOCK_binlog; extern PSI_cond_key key_COND_binlog_send; #endif @@ -365,7 +366,6 @@ public: */ class Repl_semi_sync_master :public Repl_semi_sync_base { - private: Active_tranx *m_active_tranxs; /* active transaction list: the list will be cleared when semi-sync switches off. */ @@ -491,8 +491,8 @@ class Repl_semi_sync_master /* Enable the object to enable semi-sync replication inside the master. */ int enable_master(); - /* Enable the object to enable semi-sync replication inside the master. */ - int disable_master(); + /* Disable the object to disable semi-sync replication inside the master. */ + void disable_master(); /* Add a semi-sync replication slave */ void add_slave(); @@ -619,6 +619,8 @@ class Repl_semi_sync_master int before_reset_master(); void check_and_switch(); + + mysql_mutex_t LOCK_rpl_semi_sync_master_enabled; }; enum rpl_semi_sync_master_wait_point_t { diff --git a/sql/semisync_master_ack_receiver.cc b/sql/semisync_master_ack_receiver.cc index 607d4844658..81f494c9d34 100644 --- a/sql/semisync_master_ack_receiver.cc +++ b/sql/semisync_master_ack_receiver.cc @@ -185,8 +185,7 @@ static void init_net(NET *net, unsigned char *buff, unsigned int buff_len) void Ack_receiver::run() { - // skip LOCK_global_system_variables due to the 3rd arg - THD *thd= new THD(next_thread_id(), false, true); + THD *thd= new THD(next_thread_id()); NET net; unsigned char net_buff[REPLY_MESSAGE_MAX_LENGTH]; diff --git a/sql/session_tracker.cc b/sql/session_tracker.cc index 63a6770f7d1..f4dab11bb42 100644 --- a/sql/session_tracker.cc +++ b/sql/session_tracker.cc @@ -322,6 +322,7 @@ bool Session_sysvars_tracker::vars_list::construct_var_list(char *buf, void Session_sysvars_tracker::init(THD *thd) { + mysql_mutex_assert_owner(&LOCK_global_system_variables); DBUG_ASSERT(thd->variables.session_track_system_variables == global_system_variables.session_track_system_variables); DBUG_ASSERT(global_system_variables.session_track_system_variables); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index da04ddad49c..2eebfbb6db0 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -597,7 +597,7 @@ extern "C" void thd_kill_timeout(THD* thd) thd->awake(KILL_TIMEOUT); } -THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock) +THD::THD(my_thread_id id, bool is_wsrep_applier) :Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION, /* statement id */ 0), rli_fake(0), rgi_fake(0), rgi_slave(NULL), @@ -792,7 +792,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier, bool skip_global_sys_var_lock) /* Call to init() below requires fully initialized Open_tables_state. */ reset_open_tables_state(this); - init(skip_global_sys_var_lock); + init(); #if defined(ENABLED_PROFILING) profiling.set_thd(this); #endif @@ -1167,11 +1167,10 @@ const Type_handler *THD::type_handler_for_date() const Init common variables that has to be reset on start and on change_user */ -void THD::init(bool skip_lock) +void THD::init() { DBUG_ENTER("thd::init"); - if (!skip_lock) - mysql_mutex_lock(&LOCK_global_system_variables); + mysql_mutex_lock(&LOCK_global_system_variables); plugin_thdvar_init(this); /* plugin_thd_var_init() sets variables= global_system_variables, which @@ -1184,8 +1183,7 @@ void THD::init(bool skip_lock) ::strmake(default_master_connection_buff, global_system_variables.default_master_connection.str, variables.default_master_connection.length); - if (!skip_lock) - mysql_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_unlock(&LOCK_global_system_variables); user_time.val= start_time= start_time_sec_part= 0; diff --git a/sql/sql_class.h b/sql/sql_class.h index e1119757957..221e453eab5 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -3263,17 +3263,12 @@ public: /** @param id thread identifier @param is_wsrep_applier thread type - @param skip_lock instruct whether @c LOCK_global_system_variables - is already locked, to not acquire it then. */ - THD(my_thread_id id, bool is_wsrep_applier= false, bool skip_lock= false); + THD(my_thread_id id, bool is_wsrep_applier= false); ~THD(); - /** - @param skip_lock instruct whether @c LOCK_global_system_variables - is already locked, to not acquire it then. - */ - void init(bool skip_lock= false); + + void init(); /* Initialize memory roots necessary for query processing and (!) pre-allocate memory for it. We can't do that in THD constructor because diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 004fd4baecb..185078ff363 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -3144,6 +3144,8 @@ static Sys_var_replicate_events_marked_for_skip Replicate_events_marked_for_skip static bool fix_rpl_semi_sync_master_enabled(sys_var *self, THD *thd, enum_var_type type) { + mysql_mutex_unlock(&LOCK_global_system_variables); + mysql_mutex_lock(&repl_semisync_master.LOCK_rpl_semi_sync_master_enabled); if (rpl_semi_sync_master_enabled) { if (repl_semisync_master.enable_master() != 0) @@ -3156,11 +3158,11 @@ static bool fix_rpl_semi_sync_master_enabled(sys_var *self, THD *thd, } else { - if (repl_semisync_master.disable_master() != 0) - rpl_semi_sync_master_enabled= true; - if (!rpl_semi_sync_master_enabled) - ack_receiver.stop(); + repl_semisync_master.disable_master(); + ack_receiver.stop(); } + mysql_mutex_unlock(&repl_semisync_master.LOCK_rpl_semi_sync_master_enabled); + mysql_mutex_lock(&LOCK_global_system_variables); return false; } From bcc1359223c254e7649383c0993b6d27d5002c5d Mon Sep 17 00:00:00 2001 From: Eugene Kosov Date: Sat, 16 Mar 2019 21:06:04 +0300 Subject: [PATCH 40/43] MDEV-17702 fix unaligned access UB in sint4korr() and similar functions Disable (hopefully temprorary) this check. Also add tests for some serialized functions. --- CMakeLists.txt | 2 +- unittest/mysys/CMakeLists.txt | 2 +- unittest/mysys/byte_order-t.c | 102 ++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 unittest/mysys/byte_order-t.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 03ab7216bad..f2397d29968 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -217,7 +217,7 @@ IF (WITH_UBSAN) IF(SECURITY_HARDENED) MESSAGE(FATAL_ERROR "WITH_UBSAN and SECURITY_HARDENED are mutually exclusive") ENDIF() - MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=undefined" DEBUG RELWITHDEBINFO) + MY_CHECK_AND_SET_COMPILER_FLAG("-fsanitize=undefined -fno-sanitize=alignment" DEBUG RELWITHDEBINFO) ENDIF() diff --git a/unittest/mysys/CMakeLists.txt b/unittest/mysys/CMakeLists.txt index 0c61ff09af2..3be57e27943 100644 --- a/unittest/mysys/CMakeLists.txt +++ b/unittest/mysys/CMakeLists.txt @@ -14,7 +14,7 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA MY_ADD_TESTS(bitmap base64 my_atomic my_rdtsc lf my_malloc my_getopt dynstring - aes + aes byte_order LINK_LIBRARIES mysys) MY_ADD_TESTS(my_vsnprintf LINK_LIBRARIES strings mysys) diff --git a/unittest/mysys/byte_order-t.c b/unittest/mysys/byte_order-t.c new file mode 100644 index 00000000000..e276e597fbf --- /dev/null +++ b/unittest/mysys/byte_order-t.c @@ -0,0 +1,102 @@ +/* Copyright (c) 2019, MariaDB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + 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-1301 USA */ + +/** + @file + + Unit tests for serialization and deserialization functions +*/ + +#include "tap.h" + +#include "my_byteorder.h" +#include "myisampack.h" +#include "m_string.h" + +void test_byte_order() +{ + MY_ALIGNED(CPU_LEVEL1_DCACHE_LINESIZE) + uchar buf[CPU_LEVEL1_DCACHE_LINESIZE * 2]; + + uchar *aligned= buf; + uchar *not_aligned= buf + CPU_LEVEL1_DCACHE_LINESIZE - 1; + +#define TEST(STORE_NAME, LOAD_NAME, TYPE, VALUE, BYTES) \ + { \ + TYPE value= VALUE; \ + uchar bytes[]= BYTES; \ + STORE_NAME(aligned, value); \ + ok(!memcmp(aligned, bytes, sizeof(bytes)), "aligned\t\t" #STORE_NAME); \ + ok(LOAD_NAME(aligned) == value, "aligned\t\t" #LOAD_NAME); \ + STORE_NAME(not_aligned, value); \ + ok(!memcmp(not_aligned, bytes, sizeof(bytes)), \ + "not aligned\t" #STORE_NAME); \ + ok(LOAD_NAME(not_aligned) == value, "not aligned\t" #LOAD_NAME); \ + } + +#define ARRAY_2(A, B) {A, B} +#define ARRAY_3(A, B, C) {A, B, C} +#define ARRAY_4(A, B, C, D) {A, B, C, D} +#define ARRAY_5(A, B, C, D, E) {A, B, C, D, E} +#define ARRAY_6(A, B, C, D, E, F) {A, B, C, D, E, F} +#define ARRAY_7(A, B, C, D, E, F, G) {A, B, C, D, E, F, G} +#define ARRAY_8(A, B, C, D, E, F, G, H) {A, B, C, D, E, F, G, H} + + TEST(int2store, sint2korr, int16, 0x0201, ARRAY_2(1, 2)); + TEST(int3store, sint3korr, int32, 0xffffffff, ARRAY_3(0xff, 0xff, 0xff)); + TEST(int3store, sint3korr, int32, 0x030201, ARRAY_3(1, 2, 3)); + TEST(int4store, sint4korr, int32, 0xffffffff, + ARRAY_4(0xff, 0xff, 0xff, 0xff)); + TEST(int4store, sint4korr, int32, 0x04030201, ARRAY_4(1, 2, 3, 4)); + TEST(int8store, sint8korr, longlong, 0x0807060504030201, + ARRAY_8(1, 2, 3, 4, 5, 6, 7, 8)); + TEST(int8store, sint8korr, longlong, 0xffffffffffffffff, + ARRAY_8(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff)); + + TEST(int2store, uint2korr, uint16, 0x0201, ARRAY_2(1, 2)); + TEST(int3store, uint3korr, uint32, 0x030201, ARRAY_3(1, 2, 3)); + TEST(int4store, uint4korr, uint32, 0x04030201, ARRAY_4(1, 2, 3, 4)); + TEST(int5store, uint5korr, ulonglong, 0x0504030201, ARRAY_5(1, 2, 3, 4, 5)); + TEST(int6store, uint6korr, ulonglong, 0x060504030201, + ARRAY_6(1, 2, 3, 4, 5, 6)); + TEST(int8store, uint8korr, ulonglong, 0x0807060504030201, + ARRAY_8(1, 2, 3, 4, 5, 6, 7, 8)); + + TEST(mi_int5store, mi_uint5korr, ulonglong, 0x0504030201, + ARRAY_5(5, 4, 3, 2, 1)); + TEST(mi_int6store, mi_uint6korr, ulonglong, 0x060504030201, + ARRAY_6(6, 5, 4, 3, 2, 1)); + TEST(mi_int7store, mi_uint7korr, ulonglong, 0x07060504030201, + ARRAY_7(7, 6, 5, 4, 3, 2, 1)); + TEST(mi_int8store, mi_uint8korr, ulonglong, 0x0807060504030201, + ARRAY_8(8, 7, 6, 5, 4, 3, 2, 1)); + +#undef ARRAY_8 +#undef ARRAY_7 +#undef ARRAY_6 +#undef ARRAY_5 +#undef ARRAY_4 +#undef ARRAY_3 +#undef ARRAY_2 + +#undef TEST +} + +int main(int argc, char **argv) +{ + plan(68); + test_byte_order(); + return exit_status(); +} From 3db94d2403c1f2791bddd43656d7b0d6320b453d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 3 May 2019 20:02:11 +0300 Subject: [PATCH 41/43] MDEV-19346: Remove dummy InnoDB log checkpoints log_checkpoint(), log_make_checkpoint_at(): Remove the parameter write_always. It seems that the primary purpose of this parameter was to ensure in the function recv_reset_logs() that both checkpoint header pages will be overwritten, when the function is called from the never-enabled function recv_recovery_from_archive_start(). create_log_files(): Merge recv_reset_logs() to its only caller. Debug instrumentation: Prefer to flush the redo log, instead of triggering a redo log checkpoint. page_header_set_field(): Disable a debug assertion that will always fail due to MDEV-19344, now that we no longer initiate a redo log checkpoint before an injected crash. In recv_reset_logs() there used to be two calls to log_make_checkpoint_at(). The apparent purpose of this was to ensure that both InnoDB redo log checkpoint header pages will be initialized or overwritten. The second call was removed (without any explanation) in MySQL 5.6.3: mysql/mysql-server@4ca37968da54ddc6b3b6628f41428ddba1c79bb8 In MySQL 5.6.8 WL#6494, starting with mysql/mysql-server@00a0ba8ad92569fcf08212b3b8cf046dc8a0ce10 the function recv_reset_logs() was not only invoked during InnoDB data file initialization, but also during a regular startup when the redo log is being resized. mysql/mysql-server@45e91679832219e2593c77185342f11f85232b58 in MySQL 5.7.2 removed the UNIV_LOG_ARCHIVE code, but still did not remove the parameter write_always. --- storage/innobase/buf/buf0dblwr.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/handler/handler0alter.cc | 1 - storage/innobase/include/log0log.h | 18 ++------ storage/innobase/include/log0recv.h | 10 ----- storage/innobase/include/page0page.ic | 2 + storage/innobase/log/log0log.cc | 50 ++++++++--------------- storage/innobase/log/log0recv.cc | 48 ---------------------- storage/innobase/row/row0import.cc | 2 +- storage/innobase/row/row0ins.cc | 3 +- storage/innobase/row/row0mysql.cc | 4 +- storage/innobase/row/row0trunc.cc | 4 +- storage/innobase/srv/srv0srv.cc | 4 +- storage/innobase/srv/srv0start.cc | 23 ++++++++++- storage/innobase/trx/trx0trx.cc | 3 +- 15 files changed, 56 insertions(+), 120 deletions(-) diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc index 194cc848234..200a65ba6ef 100644 --- a/storage/innobase/buf/buf0dblwr.cc +++ b/storage/innobase/buf/buf0dblwr.cc @@ -328,7 +328,7 @@ too_small: mtr_commit(&mtr); /* Flush the modified pages to disk and make a checkpoint */ - log_make_checkpoint_at(LSN_MAX, TRUE); + log_make_checkpoint_at(LSN_MAX); /* Remove doublewrite pages from LRU */ buf_pool_invalidate(); diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ecf85a81638..18158eae595 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -19110,7 +19110,7 @@ checkpoint_now_set( + (log_sys->append_on_checkpoint != NULL ? log_sys->append_on_checkpoint->size() : 0) < log_sys->lsn) { - log_make_checkpoint_at(LSN_MAX, TRUE); + log_make_checkpoint_at(LSN_MAX); fil_flush_file_spaces(FIL_TYPE_LOG); } diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc index 05bb8ac61cd..005c0fd5adf 100644 --- a/storage/innobase/handler/handler0alter.cc +++ b/storage/innobase/handler/handler0alter.cc @@ -8474,7 +8474,6 @@ ha_innobase::commit_inplace_alter_table( and the .frm files must be swapped manually by the administrator. No loss of data. */ DBUG_EXECUTE_IF("innodb_alter_commit_crash_after_commit", - log_make_checkpoint_at(LSN_MAX, TRUE); log_buffer_flush_to_disk(); DBUG_SUICIDE();); } diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h index 745714e791b..817cf8e8a61 100644 --- a/storage/innobase/include/log0log.h +++ b/storage/innobase/include/log0log.h @@ -2,7 +2,7 @@ Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved. Copyright (c) 2009, Google Inc. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, MariaDB Corporation. Portions of this file contain modifications contributed and copyrighted by Google, Inc. Those modifications are gratefully acknowledged and are described @@ -208,23 +208,13 @@ blocks from the buffer pool: it only checks what is lsn of the oldest modification in the pool, and writes information about the lsn in log files. Use log_make_checkpoint_at() to flush also the pool. @param[in] sync whether to wait for the write to complete -@param[in] write_always force a write even if no log -has been generated since the latest checkpoint @return true if success, false if a checkpoint write was already running */ -bool -log_checkpoint( - bool sync, - bool write_always); +bool log_checkpoint(bool sync); /** Make a checkpoint at or after a specified LSN. @param[in] lsn the log sequence number, or LSN_MAX -for the latest LSN -@param[in] write_always force a write even if no log -has been generated since the latest checkpoint */ -void -log_make_checkpoint_at( - lsn_t lsn, - bool write_always); +for the latest LSN */ +void log_make_checkpoint_at(lsn_t lsn); /****************************************************************//** Makes a checkpoint at the latest lsn and writes it to first page of each diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h index daa8e85fbf5..7526999a1e4 100644 --- a/storage/innobase/include/log0recv.h +++ b/storage/innobase/include/log0recv.h @@ -69,16 +69,6 @@ Initiates the rollback of active transactions. */ void recv_recovery_rollback_active(void); /*===============================*/ -/******************************************************//** -Resets the logs. The contents of log files will be lost! */ -void -recv_reset_logs( -/*============*/ - lsn_t lsn); /*!< in: reset to this lsn - rounded up to be divisible by - OS_FILE_LOG_BLOCK_SIZE, after - which we add - LOG_BLOCK_HDR_SIZE */ /** Clean up after recv_sys_init() */ void recv_sys_close(); diff --git a/storage/innobase/include/page0page.ic b/storage/innobase/include/page0page.ic index d6fded4f178..76d041347fb 100644 --- a/storage/innobase/include/page0page.ic +++ b/storage/innobase/include/page0page.ic @@ -173,7 +173,9 @@ page_header_set_field( { ut_ad(page); ut_ad(field <= PAGE_N_RECS); +#if 0 /* FIXME: MDEV-19344 hits this */ ut_ad(field != PAGE_N_RECS || val); +#endif ut_ad(field == PAGE_N_HEAP || val < srv_page_size); ut_ad(field != PAGE_N_HEAP || (val & 0x7fff) < srv_page_size); diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc index 3a54af8e3c2..da301a3b4f1 100644 --- a/storage/innobase/log/log0log.cc +++ b/storage/innobase/log/log0log.cc @@ -337,7 +337,7 @@ log_margin_checkpoint_age( if (!flushed_enough) { os_thread_sleep(100000); } - log_checkpoint(true, false); + log_checkpoint(true); log_mutex_enter(); } @@ -1610,13 +1610,8 @@ blocks from the buffer pool: it only checks what is lsn of the oldest modification in the pool, and writes information about the lsn in log files. Use log_make_checkpoint_at() to flush also the pool. @param[in] sync whether to wait for the write to complete -@param[in] write_always force a write even if no log -has been generated since the latest checkpoint @return true if success, false if a checkpoint write was already running */ -bool -log_checkpoint( - bool sync, - bool write_always) +bool log_checkpoint(bool sync) { lsn_t oldest_lsn; @@ -1657,9 +1652,15 @@ log_checkpoint( flushed up to oldest_lsn. */ ut_ad(oldest_lsn >= log_sys->last_checkpoint_lsn); - if (!write_always - && oldest_lsn - <= log_sys->last_checkpoint_lsn + SIZE_OF_MLOG_CHECKPOINT) { + if (oldest_lsn + > log_sys->last_checkpoint_lsn + SIZE_OF_MLOG_CHECKPOINT) { + /* Some log has been written since the previous checkpoint. */ + } else if (srv_shutdown_state != SRV_SHUTDOWN_NONE) { + /* MariaDB 10.3 startup expects the redo log file to be + logically empty (not even containing a MLOG_CHECKPOINT record) + after a clean shutdown. Perform an extra checkpoint at + shutdown. */ + } else { /* Do nothing, because nothing was logged (other than a MLOG_CHECKPOINT marker) since the previous checkpoint. */ log_mutex_exit(); @@ -1691,20 +1692,6 @@ log_checkpoint( log_write_up_to(flush_lsn, true); - DBUG_EXECUTE_IF( - "using_wa_checkpoint_middle", - if (write_always) { - DEBUG_SYNC_C("wa_checkpoint_middle"); - - const my_bool b = TRUE; - buf_flush_page_cleaner_disabled_debug_update( - NULL, NULL, NULL, &b); - dict_stats_disabled_debug_update( - NULL, NULL, NULL, &b); - srv_master_thread_disabled_debug_update( - NULL, NULL, NULL, &b); - }); - log_mutex_enter(); ut_ad(log_sys->flushed_to_disk_lsn >= flush_lsn); @@ -1737,13 +1724,8 @@ log_checkpoint( /** Make a checkpoint at or after a specified LSN. @param[in] lsn the log sequence number, or LSN_MAX -for the latest LSN -@param[in] write_always force a write even if no log -has been generated since the latest checkpoint */ -void -log_make_checkpoint_at( - lsn_t lsn, - bool write_always) +for the latest LSN */ +void log_make_checkpoint_at(lsn_t lsn) { /* Preflush pages synchronously */ @@ -1751,7 +1733,7 @@ log_make_checkpoint_at( /* Flush as much as we can */ } - while (!log_checkpoint(true, write_always)) { + while (!log_checkpoint(true)) { /* Force a checkpoint */ } } @@ -1834,7 +1816,7 @@ loop: } if (do_checkpoint) { - log_checkpoint(checkpoint_sync, FALSE); + log_checkpoint(checkpoint_sync); if (checkpoint_sync) { @@ -2083,7 +2065,7 @@ wait_suspend_loop: if (!srv_read_only_mode) { service_manager_extend_timeout(INNODB_EXTEND_TIMEOUT_INTERVAL, "ensuring dirty buffer pool are written to log"); - log_make_checkpoint_at(LSN_MAX, TRUE); + log_make_checkpoint_at(LSN_MAX); log_mutex_enter(); diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc index 251ee2435f5..60279e7fc90 100644 --- a/storage/innobase/log/log0recv.cc +++ b/storage/innobase/log/log0recv.cc @@ -2849,11 +2849,6 @@ loop: if (lsn == checkpoint_lsn) { if (recv_sys->mlog_checkpoint_lsn) { - /* At recv_reset_logs() we may - write a duplicate MLOG_CHECKPOINT - for the same checkpoint LSN. Thus - recv_sys->mlog_checkpoint_lsn - can differ from the current LSN. */ ut_ad(recv_sys->mlog_checkpoint_lsn <= recv_sys->recovered_lsn); break; @@ -4016,49 +4011,6 @@ recv_recovery_rollback_active(void) } } -/******************************************************//** -Resets the logs. The contents of log files will be lost! */ -void -recv_reset_logs( -/*============*/ - lsn_t lsn) /*!< in: reset to this lsn - rounded up to be divisible by - OS_FILE_LOG_BLOCK_SIZE, after - which we add - LOG_BLOCK_HDR_SIZE */ -{ - ut_ad(log_mutex_own()); - - log_sys->lsn = ut_uint64_align_up(lsn, OS_FILE_LOG_BLOCK_SIZE); - - log_sys->log.lsn = log_sys->lsn; - log_sys->log.lsn_offset = LOG_FILE_HDR_SIZE; - - log_sys->buf_next_to_write = 0; - log_sys->write_lsn = log_sys->lsn; - - log_sys->next_checkpoint_no = 0; - log_sys->last_checkpoint_lsn = 0; - - memset(log_sys->buf, 0, log_sys->buf_size); - log_block_init(log_sys->buf, log_sys->lsn); - log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE); - - log_sys->buf_free = LOG_BLOCK_HDR_SIZE; - log_sys->lsn += LOG_BLOCK_HDR_SIZE; - - MONITOR_SET(MONITOR_LSN_CHECKPOINT_AGE, - (log_sys->lsn - log_sys->last_checkpoint_lsn)); - - log_mutex_exit(); - - /* Reset the checkpoint fields in logs */ - - log_make_checkpoint_at(LSN_MAX, TRUE); - - log_mutex_enter(); -} - /** Find a doublewrite copy of a page. @param[in] space_id tablespace identifier @param[in] page_no page number diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc index 159535fba19..94c6d12b19e 100644 --- a/storage/innobase/row/row0import.cc +++ b/storage/innobase/row/row0import.cc @@ -2090,7 +2090,7 @@ row_import_cleanup( DBUG_EXECUTE_IF("ib_import_before_checkpoint_crash", DBUG_SUICIDE();); - log_make_checkpoint_at(LSN_MAX, TRUE); + log_make_checkpoint_at(LSN_MAX); return(err); } diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 03665ccdc3c..8bfef78cd8c 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -2722,8 +2722,7 @@ err_exit: DBUG_EXECUTE_IF( "row_ins_extern_checkpoint", - log_make_checkpoint_at( - LSN_MAX, TRUE);); + log_write_up_to(mtr.commit_lsn(), true);); err = row_ins_index_entry_big_rec( entry, big_rec, offsets, &offsets_heap, index, thr_get_trx(thr)->mysql_thd); diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc index e19501edea4..a06c3cbd1a8 100644 --- a/storage/innobase/row/row0mysql.cc +++ b/storage/innobase/row/row0mysql.cc @@ -2882,13 +2882,13 @@ row_discard_tablespace_end( } DBUG_EXECUTE_IF("ib_discard_before_commit_crash", - log_make_checkpoint_at(LSN_MAX, TRUE); + log_write_up_to(LSN_MAX, true); DBUG_SUICIDE();); trx_commit_for_mysql(trx); DBUG_EXECUTE_IF("ib_discard_after_commit_crash", - log_make_checkpoint_at(LSN_MAX, TRUE); + log_write_up_to(LSN_MAX, true); DBUG_SUICIDE();); row_mysql_unlock_data_dictionary(trx); diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc index 847b0d0ae06..cffcc73f312 100644 --- a/storage/innobase/row/row0trunc.cc +++ b/storage/innobase/row/row0trunc.cc @@ -1996,7 +1996,7 @@ dberr_t row_truncate_table_for_mysql(dict_table_t* table, trx_t* trx) DBUG_EXECUTE_IF("ib_trunc_crash_with_intermediate_log_checkpoint", log_buffer_flush_to_disk(); os_thread_sleep(2000000); - log_checkpoint(TRUE, TRUE); + log_checkpoint(TRUE); os_thread_sleep(1000000); DBUG_SUICIDE();); @@ -2224,7 +2224,7 @@ truncate_t::fixup_tables_in_non_system_tablespace() if (err == DB_SUCCESS && s_tables.size() > 0) { - log_make_checkpoint_at(LSN_MAX, TRUE); + log_make_checkpoint_at(LSN_MAX); } for (ulint i = 0; i < s_tables.size(); ++i) { diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc index 58596175681..b704d495946 100644 --- a/storage/innobase/srv/srv0srv.cc +++ b/storage/innobase/srv/srv0srv.cc @@ -2261,7 +2261,7 @@ srv_master_do_active_tasks(void) /* Make a new checkpoint */ if (cur_time % SRV_MASTER_CHECKPOINT_INTERVAL == 0) { srv_main_thread_op_info = "making checkpoint"; - log_checkpoint(TRUE, FALSE); + log_checkpoint(true); MONITOR_INC_TIME_IN_MICRO_SECS( MONITOR_SRV_CHECKPOINT_MICROSECOND, counter_time); } @@ -2349,7 +2349,7 @@ srv_master_do_idle_tasks(void) /* Make a new checkpoint */ srv_main_thread_op_info = "making checkpoint"; - log_checkpoint(TRUE, FALSE); + log_checkpoint(true); MONITOR_INC_TIME_IN_MICRO_SECS(MONITOR_SRV_CHECKPOINT_MICROSECOND, counter_time); } diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc index d75310607b3..95d1433f09c 100644 --- a/storage/innobase/srv/srv0start.cc +++ b/storage/innobase/srv/srv0start.cc @@ -495,9 +495,30 @@ create_log_files( return(DB_ERROR); } ut_d(recv_no_log_write = false); - recv_reset_logs(lsn); + log_sys->lsn = ut_uint64_align_up(lsn, OS_FILE_LOG_BLOCK_SIZE); + + log_sys->log.lsn = log_sys->lsn; + log_sys->log.lsn_offset = LOG_FILE_HDR_SIZE; + + log_sys->buf_next_to_write = 0; + log_sys->write_lsn = log_sys->lsn; + + log_sys->next_checkpoint_no = 0; + log_sys->last_checkpoint_lsn = 0; + + memset(log_sys->buf, 0, log_sys->buf_size); + log_block_init(log_sys->buf, log_sys->lsn); + log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE); + + log_sys->buf_free = LOG_BLOCK_HDR_SIZE; + log_sys->lsn += LOG_BLOCK_HDR_SIZE; + + MONITOR_SET(MONITOR_LSN_CHECKPOINT_AGE, + (log_sys->lsn - log_sys->last_checkpoint_lsn)); log_mutex_exit(); + log_make_checkpoint_at(LSN_MAX); + return(DB_SUCCESS); } diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc index 91e60571438..88e9313cc06 100644 --- a/storage/innobase/trx/trx0trx.cc +++ b/storage/innobase/trx/trx0trx.cc @@ -1859,7 +1859,8 @@ trx_commit_low( DBUG_EXECUTE_IF("ib_crash_during_trx_commit_in_mem", if (trx->has_logged()) { - log_make_checkpoint_at(LSN_MAX, TRUE); + log_write_up_to(mtr->commit_lsn(), + true); DBUG_SUICIDE(); }); /*--------------*/ From ce195987c3c995470992f16ca7a985796d6b65a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= Date: Fri, 3 May 2019 16:47:07 +0300 Subject: [PATCH 42/43] MDEV-19385: Inconsistent definition of dtuple_get_nth_v_field() The accessor dtuple_get_nth_v_field() was defined differently between debug and release builds in MySQL 5.7.8 in mysql/mysql-server@c47e1751b742454de553937039bbf2bcbe3c6bc7 and a debug assertion to document or enforce the questionable assumption tuple->v_fields == &tuple->fields[tuple->n_fields] was missing. This was apparently no problem until MDEV-11369 introduced instant ADD COLUMN to MariaDB Server 10.3. With that work present, in one test case, trx_undo_report_insert_virtual() could in release builds fetch the wrong value for a virtual column. We replace many of the dtuple_t accessors with const-preserving inline functions, and fix missing or misleadingly applied const qualifiers accordingly. --- storage/innobase/data/data0data.cc | 4 +- storage/innobase/fts/fts0fts.cc | 3 +- storage/innobase/gis/gis0geo.cc | 23 ++-- storage/innobase/gis/gis0rtree.cc | 9 +- storage/innobase/gis/gis0sea.cc | 6 +- storage/innobase/handler/ha_innodb.cc | 2 +- storage/innobase/include/data0data.h | 179 +++++++++++--------------- storage/innobase/include/data0data.ic | 155 +--------------------- storage/innobase/include/gis0geo.h | 3 +- storage/innobase/include/rem0cmp.ic | 4 +- storage/innobase/include/row0mysql.h | 2 +- storage/innobase/include/row0vers.h | 6 +- storage/innobase/include/trx0rec.h | 6 +- storage/innobase/rem/rem0rec.cc | 4 +- storage/innobase/row/row0ins.cc | 4 +- storage/innobase/row/row0merge.cc | 15 +-- storage/innobase/row/row0row.cc | 16 +-- storage/innobase/row/row0sel.cc | 20 +-- storage/innobase/row/row0upd.cc | 30 ++--- storage/innobase/row/row0vers.cc | 22 ++-- storage/innobase/trx/trx0rec.cc | 13 +- 21 files changed, 168 insertions(+), 358 deletions(-) diff --git a/storage/innobase/data/data0data.cc b/storage/innobase/data/data0data.cc index 6b63960e00f..5b3a898e4d0 100644 --- a/storage/innobase/data/data0data.cc +++ b/storage/innobase/data/data0data.cc @@ -37,7 +37,7 @@ Created 5/30/1994 Heikki Tuuri /** Dummy variable to catch access to uninitialized fields. In the debug version, dtuple_create() will make all fields of dtuple_t point to data_error. */ -byte data_error; +ut_d(byte data_error); #endif /* UNIV_DEBUG */ /** Compare two data tuples. @@ -416,7 +416,7 @@ dfield_print_also_hex( break; } - data = static_cast(dfield_get_data(dfield)); + data = static_cast(dfield_get_data(dfield)); /* fall through */ case DATA_BINARY: diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc index 206aa7231c1..a5e1d5eeb4c 100644 --- a/storage/innobase/fts/fts0fts.cc +++ b/storage/innobase/fts/fts0fts.cc @@ -3366,12 +3366,11 @@ fts_fetch_doc_from_tuple( const dict_field_t* ifield; const dict_col_t* col; ulint pos; - dfield_t* field; ifield = dict_index_get_nth_field(index, i); col = dict_field_get_col(ifield); pos = dict_col_get_no(col); - field = dtuple_get_nth_field(tuple, pos); + const dfield_t* field = dtuple_get_nth_field(tuple, pos); if (!get_doc->index_cache->charset) { get_doc->index_cache->charset = fts_get_charset( diff --git a/storage/innobase/gis/gis0geo.cc b/storage/innobase/gis/gis0geo.cc index 436249c0026..6ea0d157a01 100644 --- a/storage/innobase/gis/gis0geo.cc +++ b/storage/innobase/gis/gis0geo.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, 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 @@ -68,9 +69,9 @@ static int rtree_add_point_to_mbr( /*===================*/ - uchar** wkb, /*!< in: pointer to wkb, + const uchar** wkb, /*!< in: pointer to wkb, where point is stored */ - uchar* end, /*!< in: end of wkb. */ + const uchar* end, /*!< in: end of wkb. */ uint n_dims, /*!< in: dimensions. */ uchar byte_order, /*!< in: byte order. */ double* mbr) /*!< in/out: mbr, which @@ -108,9 +109,9 @@ static int rtree_get_point_mbr( /*================*/ - uchar** wkb, /*!< in: pointer to wkb, + const uchar** wkb, /*!< in: pointer to wkb, where point is stored. */ - uchar* end, /*!< in: end of wkb. */ + const uchar* end, /*!< in: end of wkb. */ uint n_dims, /*!< in: dimensions. */ uchar byte_order, /*!< in: byte order. */ double* mbr) /*!< in/out: mbr, @@ -127,9 +128,9 @@ static int rtree_get_linestring_mbr( /*=====================*/ - uchar** wkb, /*!< in: pointer to wkb, + const uchar** wkb, /*!< in: pointer to wkb, where point is stored. */ - uchar* end, /*!< in: end of wkb. */ + const uchar* end, /*!< in: end of wkb. */ uint n_dims, /*!< in: dimensions. */ uchar byte_order, /*!< in: byte order. */ double* mbr) /*!< in/out: mbr, @@ -158,9 +159,9 @@ static int rtree_get_polygon_mbr( /*==================*/ - uchar** wkb, /*!< in: pointer to wkb, + const uchar** wkb, /*!< in: pointer to wkb, where point is stored. */ - uchar* end, /*!< in: end of wkb. */ + const uchar* end, /*!< in: end of wkb. */ uint n_dims, /*!< in: dimensions. */ uchar byte_order, /*!< in: byte order. */ double* mbr) /*!< in/out: mbr, @@ -195,9 +196,9 @@ static int rtree_get_geometry_mbr( /*===================*/ - uchar** wkb, /*!< in: pointer to wkb, + const uchar** wkb, /*!< in: pointer to wkb, where point is stored. */ - uchar* end, /*!< in: end of wkb. */ + const uchar* end, /*!< in: end of wkb. */ uint n_dims, /*!< in: dimensions. */ double* mbr, /*!< in/out: mbr. */ int top) /*!< in: if it is the top, @@ -297,7 +298,7 @@ stored in "well-known binary representation" (wkb) format. int rtree_mbr_from_wkb( /*===============*/ - uchar* wkb, /*!< in: wkb */ + const uchar* wkb, /*!< in: wkb */ uint size, /*!< in: size of wkb. */ uint n_dims, /*!< in: dimensions. */ double* mbr) /*!< in/out: mbr, which must diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc index a3790f5440e..501989061c1 100644 --- a/storage/innobase/gis/gis0rtree.cc +++ b/storage/innobase/gis/gis0rtree.cc @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2019, 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 @@ -64,7 +65,7 @@ rtr_page_split_initialize_nodes( page_t* page; ulint n_uniq; ulint len; - byte* source_cur; + const byte* source_cur; block = btr_cur_get_block(cursor); page = buf_block_get_frame(block); @@ -104,7 +105,7 @@ rtr_page_split_initialize_nodes( } /* Put the insert key to node list */ - source_cur = static_cast(dfield_get_data( + source_cur = static_cast(dfield_get_data( dtuple_get_nth_field(tuple, 0))); cur->coords = reserve_coords(buf_pos, SPDIMS); rec = (byte*) mem_heap_alloc( @@ -1874,11 +1875,11 @@ rtr_estimate_n_rows_in_range( ulint dtuple_f_len MY_ATTRIBUTE((unused)); rtr_mbr_t range_mbr; double range_area; - byte* range_mbr_ptr; dtuple_field = dtuple_get_nth_field(tuple, 0); dtuple_f_len = dfield_get_len(dtuple_field); - range_mbr_ptr = reinterpret_cast(dfield_get_data(dtuple_field)); + const byte* range_mbr_ptr = static_cast( + dfield_get_data(dtuple_field)); ut_ad(dtuple_f_len >= DATA_MBR_LEN); rtr_read_mbr(range_mbr_ptr, &range_mbr); diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc index cdddc346c77..995d99ad73b 100644 --- a/storage/innobase/gis/gis0sea.cc +++ b/storage/innobase/gis/gis0sea.cc @@ -1631,15 +1631,13 @@ rtr_get_mbr_from_tuple( { const dfield_t* dtuple_field; ulint dtuple_f_len; - byte* data; dtuple_field = dtuple_get_nth_field(dtuple, 0); dtuple_f_len = dfield_get_len(dtuple_field); ut_a(dtuple_f_len >= 4 * sizeof(double)); - data = static_cast(dfield_get_data(dtuple_field)); - - rtr_read_mbr(data, mbr); + rtr_read_mbr(static_cast(dfield_get_data(dtuple_field)), + mbr); } /****************************************************************//** diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 18158eae595..eb6664c427a 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -21784,7 +21784,7 @@ void innobase_free_row_for_vcol(VCOL_STORAGE *storage) to store the value in passed in "my_rec" */ dfield_t* innobase_get_computed_value( - const dtuple_t* row, + dtuple_t* row, const dict_v_col_t* col, const dict_index_t* index, mem_heap_t** local_heap, diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h index c181aa01a38..b9877656aaf 100644 --- a/storage/innobase/include/data0data.h +++ b/storage/innobase/include/data0data.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, 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 @@ -31,6 +31,7 @@ Created 5/30/1994 Heikki Tuuri #include "data0type.h" #include "mem0mem.h" #include "dict0types.h" +#include "btr0types.h" #include @@ -39,29 +40,11 @@ index record which needs external storage of data fields */ struct big_rec_t; struct upd_t; -#ifdef UNIV_DEBUG -/*********************************************************************//** -Gets pointer to the type struct of SQL data field. -@return pointer to the type struct */ -UNIV_INLINE -dtype_t* -dfield_get_type( -/*============*/ - const dfield_t* field) /*!< in: SQL data field */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*********************************************************************//** -Gets pointer to the data in a field. -@return pointer to data */ -UNIV_INLINE -void* -dfield_get_data( -/*============*/ - const dfield_t* field) /*!< in: field */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -#else /* UNIV_DEBUG */ -# define dfield_get_type(field) (&(field)->type) -# define dfield_get_data(field) ((field)->data) -#endif /* UNIV_DEBUG */ +/** Dummy variable to catch access to uninitialized fields. In the +debug version, dtuple_create() will make all fields of dtuple_t point +to data_error. */ +ut_d(extern byte data_error); + /*********************************************************************//** Sets the type struct of SQL data field. */ UNIV_INLINE @@ -72,15 +55,6 @@ dfield_set_type( const dtype_t* type); /*!< in: pointer to data type struct */ /*********************************************************************//** -Gets length of field data. -@return length of data; UNIV_SQL_NULL if SQL null data */ -UNIV_INLINE -ulint -dfield_get_len( -/*===========*/ - const dfield_t* field) /*!< in: field */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*********************************************************************//** Sets length in a field. */ UNIV_INLINE void @@ -89,32 +63,6 @@ dfield_set_len( dfield_t* field, /*!< in: field */ ulint len) /*!< in: length or UNIV_SQL_NULL */ MY_ATTRIBUTE((nonnull)); -/*********************************************************************//** -Determines if a field is SQL NULL -@return nonzero if SQL null data */ -UNIV_INLINE -ulint -dfield_is_null( -/*===========*/ - const dfield_t* field) /*!< in: field */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*********************************************************************//** -Determines if a field is externally stored -@return nonzero if externally stored */ -UNIV_INLINE -ulint -dfield_is_ext( -/*==========*/ - const dfield_t* field) /*!< in: field */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*********************************************************************//** -Sets the "external storage" flag */ -UNIV_INLINE -void -dfield_set_ext( -/*===========*/ - dfield_t* field) /*!< in/out: field */ - MY_ATTRIBUTE((nonnull)); /** Gets spatial status for "external storage" @param[in,out] field field */ @@ -221,46 +169,7 @@ dfield_data_is_binary_equal( ulint len, /*!< in: data length or UNIV_SQL_NULL */ const byte* data) /*!< in: data */ MY_ATTRIBUTE((nonnull, warn_unused_result)); -/*********************************************************************//** -Gets number of fields in a data tuple. -@return number of fields */ -UNIV_INLINE -ulint -dtuple_get_n_fields( -/*================*/ - const dtuple_t* tuple) /*!< in: tuple */ - MY_ATTRIBUTE((nonnull, warn_unused_result)); -/** Gets number of virtual fields in a data tuple. -@param[in] tuple dtuple to check -@return number of fields */ -UNIV_INLINE -ulint -dtuple_get_n_v_fields( - const dtuple_t* tuple); -#ifdef UNIV_DEBUG -/** Gets nth field of a tuple. -@param[in] tuple tuple -@param[in] n index of field -@return nth field */ -UNIV_INLINE -dfield_t* -dtuple_get_nth_field( - const dtuple_t* tuple, - ulint n); -/** Gets nth virtual field of a tuple. -@param[in] tuple tuple -@oaran[in] n the nth field to get -@return nth field */ -UNIV_INLINE -dfield_t* -dtuple_get_nth_v_field( - const dtuple_t* tuple, - ulint n); -#else /* UNIV_DEBUG */ -# define dtuple_get_nth_field(tuple, n) ((tuple)->fields + (n)) -# define dtuple_get_nth_v_field(tuple, n) ((tuple)->fields + (tuple)->n_fields + (n)) -#endif /* UNIV_DEBUG */ /*********************************************************************//** Gets info bits in a data tuple. @return info bits */ @@ -338,19 +247,12 @@ dtuple_create( /** Initialize the virtual field data in a dtuple_t @param[in,out] vrow dtuple contains the virtual fields */ -UNIV_INLINE -void -dtuple_init_v_fld( - const dtuple_t* vrow); +UNIV_INLINE void dtuple_init_v_fld(dtuple_t* vrow); /** Duplicate the virtual field data in a dtuple_t @param[in,out] vrow dtuple contains the virtual fields @param[in] heap heap memory to use */ -UNIV_INLINE -void -dtuple_dup_v_fld( - const dtuple_t* vrow, - mem_heap_t* heap); +UNIV_INLINE void dtuple_dup_v_fld(dtuple_t* vrow, mem_heap_t* heap); /** Creates a data tuple with possible virtual columns to a memory heap. @param[in] heap memory heap where the tuple is created @@ -619,6 +521,69 @@ struct dtuple_t { #endif /* UNIV_DEBUG */ }; +inline ulint dtuple_get_n_fields(const dtuple_t* tuple) +{ return tuple->n_fields; } +inline dtype_t* dfield_get_type(dfield_t* field) { return &field->type; } +inline const dtype_t* dfield_get_type(const dfield_t* field) +{ return &field->type; } +inline void* dfield_get_data(dfield_t* field) +{ + ut_ad(field->len == UNIV_SQL_NULL || field->data != &data_error); + return field->data; +} +inline const void* dfield_get_data(const dfield_t* field) +{ + ut_ad(field->len == UNIV_SQL_NULL || field->data != &data_error); + return field->data; +} +inline ulint dfield_get_len(const dfield_t* field) { return field->len; } +inline bool dfield_is_null(const dfield_t* field) +{ return field->len == UNIV_SQL_NULL; } +/** @return whether a column is to be stored off-page */ +inline bool dfield_is_ext(const dfield_t* field) +{ + ut_ad(!field->ext || field->len >= BTR_EXTERN_FIELD_REF_SIZE); + return static_cast(field->ext); +} +/** Set the "external storage" flag */ +inline void dfield_set_ext(dfield_t* field) { field->ext = 1; } + +/** Gets number of virtual fields in a data tuple. +@param[in] tuple dtuple to check +@return number of fields */ +inline ulint +dtuple_get_n_v_fields(const dtuple_t* tuple) { return tuple->n_v_fields; } + +inline const dfield_t* dtuple_get_nth_field(const dtuple_t* tuple, ulint n) +{ + ut_ad(n < tuple->n_fields); + return &tuple->fields[n]; +} +inline dfield_t* dtuple_get_nth_field(dtuple_t* tuple, ulint n) +{ + ut_ad(n < tuple->n_fields); + return &tuple->fields[n]; +} + +/** Get a virtual column in a table row or an extended clustered index record. +@param[in] tuple tuple +@oaran[in] n the nth virtual field to get +@return nth virtual field */ +inline const dfield_t* dtuple_get_nth_v_field(const dtuple_t* tuple, ulint n) +{ + ut_ad(n < tuple->n_v_fields); + return &tuple->v_fields[n]; +} +/** Get a virtual column in a table row or an extended clustered index record. +@param[in] tuple tuple +@oaran[in] n the nth virtual field to get +@return nth virtual field */ +inline dfield_t* dtuple_get_nth_v_field(dtuple_t* tuple, ulint n) +{ + ut_ad(n < tuple->n_v_fields); + return &tuple->v_fields[n]; +} + /** A slot for a field in a big rec vector */ struct big_rec_field_t { diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic index f8689db54ec..448566e452f 100644 --- a/storage/innobase/include/data0data.ic +++ b/storage/innobase/include/data0data.ic @@ -24,28 +24,7 @@ SQL data field and tuple Created 5/30/1994 Heikki Tuuri *************************************************************************/ -#include "mem0mem.h" #include "ut0rnd.h" -#include "btr0types.h" - -#ifdef UNIV_DEBUG -/** Dummy variable to catch access to uninitialized fields. In the -debug version, dtuple_create() will make all fields of dtuple_t point -to data_error. */ -extern byte data_error; - -/*********************************************************************//** -Gets pointer to the type struct of SQL data field. -@return pointer to the type struct */ -UNIV_INLINE -dtype_t* -dfield_get_type( -/*============*/ - const dfield_t* field) /*!< in: SQL data field */ -{ - return((dtype_t*) &(field->type)); -} -#endif /* UNIV_DEBUG */ /*********************************************************************//** Sets the type struct of SQL data field. */ @@ -62,38 +41,6 @@ dfield_set_type( field->type = *type; } -#ifdef UNIV_DEBUG -/*********************************************************************//** -Gets pointer to the data in a field. -@return pointer to data */ -UNIV_INLINE -void* -dfield_get_data( -/*============*/ - const dfield_t* field) /*!< in: field */ -{ - ut_ad((field->len == UNIV_SQL_NULL) - || (field->data != &data_error)); - - return((void*) field->data); -} -#endif /* UNIV_DEBUG */ - -/*********************************************************************//** -Gets length of field data. -@return length of data; UNIV_SQL_NULL if SQL null data */ -UNIV_INLINE -ulint -dfield_get_len( -/*===========*/ - const dfield_t* field) /*!< in: field */ -{ - ut_ad((field->len == UNIV_SQL_NULL) - || (field->data != &data_error)); - - return(field->len); -} - /*********************************************************************//** Sets length in a field. */ UNIV_INLINE @@ -111,42 +58,6 @@ dfield_set_len( field->len = static_cast(len); } -/*********************************************************************//** -Determines if a field is SQL NULL -@return nonzero if SQL null data */ -UNIV_INLINE -ulint -dfield_is_null( -/*===========*/ - const dfield_t* field) /*!< in: field */ -{ - return(field->len == UNIV_SQL_NULL); -} - -/*********************************************************************//** -Determines if a field is externally stored -@return nonzero if externally stored */ -UNIV_INLINE -ulint -dfield_is_ext( -/*==========*/ - const dfield_t* field) /*!< in: field */ -{ - ut_ad(!field->ext || field->len >= BTR_EXTERN_FIELD_REF_SIZE); - return(field->ext); -} - -/*********************************************************************//** -Sets the "external storage" flag */ -UNIV_INLINE -void -dfield_set_ext( -/*===========*/ - dfield_t* field) /*!< in/out: field */ -{ - field->ext = 1; -} - /** Gets spatial status for "external storage" @param[in,out] field field */ UNIV_INLINE @@ -366,63 +277,6 @@ dtuple_set_n_fields_cmp( tuple->n_fields_cmp = n_fields_cmp; } -/*********************************************************************//** -Gets number of fields in a data tuple. -@return number of fields */ -UNIV_INLINE -ulint -dtuple_get_n_fields( -/*================*/ - const dtuple_t* tuple) /*!< in: tuple */ -{ - return(tuple->n_fields); -} - -/** Gets the number of virtual fields in a data tuple. -@param[in] tuple dtuple to check -@return number of fields */ -UNIV_INLINE -ulint -dtuple_get_n_v_fields( - const dtuple_t* tuple) -{ - ut_ad(tuple); - - return(tuple->n_v_fields); -} -#ifdef UNIV_DEBUG -/** Gets nth field of a tuple. -@param[in] tuple tuple -@param[in] n index of field -@return nth field */ -UNIV_INLINE -dfield_t* -dtuple_get_nth_field( - const dtuple_t* tuple, - ulint n) -{ - ut_ad(tuple); - ut_ad(n < tuple->n_fields); - - return((dfield_t*) tuple->fields + n); -} -/** Gets nth virtual field of a tuple. -@param[in] tuple tuple -@oaran[in] n the nth field to get -@return nth field */ -UNIV_INLINE -dfield_t* -dtuple_get_nth_v_field( - const dtuple_t* tuple, - ulint n) -{ - ut_ad(tuple); - ut_ad(n < tuple->n_v_fields); - - return(static_cast(tuple->v_fields + n)); -} -#endif /* UNIV_DEBUG */ - /** Creates a data tuple from an already allocated chunk of memory. The size of the chunk must be at least DTUPLE_EST_ALLOC(n_fields). The default value for number of fields used in record comparisons @@ -487,12 +341,10 @@ dtuple_create_from_mem( /** Duplicate the virtual field data in a dtuple_t @param[in,out] vrow dtuple contains the virtual fields -@param[in] heap heap memory to use */ +@param[in,out] heap heap memory to use */ UNIV_INLINE void -dtuple_dup_v_fld( - const dtuple_t* vrow, - mem_heap_t* heap) +dtuple_dup_v_fld(dtuple_t* vrow, mem_heap_t* heap) { for (ulint i = 0; i < vrow->n_v_fields; i++) { dfield_t* dfield = dtuple_get_nth_v_field(vrow, i); @@ -504,8 +356,7 @@ dtuple_dup_v_fld( @param[in,out] vrow dtuple contains the virtual fields */ UNIV_INLINE void -dtuple_init_v_fld( - const dtuple_t* vrow) +dtuple_init_v_fld(dtuple_t* vrow) { for (ulint i = 0; i < vrow->n_v_fields; i++) { dfield_t* dfield = dtuple_get_nth_v_field(vrow, i); diff --git a/storage/innobase/include/gis0geo.h b/storage/innobase/include/gis0geo.h index 08895af545e..9a5d426cd7c 100644 --- a/storage/innobase/include/gis0geo.h +++ b/storage/innobase/include/gis0geo.h @@ -1,5 +1,6 @@ /***************************************************************************** Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. +Copyright (c) 2019, 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 @@ -73,7 +74,7 @@ stored in "well-known binary representation" (wkb) format. int rtree_mbr_from_wkb( /*===============*/ - uchar* wkb, /*!< in: pointer to wkb. */ + const uchar* wkb, /*!< in: pointer to wkb. */ uint size, /*!< in: size of wkb. */ uint n_dims, /*!< in: dimensions. */ double* mbr); /*!< in/out: mbr. */ diff --git a/storage/innobase/include/rem0cmp.ic b/storage/innobase/include/rem0cmp.ic index 290c1455f27..9ba61ca1f94 100644 --- a/storage/innobase/include/rem0cmp.ic +++ b/storage/innobase/include/rem0cmp.ic @@ -127,10 +127,10 @@ cmp_dfield_dfield_like_prefix( if (CHARSET_INFO* cs = get_charset(cs_num, MYF(MY_WME))) { return(cs->coll->strnncoll( cs, - static_cast( + static_cast( dfield_get_data(dfield1)), dfield_get_len(dfield1), - static_cast( + static_cast( dfield_get_data(dfield2)), dfield_get_len(dfield2), 1)); diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h index 5dd34f5679b..29dc9c120a7 100644 --- a/storage/innobase/include/row0mysql.h +++ b/storage/innobase/include/row0mysql.h @@ -858,7 +858,7 @@ void innobase_free_row_for_vcol(VCOL_STORAGE *storage); @return the field filled with computed value */ dfield_t* innobase_get_computed_value( - const dtuple_t* row, + dtuple_t* row, const dict_v_col_t* col, const dict_index_t* index, mem_heap_t** local_heap, diff --git a/storage/innobase/include/row0vers.h b/storage/innobase/include/row0vers.h index ac03478e083..a6dd14f8fd8 100644 --- a/storage/innobase/include/row0vers.h +++ b/storage/innobase/include/row0vers.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, MariaDB Corporation. +Copyright (c) 2017, 2019, 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 @@ -124,7 +124,7 @@ row_vers_build_for_consistent_read( if the history is missing or the record does not exist in the view, that is, it was freshly inserted afterwards */ - const dtuple_t**vrow); /*!< out: reports virtual column info if any */ + dtuple_t** vrow); /*!< out: reports virtual column info if any */ /*****************************************************************//** Constructs the last committed version of a clustered index record, @@ -149,7 +149,7 @@ row_vers_build_for_semi_consistent_read( const rec_t** old_vers,/*!< out: rec, old version, or NULL if the record does not exist in the view, that is, it was freshly inserted afterwards */ - const dtuple_t**vrow); /*!< out: holds virtual column info if any + dtuple_t** vrow); /*!< out: holds virtual column info if any is updated in the view */ #endif diff --git a/storage/innobase/include/trx0rec.h b/storage/innobase/include/trx0rec.h index ea6269b5ba4..99cebc36522 100644 --- a/storage/innobase/include/trx0rec.h +++ b/storage/innobase/include/trx0rec.h @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, 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 @@ -250,7 +250,7 @@ trx_undo_prev_version_build( dtuple if it is not yet created. This heap diffs from "heap" above in that it could be prebuilt->old_vers_heap for selection */ - const dtuple_t**vrow, /*!< out: virtual column info, if any */ + dtuple_t** vrow, /*!< out: virtual column info, if any */ ulint v_status); /*!< in: status determine if it is going into this function by purge thread or not. @@ -299,7 +299,7 @@ void trx_undo_read_v_cols( const dict_table_t* table, const byte* ptr, - const dtuple_t* row, + dtuple_t* row, bool in_purge); /** Read virtual column index from undo log if the undo log contains such diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc index ed80696a742..8b153e28bed 100644 --- a/storage/innobase/rem/rem0rec.cc +++ b/storage/innobase/rem/rem0rec.cc @@ -838,9 +838,7 @@ rec_get_converted_size_comp_prefix_low( col = dict_field_get_col(field); #ifdef UNIV_DEBUG - dtype_t* type; - - type = dfield_get_type(&fields[i]); + const dtype_t* type = dfield_get_type(&fields[i]); if (dict_index_is_spatial(index)) { if (DATA_GEOMETRY_MTYPE(col->mtype) && i == 0) { ut_ad(type->prtype & DATA_GIS_MBR); diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc index 8bfef78cd8c..59d46d86aab 100644 --- a/storage/innobase/row/row0ins.cc +++ b/storage/innobase/row/row0ins.cc @@ -3327,14 +3327,14 @@ row_ins_spatial_index_entry_set_mbr_field( dfield_t* field, /*!< in/out: mbr field */ const dfield_t* row_field) /*!< in: row field */ { - uchar* dptr = NULL; ulint dlen = 0; double mbr[SPDIMS * 2]; /* This must be a GEOMETRY datatype */ ut_ad(DATA_GEOMETRY_MTYPE(field->type.mtype)); - dptr = static_cast(dfield_get_data(row_field)); + const byte* dptr = static_cast( + dfield_get_data(row_field)); dlen = dfield_get_len(row_field); /* obtain the MBR */ diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc index 3447ade7606..e1ef6983073 100644 --- a/storage/innobase/row/row0merge.cc +++ b/storage/innobase/row/row0merge.cc @@ -453,7 +453,7 @@ row_merge_buf_redundant_convert( ut_ad(field_len <= len); if (row_field->ext) { - const byte* field_data = static_cast( + const byte* field_data = static_cast( dfield_get_data(row_field)); ulint ext_len; @@ -483,7 +483,7 @@ row_merge_buf_redundant_convert( @param[in] old_table original table @param[in] new_table new table @param[in,out] psort_info parallel sort info -@param[in] row table row +@param[in,out] row table row @param[in] ext cache of externally stored column prefixes, or NULL @param[in,out] doc_id Doc ID if we are creating @@ -505,7 +505,7 @@ row_merge_buf_add( const dict_table_t* old_table, const dict_table_t* new_table, fts_psort_t* psort_info, - const dtuple_t* row, + dtuple_t* row, const row_ext_t* ext, doc_id_t* doc_id, mem_heap_t* conv_heap, @@ -642,7 +642,7 @@ row_merge_buf_add( row, index->table->fts->doc_col); *doc_id = (doc_id_t) mach_read_from_8( - static_cast( + static_cast( dfield_get_data(doc_field))); if (*doc_id == 0) { @@ -1904,7 +1904,7 @@ row_merge_read_clustered_index( const rec_t* rec; ulint* offsets; - const dtuple_t* row; + dtuple_t* row; row_ext_t* ext; page_cur_t* cur = btr_pcur_get_page_cur(&pcur); @@ -2154,9 +2154,8 @@ end_of_index: ut_ad(add_autoinc < dict_table_get_n_user_cols(new_table)); - const dfield_t* dfield; - - dfield = dtuple_get_nth_field(row, add_autoinc); + dfield_t* dfield = dtuple_get_nth_field(row, + add_autoinc); if (dfield_is_null(dfield)) { goto write_buffers; } diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc index 687eab903f8..55893589f85 100644 --- a/storage/innobase/row/row0row.cc +++ b/storage/innobase/row/row0row.cc @@ -95,7 +95,7 @@ row_build_index_entry_low( const dict_col_t* col; ulint col_no = 0; dfield_t* dfield; - dfield_t* dfield2; + const dfield_t* dfield2; ulint len; if (i >= entry_len) { @@ -162,7 +162,7 @@ row_build_index_entry_low( dfield_set_data(dfield, mbr, mbr_len); if (dfield2->data) { - uchar* dptr = NULL; + const uchar* dptr = NULL; ulint dlen = 0; ulint flen = 0; double tmp_mbr[SPDIMS * 2]; @@ -170,7 +170,7 @@ row_build_index_entry_low( if (dfield_is_ext(dfield2)) { if (flag == ROW_BUILD_FOR_PURGE) { - byte* ptr = NULL; + const byte* ptr = NULL; spatial_status_t spatial_status; spatial_status = @@ -179,7 +179,7 @@ row_build_index_entry_low( switch (spatial_status) { case SPATIAL_ONLY: - ptr = static_cast( + ptr = static_cast( dfield_get_data( dfield2)); ut_ad(dfield_get_len(dfield2) @@ -187,7 +187,7 @@ row_build_index_entry_low( break; case SPATIAL_MIXED: - ptr = static_cast( + ptr = static_cast( dfield_get_data( dfield2)) + dfield_get_len( @@ -216,13 +216,13 @@ row_build_index_entry_low( flen = BTR_EXTERN_FIELD_REF_SIZE; ut_ad(dfield_get_len(dfield2) >= BTR_EXTERN_FIELD_REF_SIZE); - dptr = static_cast( + dptr = static_cast( dfield_get_data(dfield2)) + dfield_get_len(dfield2) - BTR_EXTERN_FIELD_REF_SIZE; } else { flen = dfield_get_len(dfield2); - dptr = static_cast( + dptr = static_cast( dfield_get_data(dfield2)); } @@ -240,7 +240,7 @@ row_build_index_entry_low( flen, temp_heap); } else { - dptr = static_cast( + dptr = static_cast( dfield_get_data(dfield2)); dlen = dfield_get_len(dfield2); diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc index 6f9e903623c..37918477c44 100644 --- a/storage/innobase/row/row0sel.cc +++ b/storage/innobase/row/row0sel.cc @@ -222,7 +222,6 @@ row_sel_sec_rec_is_for_clust_rec( reconstructed from base column in cluster index */ if (is_virtual) { const dict_v_col_t* v_col; - const dtuple_t* row; dfield_t* vfield; row_ext_t* ext; @@ -239,10 +238,11 @@ row_sel_sec_rec_is_for_clust_rec( v_col = reinterpret_cast(col); - row = row_build(ROW_COPY_POINTERS, - clust_index, clust_rec, - clust_offs, - NULL, NULL, NULL, &ext, heap); + dtuple_t* row = row_build( + ROW_COPY_POINTERS, + clust_index, clust_rec, + clust_offs, + NULL, NULL, NULL, &ext, heap); vfield = innobase_get_computed_value( row, v_col, clust_index, @@ -804,7 +804,7 @@ row_sel_build_committed_vers_for_mysql( record does not exist in the view: i.e., it was freshly inserted afterwards */ - const dtuple_t**vrow, /*!< out: to be filled with old virtual + dtuple_t** vrow, /*!< out: to be filled with old virtual column version if any */ mtr_t* mtr) /*!< in: mtr */ { @@ -3291,7 +3291,7 @@ row_sel_build_prev_vers_for_mysql( record does not exist in the view: i.e., it was freshly inserted afterwards */ - const dtuple_t**vrow, /*!< out: dtuple to hold old virtual + dtuple_t** vrow, /*!< out: dtuple to hold old virtual column data */ mtr_t* mtr) /*!< in: mtr */ { @@ -3335,7 +3335,7 @@ row_sel_get_clust_rec_for_mysql( rec_get_offsets(out_rec, clust_index) */ mem_heap_t** offset_heap,/*!< in/out: memory heap from which the offsets are allocated */ - const dtuple_t**vrow, /*!< out: virtual column to fill */ + dtuple_t** vrow, /*!< out: virtual column to fill */ mtr_t* mtr) /*!< in: mtr used to get access to the non-clustered record; the same mtr is used to access the clustered index */ @@ -4038,7 +4038,7 @@ void row_sel_fill_vrow( const rec_t* rec, dict_index_t* index, - const dtuple_t** vrow, + dtuple_t** vrow, mem_heap_t* heap) { ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -4230,7 +4230,7 @@ row_search_mvcc( dict_index_t* clust_index; que_thr_t* thr; const rec_t* rec; - const dtuple_t* vrow = NULL; + dtuple_t* vrow = NULL; const rec_t* result_rec = NULL; const rec_t* clust_rec; dberr_t err = DB_SUCCESS; diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 7e4b512ca27..d16f7cfad4e 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -856,7 +856,7 @@ row_upd_index_write_log( mlog_catenate_string( mtr, - static_cast( + static_cast( dfield_get_data(new_val)), len); @@ -1052,8 +1052,6 @@ row_upd_build_difference_binary( dberr_t* error) { upd_field_t* upd_field; - dfield_t* dfield; - const byte* data; ulint len; upd_t* update; ulint n_diff; @@ -1084,10 +1082,8 @@ row_upd_build_difference_binary( } for (i = 0; i < n_fld; i++) { - - data = rec_get_nth_field(rec, offsets, i, &len); - - dfield = dtuple_get_nth_field(entry, i); + const byte* data = rec_get_nth_field(rec, offsets, i, &len); + const dfield_t* dfield = dtuple_get_nth_field(entry, i); /* NOTE: we compare the fields as binary strings! (No collation) */ @@ -1155,8 +1151,6 @@ row_upd_build_difference_binary( index->table, NULL, NULL, &ext, heap); } - dfield = dtuple_get_nth_v_field(entry, i); - dfield_t* vfield = innobase_get_computed_value( update->old_vrow, col, index, &v_heap, heap, NULL, thd, mysql_table, record, @@ -1167,6 +1161,9 @@ row_upd_build_difference_binary( return(NULL); } + const dfield_t* dfield = dtuple_get_nth_v_field( + entry, i); + if (!dfield_data_is_binary_equal( dfield, vfield->len, static_cast(vfield->data))) { @@ -1771,7 +1768,7 @@ row_upd_changes_ord_field_binary_func( double mbr2[SPDIMS * 2]; rtr_mbr_t* old_mbr; rtr_mbr_t* new_mbr; - uchar* dptr = NULL; + const uchar* dptr = NULL; ulint flen = 0; ulint dlen = 0; mem_heap_t* temp_heap = NULL; @@ -1792,7 +1789,7 @@ row_upd_changes_ord_field_binary_func( /* For off-page stored data, we need to read the whole field data. */ flen = dfield_get_len(dfield); - dptr = static_cast( + dptr = static_cast( dfield_get_data(dfield)); temp_heap = mem_heap_create(1000); @@ -1802,7 +1799,7 @@ row_upd_changes_ord_field_binary_func( flen, temp_heap); } else { - dptr = static_cast(dfield->data); + dptr = static_cast(dfield->data); dlen = dfield->len; } @@ -1822,13 +1819,13 @@ row_upd_changes_ord_field_binary_func( flen = BTR_EXTERN_FIELD_REF_SIZE; ut_ad(dfield_get_len(new_field) >= BTR_EXTERN_FIELD_REF_SIZE); - dptr = static_cast( + dptr = static_cast( dfield_get_data(new_field)) + dfield_get_len(new_field) - BTR_EXTERN_FIELD_REF_SIZE; } else { flen = dfield_get_len(new_field); - dptr = static_cast( + dptr = static_cast( dfield_get_data(new_field)); } @@ -1842,7 +1839,8 @@ row_upd_changes_ord_field_binary_func( flen, temp_heap); } else { - dptr = static_cast(upd_field->new_val.data); + dptr = static_cast( + upd_field->new_val.data); dlen = upd_field->new_val.len; } rtree_mbr_from_wkb(dptr + GEO_DATA_HEADER_SIZE, @@ -1900,7 +1898,7 @@ row_upd_changes_ord_field_binary_func( ut_a(dict_index_is_clust(index) || ind_field->prefix_len <= dfield_len); - buf = static_cast(dfield_get_data(dfield)); + buf= static_cast(dfield_get_data(dfield)); copy_dfield: ut_a(dfield_len > 0); dfield_copy(&dfield_ext, dfield); diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc index 30aa44dcb33..a099efc826c 100644 --- a/storage/innobase/row/row0vers.cc +++ b/storage/innobase/row/row0vers.cc @@ -1,7 +1,7 @@ /***************************************************************************** Copyright (c) 1997, 2017, Oracle and/or its affiliates. All Rights Reserved. -Copyright (c) 2017, 2018, MariaDB Corporation. +Copyright (c) 2017, 2019, 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 @@ -98,7 +98,7 @@ row_vers_impl_x_locked_low( mem_heap_t* heap; dtuple_t* ientry = NULL; mem_heap_t* v_heap = NULL; - const dtuple_t* cur_vrow = NULL; + dtuple_t* cur_vrow = NULL; DBUG_ENTER("row_vers_impl_x_locked_low"); @@ -165,7 +165,7 @@ row_vers_impl_x_locked_low( ulint vers_del; trx_id_t prev_trx_id; mem_heap_t* old_heap = heap; - const dtuple_t* vrow = NULL; + dtuple_t* vrow = NULL; /* We keep the semaphore in mtr on the clust_rec page, so that no other transaction can update it and get an @@ -519,7 +519,7 @@ row_vers_build_cur_vrow_low( roll_ptr_t roll_ptr, trx_id_t trx_id, mem_heap_t* v_heap, - const dtuple_t** vrow, + dtuple_t** vrow, mtr_t* mtr) { const rec_t* version; @@ -636,7 +636,7 @@ row_vers_vc_matches_cluster( roll_ptr_t roll_ptr, trx_id_t trx_id, mem_heap_t* v_heap, - const dtuple_t**vrow, + dtuple_t** vrow, mtr_t* mtr) { const rec_t* version; @@ -801,7 +801,7 @@ func_exit: @param[in,out] vcol_info virtual column information for purge thread @return dtuple contains virtual column data */ static -const dtuple_t* +dtuple_t* row_vers_build_cur_vrow( bool in_purge, const rec_t* rec, @@ -816,7 +816,7 @@ row_vers_build_cur_vrow( mtr_t* mtr, purge_vcol_info_t* vcol_info) { - const dtuple_t* cur_vrow = NULL; + dtuple_t* cur_vrow = NULL; roll_ptr_t t_roll_ptr = row_get_rec_roll_ptr( rec, clust_index, *clust_offsets); @@ -897,9 +897,9 @@ row_vers_old_has_index_entry( dtuple_t* row; const dtuple_t* entry; ulint comp; - const dtuple_t* vrow = NULL; + dtuple_t* vrow = NULL; mem_heap_t* v_heap = NULL; - const dtuple_t* cur_vrow = NULL; + dtuple_t* cur_vrow = NULL; ut_ad(mtr_memo_contains_page_flagged(mtr, rec, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_S_FIX)); @@ -1162,7 +1162,7 @@ row_vers_build_for_consistent_read( if the history is missing or the record does not exist in the view, that is, it was freshly inserted afterwards */ - const dtuple_t**vrow) /*!< out: virtual row */ + dtuple_t** vrow) /*!< out: virtual row */ { const rec_t* version; rec_t* prev_version; @@ -1275,7 +1275,7 @@ row_vers_build_for_semi_consistent_read( const rec_t** old_vers,/*!< out: rec, old version, or NULL if the record does not exist in the view, that is, it was freshly inserted afterwards */ - const dtuple_t** vrow) /*!< out: virtual row, old version, or NULL + dtuple_t** vrow) /*!< out: virtual row, old version, or NULL if it is not updated in the view */ { const rec_t* version; diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 5c8b2f9441f..7695e35fb7a 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -388,8 +388,6 @@ trx_undo_report_insert_virtual( for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(table); col_no++) { - dfield_t* vfield = NULL; - const dict_v_col_t* col = dict_table_get_nth_v_col(table, col_no); @@ -412,7 +410,8 @@ trx_undo_report_insert_virtual( return(false); } - vfield = dtuple_get_nth_v_field(row, col->v_pos); + const dfield_t* vfield = dtuple_get_nth_v_field( + row, col->v_pos); ulint flen = vfield->len; if (flen != UNIV_SQL_NULL) { @@ -1331,8 +1330,6 @@ already_logged: for (col_no = 0; col_no < dict_table_get_n_v_cols(table); col_no++) { - dfield_t* vfield = NULL; - const dict_v_col_t* col = dict_table_get_nth_v_col(table, col_no); @@ -1362,6 +1359,8 @@ already_logged: return(0); } + const dfield_t* vfield = NULL; + if (update) { ut_ad(!row); if (update->old_vrow == NULL) { @@ -2300,7 +2299,7 @@ trx_undo_prev_version_build( dtuple if it is not yet created. This heap diffs from "heap" above in that it could be prebuilt->old_vers_heap for selection */ - const dtuple_t**vrow, /*!< out: virtual column info, if any */ + dtuple_t** vrow, /*!< out: virtual column info, if any */ ulint v_status) /*!< in: status determine if it is going into this function by purge thread or not. @@ -2503,7 +2502,7 @@ void trx_undo_read_v_cols( const dict_table_t* table, const byte* ptr, - const dtuple_t* row, + dtuple_t* row, bool in_purge) { const byte* end_ptr; From e8dd18a474ee6b48eb7f92e3831f9e359b0bdc6e Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich Date: Sat, 4 May 2019 12:43:29 +0400 Subject: [PATCH 43/43] Restore vars_list destructor Regression after reverting fair THD members constructors/destructors. vars_list can be used standalone, in such cases destructor is needed. Part of MDEV-14984 - regression in connect performance --- sql/session_tracker.h | 1 + 1 file changed, 1 insertion(+) diff --git a/sql/session_tracker.h b/sql/session_tracker.h index b6694970c38..226b026d590 100644 --- a/sql/session_tracker.h +++ b/sql/session_tracker.h @@ -164,6 +164,7 @@ class Session_sysvars_tracker: public State_tracker } public: vars_list(): track_all(false) { init(); } + ~vars_list() { if (my_hash_inited(&m_registered_sysvars)) free_hash(); } void deinit() { free_hash(); } sysvar_node_st *insert_or_search(const sys_var *svar)