mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 02:05:57 +01:00
Merge 10.1 into 10.2
This commit is contained in:
commit
d72eebaa3d
14 changed files with 486 additions and 308 deletions
|
@ -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'
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -66,7 +66,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
|
||||
|
|
|
@ -815,7 +815,6 @@ String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset)
|
|||
String *Item_nodeset_func_predicate::val_nodeset(String *str)
|
||||
{
|
||||
Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
|
||||
Item_func *comp_func= (Item_func*)args[1];
|
||||
uint pos= 0, size;
|
||||
prepare(str);
|
||||
size= (uint)(fltend - fltbeg);
|
||||
|
@ -825,7 +824,7 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str)
|
|||
((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
|
||||
flt->pos,
|
||||
size);
|
||||
if (comp_func->val_int())
|
||||
if (args[1]->val_int())
|
||||
((XPathFilter*)str)->append_element(flt->num, pos++);
|
||||
}
|
||||
return str;
|
||||
|
|
|
@ -971,8 +971,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
|
||||
|
@ -983,7 +992,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
|
||||
|
|
|
@ -350,6 +350,7 @@ class set_var_default_role: public set_var_base
|
|||
{
|
||||
LEX_USER *user, *real_user;
|
||||
LEX_STRING role;
|
||||
const char *real_role;
|
||||
public:
|
||||
set_var_default_role(LEX_USER *user_arg, LEX_STRING role_arg) :
|
||||
user(user_arg), role(role_arg) {}
|
||||
|
|
170
sql/sql_acl.cc
170
sql/sql_acl.cc
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (c) 2000, 2018, Oracle and/or its affiliates.
|
||||
Copyright (c) 2009, 2018, MariaDB
|
||||
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
|
||||
|
@ -201,7 +201,6 @@ LEX_STRING current_user= { C_STRING_WITH_LEN("*current_user") };
|
|||
LEX_STRING current_role= { C_STRING_WITH_LEN("*current_role") };
|
||||
LEX_STRING current_user_and_current_role= { C_STRING_WITH_LEN("*current_user_and_current_role") };
|
||||
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
static plugin_ref old_password_plugin;
|
||||
#endif
|
||||
|
@ -2618,8 +2617,43 @@ bool acl_getroot(Security_context *sctx, char *user, char *host,
|
|||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
static int check_user_can_set_role(const char *user, const char *host,
|
||||
const char *ip, const char *rolename, ulonglong *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)
|
||||
{
|
||||
ACL_USER *result= NULL;
|
||||
mysql_mutex_assert_owner(&acl_cache->lock);
|
||||
for (uint i=0; i < acl_users.elements; i++)
|
||||
{
|
||||
ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
|
||||
if ((!acl_user_tmp->user.str ||
|
||||
!strcmp(user, acl_user_tmp->user.str)) &&
|
||||
compare_hostname(&acl_user_tmp->host, host, ip))
|
||||
{
|
||||
result= acl_user_tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static int check_user_can_set_role(THD *thd, const char *user, const char *host,
|
||||
const char *ip, const char *rolename,
|
||||
ulonglong *access)
|
||||
{
|
||||
ACL_ROLE *role;
|
||||
ACL_USER_BASE *acl_user_base;
|
||||
|
@ -2636,10 +2670,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;
|
||||
|
||||
|
@ -2649,9 +2680,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;
|
||||
}
|
||||
|
||||
|
@ -2672,7 +2703,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;
|
||||
}
|
||||
|
@ -2681,17 +2711,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, char *rolename, ulonglong *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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3471,9 +3550,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,
|
||||
|
@ -3494,16 +3576,6 @@ int acl_set_default_role(THD *thd, const char *host, const char *user,
|
|||
DBUG_PRINT("enter",("host: '%s' user: '%s' rolename: '%s'",
|
||||
safe_str(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;
|
||||
|
||||
|
@ -3667,31 +3739,6 @@ bool is_acl_user(const char *host, const char *user)
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
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)
|
||||
{
|
||||
ACL_USER *result= NULL;
|
||||
mysql_mutex_assert_owner(&acl_cache->lock);
|
||||
for (uint i=0; i < acl_users.elements; i++)
|
||||
{
|
||||
ACL_USER *acl_user_tmp= dynamic_element(&acl_users, i, ACL_USER*);
|
||||
if ((!acl_user_tmp->user.str ||
|
||||
!strcmp(user, acl_user_tmp->user.str)) &&
|
||||
compare_hostname(&acl_user_tmp->host, host, ip))
|
||||
{
|
||||
result= acl_user_tmp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Find first entry that matches the specified user@host pair
|
||||
*/
|
||||
|
@ -3997,7 +4044,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;
|
||||
|
@ -9244,17 +9291,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.
|
||||
|
||||
|
@ -11094,7 +11130,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
|
||||
|
@ -11511,7 +11547,7 @@ int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
|
|||
ulong j,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],
|
||||
|
|
|
@ -409,7 +409,7 @@ bool acl_check_proxy_grant_access (THD *thd, const char *host, const char *user,
|
|||
bool with_grant);
|
||||
int acl_setrole(THD *thd, char *rolename, ulonglong access);
|
||||
int acl_check_setrole(THD *thd, char *rolename, ulonglong *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);
|
||||
|
||||
|
|
|
@ -2216,27 +2216,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;
|
||||
}
|
||||
|
@ -2302,88 +2288,10 @@ 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
|
||||
|
@ -2929,15 +2837,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();
|
||||
|
@ -2954,7 +2873,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;
|
||||
|
@ -3016,9 +2935,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);
|
||||
}
|
||||
|
||||
|
@ -3056,71 +2974,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
|
||||
|
@ -3156,26 +3009,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);
|
||||
|
@ -3183,8 +3035,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);
|
||||
}
|
||||
|
||||
|
@ -3232,6 +3085,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];
|
||||
|
@ -3242,38 +3112,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);
|
||||
|
||||
if (open_stat_tables(thd, stat_tables, &open_tables_backup, FALSE))
|
||||
|
@ -3281,32 +3155,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
close_system_tables(thd, &open_tables_backup);
|
||||
|
||||
|
|
|
@ -280,7 +280,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 */
|
||||
};
|
||||
|
||||
|
|
|
@ -440,10 +440,6 @@ void TABLE_SHARE::destroy()
|
|||
|
||||
delete_stat_values_for_table_share(this);
|
||||
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)
|
||||
|
|
91
sql/table.h
91
sql/table.h
|
@ -567,15 +567,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(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Reference in a new issue