diff options
30 files changed, 503 insertions, 375 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b170ecabef5..02f13e39e58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,9 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8.7) IF(POLICY CMP0022) CMAKE_POLICY(SET CMP0022 NEW) ENDIF() +IF(POLICY CMP0048) + CMAKE_POLICY(SET CMP0048 NEW) +ENDIF() IF(POLICY CMP0054) CMAKE_POLICY(SET CMP0054 NEW) ENDIF() diff --git a/cmake/FindBISON.cmake b/cmake/FindBISON.cmake new file mode 100644 index 00000000000..28ae3f8fecb --- /dev/null +++ b/cmake/FindBISON.cmake @@ -0,0 +1,8 @@ +IF(DEFINED BISON_EXECUTABLE) + SET(bison_quiet QUIET) +ENDIF() + +set(orig_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}) +unset(CMAKE_MODULE_PATH) +find_package(BISON ${BISON_FIND_VERSION} ${bison_quiet} ${BISON_FIND_REQUIRED}) +set(CMAKE_MODULE_PATH ${orig_CMAKE_MODULE_PATH}) diff --git a/mysql-test/suite/roles/set_default_role_for.result b/mysql-test/suite/roles/set_default_role_for.result index dff41917879..533a646e6e3 100644 --- a/mysql-test/suite/roles/set_default_role_for.result +++ b/mysql-test/suite/roles/set_default_role_for.result @@ -14,7 +14,7 @@ set default role role_a for user_a@localhost; set default role invalid_role for user_a@localhost; ERROR OP000: Invalid role specification `invalid_role` set default role role_b for user_a@localhost; -ERROR OP000: Invalid role specification `role_b` +ERROR OP000: User `user_a@localhost` has not been granted role `role_b` set default role role_b for user_b@localhost; show grants; Grants for user_a@localhost @@ -36,7 +36,7 @@ User Host default_role user_a localhost role_a user_b localhost role_b set default role role_b for current_user; -ERROR OP000: Invalid role specification `role_b` +ERROR OP000: User `user_a@localhost` has not been granted role `role_b` show grants; Grants for user_b@localhost GRANT `role_b` TO `user_b`@`localhost` diff --git a/mysql-test/suite/roles/set_default_role_invalid.result b/mysql-test/suite/roles/set_default_role_invalid.result index 5af0cc12be2..c8789594593 100644 --- a/mysql-test/suite/roles/set_default_role_invalid.result +++ b/mysql-test/suite/roles/set_default_role_invalid.result @@ -38,3 +38,90 @@ ERROR 42000: SELECT command denied to user 'test_user'@'localhost' for table 'us drop role test_role; drop role not_granted_role; drop user test_user@localhost; +# +# MDEV-22312: Bad error message for SET DEFAULT ROLE when user account +# is not granted the role +# +CREATE USER a; +CREATE USER b; +CREATE ROLE r1; +CREATE ROLE r2; +SET DEFAULT ROLE r1 FOR a; +ERROR OP000: User `a@%` has not been granted role `r1` +GRANT r1 TO b; +GRANT r2 TO b; +SET DEFAULT ROLE r1 FOR b; +# Change user b +SELECT CURRENT_ROLE; +CURRENT_ROLE +r1 +SET ROLE r2; +SELECT CURRENT_ROLE; +CURRENT_ROLE +r2 +SET DEFAULT ROLE r1 FOR a; +ERROR 42000: Access denied for user 'b'@'%' to database 'mysql' +SET DEFAULT ROLE r2; +# Change user root (session 1: select_priv to b) +GRANT SELECT ON mysql.* TO b; +# Change user b (session 1: select_priv) +SHOW GRANTS FOR b; +Grants for b@% +GRANT `r1` TO `b`@`%` +GRANT `r2` TO `b`@`%` +GRANT USAGE ON *.* TO `b`@`%` +GRANT SELECT ON `mysql`.* TO `b`@`%` +SET DEFAULT ROLE r1 FOR a; +ERROR 42000: Access denied for user 'b'@'%' to database 'mysql' +SELECT CURRENT_ROLE; +CURRENT_ROLE +r2 +SET DEFAULT ROLE NONE; +SELECT CURRENT_ROLE; +CURRENT_ROLE +r2 +SET DEFAULT ROLE current_role FOR current_user; +SET DEFAULT ROLE invalid_role; +ERROR OP000: Invalid role specification `invalid_role` +SET DEFAULT ROLE invalid_role FOR a; +ERROR 42000: Access denied for user 'b'@'%' to database 'mysql' +SET DEFAULT ROLE none FOR a; +ERROR 42000: Access denied for user 'b'@'%' to database 'mysql' +# Change user root (session 2: adding update_priv to user b) +GRANT UPDATE ON mysql.* TO b; +# Change user b +SHOW GRANTS FOR b; +Grants for b@% +GRANT `r1` TO `b`@`%` +GRANT `r2` TO `b`@`%` +GRANT USAGE ON *.* TO `b`@`%` +GRANT SELECT, UPDATE ON `mysql`.* TO `b`@`%` +SET DEFAULT ROLE r1 FOR a; +ERROR OP000: User `a@%` has not been granted role `r1` +SET DEFAULT ROLE invalid_role; +ERROR OP000: Invalid role specification `invalid_role` +SET DEFAULT ROLE invalid_role FOR a; +ERROR OP000: Invalid role specification `invalid_role` +SET DEFAULT ROLE none FOR a; +# Change user root (session 3: Grant role to user a) +GRANT r1 TO a; +SET DEFAULT ROLE r1 FOR a; +# Change user a (verify session 3) +SELECT CURRENT_ROLE; +CURRENT_ROLE +r1 +SET DEFAULT ROLE None; +# Change user b (session 3: role granted to user a) +SET DEFAULT ROLE r1 FOR a; +SET DEFAULT ROLE r2 FOR a; +ERROR OP000: User `a@%` has not been granted role `r2` +SET DEFAULT ROLE invalid_role; +ERROR OP000: Invalid role specification `invalid_role` +SET DEFAULT ROLE invalid_role FOR a; +ERROR OP000: Invalid role specification `invalid_role` +SELECT user, host, default_role FROM mysql.user where user='a' or user='b'; +User Host default_role +a % r1 +b % r2 +DROP ROLE r1, r2; +DROP USER a, b; diff --git a/mysql-test/suite/roles/set_default_role_invalid.test b/mysql-test/suite/roles/set_default_role_invalid.test index 8e72e316d4b..02fca1107e2 100644 --- a/mysql-test/suite/roles/set_default_role_invalid.test +++ b/mysql-test/suite/roles/set_default_role_invalid.test @@ -60,3 +60,110 @@ change_user 'root'; drop role test_role; drop role not_granted_role; drop user test_user@localhost; + +--echo # +--echo # MDEV-22312: Bad error message for SET DEFAULT ROLE when user account +--echo # is not granted the role +--echo # + +CREATE USER a; +CREATE USER b; +CREATE ROLE r1; +CREATE ROLE r2; +# Role has not been granted to user a, but the role is visible to current_user +--error ER_INVALID_ROLE +SET DEFAULT ROLE r1 FOR a; +# Granting roles to user b +GRANT r1 TO b; +GRANT r2 TO b; +# After granting the role, role can be set as default +SET DEFAULT ROLE r1 FOR b; + +--echo # Change user b +change_user b; +SELECT CURRENT_ROLE; +SET ROLE r2; +SELECT CURRENT_ROLE; +# User b has no UPDATE_PRIV for mysql.user +--error ER_DBACCESS_DENIED_ERROR +SET DEFAULT ROLE r1 FOR a; +SET DEFAULT ROLE r2; + +--echo # Change user root (session 1: select_priv to b) +change_user root; +# Let's grant select_priv to user b +GRANT SELECT ON mysql.* TO b; + +--echo # Change user b (session 1: select_priv) +change_user b; +SHOW GRANTS FOR b; +# User must have update_priv before setting the role +--error ER_DBACCESS_DENIED_ERROR +SET DEFAULT ROLE r1 FOR a; +# Testing the `CURRENT_ROLE` as a special case +SELECT CURRENT_ROLE; +SET DEFAULT ROLE NONE; +SELECT CURRENT_ROLE; +SET DEFAULT ROLE current_role FOR current_user; +# Testing of non-existing role +--error ER_INVALID_ROLE +SET DEFAULT ROLE invalid_role; +# Testing of non-existing role for different user +--error ER_DBACCESS_DENIED_ERROR +SET DEFAULT ROLE invalid_role FOR a; +# Testing the `None` role for different user +-- error ER_DBACCESS_DENIED_ERROR +SET DEFAULT ROLE none FOR a; + +--echo # Change user root (session 2: adding update_priv to user b) +change_user root; +# update_priv are enough +GRANT UPDATE ON mysql.* TO b; + +--echo # Change user b +change_user b; +SHOW GRANTS FOR b; +# In all tests in session user a has not been granted the role +# Testing setting role for different user, should fail with new error +--error ER_INVALID_ROLE +SET DEFAULT ROLE r1 FOR a; +# Testing of non-existing role +--error ER_INVALID_ROLE +SET DEFAULT ROLE invalid_role; +# Testing of non-existing role for different user with update_priv +--error ER_INVALID_ROLE +SET DEFAULT ROLE invalid_role FOR a; +# Testing the `None` role for different user with update_priv +SET DEFAULT ROLE none FOR a; + +--echo # Change user root (session 3: Grant role to user a) +change_user root; +# After granting the privilege for a, user b can set default role +GRANT r1 TO a; +SET DEFAULT ROLE r1 FOR a; + +--echo # Change user a (verify session 3) +change_user a; +SELECT CURRENT_ROLE; +SET DEFAULT ROLE None; + +--echo # Change user b (session 3: role granted to user a) +change_user b; +# This should set role because b has update_priv +SET DEFAULT ROLE r1 FOR a; +# Testing non-granted role r2 still should fail +-- error ER_INVALID_ROLE +SET DEFAULT ROLE r2 FOR a; +# Testing of non-existing role +--error ER_INVALID_ROLE +SET DEFAULT ROLE invalid_role; +# Testing of non-existing role for different user +--error ER_INVALID_ROLE +SET DEFAULT ROLE invalid_role FOR a; + +# Clear the workspace +change_user root; +--sorted_result +SELECT user, host, default_role FROM mysql.user where user='a' or user='b'; +DROP ROLE r1, r2; +DROP USER a, b; diff --git a/mysql-test/suite/roles/set_role-recursive.result b/mysql-test/suite/roles/set_role-recursive.result index 0413a9c4e04..be11728ad4e 100644 --- a/mysql-test/suite/roles/set_role-recursive.result +++ b/mysql-test/suite/roles/set_role-recursive.result @@ -67,7 +67,7 @@ Grants for test_user@localhost GRANT USAGE ON *.* TO `test_user`@`localhost` GRANT `test_role1` TO `test_user`@`localhost` set role test_role2; -ERROR OP000: Invalid role specification `test_role2` +ERROR OP000: User `test_user@localhost` has not been granted role `test_role2` select current_user(), current_role(); current_user() current_role() test_user@localhost NULL diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index fff8c33ac21..4e7757f71db 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -788,7 +788,6 @@ bool Item_nodeset_func_attributebyname::val_native(THD *thd, Native *nodeset) bool Item_nodeset_func_predicate::val_native(THD *thd, Native *str) { Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0]; - Item_func *comp_func= (Item_func*)args[1]; uint pos= 0, size; prepare(thd, str); size= (uint)(fltend - fltbeg); @@ -797,7 +796,7 @@ bool Item_nodeset_func_predicate::val_native(THD *thd, Native *str) nodeset_func->context_cache.length(0); MY_XPATH_FLT(flt->num, flt->pos, size). append_to(&nodeset_func->context_cache); - if (comp_func->val_int()) + if (args[1]->val_int()) MY_XPATH_FLT(flt->num, pos++).append_to(str); } return false; diff --git a/sql/set_var.cc b/sql/set_var.cc index 0ace4658be7..38c8d1f1775 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -994,8 +994,17 @@ int set_var_default_role::check(THD *thd) { #ifndef NO_EMBEDDED_ACCESS_CHECKS real_user= get_current_user(thd, user); - int status= acl_check_set_default_role(thd, real_user->host.str, real_user->user.str); - return status; + real_role= role.str; + if (role.str == current_role.str) + { + if (!thd->security_ctx->priv_role[0]) + real_role= "NONE"; + else + real_role= thd->security_ctx->priv_role; + } + + return acl_check_set_default_role(thd, real_user->host.str, + real_user->user.str, real_role); #else return 0; #endif @@ -1006,7 +1015,8 @@ int set_var_default_role::update(THD *thd) #ifndef NO_EMBEDDED_ACCESS_CHECKS Reprepare_observer *save_reprepare_observer= thd->m_reprepare_observer; thd->m_reprepare_observer= 0; - int res= acl_set_default_role(thd, real_user->host.str, real_user->user.str, role.str); + int res= acl_set_default_role(thd, real_user->host.str, real_user->user.str, + real_role); thd->m_reprepare_observer= save_reprepare_observer; return res; #else diff --git a/sql/set_var.h b/sql/set_var.h index 41a0010acf2..18c4dbc664e 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -1,7 +1,7 @@ #ifndef SET_VAR_INCLUDED #define SET_VAR_INCLUDED /* Copyright (c) 2002, 2013, Oracle and/or its affiliates. - Copyright (c) 2009, 2014, SkySQL Ab. + Copyright (c) 2009, 2020, 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 @@ -370,6 +370,7 @@ class set_var_default_role: public set_var_base { LEX_USER *user, *real_user; LEX_CSTRING role; + const char *real_role; public: set_var_default_role(LEX_USER *user_arg, LEX_CSTRING role_arg) : user(user_arg), role(role_arg) {} diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 4271340340b..d8a05686166 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1,5 +1,5 @@ /* Copyright (c) 2000, 2018, Oracle and/or its affiliates. - Copyright (c) 2009, 2020, MariaDB Corporation. + Copyright (c) 2009, 2020, 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 @@ -3124,8 +3124,33 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host, DBUG_RETURN(res); } -static int check_user_can_set_role(const char *user, const char *host, - const char *ip, const char *rolename, privilege_t *access) +static int check_role_is_granted_callback(ACL_USER_BASE *grantee, void *data) +{ + LEX_CSTRING *rolename= static_cast<LEX_CSTRING *>(data); + if (rolename->length == grantee->user.length && + !strcmp(rolename->str, grantee->user.str)) + return -1; // End search, we've found our role. + + /* Keep looking, we haven't found our role yet. */ + return 0; +} + +/* + unlike find_user_exact and find_user_wild, + this function finds anonymous users too, it's when a + user is not empty, but priv_user (acl_user->user) is empty. +*/ +static ACL_USER *find_user_or_anon(const char *host, const char *user, const char *ip) +{ + return find_by_username_or_anon<ACL_USER> + (reinterpret_cast<ACL_USER*>(acl_users.buffer), acl_users.elements, + user, host, ip, NULL, FALSE, NULL); +} + + +static int check_user_can_set_role(THD *thd, const char *user, + const char *host, const char *ip, + const char *rolename, privilege_t *access) { ACL_ROLE *role; ACL_USER_BASE *acl_user_base; @@ -3142,10 +3167,7 @@ static int check_user_can_set_role(const char *user, const char *host, /* get the current user */ acl_user= find_user_wild(host, user, ip); if (acl_user == NULL) - { - my_error(ER_INVALID_CURRENT_USER, MYF(0)); - result= -1; - } + result= ER_INVALID_CURRENT_USER; else if (access) *access= acl_user->access; @@ -3155,9 +3177,9 @@ static int check_user_can_set_role(const char *user, const char *host, role= find_acl_role(rolename); /* According to SQL standard, the same error message must be presented */ - if (role == NULL) { - my_error(ER_INVALID_ROLE, MYF(0), rolename); - result= -1; + if (role == NULL) + { + result= ER_INVALID_ROLE; goto end; } @@ -3178,7 +3200,6 @@ static int check_user_can_set_role(const char *user, const char *host, /* According to SQL standard, the same error message must be presented */ if (!is_granted) { - my_error(ER_INVALID_ROLE, MYF(0), rolename); result= 1; goto end; } @@ -3187,17 +3208,66 @@ static int check_user_can_set_role(const char *user, const char *host, { *access = acl_user->access | role->access; } + end: mysql_mutex_unlock(&acl_cache->lock); - return result; + /* We present different error messages depending if the user has sufficient + privileges to know if the INVALID_ROLE exists. */ + switch (result) + { + case ER_INVALID_CURRENT_USER: + my_error(ER_INVALID_CURRENT_USER, MYF(0), rolename); + break; + case ER_INVALID_ROLE: + /* Role doesn't exist at all */ + my_error(ER_INVALID_ROLE, MYF(0), rolename); + break; + case 1: + StringBuffer<1024> c_usr; + LEX_CSTRING role_lex; + /* First, check if current user can see mysql database. */ + bool read_access= !check_access(thd, SELECT_ACL, "mysql", NULL, NULL, 1, 1); + + role_lex.str= rolename; + role_lex.length= strlen(rolename); + mysql_mutex_lock(&acl_cache->lock); + ACL_USER *cur_user= find_user_or_anon(thd->security_ctx->priv_host, + thd->security_ctx->priv_user, + thd->security_ctx->ip); + + /* If the current user does not have select priv to mysql database, + see if the current user can discover the role if it was granted to him. + */ + if (cur_user && (read_access || + traverse_role_graph_down(cur_user, &role_lex, + check_role_is_granted_callback, + NULL) == -1)) + { + /* Role is not granted but current user can see the role */ + c_usr.append(user, strlen(user)); + c_usr.append('@'); + c_usr.append(host, strlen(host)); + my_printf_error(ER_INVALID_ROLE, "User %`s has not been granted role %`s", + MYF(0), c_usr.c_ptr(), rolename); + } + else + { + /* Role is not granted and current user cannot see the role */ + my_error(ER_INVALID_ROLE, MYF(0), rolename); + } + mysql_mutex_unlock(&acl_cache->lock); + break; + } + + return result; } + int acl_check_setrole(THD *thd, const char *rolename, privilege_t *access) { - /* Yes! priv_user@host. Don't ask why - that's what check_access() does. */ - return check_user_can_set_role(thd->security_ctx->priv_user, - thd->security_ctx->host, thd->security_ctx->ip, rolename, access); + return check_user_can_set_role(thd, thd->security_ctx->priv_user, + thd->security_ctx->host, thd->security_ctx->ip, rolename, access); } @@ -3936,9 +4006,12 @@ wsrep_error_label: DBUG_RETURN(result); } -int acl_check_set_default_role(THD *thd, const char *host, const char *user) +int acl_check_set_default_role(THD *thd, const char *host, const char *user, + const char *role) { - return check_alter_user(thd, host, user); + DBUG_ENTER("acl_check_set_default_role"); + DBUG_RETURN(check_alter_user(thd, host, user) || + check_user_can_set_role(thd, user, host, NULL, role, NULL)); } int acl_set_default_role(THD *thd, const char *host, const char *user, @@ -3958,16 +4031,6 @@ int acl_set_default_role(THD *thd, const char *host, const char *user, DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'", user, safe_str(host), safe_str(rolename))); - if (rolename == current_role.str) { - if (!thd->security_ctx->priv_role[0]) - rolename= "NONE"; - else - rolename= thd->security_ctx->priv_role; - } - - if (check_user_can_set_role(user, host, host, rolename, NULL)) - DBUG_RETURN(result); - if (!strcasecmp(rolename, "NONE")) clear_role= TRUE; @@ -4123,19 +4186,6 @@ bool is_acl_user(const char *host, const char *user) /* - unlike find_user_exact and find_user_wild, - this function finds anonymous users too, it's when a - user is not empty, but priv_user (acl_user->user) is empty. -*/ -static ACL_USER *find_user_or_anon(const char *host, const char *user, const char *ip) -{ - return find_by_username_or_anon<ACL_USER> - (reinterpret_cast<ACL_USER*>(acl_users.buffer), acl_users.elements, - user, host, ip, NULL, FALSE, NULL); -} - - -/* Find first entry that matches the specified user@host pair */ static ACL_USER *find_user_exact(const char *host, const char *user) @@ -4420,7 +4470,7 @@ static bool test_if_create_new_users(THD *thd) if (!(db_access & INSERT_ACL)) { if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE)) - create_new_users=0; + create_new_users=0; } } return create_new_users; @@ -9725,17 +9775,6 @@ void get_mqh(const char *user, const char *host, USER_CONN *uc) mysql_mutex_unlock(&acl_cache->lock); } -static int check_role_is_granted_callback(ACL_USER_BASE *grantee, void *data) -{ - LEX_CSTRING *rolename= static_cast<LEX_CSTRING *>(data); - if (rolename->length == grantee->user.length && - !strcmp(rolename->str, grantee->user.str)) - return -1; // End search, we've found our role. - - /* Keep looking, we haven't found our role yet. */ - return 0; -} - /* Modify a privilege table. @@ -11607,7 +11646,7 @@ acl_check_proxy_grant_access(THD *thd, const char *host, const char *user, Security context in THD contains two pairs of (user,host): 1. (user,host) pair referring to inbound connection. 2. (priv_user,priv_host) pair obtained from mysql.user table after doing - authnetication of incoming connection. + authentication of incoming connection. Privileges should be checked wrt (priv_user, priv_host) tuple, because (user,host) pair obtained from inbound connection may have different values than what is actually stored in mysql.user table and while granting @@ -12243,7 +12282,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond) privilege_t test_access(want_access & ~GRANT_ACL); for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1) { - if (test_access & j) + if (test_access & j) { if (update_schema_privilege(thd, table, buff, 0, 0, 0, 0, command_array[priv_id], diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 2cf1637c8db..570da144b46 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -2,7 +2,7 @@ #define SQL_ACL_INCLUDED /* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved. - Copyright (c) 2017, MariaDB Corporation. + Copyright (c) 2017, 2020, 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 @@ -280,7 +280,8 @@ bool acl_check_proxy_grant_access (THD *thd, const char *host, const char *user, bool with_grant); int acl_setrole(THD *thd, const char *rolename, privilege_t access); int acl_check_setrole(THD *thd, const char *rolename, privilege_t *access); -int acl_check_set_default_role(THD *thd, const char *host, const char *user); +int acl_check_set_default_role(THD *thd, const char *host, const char *user, + const char *role); int acl_set_default_role(THD *thd, const char *host, const char *user, const char *rolename); diff --git a/sql/sql_statistics.cc b/sql/sql_statistics.cc index 0598698f7e5..879955af723 100644 --- a/sql/sql_statistics.cc +++ b/sql/sql_statistics.cc @@ -1,5 +1,5 @@ /* Copyright (C) 2009 MySQL AB - Copyright (c) 2019, MariaDB Corporation. + Copyright (c) 2019, 2020, 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 @@ -2231,27 +2231,13 @@ static int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share) DBUG_ENTER("alloc_statistics_for_table_share"); - DEBUG_SYNC(thd, "statistics_mem_alloc_start1"); - DEBUG_SYNC(thd, "statistics_mem_alloc_start2"); - - mysql_mutex_lock(&table_share->LOCK_share); - - if (stats_cb->stats_can_be_read) - { - mysql_mutex_unlock(&table_share->LOCK_share); - DBUG_RETURN(0); - } - Table_statistics *table_stats= stats_cb->table_stats; if (!table_stats) { table_stats= (Table_statistics *) alloc_root(&stats_cb->mem_root, sizeof(Table_statistics)); if (!table_stats) - { - mysql_mutex_unlock(&table_share->LOCK_share); DBUG_RETURN(1); - } memset(table_stats, 0, sizeof(Table_statistics)); stats_cb->table_stats= table_stats; } @@ -2317,89 +2303,11 @@ static int alloc_statistics_for_table_share(THD* thd, TABLE_SHARE *table_share) } } } - - if (column_stats && index_stats && idx_avg_frequency) - stats_cb->stats_can_be_read= TRUE; - - mysql_mutex_unlock(&table_share->LOCK_share); - - DBUG_RETURN(0); + DBUG_RETURN(column_stats && index_stats && idx_avg_frequency ? 0 : 1); } /** - @brief - Allocate memory for the histogram used by a table share - - @param - thd Thread handler - @param - table_share Table share for which the memory for histogram data is allocated - @param - is_safe TRUE <-> at any time only one thread can perform the function - - @note - The function allocates the memory for the histogram built for a table in the - table's share memory with the intention to read the data there from the - system persistent statistical table mysql.column_stats, - The memory is allocated in the table_share's mem_root. - If the parameter is_safe is TRUE then it is guaranteed that at any given time - only one thread is executed the code of the function. - - @retval - 0 If the memory for all statistical data has been successfully allocated - @retval - 1 Otherwise - - @note - Currently the function always is called with the parameter is_safe set - to FALSE. -*/ - -static -int alloc_histograms_for_table_share(THD* thd, TABLE_SHARE *table_share, - bool is_safe) -{ - TABLE_STATISTICS_CB *stats_cb= &table_share->stats_cb; - - DBUG_ENTER("alloc_histograms_for_table_share"); - - if (!is_safe) - mysql_mutex_lock(&table_share->LOCK_share); - - if (stats_cb->histograms_can_be_read) - { - if (!is_safe) - mysql_mutex_unlock(&table_share->LOCK_share); - DBUG_RETURN(0); - } - - Table_statistics *table_stats= stats_cb->table_stats; - ulong total_hist_size= table_stats->total_hist_size; - - if (total_hist_size && !table_stats->histograms) - { - uchar *histograms= (uchar *) alloc_root(&stats_cb->mem_root, - total_hist_size); - if (!histograms) - { - if (!is_safe) - mysql_mutex_unlock(&table_share->LOCK_share); - DBUG_RETURN(1); - } - memset(histograms, 0, total_hist_size); - table_stats->histograms= histograms; - stats_cb->histograms_can_be_read= TRUE; - } - - if (!is_safe) - mysql_mutex_unlock(&table_share->LOCK_share); - - DBUG_RETURN(0); - -} - -/** @brief Initialize the aggregation fields to collect statistics on a column @@ -2991,15 +2899,26 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) Field **field_ptr; KEY *key_info, *key_info_end; TABLE_SHARE *table_share= table->s; - Table_statistics *read_stats= table_share->stats_cb.table_stats; enum_check_fields old_check_level= thd->count_cuted_fields; DBUG_ENTER("read_statistics_for_table"); + DEBUG_SYNC(thd, "statistics_mem_alloc_start1"); + DEBUG_SYNC(thd, "statistics_mem_alloc_start2"); + + if (!table_share->stats_cb.start_stats_load()) + DBUG_RETURN(table_share->stats_cb.stats_are_ready() ? 0 : 1); + + if (alloc_statistics_for_table_share(thd, table_share)) + { + table_share->stats_cb.abort_stats_load(); + DBUG_RETURN(1); + } /* Don't write warnings for internal field conversions */ thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* Read statistics from the statistical table table_stats */ + Table_statistics *read_stats= table_share->stats_cb.table_stats; stat_table= stat_tables[TABLE_STAT].table; Table_stat table_stat(stat_table, table); table_stat.set_key_fields(); @@ -3016,7 +2935,7 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) column_stat.get_stat_values(); total_hist_size+= table_field->read_stats->histogram.get_size(); } - read_stats->total_hist_size= total_hist_size; + table_share->stats_cb.total_hist_size= total_hist_size; /* Read statistics from the statistical table index_stats */ stat_table= stat_tables[INDEX_STAT].table; @@ -3078,9 +2997,8 @@ int read_statistics_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) } } - table->stats_is_read= TRUE; thd->count_cuted_fields= old_check_level; - + table_share->stats_cb.end_stats_load(); DBUG_RETURN(0); } @@ -3120,71 +3038,6 @@ void delete_stat_values_for_table_share(TABLE_SHARE *table_share) /** @brief - Check whether any statistics is to be read for tables from a table list - - @param - thd The thread handle - @param - tables The tables list for whose tables the check is to be done - - @details - The function checks whether for any of the tables opened and locked for - a statement statistics from statistical tables is needed to be read. - - @retval - TRUE statistics for any of the tables is needed to be read - @retval - FALSE Otherwise -*/ - -static -bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables) -{ - if (!tables) - return FALSE; - - /* - Do not read statistics for any query that explicity involves - statistical tables, failure to to do so we may end up - in a deadlock. - */ - - for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) - { - if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table) - { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && - table_share->table_category != TABLE_CATEGORY_USER - && is_stat_table(&tl->db, &tl->alias)) - return FALSE; - } - } - - for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) - { - if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table) - { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && - table_share->stats_cb.stats_can_be_read && - (!table_share->stats_cb.stats_is_read || - (!table_share->stats_cb.histograms_are_read && - thd->variables.optimizer_use_condition_selectivity > 3))) - return TRUE; - if (table_share->stats_cb.stats_is_read) - tl->table->stats_is_read= TRUE; - if (table_share->stats_cb.histograms_are_read) - tl->table->histograms_are_read= TRUE; - } - } - - return FALSE; -} - - -/** - @brief Read histogram for a table from the persistent statistical tables @param @@ -3218,26 +3071,25 @@ bool statistics_for_tables_is_needed(THD *thd, TABLE_LIST *tables) static int read_histograms_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) { - TABLE_SHARE *table_share= table->s; - + TABLE_STATISTICS_CB *stats_cb= &table->s->stats_cb; DBUG_ENTER("read_histograms_for_table"); - if (!table_share->stats_cb.histograms_can_be_read) + if (stats_cb->start_histograms_load()) { - (void) alloc_histograms_for_table_share(thd, table_share, FALSE); - } - if (table_share->stats_cb.histograms_can_be_read && - !table_share->stats_cb.histograms_are_read) - { - Field **field_ptr; - uchar *histogram= table_share->stats_cb.table_stats->histograms; - TABLE *stat_table= stat_tables[COLUMN_STAT].table; - Column_stat column_stat(stat_table, table); - for (field_ptr= table_share->field; *field_ptr; field_ptr++) + uchar *histogram= (uchar *) alloc_root(&stats_cb->mem_root, + stats_cb->total_hist_size); + if (!histogram) + { + stats_cb->abort_histograms_load(); + DBUG_RETURN(1); + } + memset(histogram, 0, stats_cb->total_hist_size); + + Column_stat column_stat(stat_tables[COLUMN_STAT].table, table); + for (Field **field_ptr= table->s->field; *field_ptr; field_ptr++) { Field *table_field= *field_ptr; - uint hist_size= table_field->read_stats->histogram.get_size(); - if (hist_size) + if (uint hist_size= table_field->read_stats->histogram.get_size()) { column_stat.set_key_fields(table_field); table_field->read_stats->histogram.set_values(histogram); @@ -3245,8 +3097,9 @@ int read_histograms_for_table(THD *thd, TABLE *table, TABLE_LIST *stat_tables) histogram+= hist_size; } } + stats_cb->end_histograms_load(); } - + table->histograms_are_read= true; DBUG_RETURN(0); } @@ -3294,6 +3147,23 @@ int read_statistics_for_tables_if_needed(THD *thd, TABLE_LIST *tables) } +static void dump_stats_from_share_to_table(TABLE *table) +{ + TABLE_SHARE *table_share= table->s; + KEY *key_info= table_share->key_info; + KEY *key_info_end= key_info + table_share->keys; + KEY *table_key_info= table->key_info; + for ( ; key_info < key_info_end; key_info++, table_key_info++) + table_key_info->read_stats= key_info->read_stats; + + Field **field_ptr= table_share->field; + Field **table_field_ptr= table->field; + for ( ; *field_ptr; field_ptr++, table_field_ptr++) + (*table_field_ptr)->read_stats= (*field_ptr)->read_stats; + table->stats_is_read= true; +} + + int read_statistics_for_tables(THD *thd, TABLE_LIST *tables) { TABLE_LIST stat_tables[STATISTICS_TABLES]; @@ -3303,38 +3173,42 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables) if (thd->bootstrap || thd->variables.use_stat_tables == NEVER) DBUG_RETURN(0); + bool found_stat_table= false; + bool statistics_for_tables_is_needed= false; + for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) { - if (tl->table) + TABLE_SHARE *table_share; + if (!tl->is_view_or_derived() && tl->table && (table_share= tl->table->s) && + table_share->tmp_table == NO_TMP_TABLE) { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && table_share->table_category == TABLE_CATEGORY_USER && - table_share->tmp_table == NO_TMP_TABLE) + if (table_share->table_category == TABLE_CATEGORY_USER) { - if (table_share->stats_cb.stats_can_be_read || - !alloc_statistics_for_table_share(thd, table_share)) + if (table_share->stats_cb.stats_are_ready()) { - if (table_share->stats_cb.stats_can_be_read) - { - KEY *key_info= table_share->key_info; - KEY *key_info_end= key_info + table_share->keys; - KEY *table_key_info= tl->table->key_info; - for ( ; key_info < key_info_end; key_info++, table_key_info++) - table_key_info->read_stats= key_info->read_stats; - Field **field_ptr= table_share->field; - Field **table_field_ptr= tl->table->field; - for ( ; *field_ptr; field_ptr++, table_field_ptr++) - (*table_field_ptr)->read_stats= (*field_ptr)->read_stats; - tl->table->stats_is_read= table_share->stats_cb.stats_is_read; - } + if (!tl->table->stats_is_read) + dump_stats_from_share_to_table(tl->table); + tl->table->histograms_are_read= + table_share->stats_cb.histograms_are_ready(); + if (table_share->stats_cb.histograms_are_ready() || + thd->variables.optimizer_use_condition_selectivity <= 3) + continue; } + statistics_for_tables_is_needed= true; } + else if (is_stat_table(&tl->db, &tl->alias)) + found_stat_table= true; } } DEBUG_SYNC(thd, "statistics_read_start"); - if (!statistics_for_tables_is_needed(thd, tables)) + /* + Do not read statistics for any query that explicity involves + statistical tables, failure to to do so we may end up + in a deadlock. + */ + if (found_stat_table || !statistics_for_tables_is_needed) DBUG_RETURN(0); start_new_trans new_trans(thd); @@ -3344,32 +3218,22 @@ int read_statistics_for_tables(THD *thd, TABLE_LIST *tables) for (TABLE_LIST *tl= tables; tl; tl= tl->next_global) { - if (!tl->is_view_or_derived() && !is_temporary_table(tl) && tl->table) - { - TABLE_SHARE *table_share= tl->table->s; - if (table_share && !(table_share->table_category == TABLE_CATEGORY_USER)) - continue; - - if (table_share && - table_share->stats_cb.stats_can_be_read && - !table_share->stats_cb.stats_is_read) + TABLE_SHARE *table_share; + if (!tl->is_view_or_derived() && tl->table && (table_share= tl->table->s) && + table_share->tmp_table == NO_TMP_TABLE && + table_share->table_category == TABLE_CATEGORY_USER) + { + if (!tl->table->stats_is_read) { - (void) read_statistics_for_table(thd, tl->table, stat_tables); - table_share->stats_cb.stats_is_read= TRUE; + if (!read_statistics_for_table(thd, tl->table, stat_tables)) + dump_stats_from_share_to_table(tl->table); + else + continue; } - if (table_share->stats_cb.stats_is_read) - tl->table->stats_is_read= TRUE; - if (thd->variables.optimizer_use_condition_selectivity > 3 && - table_share && table_share->stats_cb.stats_can_be_read && - !table_share->stats_cb.histograms_are_read) - { + if (thd->variables.optimizer_use_condition_selectivity > 3) (void) read_histograms_for_table(thd, tl->table, stat_tables); - table_share->stats_cb.histograms_are_read= TRUE; - } - if (table_share->stats_cb.histograms_are_read) - tl->table->histograms_are_read= TRUE; } - } + } thd->commit_whole_transaction_and_close_tables(); new_trans.restore_old_transaction(); diff --git a/sql/sql_statistics.h b/sql/sql_statistics.h index 5fc9d7b5c75..b90c614b74f 100644 --- a/sql/sql_statistics.h +++ b/sql/sql_statistics.h @@ -295,7 +295,6 @@ public: Column_statistics *column_stats; /* Array of statistical data for columns */ Index_statistics *index_stats; /* Array of statistical data for indexes */ ulong *idx_avg_frequency; /* Array of records per key for index prefixes */ - ulong total_hist_size; /* Total size of all histograms */ uchar *histograms; /* Sequence of histograms */ }; diff --git a/sql/table.cc b/sql/table.cc index 9273e01572e..41e75347877 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -465,10 +465,6 @@ void TABLE_SHARE::destroy() delete_stat_values_for_table_share(this); delete sequence; free_root(&stats_cb.mem_root, MYF(0)); - stats_cb.stats_can_be_read= FALSE; - stats_cb.stats_is_read= FALSE; - stats_cb.histograms_can_be_read= FALSE; - stats_cb.histograms_are_read= FALSE; /* The mutexes are initialized only for shares that are part of the TDC */ if (tmp_table == NO_TMP_TABLE) diff --git a/sql/table.h b/sql/table.h index 2c7a042be69..f2fad6c19b2 100644 --- a/sql/table.h +++ b/sql/table.h @@ -25,6 +25,7 @@ #ifndef MYSQL_CLIENT +#include "my_cpu.h" /* LF_BACKOFF() */ #include "hash.h" /* HASH */ #include "handler.h" /* row_type, ha_choice, handler */ #include "mysql_com.h" /* enum_field_types */ @@ -607,15 +608,94 @@ enum open_frm_error { from persistent statistical tables */ -struct TABLE_STATISTICS_CB +class TABLE_STATISTICS_CB { + class Statistics_state + { + enum state_codes + { + EMPTY, /** data is not loaded */ + LOADING, /** data is being loaded in some connection */ + READY /** data is loaded and available for use */ + }; + int32 state; + + public: + /** No state copy */ + Statistics_state &operator=(const Statistics_state &) { return *this; } + + /** Checks if data loading have been completed */ + bool is_ready() const + { + return my_atomic_load32_explicit(const_cast<int32*>(&state), + MY_MEMORY_ORDER_ACQUIRE) == READY; + } + + /** + Sets mutual exclusion for data loading + + If stats are in LOADING state, waits until state change. + + @return + @retval true atomic EMPTY -> LOADING transfer completed, ok to load + @retval false stats are in READY state, no need to load + */ + bool start_load() + { + for (;;) + { + int32 expected= EMPTY; + if (my_atomic_cas32_weak_explicit(&state, &expected, LOADING, + MY_MEMORY_ORDER_RELAXED, + MY_MEMORY_ORDER_RELAXED)) + return true; + if (expected == READY) + return false; + (void) LF_BACKOFF(); + } + } + + /** Marks data available for subsequent use */ + void end_load() + { + DBUG_ASSERT(my_atomic_load32_explicit(&state, MY_MEMORY_ORDER_RELAXED) == + LOADING); + my_atomic_store32_explicit(&state, READY, MY_MEMORY_ORDER_RELEASE); + } + + /** Restores empty state on error (e.g. OOM) */ + void abort_load() + { + DBUG_ASSERT(my_atomic_load32_explicit(&state, MY_MEMORY_ORDER_RELAXED) == + LOADING); + my_atomic_store32_explicit(&state, EMPTY, MY_MEMORY_ORDER_RELAXED); + } + }; + + class Statistics_state stats_state; + class Statistics_state hist_state; + +public: MEM_ROOT mem_root; /* MEM_ROOT to allocate statistical data for the table */ Table_statistics *table_stats; /* Structure to access the statistical data */ - bool stats_can_be_read; /* Memory for statistical data is allocated */ - bool stats_is_read; /* Statistical data for table has been read - from statistical tables */ - bool histograms_can_be_read; - bool histograms_are_read; + ulong total_hist_size; /* Total size of all histograms */ + + bool histograms_are_ready() const + { + return !total_hist_size || hist_state.is_ready(); + } + + bool start_histograms_load() + { + return total_hist_size && hist_state.start_load(); + } + + void end_histograms_load() { hist_state.end_load(); } + void abort_histograms_load() { hist_state.abort_load(); } + bool stats_are_ready() const { return stats_state.is_ready(); } + bool start_stats_load() { return stats_state.start_load(); } + void end_stats_load() { stats_state.end_load(); } + void abort_stats_load() { stats_state.abort_load(); } }; /** diff --git a/storage/connect/CMakeLists.txt b/storage/connect/CMakeLists.txt index 4ce5b9c6429..e2a919d4684 100644 --- a/storage/connect/CMakeLists.txt +++ b/storage/connect/CMakeLists.txt @@ -314,7 +314,7 @@ ENDIF(CONNECT_WITH_MONGO) OPTION(CONNECT_WITH_REST "Compile CONNECT storage engine with REST support" ON) IF(CONNECT_WITH_REST) - MESSAGE(STATUS "=====> REST support is ON") + MESSAGE_ONCE(CONNECT_WITH_REST "REST support is ON") SET(CONNECT_SOURCES ${CONNECT_SOURCES} tabrest.cpp tabrest.h) add_definitions(-DREST_SUPPORT) FIND_PACKAGE(cpprestsdk QUIET) diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc index 8f97d674d15..9ddc2025fcf 100644 --- a/storage/innobase/btr/btr0cur.cc +++ b/storage/innobase/btr/btr0cur.cc @@ -4544,7 +4544,7 @@ btr_cur_optimistic_update( ULINT_UNDEFINED, heap); #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG ut_a(!rec_offs_any_null_extern(rec, *offsets) - || trx_is_recv(thr_get_trx(thr))); + || thr_get_trx(thr) == trx_roll_crash_recv_trx); #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (UNIV_LIKELY(!update->is_metadata()) diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc index d2a51736793..7b2251fd7de 100644 --- a/storage/innobase/btr/btr0pcur.cc +++ b/storage/innobase/btr/btr0pcur.cc @@ -154,7 +154,7 @@ before_first: ut_ad(index->table->instant); ut_ad(page_get_n_recs(block->frame) == 1); ut_ad(page_is_leaf(block->frame)); - ut_ad(page_get_page_no(block->frame) == index->page); + ut_ad(!page_has_siblings(block->frame)); cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE; return; } diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc index bce9e90e7a7..2b70c0ccff1 100644 --- a/storage/innobase/buf/buf0buf.cc +++ b/storage/innobase/buf/buf0buf.cc @@ -3725,7 +3725,7 @@ evict_from_pool: /* Decompress the page while not holding buf_pool.mutex or block->mutex. */ - if (!buf_zip_decompress(block, TRUE)) { + if (!buf_zip_decompress(block, false)) { mutex_enter(&buf_pool.mutex); buf_page_mutex_enter(fix_block); buf_block_set_io_fix(fix_block, BUF_IO_NONE); diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc index 2180f494a22..6f2e685a441 100644 --- a/storage/innobase/buf/buf0flu.cc +++ b/storage/innobase/buf/buf0flu.cc @@ -1132,7 +1132,7 @@ buf_flush_write_block_low( break; case BUF_BLOCK_ZIP_DIRTY: frame = bpage->zip.data; - ut_a(page_zip_verify_checksum(frame, bpage->zip_size())); + buf_flush_update_zip_checksum(frame, bpage->zip_size()); break; case BUF_BLOCK_FILE_PAGE: frame = bpage->zip.data; diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc index eb20aca98a0..66aa34254a6 100644 --- a/storage/innobase/buf/buf0lru.cc +++ b/storage/innobase/buf/buf0lru.cc @@ -1443,27 +1443,6 @@ func_exit: UNIV_MEM_INVALID(((buf_block_t*) bpage)->frame, srv_page_size); - if (b != NULL) { - - /* Compute and stamp the compressed page - checksum while not holding any mutex. The - block is already half-freed - (BUF_BLOCK_REMOVE_HASH) and removed from - buf_pool.page_hash, thus inaccessible by any - other thread. */ - - ut_ad(b->zip_size()); - - const uint32_t checksum = page_zip_calc_checksum( - b->zip.data, - b->zip_size(), - static_cast<srv_checksum_algorithm_t>( - srv_checksum_algorithm)); - - mach_write_to_4(b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM, - checksum); - } - mutex_enter(&buf_pool.mutex); if (b != NULL) { diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index c908b033cb5..4ed4237fd18 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -3507,7 +3507,7 @@ static int innodb_init_params() pages, even for larger pages */ if (srv_page_size > UNIV_PAGE_SIZE_DEF && innobase_buffer_pool_size < (24 * 1024 * 1024)) { - ib::info() << "innodb_page_size=" + ib::error() << "innodb_page_size=" << srv_page_size << " requires " << "innodb_buffer_pool_size > 24M current " << innobase_buffer_pool_size; diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h index 63aeaa9251b..651fcb1aa36 100644 --- a/storage/innobase/include/que0que.h +++ b/storage/innobase/include/que0que.h @@ -154,16 +154,6 @@ trx_t* thr_get_trx( /*========*/ que_thr_t* thr); /*!< in: query thread */ -/*******************************************************************//** -Determines if this thread is rolling back an incomplete transaction -in crash recovery. -@return TRUE if thr is rolling back an incomplete transaction in crash -recovery */ -UNIV_INLINE -ibool -thr_is_recv( -/*========*/ - const que_thr_t* thr); /*!< in: query thread */ /***********************************************************************//** Gets the type of a graph node. */ UNIV_INLINE diff --git a/storage/innobase/include/que0que.ic b/storage/innobase/include/que0que.ic index 5b775820df7..1c3ac242bf2 100644 --- a/storage/innobase/include/que0que.ic +++ b/storage/innobase/include/que0que.ic @@ -1,6 +1,7 @@ /***************************************************************************** Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved. +Copyright (c) 2020, 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 @@ -36,20 +37,6 @@ thr_get_trx( return(thr->graph->trx); } -/*******************************************************************//** -Determines if this thread is rolling back an incomplete transaction -in crash recovery. -@return TRUE if thr is rolling back an incomplete transaction in crash -recovery */ -UNIV_INLINE -ibool -thr_is_recv( -/*========*/ - const que_thr_t* thr) /*!< in: query thread */ -{ - return(trx_is_recv(thr->graph->trx)); -} - /***********************************************************************//** Gets the first thr in a fork. */ UNIV_INLINE diff --git a/storage/innobase/include/trx0roll.h b/storage/innobase/include/trx0roll.h index 89b8bdead53..6a562dcb425 100644 --- a/storage/innobase/include/trx0roll.h +++ b/storage/innobase/include/trx0roll.h @@ -35,15 +35,6 @@ extern bool trx_rollback_is_active; extern const trx_t* trx_roll_crash_recv_trx; /*******************************************************************//** -Determines if this transaction is rolling back an incomplete transaction -in crash recovery. -@return TRUE if trx is an incomplete transaction that is being rolled -back in crash recovery */ -ibool -trx_is_recv( -/*========*/ - const trx_t* trx); /*!< in: transaction */ -/*******************************************************************//** Returns a transaction savepoint taken at this point in time. @return savepoint */ trx_savept_t diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc index 2fb48f4036a..39f7ddbd79a 100644 --- a/storage/innobase/row/row0umod.cc +++ b/storage/innobase/row/row0umod.cc @@ -964,7 +964,7 @@ row_undo_mod_upd_del_sec( does not exist. However, this situation may only occur during the rollback of incomplete transactions. */ - ut_a(thr_is_recv(thr)); + ut_a(thr_get_trx(thr) == trx_roll_crash_recv_trx); } else { err = row_undo_mod_del_mark_or_remove_sec( node, thr, index, entry); diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc index 06c18e15ef3..5583cab54da 100644 --- a/storage/innobase/row/row0upd.cc +++ b/storage/innobase/row/row0upd.cc @@ -1557,7 +1557,8 @@ row_upd_changes_ord_field_binary_func( when the server had crashed before storing the field. */ ut_ad(thr->graph->trx->is_recovered); - ut_ad(trx_is_recv(thr->graph->trx)); + ut_ad(thr->graph->trx + == trx_roll_crash_recv_trx); return(TRUE); } diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc index 5a05ce988f9..cda1bd6f22c 100644 --- a/storage/innobase/trx/trx0rec.cc +++ b/storage/innobase/trx/trx0rec.cc @@ -1915,10 +1915,9 @@ dberr_t trx_undo_report_rename(trx_t* trx, const dict_table_t* table) } } } - - mtr.commit(); } + mtr.commit(); return err; } diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc index 3d89bea98e9..85daf649c6a 100644 --- a/storage/innobase/trx/trx0roll.cc +++ b/storage/innobase/trx/trx0roll.cc @@ -570,19 +570,6 @@ trx_release_savepoint_for_mysql( } /*******************************************************************//** -Determines if this transaction is rolling back an incomplete transaction -in crash recovery. -@return TRUE if trx is an incomplete transaction that is being rolled -back in crash recovery */ -ibool -trx_is_recv( -/*========*/ - const trx_t* trx) /*!< in: transaction */ -{ - return(trx == trx_roll_crash_recv_trx); -} - -/*******************************************************************//** Returns a transaction savepoint taken at this point in time. @return savepoint */ trx_savept_t diff --git a/storage/mroonga/mrn_table.cpp b/storage/mroonga/mrn_table.cpp index b10668cfcce..b1b2db6161b 100644 --- a/storage/mroonga/mrn_table.cpp +++ b/storage/mroonga/mrn_table.cpp @@ -932,7 +932,7 @@ MRN_SHARE *mrn_get_share(const char *table_name, TABLE *table, int *error) share->wrap_key_info = NULL; share->wrap_primary_key = MAX_KEY; } - memcpy(wrap_table_share, table->s, sizeof(*wrap_table_share)); + *wrap_table_share= *table->s; mrn_init_sql_alloc(current_thd, &(wrap_table_share->mem_root)); wrap_table_share->keys = share->wrap_keys; wrap_table_share->key_info = share->wrap_key_info; |