Commit ada4f591 authored by unknown's avatar unknown

Change name -> alias in TABLE_LIST.

Added missing mutex-lock around critical section in GRANT handling.


Docs/manual.texi:
  ChangeLog
sql/lock.cc:
  Change name -> alias in TABLE_LIST.
sql/slave.cc:
  Change name -> alias in TABLE_LIST.
sql/sql_acl.cc:
  Added missing mutex-lock around critical section in GRANT handling.
  Changed name -> alias
sql/sql_base.cc:
  Change name -> alias in TABLE_LIST.
sql/sql_insert.cc:
  Change name -> alias in TABLE_LIST.
sql/sql_parse.cc:
  Change name -> alias in TABLE_LIST.
sql/sql_show.cc:
  Change name -> alias in TABLE_LIST.
sql/sql_table.cc:
  Change name -> alias in TABLE_LIST.
sql/sql_udf.cc:
  Change name -> alias in TABLE_LIST.
sql/table.h:
  Change name -> alias in TABLE_LIST.
tests/grant.pl:
  Fixed grant test
parent 29be6179
......@@ -46931,10 +46931,16 @@ not yet 100% confident in this code.
@item
Fixed core dump bug when using the @code{BINARY} cast on a @code{NULL} value.
@item
Fixed race condition when someone did a @code{GRANT} at the same time a new
user logged in or did a @code{USE DATABASE}.
@item
Fixed bug in @code{ALTER TABLE} and @code{RENAME TABLE} when running with
@code{-O lower_case_table_names=1} (typically on windows) when giving the
table name in uppercase.
@item
Fixed that @code{-O lower_case_table_names=1} also converts database
names to lower case.
@item
Fixed unlikely core dump with @code{SELECT ... ORDER BY ... LIMIT}.
@item
Changed @code{AND/OR} to report that they can return NULL. This fixes a
......@@ -419,7 +419,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
uint key_length;
DBUG_ENTER("lock_table_name");
key_length=(uint) (strmov(strmov(key,table_list->db)+1,table_list->name)
key_length=(uint) (strmov(strmov(key,table_list->db)+1,table_list->real_name)
-key)+ 1;
/* Only insert the table if we haven't insert it already */
......@@ -447,7 +447,7 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list)
my_free((gptr) table,MYF(0));
DBUG_RETURN(-1);
}
if (remove_table_from_cache(thd, table_list->db, table_list->name))
if (remove_table_from_cache(thd, table_list->db, table_list->real_name))
DBUG_RETURN(1); // Table is in use
DBUG_RETURN(0);
}
......
......@@ -399,7 +399,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db,
bzero((char*) &tables,sizeof(tables));
tables.db = (char*)db;
tables.name = tables.real_name = (char*)table_name;
tables.alias= tables.real_name= (char*)table_name;
tables.lock_type = TL_WRITE;
thd->proc_info = "Opening master dump table";
if (!open_ltable(thd, &tables, TL_WRITE))
......@@ -1073,7 +1073,7 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
TABLE_LIST tables;
bzero((char*) &tables,sizeof(tables));
tables.db = thd->db;
tables.name = tables.real_name = (char*)lev->table_name;
tables.alias= tables.real_name= (char*)lev->table_name;
tables.lock_type = TL_WRITE;
// the table will be opened in mysql_load
if(table_rules_on && !tables_ok(thd, &tables))
......
......@@ -130,9 +130,9 @@ int acl_init(bool dont_read_acl_tables)
thd->open_tables=0;
thd->db=my_strdup("mysql",MYF(0));
bzero((char*) &tables,sizeof(tables));
tables[0].name=tables[0].real_name=(char*) "host";
tables[1].name=tables[1].real_name=(char*) "user";
tables[2].name=tables[2].real_name=(char*) "db";
tables[0].alias=tables[0].real_name=(char*) "host";
tables[1].alias=tables[1].real_name=(char*) "user";
tables[2].alias=tables[2].real_name=(char*) "db";
tables[0].next=tables+1;
tables[1].next=tables+2;
tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
......@@ -922,7 +922,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
DBUG_PRINT("enter",("user: %s host: %s",user,host));
bzero((char*) &tables,sizeof(tables));
tables.name=tables.real_name=(char*) "user";
tables.alias=tables.real_name=(char*) "user";
tables.db=(char*) "mysql";
if (!(table=open_ltable(thd,&tables,TL_WRITE)))
DBUG_RETURN(1); /* purecov: deadcode */
......@@ -1653,7 +1653,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
check->column.length(),0,0))
{
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
check->column.c_ptr(),table_list->name);
check->column.c_ptr(),table_list->alias);
DBUG_RETURN(-1);
}
column_priv |= check->rights | (rights & COL_ACLS);
......@@ -1664,11 +1664,11 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
{
char buf[FN_REFLEN];
sprintf(buf,"%s/%s/%s.frm",mysql_data_home,table_list->db,
table_list->name);
table_list->real_name);
fn_format(buf,buf,"","",4+16+32);
if (access(buf,F_OK))
{
my_error(ER_NO_SUCH_TABLE,MYF(0),table_list->db,table_list->name);
my_error(ER_NO_SUCH_TABLE,MYF(0),table_list->db,table_list->real_name);
DBUG_RETURN(-1);
}
}
......@@ -1676,9 +1676,9 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
/* open the mysql.tables_priv and mysql.columns_priv tables */
bzero((char*) &tables,sizeof(tables));
tables[0].name=tables[0].real_name= (char*) "user";
tables[1].name=tables[1].real_name= (char*) "tables_priv";
tables[2].name=tables[2].real_name= (char*) "columns_priv";
tables[0].alias=tables[0].real_name= (char*) "user";
tables[1].alias=tables[1].real_name= (char*) "tables_priv";
tables[2].alias=tables[2].real_name= (char*) "columns_priv";
tables[0].next=tables+1;
/* Don't open column table if we don't need it ! */
tables[1].next=((column_priv ||
......@@ -1702,6 +1702,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
while ((Str = str_list++))
{
int error;
GRANT_TABLE *grant_table;
if (!Str->host.str)
{
......@@ -1716,11 +1717,14 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
continue;
}
/* Create user if needed */
if (replace_user_table(tables[0].table,
*Str,
0,
revoke_grant ? 'N' : 'Y',
create_new_users))
pthread_mutex_lock(&acl_cache->lock);
error=replace_user_table(tables[0].table,
*Str,
0,
revoke_grant ? 'N' : 'Y',
create_new_users);
pthread_mutex_unlock(&acl_cache->lock);
if (error)
{
result= -1; // Remember error
continue; // Add next user
......@@ -1729,20 +1733,20 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
/* Find/create cached table grant */
grant_table= table_hash_search(Str->host.str,NullS,table_list->db,
Str->user.str,
table_list->name,1);
table_list->real_name,1);
if (!grant_table)
{
if (revoke_grant)
{
my_printf_error(ER_NONEXISTING_TABLE_GRANT,
ER(ER_NONEXISTING_TABLE_GRANT),MYF(0),
Str->user.str, Str->host.str,table_list->name);
Str->user.str, Str->host.str, table_list->real_name);
result= -1;
continue;
}
grant_table = new GRANT_TABLE (Str->host.str,table_list->db,
Str->user.str,
table_list->name,
table_list->real_name,
rights,
column_priv);
if (!grant_table) // end of memory
......@@ -1789,7 +1793,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
if (replace_table_table(thd,grant_table,tables[1].table,*Str,
table_list->db,
table_list->name,
table_list->real_name,
rights, column_priv, revoke_grant))
{ // Crashend table ??
result= -1; /* purecov: deadcode */
......@@ -1799,7 +1803,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
if ((replace_column_table(grant_table,tables[2].table, *Str,
columns,
table_list->db,
table_list->name,
table_list->real_name,
rights, revoke_grant)))
{
result= -1;
......@@ -1836,8 +1840,8 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
/* open the mysql.user and mysql.db tables */
tables[0].name=tables[0].real_name=(char*) "user";
tables[1].name=tables[1].real_name=(char*) "db";
tables[0].alias=tables[0].real_name=(char*) "user";
tables[1].alias=tables[1].real_name=(char*) "db";
tables[0].next=tables+1;
tables[1].next=0;
tables[0].lock_type=tables[1].lock_type=TL_WRITE;
......@@ -1930,8 +1934,8 @@ int grant_init (void)
thd->open_tables=0;
thd->db=my_strdup("mysql",MYF(0));
bzero((char*) &tables,sizeof(tables));
tables[0].name=tables[0].real_name= (char*) "tables_priv";
tables[1].name=tables[1].real_name= (char*) "columns_priv";
tables[0].alias=tables[0].real_name= (char*) "tables_priv";
tables[1].alias=tables[1].real_name= (char*) "columns_priv";
tables[0].next=tables+1;
tables[0].lock_type=tables[1].lock_type=TL_READ;
tables[0].db=tables[1].db=thd->db;
......@@ -2270,6 +2274,7 @@ bool check_grant_db(THD *thd,const char *db)
uint get_table_grant(THD *thd, TABLE_LIST *table)
{
uint privilege;
char *user = thd->priv_user;
const char *db = table->db ? table->db : thd->db;
GRANT_TABLE *grant_table;
......@@ -2281,8 +2286,9 @@ uint get_table_grant(THD *thd, TABLE_LIST *table)
table->grant.version=grant_version;
if (grant_table)
table->grant.privilege|= grant_table->privs;
privilege= table->grant.privilege;
pthread_mutex_unlock(&LOCK_grant);
return table->grant.privilege;
return privilege;
}
......@@ -2335,7 +2341,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
int error = 0;
ACL_USER *acl_user; ACL_DB *acl_db;
char buff[1024];
DBUG_ENTER("mysql_grant");
DBUG_ENTER("mysql_show_grants");
LINT_INIT(acl_user);
if (!initialized)
......@@ -2384,6 +2390,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (send_fields(thd,field_list,1))
DBUG_RETURN(-1);
pthread_mutex_lock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
/* Add first global access grants */
......@@ -2578,13 +2585,16 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
thd->packet.length()))
{
error=-1;
goto end;
break;
}
}
}
}
end:
VOID(pthread_mutex_unlock(&acl_cache->lock));
pthread_mutex_unlock(&LOCK_grant);
send_eof(&thd->net);
DBUG_RETURN(error);
}
......
......@@ -354,7 +354,7 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh,
bool found=0;
for (TABLE_LIST *table=tables ; table ; table=table->next)
{
if (remove_table_from_cache(thd, table->db, table->name, 1))
if (remove_table_from_cache(thd, table->db, table->real_name, 1))
found=1;
}
if (!found)
......@@ -715,7 +715,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
DBUG_RETURN(0);
char* db = thd->db ? thd->db : table_list->db;
char* table_name = table_list->name;
char* table_name = table_list->real_name;
char key[MAX_DBKEY_LENGTH];
uint key_length;
key_length=(uint) (strmov(strmov(key,db)+1,table_name)-key)+1;
......@@ -1285,7 +1285,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
TABLE_LIST table_list;
table_list.db=(char*) db;
table_list.name=(char*) name;
table_list.real_name=(char*) name;
table_list.next=0;
if ((error=lock_table_name(thd,&table_list)))
{
......@@ -1356,7 +1356,7 @@ int open_tables(THD *thd,TABLE_LIST *start)
!(tables->table=open_table(thd,
tables->db ? tables->db : thd->db,
tables->real_name,
tables->name, &refresh)))
tables->alias, &refresh)))
{
if (refresh) // Refresh in progress
{
......@@ -1412,7 +1412,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
thd->proc_info="Opening table";
while (!(table=open_table(thd,table_list->db ? table_list->db : thd->db,
table_list->real_name,table_list->name,
table_list->real_name, table_list->alias,
&refresh)) && refresh) ;
if (table)
{
......@@ -1440,7 +1440,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
{
my_printf_error(ER_TABLE_NOT_LOCKED_FOR_WRITE,
ER(ER_TABLE_NOT_LOCKED_FOR_WRITE),
MYF(0),table_list->name);
MYF(0),table_list->alias);
table=0;
}
else if ((error=table->file->start_stmt(thd)))
......@@ -1642,7 +1642,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables)
bool found_table=0;
for (; tables ; tables=tables->next)
{
if (!strcmp(tables->name,table_name) &&
if (!strcmp(tables->alias,table_name) &&
(!db ||
(tables->db && !strcmp(db,tables->db)) ||
(!tables->db && !strcmp(db,thd->db))))
......@@ -1882,7 +1882,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
if (grant_option && !thd->master_access &&
check_grant_all_columns(thd,SELECT_ACL,table) )
DBUG_RETURN(-1);
if (!table_name || (!strcmp(table_name,tables->name) &&
if (!table_name || (!strcmp(table_name,tables->alias) &&
(!db_name || !tables->db ||
!strcmp(tables->db,db_name))))
{
......
......@@ -73,7 +73,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
}
TABLE_LIST table_list;
bzero((char*) &table_list,sizeof(table_list));
table_list.name=table->table_name;
table_list.alias= table_list.real_name= table->table_name;
table_list.table=table;
table_list.grant=table->grant;
......@@ -615,7 +615,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
}
tmp->table_list= *table_list; // Needed to open table
tmp->table_list.db= tmp->thd.db;
tmp->table_list.name= tmp->table_list.real_name=tmp->thd.query;
tmp->table_list.alias= tmp->table_list.real_name= tmp->thd.query;
tmp->lock();
pthread_mutex_lock(&tmp->mutex);
if ((error=pthread_create(&tmp->thd.real_id,&connection_attrib,
......
......@@ -671,7 +671,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
if (!(table_list = (TABLE_LIST*) sql_calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(1); // out of memory
table_list->db = db;
table_list->real_name = table_list->name = tbl_name;
table_list->real_name = table_list->alias = tbl_name;
table_list->lock_type = TL_READ_NO_INSERT;
table_list->next = 0;
remove_escape(table_list->real_name);
......@@ -857,7 +857,7 @@ bool do_command(THD *thd)
break;
}
thd->free_list=0;
table_list.name=table_list.real_name=thd->strdup(packet+1);
table_list.alias= table_list.real_name= thd->strdup(packet+1);
thd->query=fields=thd->strdup(strend(packet+1)+1);
mysql_log.write(thd,command,"%s %s",table_list.real_name,fields);
remove_escape(table_list.real_name); // This can't have wildcards
......@@ -889,6 +889,8 @@ bool do_command(THD *thd)
net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
if (lower_case_table_names)
casedn_str(db);
if (check_access(thd,CREATE_ACL,db,0,1))
break;
mysql_log.write(thd,command,packet+1);
......@@ -905,6 +907,8 @@ bool do_command(THD *thd)
net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL");
break;
}
if (lower_case_table_names)
casedn_str(db);
if (check_access(thd,DROP_ACL,db,0,1) || end_active_trans(thd))
break;
mysql_log.write(thd,command,db);
......@@ -1261,9 +1265,9 @@ mysql_execute_command(void)
if (error)
goto error;
}
if (strlen(tables->name) > NAME_LEN)
if (strlen(tables->real_name) > NAME_LEN)
{
net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->real_name);
break;
}
......@@ -1292,9 +1296,9 @@ mysql_execute_command(void)
if (error)
goto error;
}
if (strlen(tables->name) > NAME_LEN)
if (strlen(tables->real_name) > NAME_LEN)
{
net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->name);
net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->real_name);
res=0;
break;
}
......@@ -1767,7 +1771,7 @@ mysql_execute_command(void)
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
remove_escape(tables->name);
remove_escape(tables->real_name);
if (!tables->db)
tables->db=thd->db;
if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,&thd->col_access))
......@@ -1794,7 +1798,7 @@ mysql_execute_command(void)
goto error; /* purecov: inspected */
}
remove_escape(db); // Fix escaped '_'
remove_escape(tables->name);
remove_escape(tables->real_name);
if (!tables->db)
tables->db=thd->db;
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
......@@ -1923,6 +1927,8 @@ mysql_execute_command(void)
net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
break;
}
if (lower_case_table_names)
casedn_str(lex->name);
if (check_access(thd,CREATE_ACL,lex->name,0,1))
break;
mysql_create_db(thd,lex->name,lex->create_info.options);
......@@ -1935,6 +1941,8 @@ mysql_execute_command(void)
net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name);
break;
}
if (lower_case_table_names)
casedn_str(lex->name);
if (check_access(thd,DROP_ACL,lex->name,0,1) ||
end_active_trans(thd))
break;
......@@ -2748,12 +2756,16 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
if (!(alias_str=sql_strmake(alias_str,table->table.length)))
DBUG_RETURN(0);
if (lower_case_table_names)
{
casedn_str(table->table.str);
if (table->db.str)
casedn_str(table->db.str);
}
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
DBUG_RETURN(0); /* purecov: inspected */
ptr->db= table->db.str;
ptr->real_name=table->table.str;
ptr->name=alias_str;
ptr->alias=alias_str;
ptr->lock_type=flags;
ptr->updating=updating;
if (use_index)
......@@ -2771,7 +2783,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.table_list.first ; tables ;
tables=tables->next)
{
if (!strcmp(alias_str,tables->name) &&
if (!strcmp(alias_str,tables->alias) &&
!strcmp(ptr->db ? ptr->db : current_db,
tables->db ? tables->db : current_db))
{
......
......@@ -306,7 +306,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
packet->length(0);
net_store_data(packet,file_name);
table_list.db=(char*) db;
table_list.real_name=table_list.name=file_name;
table_list.real_name= table_list.alias= file_name;
if (!(table = open_ltable(thd, &table_list, TL_READ)))
{
for (uint i=0 ; i < field_list.elements ; i++)
......@@ -423,7 +423,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
/***************************************************************************
** List all columns in a table
** List all columns in a table_list->real_name
***************************************************************************/
int
......
......@@ -810,7 +810,7 @@ static int send_check_errmsg(THD* thd, TABLE_LIST* table,
String* packet = &thd->packet;
packet->length(0);
net_store_data(packet, table->name);
net_store_data(packet, table->alias);
net_store_data(packet, (char*)operator_name);
net_store_data(packet, "error");
net_store_data(packet, errmsg);
......@@ -835,7 +835,7 @@ static int prepare_for_restore(THD* thd, TABLE_LIST* table)
{
char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
char* table_name = table->name;
char* table_name = table->real_name;
char* db = thd->db ? thd->db : table->db;
if (!fn_format(src_path, table_name, backup_dir, reg_ext, 4 + 64))
......@@ -922,7 +922,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
char table_name[NAME_LEN*2+2];
char* db = (table->db) ? table->db : thd->db;
bool fatal_error=0;
strxmov(table_name,db ? db : "",".",table->name,NullS);
strxmov(table_name,db ? db : "",".",table->real_name,NullS);
thd->open_options|= extra_open_options;
table->table = open_ltable(thd, table, lock_type);
......@@ -1754,7 +1754,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
MYF(MY_FAE | MY_ZEROFILL));
bzero((char*) &tables,sizeof(tables));
tables.table = from;
tables.name = tables.real_name= from->real_name;
tables.alias = tables.real_name= from->real_name;
tables.db = from->table_cache_key;
error=1;
......
......@@ -144,7 +144,7 @@ void udf_init()
new_thd->db = my_strdup("mysql", MYF(0));
bzero((gptr) &tables,sizeof(tables));
tables.name = tables.real_name = (char*) "func";
tables.alias= tables.real_name= (char*) "func";
tables.lock_type = TL_READ;
tables.db=new_thd->db;
......@@ -406,7 +406,7 @@ int mysql_create_function(THD *thd,udf_func *udf)
bzero((char*) &tables,sizeof(tables));
tables.db= (char*) "mysql";
tables.real_name=tables.name= (char*) "func";
tables.real_name= tables.alias= (char*) "func";
/* Allow creation of functions even if we can't open func table */
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
......@@ -460,7 +460,7 @@ int mysql_drop_function(THD *thd,const char *udf_name)
bzero((char*) &tables,sizeof(tables));
tables.db=(char*) "mysql";
tables.real_name=tables.name=(char*) "func";
tables.real_name= tables.alias= (char*) "func";
if (!(table = open_ltable(thd,&tables,TL_WRITE)))
goto err;
if (!table->file->index_read_idx(table->record[0],0,(byte*) udf_name,
......
......@@ -136,7 +136,7 @@ struct st_table {
typedef struct st_table_list {
struct st_table_list *next;
char *db,*name,*real_name;
char *db,*alias,*real_name;
Item *on_expr; /* Used with outer join */
struct st_table_list *natural_join; /* natural join on this table*/
List<String> *use_index,*ignore_index;
......
......@@ -299,7 +299,7 @@ safe_query("revoke GRANT OPTION on $opt_database.test from $user",1);
#
safe_query("grant select(a) on $opt_database.test to $user");
user_query("show columns from test");
user_query("show full columns from test");
safe_query("grant insert (b), update (b) on $opt_database.test to $user");
user_query("select count(a) from test");
......
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