Commit e486fe1f authored by unknown's avatar unknown

WL#2486 - natural/using joins according to SQL:2003

Post-review fixes that simplify the way access rights
are checked during name resolution and factor out all
entry points to check access rights into one single
function.


sql/item.cc:
  Simplfied find_field_in_table - factored out all acces right checks
  into a separate function.
sql/mysql_priv.h:
  Simplified the way we control whether to perform access right
  checks for columns.
sql/sql_acl.cc:
  - Added new functon check_column_grant_in_table_ref that serves as a single
    point of entry to check access rights during name resolution for different
    kinds of table references.
  - Moved check_grant_column_in_sctx to sql_acl.cc where it
    logically belongs.
  - Removed the parameter check_grants - it is checked before
    calling the function.
sql/sql_acl.h:
  - Added new function check_column_grant_in_table_ref.
  - Made check_grant_column_in_sctx available to other modules.
sql/sql_base.cc:
  - Factored out all code that check access rights for columns during
    name resolution into one function - check_column_grant_in_table_ref.
  - Moved check_grant_column_in_sctx to sql_acl.cc where it
    logically belongs.
  - Removed the parameter check_grants - it is checked before
    calling the function.
sql/table.cc:
  Removed code that duplicates the functionality of
  check_column_grant_in_table_ref, and called directly
  that function.
sql/table.h:
  check_grants method is replaced by more general
  check_column_grant_in_table_ref.
