summaryrefslogtreecommitdiff
path: root/sql/sql_acl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_acl.cc')
-rw-r--r--sql/sql_acl.cc416
1 files changed, 274 insertions, 142 deletions
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 052c5ada3a2..954f588b061 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -187,6 +187,8 @@ public:
bool eq(const char *user2, const char *host2) { return !cmp(user2, host2); }
+ const char *get_username(){ return user.str; }
+
bool wild_eq(const char *user2, const char *host2, const char *ip2)
{
if (strcmp(user.str, user2))
@@ -228,6 +230,8 @@ public:
acl_host_and_ip host;
const char *user,*db;
ulong initial_access; /* access bits present in the table */
+
+ const char *get_username() { return user; }
};
#ifndef DBUG_OFF
@@ -592,7 +596,9 @@ bool ROLE_GRANT_PAIR::init(MEM_ROOT *mem, const char *username,
/* Flag to mark that on_node was already called for this role */
#define ROLE_OPENED (1L << 3)
-static DYNAMIC_ARRAY acl_hosts, acl_users, acl_dbs, acl_proxy_users;
+static DYNAMIC_ARRAY acl_hosts, acl_users, acl_proxy_users;
+static Dynamic_array<ACL_DB> acl_dbs(0U,50U);
+typedef Dynamic_array<ACL_DB>::CMP_FUNC acl_dbs_cmp;
static HASH acl_roles;
/*
An hash containing mappings user <--> role
@@ -610,7 +616,11 @@ static DYNAMIC_ARRAY acl_wild_hosts;
static Hash_filo<acl_entry> *acl_cache;
static uint grant_version=0; /* Version of priv tables. incremented by acl_load */
static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
-static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
+static int acl_compare(const ACL_ACCESS *a, const ACL_ACCESS *b);
+static int acl_user_compare(const ACL_USER *a, const ACL_USER *b);
+static void rebuild_acl_users();
+static int acl_db_compare(const ACL_DB *a, const ACL_DB *b);
+static void rebuild_acl_dbs();
static ulong get_sort(uint count,...);
static void init_check_host(void);
static void rebuild_check_host(void);
@@ -1973,8 +1983,7 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
DBUG_PRINT("info", ("Found user %s", user.user.str));
push_new_user(user);
}
- my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
- sizeof(ACL_USER),(qsort_cmp) acl_compare);
+ rebuild_acl_users();
end_read_record(&read_record_info);
freeze_size(&acl_users);
@@ -2036,12 +2045,11 @@ static bool acl_load(THD *thd, const Grant_tables& tables)
db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
}
#endif
- (void) push_dynamic(&acl_dbs,(uchar*) &db);
+ acl_dbs.push(db);
}
- my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
- sizeof(ACL_DB),(qsort_cmp) acl_compare);
end_read_record(&read_record_info);
- freeze_size(&acl_dbs);
+ rebuild_acl_dbs();
+ acl_dbs.freeze();
const Proxies_priv_table& proxies_priv_table= tables.proxies_priv_table();
if (proxies_priv_table.table_exists())
@@ -2120,7 +2128,7 @@ void acl_free(bool end)
free_root(&acl_memroot,MYF(0));
delete_dynamic(&acl_hosts);
delete_dynamic_with_callback(&acl_users, (FREE_FUNC) free_acl_user);
- delete_dynamic(&acl_dbs);
+ acl_dbs.free_memory();
delete_dynamic(&acl_wild_hosts);
delete_dynamic(&acl_proxy_users);
my_hash_free(&acl_check_hosts);
@@ -2158,7 +2166,8 @@ void acl_free(bool end)
bool acl_reload(THD *thd)
{
- DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_dbs, old_acl_proxy_users;
+ DYNAMIC_ARRAY old_acl_hosts, old_acl_users, old_acl_proxy_users;
+ Dynamic_array<ACL_DB> old_acl_dbs(0U,0U);
HASH old_acl_roles, old_acl_roles_mappings;
MEM_ROOT old_mem;
int result;
@@ -2194,7 +2203,7 @@ bool acl_reload(THD *thd)
old_acl_dbs= acl_dbs;
my_init_dynamic_array(&acl_hosts, sizeof(ACL_HOST), 20, 50, MYF(0));
my_init_dynamic_array(&acl_users, sizeof(ACL_USER), 50, 100, MYF(0));
- my_init_dynamic_array(&acl_dbs, sizeof(ACL_DB), 50, 100, MYF(0));
+ acl_dbs.init(50, 100);
my_init_dynamic_array(&acl_proxy_users, sizeof(ACL_PROXY_USER), 50, 100, MYF(0));
my_hash_init2(&acl_roles,50, &my_charset_utf8_bin,
0, 0, 0, (my_hash_get_key) acl_role_get_key, 0,
@@ -2215,6 +2224,7 @@ bool acl_reload(THD *thd)
acl_roles_mappings= old_acl_roles_mappings;
acl_proxy_users= old_acl_proxy_users;
acl_dbs= old_acl_dbs;
+ old_acl_dbs.init(0,0);
acl_memroot= old_mem;
init_check_host();
}
@@ -2225,7 +2235,6 @@ bool acl_reload(THD *thd)
delete_dynamic(&old_acl_hosts);
delete_dynamic_with_callback(&old_acl_users, (FREE_FUNC) free_acl_user);
delete_dynamic(&old_acl_proxy_users);
- delete_dynamic(&old_acl_dbs);
my_hash_free(&old_acl_roles_mappings);
}
mysql_mutex_unlock(&acl_cache->lock);
@@ -2317,7 +2326,7 @@ static ulong get_sort(uint count,...)
}
-static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
+static int acl_compare(const ACL_ACCESS *a, const ACL_ACCESS *b)
{
if (a->sort > b->sort)
return -1;
@@ -2326,6 +2335,154 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
return 0;
}
+static int acl_user_compare(const ACL_USER *a, const ACL_USER *b)
+{
+ int res= strcmp(a->user.str, b->user.str);
+ if (res)
+ return res;
+
+ res= acl_compare(a, b);
+ if (res)
+ return res;
+
+ /*
+ For more deterministic results, resolve ambiguity between
+ "localhost" and "127.0.0.1"/"::1" by sorting "localhost" before
+ loopback addresses.
+ Test suite (on Windows) expects "root@localhost", even if
+ root@::1 would also match.
+ */
+ return -strcmp(a->host.hostname, b->host.hostname);
+}
+
+static int acl_db_compare(const ACL_DB *a, const ACL_DB *b)
+{
+ int res= strcmp(a->user, b->user);
+ if (res)
+ return res;
+
+ return acl_compare(a, b);
+}
+
+static void rebuild_acl_users()
+{
+ my_qsort((uchar*)dynamic_element(&acl_users, 0, ACL_USER*), acl_users.elements,
+ sizeof(ACL_USER), (qsort_cmp)acl_user_compare);
+}
+
+static void rebuild_acl_dbs()
+{
+ acl_dbs.sort(acl_db_compare);
+}
+
+
+/*
+ Return index of the first entry with given user in the array,
+ or UINT_MAX if not found.
+
+ Assumes the array is sorted by get_username
+*/
+template<typename T> uint find_first_user(T* arr, uint len, const char *user)
+{
+ uint low= 0;
+ uint high= len;
+ uint mid;
+
+ bool found= false;
+ if(!len)
+ return UINT_MAX;
+
+#ifndef DBUG_OFF
+ for (uint i = 0; i < len - 1; i++)
+ DBUG_ASSERT(strcmp(arr[i].get_username(), arr[i + 1].get_username()) <= 0);
+#endif
+ while (low < high)
+ {
+ mid= low + (high - low) / 2;
+ int cmp= strcmp(arr[mid].get_username(),user);
+ if (cmp == 0)
+ found= true;
+
+ if (cmp >= 0 )
+ high= mid;
+ else
+ low= mid + 1;
+ }
+ return (!found || low == len || strcmp(arr[low].get_username(), user)!=0 )?UINT_MAX:low;
+}
+
+static uint acl_find_user_by_name(const char *user)
+{
+ return find_first_user<ACL_USER>((ACL_USER *)acl_users.buffer,acl_users.elements,user);
+}
+
+static uint acl_find_db_by_username(const char *user)
+{
+ return find_first_user<ACL_DB>(acl_dbs.front(), acl_dbs.elements(), user);
+}
+
+static bool match_db(ACL_DB *acl_db, const char *db, my_bool db_is_pattern)
+{
+ return !acl_db->db || (db && !wild_compare(db, acl_db->db, db_is_pattern));
+}
+
+
+/*
+ Lookup in the acl_users or acl_dbs for the best matching entry corresponding to
+ given user, host and ip parameters (also db, in case of ACL_DB)
+
+ Historical note:
+
+ In the past, both arrays were sorted just by ACL_ENTRY::sort field and were
+ searched linearly, until the first match of (username,host) pair was found.
+
+ This function uses optimizations (binary search by username), yet preserves the
+ historical behavior, i.e the returns a match with highest ACL_ENTRY::sort.
+*/
+template <typename T> T* find_by_username_or_anon(T* arr, size_t len, const char *user,
+ const char *host, const char *ip,
+ const char *db, my_bool db_is_pattern, bool (*match_db_func)(T*,const char *,my_bool))
+{
+ size_t i;
+ T *ret = NULL;
+
+ // Check entries matching user name.
+ size_t start = find_first_user(arr, len, user);
+ for (i= start; i < len; i++)
+ {
+ T *entry= &arr[i];
+ if (i > start && strcmp(user, entry->get_username()))
+ break;
+
+ if (compare_hostname(&entry->host, host, ip) && (!match_db_func || match_db_func(entry, db, db_is_pattern)))
+ {
+ ret= entry;
+ break;
+ }
+ }
+
+ // Look also for anonymous user (username is empty string)
+ // Due to sort by name, entries for anonymous user start at the start of array.
+ for (i= 0; i < len; i++)
+ {
+ T *entry = &arr[i];
+ if (*entry->get_username() || (ret && acl_compare(entry, ret) >= 0))
+ break;
+ if (compare_hostname(&entry->host, host, ip) && (!match_db_func || match_db_func(entry, db, db_is_pattern)))
+ {
+ ret= entry;
+ break;
+ }
+ }
+ return ret;
+}
+
+static ACL_DB *acl_db_find(const char *db, const char *user, const char *host, const char *ip, my_bool db_is_pattern)
+{
+ return find_by_username_or_anon(acl_dbs.front(), acl_dbs.elements(),
+ user, host, ip, db, db_is_pattern, match_db);
+}
+
/*
Gets user credentials without authentication and resource limit checks.
@@ -2347,7 +2504,6 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
const char *ip, const char *db)
{
int res= 1;
- uint i;
ACL_USER *acl_user= 0;
DBUG_ENTER("acl_getroot");
@@ -2380,21 +2536,9 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
if (acl_user)
{
res= 0;
- for (i=0 ; i < acl_dbs.elements ; i++)
- {
- ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
- if (!*acl_db->user || !strcmp(user, acl_db->user))
- {
- if (compare_hostname(&acl_db->host, host, ip))
- {
- if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0)))
- {
- sctx->db_access= acl_db->access;
- break;
- }
- }
- }
- }
+ if (ACL_DB *acl_db= acl_db_find(db, user, host, ip, FALSE))
+ sctx->db_access= acl_db->access;
+
sctx->master_access= acl_user->access;
strmake_buf(sctx->priv_user, user);
@@ -2409,21 +2553,9 @@ bool acl_getroot(Security_context *sctx, const char *user, const char *host,
if (acl_role)
{
res= 0;
- for (i=0 ; i < acl_dbs.elements ; i++)
- {
- ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
- if (!*acl_db->user || !strcmp(user, acl_db->user))
- {
- if (compare_hostname(&acl_db->host, "", ""))
- {
- if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0)))
- {
- sctx->db_access= acl_db->access;
- break;
- }
- }
- }
- }
+ if (ACL_DB *acl_db= acl_db_find(db, user, "", "", FALSE))
+ sctx->db_access = acl_db->access;
+
sctx->master_access= acl_role->access;
strmake_buf(sctx->priv_role, user);
@@ -2622,10 +2754,10 @@ static bool acl_update_db(const char *user, const char *host, const char *db,
bool updated= false;
- for (uint i=0 ; i < acl_dbs.elements ; i++)
+ for (uint i= acl_find_db_by_username(user); i < acl_dbs.elements(); i++)
{
- ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
- if (!strcmp(user, acl_db->user))
+ ACL_DB *acl_db= &acl_dbs.at(i);
+ if (!strcmp(user,acl_db->user))
{
if ((!acl_db->host.hostname && !host[0]) ||
(acl_db->host.hostname && !strcmp(host, acl_db->host.hostname)))
@@ -2640,11 +2772,13 @@ static bool acl_update_db(const char *user, const char *host, const char *db,
acl_db->initial_access= acl_db->access;
}
else
- delete_dynamic_element(&acl_dbs,i);
+ acl_dbs.del(i);
updated= true;
}
}
}
+ else
+ break;
}
return updated;
@@ -2675,9 +2809,8 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
acl_db.db=strdup_root(&acl_memroot,db);
acl_db.initial_access= acl_db.access= privileges;
acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
- (void) push_dynamic(&acl_dbs,(uchar*) &acl_db);
- my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
- sizeof(ACL_DB),(qsort_cmp) acl_compare);
+ acl_dbs.push(acl_db);
+ rebuild_acl_dbs();
}
@@ -2723,26 +2856,16 @@ ulong acl_get(const char *host, const char *ip,
/*
Check if there are some access rights for database and user
*/
- for (i=0 ; i < acl_dbs.elements ; i++)
+ if (ACL_DB *acl_db= acl_db_find(db,user, host, ip, db_is_pattern))
{
- ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
- if (!*acl_db->user || !strcmp(user, acl_db->user))
- {
- if (compare_hostname(&acl_db->host,host,ip))
- {
- if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern))
- {
- db_access=acl_db->access;
- if (acl_db->host.hostname)
- goto exit; // Fully specified. Take it
- /* the host table is not used for roles */
- if ((!host || !host[0]) && !acl_db->host.hostname && find_acl_role(user))
- goto exit;
- break; /* purecov: tested */
- }
- }
- }
+ db_access= acl_db->access;
+ if (acl_db->host.hostname)
+ goto exit; // Fully specified. Take it
+ /* the host table is not used for roles */
+ if ((!host || !host[0]) && !acl_db->host.hostname && find_acl_role(user))
+ goto exit;
}
+
if (!db_access)
goto exit; // Can't be better
@@ -3397,20 +3520,9 @@ bool is_acl_user(const char *host, const char *user)
*/
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.length ||
- !strcmp(user, acl_user_tmp->user.str)) &&
- compare_hostname(&acl_user_tmp->host, host, ip))
- {
- result= acl_user_tmp;
- break;
- }
- }
- return result;
+ return find_by_username_or_anon<ACL_USER>
+ (reinterpret_cast<ACL_USER*>(acl_users.buffer), acl_users.elements,
+ user, host, ip, NULL, FALSE, NULL);
}
@@ -3420,11 +3532,15 @@ static ACL_USER *find_user_or_anon(const char *host, const char *user, const cha
static ACL_USER *find_user_exact(const char *host, const char *user)
{
mysql_mutex_assert_owner(&acl_cache->lock);
+ uint start= acl_find_user_by_name(user);
- for (uint i=0 ; i < acl_users.elements ; i++)
+ for (uint i= start; i < acl_users.elements; i++)
{
- ACL_USER *acl_user=dynamic_element(&acl_users, i, ACL_USER*);
- if (acl_user->eq(user, host))
+ ACL_USER *acl_user= dynamic_element(&acl_users, i, ACL_USER*);
+ if (i > start && strcmp(acl_user->user.str, user))
+ return 0;
+
+ if (!my_strcasecmp(system_charset_info, acl_user->host.hostname, host))
return acl_user;
}
return 0;
@@ -3437,10 +3553,14 @@ static ACL_USER * find_user_wild(const char *host, const char *user, const char
{
mysql_mutex_assert_owner(&acl_cache->lock);
- for (uint i=0 ; i < acl_users.elements ; i++)
+ uint start = acl_find_user_by_name(user);
+
+ for (uint i= start; i < acl_users.elements; i++)
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
- if (acl_user->wild_eq(user, host, ip))
+ if (i > start && strcmp(acl_user->user.str, user))
+ break;
+ if (compare_hostname(&acl_user->host, host, ip ? ip : host))
return acl_user;
}
return 0;
@@ -3970,8 +4090,7 @@ end:
else
{
push_new_user(new_acl_user);
- my_qsort(dynamic_element(&acl_users, 0, ACL_USER*), acl_users.elements,
- sizeof(ACL_USER),(qsort_cmp) acl_compare);
+ rebuild_acl_users();
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
rebuild_check_host();
@@ -5554,15 +5673,15 @@ static bool merge_role_global_privileges(ACL_ROLE *grantee)
return old != grantee->access;
}
-static int db_name_sort(ACL_DB * const *db1, ACL_DB * const *db2)
+static int db_name_sort(const int *db1, const int *db2)
{
- return strcmp((*db1)->db, (*db2)->db);
+ return strcmp(acl_dbs.at(*db1).db, acl_dbs.at(*db2).db);
}
/**
update ACL_DB for given database and a given role with merged privileges
- @param merged ACL_DB of the role in question (or NULL if it wasn't found)
+ @param merged ACL_DB of the role in question (or -1 if it wasn't found)
@param first first ACL_DB in an array for the database in question
@param access new privileges for the given role on the gived database
@param role the name of the given role
@@ -5572,15 +5691,15 @@ static int db_name_sort(ACL_DB * const *db1, ACL_DB * const *db2)
2 - ACL_DB was added
4 - ACL_DB was deleted
*/
-static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access,
+static int update_role_db(int merged, int first, ulong access,
const char *role)
{
- if (!first)
+ if (first < 0)
return 0;
DBUG_EXECUTE_IF("role_merge_stats", role_db_merges++;);
- if (merged == NULL)
+ if (merged < 0)
{
/*
there's no ACL_DB for this role (all db grants come from granted roles)
@@ -5595,11 +5714,11 @@ static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access,
acl_db.user= role;
acl_db.host.hostname= const_cast<char*>("");
acl_db.host.ip= acl_db.host.ip_mask= 0;
- acl_db.db= first[0]->db;
+ acl_db.db= acl_dbs.at(first).db;
acl_db.access= access;
acl_db.initial_access= 0;
acl_db.sort=get_sort(3, "", acl_db.db, role);
- push_dynamic(&acl_dbs,(uchar*) &acl_db);
+ acl_dbs.push(acl_db);
return 2;
}
else if (access == 0)
@@ -5615,13 +5734,13 @@ static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access,
2. it's O(N) operation, and we may need many of them
so we only mark elements deleted and will delete later.
*/
- merged->sort= 0; // lower than any valid ACL_DB sort value, will be sorted last
+ acl_dbs.at(merged).sort= 0; // lower than any valid ACL_DB sort value, will be sorted last
return 4;
}
- else if (merged->access != access)
+ else if (acl_dbs.at(merged).access != access)
{
/* this is easy */
- merged->access= access;
+ acl_dbs.at(merged).access= access;
return 1;
}
return 0;
@@ -5636,7 +5755,7 @@ static int update_role_db(ACL_DB *merged, ACL_DB **first, ulong access,
static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname,
role_hash_t *rhash)
{
- Dynamic_array<ACL_DB *> dbs;
+ Dynamic_array<int> dbs;
/*
Supposedly acl_dbs can be huge, but only a handful of db grants
@@ -5644,9 +5763,9 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname,
Collect these applicable db grants.
*/
- for (uint i=0 ; i < acl_dbs.elements ; i++)
+ for (uint i=0 ; i < acl_dbs.elements() ; i++)
{
- ACL_DB *db= dynamic_element(&acl_dbs,i,ACL_DB*);
+ ACL_DB *db= &acl_dbs.at(i);
if (db->host.hostname[0])
continue;
if (dbname && strcmp(db->db, dbname))
@@ -5654,7 +5773,7 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname,
ACL_ROLE *r= rhash->find(db->user, strlen(db->user));
if (!r)
continue;
- dbs.append(db);
+ dbs.append(i);
}
dbs.sort(db_name_sort);
@@ -5663,42 +5782,47 @@ static bool merge_role_db_privileges(ACL_ROLE *grantee, const char *dbname,
(that should be merged) are sorted together. The grantee's ACL_DB element
is not necessarily the first and may be not present at all.
*/
- ACL_DB **first= NULL, *merged= NULL;
+ int first= -1, merged= -1;
ulong access= 0, update_flags= 0;
- for (ACL_DB **cur= dbs.front(); cur <= dbs.back(); cur++)
+ for (int *p= dbs.front(); p <= dbs.back(); p++)
{
- if (!first || (!dbname && strcmp(cur[0]->db, cur[-1]->db)))
+ if (first<0 || (!dbname && strcmp(acl_dbs.at(*p).db, acl_dbs.at(*p-1).db)))
{ // new db name series
update_flags|= update_role_db(merged, first, access, grantee->user.str);
- merged= NULL;
+ merged= -1;
access= 0;
- first= cur;
+ first= *p;
}
- if (strcmp(cur[0]->user, grantee->user.str) == 0)
- access|= (merged= cur[0])->initial_access;
+ if (strcmp(acl_dbs.at(*p).user, grantee->user.str) == 0)
+ access|= acl_dbs.at(merged= *p).initial_access;
else
- access|= cur[0]->access;
+ access|= acl_dbs.at(*p).access;
}
update_flags|= update_role_db(merged, first, access, grantee->user.str);
- /*
- to make this code a bit simpler, we sort on deletes, to move
- deleted elements to the end of the array. strictly speaking it's
- unnecessary, it'd be faster to remove them in one O(N) array scan.
-
- on the other hand, qsort on almost sorted array is pretty fast anyway...
- */
- if (update_flags & (2|4))
- { // inserted or deleted, need to sort
- my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
- sizeof(ACL_DB),(qsort_cmp) acl_compare);
- }
if (update_flags & 4)
- { // deleted, trim the end
- while (acl_dbs.elements &&
- dynamic_element(&acl_dbs, acl_dbs.elements-1, ACL_DB*)->sort == 0)
- acl_dbs.elements--;
+ {
+ // Remove elements marked for deletion.
+ uint count= 0;
+ for(uint i= 0; i < acl_dbs.elements(); i++)
+ {
+ ACL_DB *acl_db= &acl_dbs.at(i);
+ if (acl_db->sort)
+ {
+ if (i > count)
+ acl_dbs.set(count, *acl_db);
+ count++;
+ }
+ }
+ acl_dbs.elements(count);
}
+
+
+ if (update_flags & 2)
+ { // inserted, need to sort
+ rebuild_acl_dbs();
+ }
+
return update_flags;
}
@@ -8645,16 +8769,14 @@ static bool show_database_privileges(THD *thd, const char *username,
const char *hostname,
char *buff, size_t buffsize)
{
- ACL_DB *acl_db;
ulong want_access;
- uint counter;
Protocol *protocol= thd->protocol;
- for (counter=0 ; counter < acl_dbs.elements ; counter++)
+ for (uint i=0 ; i < acl_dbs.elements() ; i++)
{
const char *user, *host;
- acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+ ACL_DB *acl_db= &acl_dbs.at(i);
user= acl_db->user;
host=acl_db->host.hostname;
@@ -9409,7 +9531,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
elements= acl_users.elements;
break;
case DB_ACL:
- elements= acl_dbs.elements;
+ elements= acl_dbs.elements();
break;
case COLUMN_PRIVILEGES_HASH:
grant_name_hash= &column_priv_hash;
@@ -9461,7 +9583,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
break;
case DB_ACL:
- acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*);
+ acl_db= &acl_dbs.at(idx);
user= acl_db->user;
host= acl_db->host.hostname;
break;
@@ -9545,7 +9667,7 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop,
break;
case DB_ACL:
- delete_dynamic_element(&acl_dbs, idx);
+ acl_dbs.del(idx);
break;
case COLUMN_PRIVILEGES_HASH:
@@ -10245,6 +10367,8 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
some_users_renamed= TRUE;
}
+ rebuild_acl_users();
+
/* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
rebuild_check_host();
@@ -10438,11 +10562,11 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
*/
do
{
- for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; )
+ for (counter= 0, revoked= 0 ; counter < acl_dbs.elements() ; )
{
- const char *user,*host;
+ const char *user, *host;
- acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+ acl_db= &acl_dbs.at(counter);
user= acl_db->user;
host= safe_str(acl_db->host.hostname);
@@ -11045,6 +11169,14 @@ static int show_column_grants(THD *thd, SHOW_VAR *var, char *buff,
return 0;
}
+static int show_database_grants(THD *thd, SHOW_VAR *var, char *buff,
+ enum enum_var_type scope)
+{
+ var->type= SHOW_UINT;
+ var->value= buff;
+ *(uint *)buff= acl_dbs.elements();
+ return 0;
+}
#else
bool check_grant(THD *, ulong, TABLE_LIST *, bool, uint, bool)
@@ -11056,7 +11188,7 @@ bool check_grant(THD *, ulong, TABLE_LIST *, bool, uint, bool)
SHOW_VAR acl_statistics[] = {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
{"column_grants", (char*)show_column_grants, SHOW_SIMPLE_FUNC},
- {"database_grants", (char*)&acl_dbs.elements, SHOW_UINT},
+ {"database_grants", (char*)show_database_grants, SHOW_SIMPLE_FUNC},
{"function_grants", (char*)&func_priv_hash.records, SHOW_ULONG},
{"procedure_grants", (char*)&proc_priv_hash.records, SHOW_ULONG},
{"package_spec_grants", (char*)&package_spec_priv_hash.records, SHOW_ULONG},
@@ -11329,11 +11461,11 @@ int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
DBUG_RETURN(0);
mysql_mutex_lock(&acl_cache->lock);
- for (counter=0 ; counter < acl_dbs.elements ; counter++)
+ for (counter=0 ; counter < acl_dbs.elements() ; counter++)
{
const char *user, *host, *is_grantable="YES";
- acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
+ acl_db=&acl_dbs.at(counter);
user= acl_db->user;
host= safe_str(acl_db->host.hostname);