parent 4fd41f7c
...@@ -5179,7 +5179,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table) ...@@ -5179,7 +5179,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
set field_idx properly. set field_idx properly.
*/ */
(void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name), (void)find_field_in_table(thd, table, field_name, (uint) strlen(field_name),
0, 0, &field_idx, 0); 0, &field_idx);
thd->set_query_id= save_set_query_id; thd->set_query_id= save_set_query_id;
triggers= table->triggers; triggers= table->triggers;
} }
......
...@@ -794,14 +794,12 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, ...@@ -794,14 +794,12 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
const char *name, uint length, const char *name, uint length,
const char *item_name, const char *db_name, const char *item_name, const char *db_name,
const char *table_name, Item **ref, const char *table_name, Item **ref,
bool check_grants_table, bool check_grants_view, bool check_privileges, bool allow_rowid,
bool allow_rowid, uint *cached_field_index_ptr, uint *cached_field_index_ptr,
bool register_tree_change, TABLE_LIST **actual_table); bool register_tree_change, TABLE_LIST **actual_table);
Field * Field *
find_field_in_table(THD *thd, TABLE *table, const char *name, find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
uint length, bool check_grants, bool allow_rowid, bool allow_rowid, uint *cached_field_index_ptr);
uint *cached_field_index_ptr,
Security_context *sctx);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
#include <openssl/des.h> #include <openssl/des.h>
......
...@@ -2763,7 +2763,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2763,7 +2763,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(), Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
column->column.length(), column->column.length(),
column->column.ptr(), NULL, NULL, column->column.ptr(), NULL, NULL,
0, 1, 1, 0, NULL, TRUE, FALSE,
&unused_field_idx, FALSE, &dummy); &unused_field_idx, FALSE, &dummy);
if (f == (Field*)0) if (f == (Field*)0)
{ {
...@@ -3617,11 +3617,28 @@ err: ...@@ -3617,11 +3617,28 @@ err:
} }
/*
Check column rights in given security context
SYNOPSIS
check_grant_column()
thd thread handler
grant grant information structure
db_name db name
table_name table name
name column name
length column name length
sctx security context
RETURN
FALSE OK
TRUE access denied
*/
bool check_grant_column(THD *thd, GRANT_INFO *grant, bool check_grant_column(THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name, const char *db_name, const char *table_name,
const char *name, uint length, uint show_tables) const char *name, uint length, Security_context *sctx)
{ {
Security_context *sctx= thd->security_ctx;
GRANT_TABLE *grant_table; GRANT_TABLE *grant_table;
GRANT_COLUMN *grant_column; GRANT_COLUMN *grant_column;
ulong want_access= grant->want_privilege & ~grant->privilege; ulong want_access= grant->want_privilege & ~grant->privilege;
...@@ -3652,28 +3669,74 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant, ...@@ -3652,28 +3669,74 @@ bool check_grant_column(THD *thd, GRANT_INFO *grant,
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
#ifdef NOT_USED
if (show_tables && (grant_column || grant->privilege & COL_ACLS))
{
rw_unlock(&LOCK_grant); /* purecov: deadcode */
DBUG_RETURN(0); /* purecov: deadcode */
}
#endif
err: err:
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
if (!show_tables) char command[128];
get_privilege_desc(command, sizeof(command), want_access);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
command,
sctx->priv_user,
sctx->host_or_ip,
name,
table_name);
DBUG_RETURN(1);
}
/*
Check the access right to a column depending on the type of table.
SYNOPSIS
check_column_grant_in_table_ref()
thd thread handler
table_ref table reference where to check the field
name name of field to check
length length of name
DESCRIPTION
Check the access rights to a column depending on the type of table
reference where the column is checked. The function provides a
generic interface to check column access rights that hides the
heterogeneity of the column representation - whether it is a view
or a stored table colum.
RETURN
FALSE OK
TRUE access denied
*/
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
const char *name, uint length)
{
GRANT_INFO *grant;
const char *db_name;
const char *table_name;
Security_context *sctx= test(table_ref->security_ctx) ?
table_ref->security_ctx : thd->security_ctx;
if (table_ref->view || table_ref->field_translation)
{ {
char command[128]; /* View or derived information schema table. */
get_privilege_desc(command, sizeof(command), want_access); grant= &(table_ref->grant);
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), db_name= table_ref->view_db.str;
command, table_name= table_ref->view_name.str;
sctx->priv_user,
sctx->host_or_ip,
name,
table_name);
} }
DBUG_RETURN(1); else
{
/* Normal or temporary table. */
TABLE *table= table_ref->table;
grant= &(table->grant);
db_name= table->s->db;
table_name= table->s->table_name;
}
if (grant->want_privilege)
return check_grant_column(thd, grant, db_name, table_name, name,
length, sctx);
else
return FALSE;
} }
......
...@@ -204,7 +204,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, ...@@ -204,7 +204,9 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
uint show_command, uint number, bool dont_print_error); uint show_command, uint number, bool dont_print_error);
bool check_grant_column (THD *thd, GRANT_INFO *grant, bool check_grant_column (THD *thd, GRANT_INFO *grant,
const char *db_name, const char *table_name, const char *db_name, const char *table_name,
const char *name, uint length, uint show_command=0); const char *name, uint length, Security_context *sctx);
bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
const char *name, uint length);
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
const char* db_name, const char *table_name, const char* db_name, const char *table_name,
Field_iterator *fields); Field_iterator *fields);
......
...@@ -2683,47 +2683,6 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table) ...@@ -2683,47 +2683,6 @@ static void update_field_dependencies(THD *thd, Field *field, TABLE *table)
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Check column rights in given security context
SYNOPSIS
check_grant_column_in_sctx()
thd thread handler
grant grant information structure
db db name
table table name
name column name
length column name length
check_grants need to check grants
sctx 0 or security context
RETURN
FALSE OK
TRUE access denied
*/
static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
const char *db, const char *table,
const char *name, uint length,
bool check_grants,
Security_context *sctx)
{
if (!check_grants)
return FALSE;
Security_context *save_security_ctx= thd->security_ctx;
bool res;
if (sctx)
{
thd->security_ctx= sctx;
}
res= check_grant_column(thd, grant, db, table, name, length);
thd->security_ctx= save_security_ctx;
return res;
}
#endif
/* /*
Find a field by name in a view that uses merge algorithm. Find a field by name in a view that uses merge algorithm.
...@@ -2736,7 +2695,6 @@ static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant, ...@@ -2736,7 +2695,6 @@ static bool check_grant_column_in_sctx(THD *thd, GRANT_INFO *grant,
item_name name of item if it will be created (VIEW) item_name name of item if it will be created (VIEW)
ref expression substituted in VIEW should be passed ref expression substituted in VIEW should be passed
using this reference (return view_ref_found) using this reference (return view_ref_found)
check_grants do check columns grants for view?
register_tree_change TRUE if ref is not stack variable and we register_tree_change TRUE if ref is not stack variable and we
need register changes in item tree need register changes in item tree
...@@ -2750,7 +2708,7 @@ static Field * ...@@ -2750,7 +2708,7 @@ static Field *
find_field_in_view(THD *thd, TABLE_LIST *table_list, find_field_in_view(THD *thd, TABLE_LIST *table_list,
const char *name, uint length, const char *name, uint length,
const char *item_name, Item **ref, const char *item_name, Item **ref,
bool check_grants, bool register_tree_change) bool register_tree_change)
{ {
DBUG_ENTER("find_field_in_view"); DBUG_ENTER("find_field_in_view");
DBUG_PRINT("enter", DBUG_PRINT("enter",
...@@ -2766,14 +2724,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, ...@@ -2766,14 +2724,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
{ {
if (!my_strcasecmp(system_charset_info, field_it.name(), name)) if (!my_strcasecmp(system_charset_info, field_it.name(), name))
{ {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grant_column_in_sctx(thd, &table_list->grant,
table_list->view_db.str,
table_list->view_name.str, name, length,
check_grants,
table_list->security_ctx))
DBUG_RETURN(WRONG_GRANT);
#endif
// in PS use own arena or data will be freed after prepare // in PS use own arena or data will be freed after prepare
if (register_tree_change) if (register_tree_change)
arena= thd->activate_stmt_arena_if_needed(&backup); arena= thd->activate_stmt_arena_if_needed(&backup);
...@@ -2822,7 +2772,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, ...@@ -2822,7 +2772,6 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
length [in] length of name length [in] length of name
ref [in/out] if 'name' is resolved to a view field, ref is ref [in/out] if 'name' is resolved to a view field, ref is
set to point to the found view field set to point to the found view field
check_grants [in] do check columns grants?
register_tree_change [in] TRUE if ref is not stack variable and we register_tree_change [in] TRUE if ref is not stack variable and we
need register changes in item tree need register changes in item tree
actual_table [out] the original table reference where the field actual_table [out] the original table reference where the field
...@@ -2843,8 +2792,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list, ...@@ -2843,8 +2792,7 @@ find_field_in_view(THD *thd, TABLE_LIST *table_list,
static Field * static Field *
find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
uint length, Item **ref, bool check_grants, uint length, Item **ref, bool register_tree_change,
bool register_tree_change,
TABLE_LIST **actual_table) TABLE_LIST **actual_table)
{ {
List_iterator_fast<Natural_join_column> List_iterator_fast<Natural_join_column>
...@@ -2869,11 +2817,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, ...@@ -2869,11 +2817,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
break; break;
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grants && nj_col->check_grants(thd, name, length))
DBUG_RETURN(WRONG_GRANT);
#endif
if (nj_col->view_field) if (nj_col->view_field)
{ {
Item *item; Item *item;
...@@ -2929,7 +2872,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, ...@@ -2929,7 +2872,6 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
table table where to search for the field table table where to search for the field
name name of field name name of field
length length of name length length of name
check_grants do check columns grants?
allow_rowid do allow finding of "_rowid" field? allow_rowid do allow finding of "_rowid" field?
cached_field_index_ptr cached position in field list (used to speedup cached_field_index_ptr cached position in field list (used to speedup
lookup for fields in prepared tables) lookup for fields in prepared tables)
...@@ -2941,9 +2883,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name, ...@@ -2941,9 +2883,7 @@ find_field_in_natural_join(THD *thd, TABLE_LIST *table_ref, const char *name,
Field * Field *
find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
bool check_grants, bool allow_rowid, bool allow_rowid, uint *cached_field_index_ptr)
uint *cached_field_index_ptr,
Security_context *sctx)
{ {
Field **field_ptr, *field; Field **field_ptr, *field;
uint cached_field_index= *cached_field_index_ptr; uint cached_field_index= *cached_field_index_ptr;
...@@ -2982,13 +2922,6 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, ...@@ -2982,13 +2922,6 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
update_field_dependencies(thd, field, table); update_field_dependencies(thd, field, table);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_grant_column_in_sctx(thd, &table->grant,
table->s->db, table->s->table_name,
name, length,
check_grants, sctx))
field= WRONG_GRANT;
#endif
DBUG_RETURN(field); DBUG_RETURN(field);
} }
...@@ -3007,8 +2940,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length, ...@@ -3007,8 +2940,7 @@ find_field_in_table(THD *thd, TABLE *table, const char *name, uint length,
table_name [in] optional table name that qualifies the field table_name [in] optional table name that qualifies the field
ref [in/out] if 'name' is resolved to a view field, ref ref [in/out] if 'name' is resolved to a view field, ref
is set to point to the found view field is set to point to the found view field
check_grants_table [in] do check columns grants for table? check_privileges [in] check privileges
check_grants_view [in] do check columns grants for view?
allow_rowid [in] do allow finding of "_rowid" field? allow_rowid [in] do allow finding of "_rowid" field?
cached_field_index_ptr [in] cached position in field list (used to cached_field_index_ptr [in] cached position in field list (used to
speedup lookup for fields in prepared tables) speedup lookup for fields in prepared tables)
...@@ -3041,8 +2973,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, ...@@ -3041,8 +2973,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
const char *name, uint length, const char *name, uint length,
const char *item_name, const char *db_name, const char *item_name, const char *db_name,
const char *table_name, Item **ref, const char *table_name, Item **ref,
bool check_grants_table, bool check_grants_view, bool check_privileges, bool allow_rowid,
bool allow_rowid, uint *cached_field_index_ptr, uint *cached_field_index_ptr,
bool register_tree_change, TABLE_LIST **actual_table) bool register_tree_change, TABLE_LIST **actual_table)
{ {
Field *fld; Field *fld;
...@@ -3087,8 +3019,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, ...@@ -3087,8 +3019,7 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
if (table_list->field_translation) if (table_list->field_translation)
{ {
/* 'table_list' is a view or an information schema table. */ /* 'table_list' is a view or an information schema table. */
if ((fld= find_field_in_view(thd, table_list, name, length, item_name, if ((fld= find_field_in_view(thd, table_list, name, length, item_name, ref,
ref, check_grants_view,
register_tree_change))) register_tree_change)))
*actual_table= table_list; *actual_table= table_list;
} }
...@@ -3097,20 +3028,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, ...@@ -3097,20 +3028,9 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
/* 'table_list' is a stored table. */ /* 'table_list' is a stored table. */
DBUG_ASSERT(table_list->table); DBUG_ASSERT(table_list->table);
if ((fld= find_field_in_table(thd, table_list->table, name, length, if ((fld= find_field_in_table(thd, table_list->table, name, length,
check_grants_table, allow_rowid, allow_rowid,
cached_field_index_ptr, cached_field_index_ptr)))
table_list->security_ctx)))
*actual_table= table_list; *actual_table= table_list;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* check for views with temporary table algorithm */
if (check_grants_view && table_list->view &&
fld && fld != WRONG_GRANT &&
check_grant_column(thd, &table_list->grant,
table_list->view_db.str,
table_list->view_name.str,
name, length))
fld= WRONG_GRANT;
#endif
} }
else else
{ {
...@@ -3129,9 +3049,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, ...@@ -3129,9 +3049,8 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
{ {
if ((fld= find_field_in_table_ref(thd, table, name, length, item_name, if ((fld= find_field_in_table_ref(thd, table, name, length, item_name,
db_name, table_name, ref, db_name, table_name, ref,
check_grants_table, check_privileges, allow_rowid,
check_grants_view, cached_field_index_ptr,
allow_rowid, cached_field_index_ptr,
register_tree_change, actual_table))) register_tree_change, actual_table)))
DBUG_RETURN(fld); DBUG_RETURN(fld);
} }
...@@ -3144,11 +3063,16 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list, ...@@ -3144,11 +3063,16 @@ find_field_in_table_ref(THD *thd, TABLE_LIST *table_list,
directly the top-most NATURAL/USING join. directly the top-most NATURAL/USING join.
*/ */
fld= find_field_in_natural_join(thd, table_list, name, length, ref, fld= find_field_in_natural_join(thd, table_list, name, length, ref,
/* TIMOUR_TODO: check this with Sanja */
check_grants_table || check_grants_view,
register_tree_change, actual_table); register_tree_change, actual_table);
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Check if there are sufficient access rights to the found field. */
if (fld && check_privileges &&
check_column_grant_in_table_ref(thd, *actual_table, name, length))
fld= WRONG_GRANT;
#endif
DBUG_RETURN(fld); DBUG_RETURN(fld);
} }
...@@ -3230,21 +3154,11 @@ find_field_in_tables(THD *thd, Item_ident *item, ...@@ -3230,21 +3154,11 @@ find_field_in_tables(THD *thd, Item_ident *item,
*/ */
if (table_ref->table && !table_ref->view) if (table_ref->table && !table_ref->view)
found= find_field_in_table(thd, table_ref->table, name, length, found= find_field_in_table(thd, table_ref->table, name, length,
test(table_ref->table-> TRUE, &(item->cached_field_index));
grant.want_privilege) &&
check_privileges,
1, &(item->cached_field_index),
table_ref->security_ctx);
else else
found= find_field_in_table_ref(thd, table_ref, name, length, item->name, found= find_field_in_table_ref(thd, table_ref, name, length, item->name,
NULL, NULL, ref, NULL, NULL, ref, check_privileges,
(table_ref->table && TRUE, &(item->cached_field_index),
test(table_ref->table->grant.
want_privilege) &&
check_privileges),
(test(table_ref->grant.want_privilege) &&
check_privileges),
1, &(item->cached_field_index),
register_tree_change, register_tree_change,
&actual_table); &actual_table);
if (found) if (found)
...@@ -3286,14 +3200,7 @@ find_field_in_tables(THD *thd, Item_ident *item, ...@@ -3286,14 +3200,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
{ {
Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length, Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length,
item->name, db, table_name, ref, item->name, db, table_name, ref,
(cur_table->table && check_privileges, allow_rowid,
test(cur_table->table->grant.
want_privilege) &&
check_privileges),
(test(cur_table->grant.
want_privilege)
&& check_privileges),
allow_rowid,
&(item->cached_field_index), &(item->cached_field_index),
register_tree_change, register_tree_change,
&actual_table); &actual_table);
......
...@@ -2606,60 +2606,6 @@ GRANT_INFO *Natural_join_column::grant() ...@@ -2606,60 +2606,6 @@ GRANT_INFO *Natural_join_column::grant()
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/*
Check the access rights for the current join column.
columns.
SYNOPSIS
Natural_join_column::check_grants()
DESCRIPTION
Check the access rights to a column from a natural join in a generic
way that hides the heterogeneity of the column representation - whether
it is a view or a stored table colum.
RETURN
FALSE The column can be accessed
TRUE There are no access rights to all equivalent columns
*/
bool
Natural_join_column::check_grants(THD *thd, const char *name, uint length)
{
GRANT_INFO *grant;
const char *db_name;
const char *table_name;
Security_context *save_security_ctx= thd->security_ctx;
Security_context *new_sctx= table_ref->security_ctx;
bool res;
if (view_field)
{
DBUG_ASSERT(table_field == NULL);
grant= &(table_ref->grant);
db_name= table_ref->view_db.str;
table_name= table_ref->view_name.str;
}
else
{
DBUG_ASSERT(table_field && view_field == NULL);
grant= &(table_ref->table->grant);
db_name= table_ref->table->s->db;
table_name= table_ref->table->s->table_name;
}
if (new_sctx)
thd->security_ctx= new_sctx;
res= check_grant_column(thd, grant, db_name, table_name, name, length);
thd->security_ctx= save_security_ctx;
return res;
}
#endif
void Field_iterator_view::set(TABLE_LIST *table) void Field_iterator_view::set(TABLE_LIST *table)
{ {
DBUG_ASSERT(table->field_translation); DBUG_ASSERT(table->field_translation);
......
...@@ -407,9 +407,6 @@ public: ...@@ -407,9 +407,6 @@ public:
const char *table_name(); const char *table_name();
const char *db_name(); const char *db_name();
GRANT_INFO *grant(); GRANT_INFO *grant();
#ifndef NO_EMBEDDED_ACCESS_CHECKS
bool check_grants(THD *thd, const char *name, uint length);
#endif
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment