Commit 61434bf8 authored by unknown's avatar unknown

Change client_flag to unsigned long (16 -> 32 bits) to handle more options.

Don't use new password format if mysql.user has old format
tables_priv was not reset on FLUSH PRIVILEGES if tables_priv was empty
Portability fixes for Windows


client/mysql.cc:
  Removed compiler warnings.
  Make quote handling simpler
include/config-win.h:
  Fix for myisam/rt_mbr.c
include/mysql.h:
  Change client_flag to unsigned long to handle more options.
libmysql/libmysql.c:
  Change client_flag to unsigned long to handle more options.
libmysqld/libmysqld.c:
  Change client_flag to unsigned long to handle more options.
myisam/rt_mbr.c:
  Portability fix for Windows
mysql-test/r/rpl_loaddata.result:
  Fix test case
sql/item_strfunc.cc:
  Don't use new password format if mysql.user has old format
sql/item_strfunc.h:
  Don't use new password format if mysql.user has old format
sql/mysql_priv.h:
  Don't use new password format if mysql.user has old format
sql/mysqld.cc:
  Don't use new password format if mysql.user has old format
sql/sql_acl.cc:
  Don't use new password format if mysql.user has old format.
  tables_priv was not reset on FLUSH PRIVILEGES if tables_priv was empty
sql/sql_class.h:
  Don't use new password format if mysql.user has old format
sql/sql_parse.cc:
  Change client_flag to unsigned long to handle more options.
sql/sql_yacc.yy:
  Don't use new password format if mysql.user has old format
strings/ctype-utf8.c:
  Remove compiler warnings
strings/ctype-win1250ch.c:
  Remove compiler warnings
tests/grant.res:
  Update results
parent 76c8b9be
......@@ -2387,14 +2387,12 @@ com_use(String *buffer __attribute__((unused)), char *line)
items in the array to zero first.
*/
enum quote_type { NO_QUOTE, SQUOTE, DQUOTE, BTICK };
char *get_arg(char *line, my_bool get_next_arg)
{
char *ptr;
my_bool quoted= 0, valid_arg= 0;
uint count= 0;
enum quote_type qtype= NO_QUOTE;
char qtype= 0;
ptr= line;
if (get_next_arg)
......@@ -2415,10 +2413,9 @@ char *get_arg(char *line, my_bool get_next_arg)
}
while (my_isspace(system_charset_info, *ptr))
ptr++;
if ((*ptr == '\'' && (qtype= SQUOTE)) ||
(*ptr == '\"' && (qtype= DQUOTE)) ||
(*ptr == '`' && (qtype= BTICK)))
if (*ptr == '\'' || *ptr == '\"' || *ptr == '`')
{
qtype= *ptr;
quoted= 1;
ptr++;
}
......@@ -2435,10 +2432,7 @@ char *get_arg(char *line, my_bool get_next_arg)
ptr= line;
ptr+= count;
}
else if ((!quoted && *ptr == ' ') ||
(*ptr == '\'' && qtype == SQUOTE) ||
(*ptr == '\"' && qtype == DQUOTE) ||
(*ptr == '`' && qtype == BTICK))
else if ((!quoted && *ptr == ' ') || (quoted && *ptr == qtype))
{
*ptr= 0;
break;
......
......@@ -152,7 +152,9 @@ typedef uint rf_SetTimer;
#define access(A,B) _access(A,B)
#endif
#if defined(__cplusplus)
#if !defined(__cplusplus)
#define inline __inline
#endif /* __cplusplus */
inline double rint(double nr)
{
......@@ -175,9 +177,6 @@ inline double ulonglong2double(ulonglong value)
}
#define my_off_t2double(A) ulonglong2double(A)
#endif /* _WIN64 */
#else
#define inline __inline
#endif /* __cplusplus */
#if SIZEOF_OFF_T > 4
#define lseek(A,B,C) _lseeki64((A),(longlong) (B),(C))
......
......@@ -117,7 +117,8 @@ typedef struct st_mysql_data {
} MYSQL_DATA;
struct st_mysql_options {
unsigned int connect_timeout,client_flag;
unsigned int connect_timeout;
unsigned long client_flag;
unsigned int port;
char *host,*user,*password,*unix_socket,*db;
struct st_dynamic_array *init_commands;
......@@ -191,7 +192,8 @@ typedef struct st_mysql
my_ulonglong extra_info; /* Used by mysqlshow */
unsigned long thread_id; /* Id for connection in server */
unsigned long packet_length;
unsigned int port,client_flag,server_capabilities;
unsigned int port;
unsigned long client_flag,server_capabilities;
unsigned int protocol_version;
unsigned int field_count;
unsigned int server_status;
......@@ -314,7 +316,7 @@ MYSQL * STDCALL mysql_real_connect(MYSQL *mysql, const char *host,
const char *db,
unsigned int port,
const char *unix_socket,
unsigned int clientflag);
unsigned long clientflag);
void STDCALL mysql_close(MYSQL *sock);
int STDCALL mysql_select_db(MYSQL *mysql, const char *db);
int STDCALL mysql_query(MYSQL *mysql, const char *q);
......
......@@ -1003,6 +1003,7 @@ static void mysql_read_default_options(struct st_mysql_options *options,
break;
case 3: /* compress */
options->compress=1;
options->client_flag|= CLIENT_COMPRESS;
break;
case 4: /* password */
if (opt_arg)
......@@ -1828,7 +1829,7 @@ mysql_connect(MYSQL *mysql,const char *host,
MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
uint port, const char *unix_socket,ulong client_flag)
{
char buff[NAME_LEN+USERNAME_LENGTH+100],charset_name_buff[16];
char *end,*host_info,*charset_name;
......@@ -1899,7 +1900,7 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
(!host || !strcmp(host,LOCAL_HOST)))
{
if ((create_shared_memory(mysql,net, mysql->options.connect_timeout)) ==
INVALID_HANDLE_VALUE)
INVALID_HANDLE_VALUE)
{
DBUG_PRINT("error",
("host: '%s' socket: '%s' shared memory: %s have_tcpip: %d",
......@@ -2178,32 +2179,28 @@ Try also with PIPE or TCP/IP
#endif /* HAVE_OPENSSL */
if (db)
client_flag|=CLIENT_CONNECT_WITH_DB;
#ifdef HAVE_COMPRESS
if ((mysql->server_capabilities & CLIENT_COMPRESS) &&
(mysql->options.compress || (client_flag & CLIENT_COMPRESS)))
client_flag|=CLIENT_COMPRESS; /* We will use compression */
else
/* Remove options that server doesn't support */
client_flag= ((client_flag &
~(CLIENT_COMPRESS | CLIENT_SSL | CLIENT_PROTOCOL_41)) |
(client_flag & mysql->server_capabilities));
#ifndef HAVE_COMPRESS
client_flag&= ~CLIENT_COMPRESS;
#endif
client_flag&= ~CLIENT_COMPRESS;
#ifdef HAVE_OPENSSL
if ((mysql->server_capabilities & CLIENT_SSL) &&
(mysql->options.use_ssl || (client_flag & CLIENT_SSL)))
if (client_flag & CLIENT_PROTOCOL_41)
{
DBUG_PRINT("info", ("Changing IO layer to SSL"));
client_flag |= CLIENT_SSL;
/* 4.1 server and 4.1 client has a 4 byte option flag */
int4store(buff,client_flag);
int4store(buff+4,max_allowed_packet);
end= buff+8;
}
else
{
if (client_flag & CLIENT_SSL)
{
DBUG_PRINT("info", ("Leaving IO layer intact because server doesn't support SSL"));
}
client_flag &= ~CLIENT_SSL;
int2store(buff,client_flag);
int3store(buff+2,max_allowed_packet);
end= buff+5;
}
#endif /* HAVE_OPENSSL */
int2store(buff,client_flag);
mysql->client_flag=client_flag;
#ifdef HAVE_OPENSSL
......@@ -2214,7 +2211,7 @@ Try also with PIPE or TCP/IP
if (client_flag & CLIENT_SSL)
{
struct st_mysql_options *options= &mysql->options;
if (my_net_write(net,buff,(uint) (2)) || net_flush(net))
if (my_net_write(net,buff,(uint) (end-buff)) || net_flush(net))
{
net->last_errno= CR_SERVER_LOST;
strmov(net->last_error,ER(net->last_errno));
......@@ -2233,8 +2230,8 @@ Try also with PIPE or TCP/IP
goto error;
}
DBUG_PRINT("info", ("IO layer change in progress..."));
if(sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),
mysql->net.vio, (long) (mysql->options.connect_timeout)))
if (sslconnect((struct st_VioSSLConnectorFd*)(mysql->connector_fd),
mysql->net.vio, (long) (mysql->options.connect_timeout)))
{
net->last_errno= CR_SSL_CONNECTION_ERROR;
strmov(net->last_error,ER(net->last_errno));
......@@ -2244,20 +2241,19 @@ Try also with PIPE or TCP/IP
}
#endif /* HAVE_OPENSSL */
DBUG_PRINT("info",("Server version = '%s' capabilites: %ld status: %d client_flag: %d",
DBUG_PRINT("info",("Server version = '%s' capabilites: %lu status: %u client_flag: %lu",
mysql->server_version,mysql->server_capabilities,
mysql->server_status, client_flag));
/* This needs to be changed as it's not useful with big packets */
int3store(buff+2,max_allowed_packet);
if (user && user[0])
strmake(buff+5,user,32); /* Max user name */
strmake(end,user,32); /* Max user name */
else
read_user_name((char*) buff+5);
read_user_name((char*) end);
/* We have to handle different version of handshake here */
#ifdef _CUSTOMCONFIG_
#include "_cust_libmysql.h";
#endif
DBUG_PRINT("info",("user: %s",buff+5));
DBUG_PRINT("info",("user: %s",end));
/*
We always start with old type handshake the only difference is message sent
If server handles secure connection type we'll not send the real scramble
......@@ -2267,25 +2263,26 @@ Try also with PIPE or TCP/IP
if (passwd[0])
{
/* Prepare false scramble */
end=strend(buff+5)+1;
end=strend(end)+1;
bfill(end, SCRAMBLE_LENGTH, 'x');
end+=SCRAMBLE_LENGTH;
*end=0;
}
else /* For empty password*/
{
end=strend(buff+5)+1;
end=strend(end)+1;
*end=0; /* Store zero length scramble */
}
}
else
{
/*
Real scramble is only sent to old servers. This can be blocked
by calling mysql_options(MYSQL *, MYSQL_SECURE_CONNECT, (char*) &1);
*/
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
end=scramble(strend(end)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
}
/* Add database if needed */
if (db && (mysql->server_capabilities & CLIENT_CONNECT_WITH_DB))
{
......@@ -3380,6 +3377,7 @@ mysql_options(MYSQL *mysql,enum mysql_option option, const char *arg)
break;
case MYSQL_OPT_COMPRESS:
mysql->options.compress= 1; /* Remember for connect */
mysql->options.client_flag|= CLIENT_COMPRESS;
break;
case MYSQL_OPT_NAMED_PIPE:
mysql->options.protocol=MYSQL_PROTOCOL_PIPE; /* Force named pipe */
......
......@@ -834,7 +834,7 @@ mysql_connect(MYSQL *mysql,const char *host,
MYSQL * STDCALL
mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
const char *passwd, const char *db,
uint port, const char *unix_socket,uint client_flag)
uint port, const char *unix_socket,ulong client_flag)
{
char buff[100],charset_name_buff[16],*end,*host_info, *charset_name;
uint pkt_length;
......@@ -991,20 +991,20 @@ mysql_real_connect(MYSQL *mysql,const char *host, const char *user,
client_flag&= ~CLIENT_COMPRESS;
if (db)
client_flag|=CLIENT_CONNECT_WITH_DB;
int2store(buff,client_flag);
int4store(buff,client_flag);
mysql->client_flag=client_flag;
max_allowed_packet=net->max_packet_size;
int3store(buff+2,max_allowed_packet);
int4store(buff+4,max_allowed_packet);
if (user && user[0])
strmake(buff+5,user,32);
strmake(buff+8,user,32);
else
read_user_name((char*) buff+5);
read_user_name((char*) buff+8);
#ifdef _CUSTOMCONFIG_
#include "_cust_libmysql.h";
#endif
DBUG_PRINT("info",("user: %s",buff+5));
end=scramble(strend(buff+5)+1, mysql->scramble_buff, passwd,
DBUG_PRINT("info",("user: %s",buff+8));
end=scramble(strend(buff+8)+1, mysql->scramble_buff, passwd,
(my_bool) (mysql->protocol_version == 9));
if (db)
......
......@@ -161,25 +161,25 @@ int rtree_key_cmp(HA_KEYSEG *keyseg, uchar *b, uchar *a, uint key_length,
return 0;
}
#define RT_VOL_KORR(type, korr_func, len) \
#define RT_VOL_KORR(type, korr_func, len, cast) \
{ \
type amin, amax; \
amin = korr_func(a); \
a += len; \
amax = korr_func(a); \
a += len; \
res *= ((double)amax - (double)amin); \
res *= (cast(amax) - cast(amin)); \
break; \
}
#define RT_VOL_GET(type, get_func, len) \
#define RT_VOL_GET(type, get_func, len, cast) \
{ \
type amin, amax; \
get_func(amin, a); \
a += len; \
get_func(amax, a); \
a += len; \
res *= ((double)amax - (double)amin); \
res *= (cast(amax) - cast(amin)); \
break; \
}
......@@ -213,27 +213,27 @@ double rtree_rect_volume(HA_KEYSEG *keyseg, uchar *a, uint key_length)
break;
}
case HA_KEYTYPE_SHORT_INT:
RT_VOL_KORR(int16, mi_sint2korr, 2);
RT_VOL_KORR(int16, mi_sint2korr, 2, (double));
case HA_KEYTYPE_USHORT_INT:
RT_VOL_KORR(uint16, mi_uint2korr, 2);
RT_VOL_KORR(uint16, mi_uint2korr, 2, (double));
case HA_KEYTYPE_INT24:
RT_VOL_KORR(int32, mi_sint3korr, 3);
RT_VOL_KORR(int32, mi_sint3korr, 3, (double));
case HA_KEYTYPE_UINT24:
RT_VOL_KORR(uint32, mi_uint3korr, 3);
RT_VOL_KORR(uint32, mi_uint3korr, 3, (double));
case HA_KEYTYPE_LONG_INT:
RT_VOL_KORR(int32, mi_sint4korr, 4);
RT_VOL_KORR(int32, mi_sint4korr, 4, (double));
case HA_KEYTYPE_ULONG_INT:
RT_VOL_KORR(uint32, mi_uint4korr, 4);
RT_VOL_KORR(uint32, mi_uint4korr, 4, (double));
#ifdef HAVE_LONG_LONG
case HA_KEYTYPE_LONGLONG:
RT_VOL_KORR(longlong, mi_sint8korr, 8);
RT_VOL_KORR(longlong, mi_sint8korr, 8, (double));
case HA_KEYTYPE_ULONGLONG:
RT_VOL_KORR(ulonglong, mi_uint8korr, 8);
RT_VOL_KORR(ulonglong, mi_uint8korr, 8, ulonglong2double);
#endif
case HA_KEYTYPE_FLOAT:
RT_VOL_GET(float, mi_float4get, 4);
RT_VOL_GET(float, mi_float4get, 4, (double));
case HA_KEYTYPE_DOUBLE:
RT_VOL_GET(double, mi_float8get, 8);
RT_VOL_GET(double, mi_float8get, 8, (double));
case HA_KEYTYPE_END:
key_length = 0;
break;
......@@ -242,27 +242,27 @@ double rtree_rect_volume(HA_KEYSEG *keyseg, uchar *a, uint key_length)
return res;
}
#define RT_D_MBR_KORR(type, korr_func, len) \
#define RT_D_MBR_KORR(type, korr_func, len, cast) \
{ \
type amin, amax; \
amin = korr_func(a); \
a += len; \
amax = korr_func(a); \
a += len; \
*res++ = (double)amin; \
*res++ = (double)amax; \
*res++ = cast(amin); \
*res++ = cast(amax); \
break; \
}
#define RT_D_MBR_GET(type, get_func, len) \
#define RT_D_MBR_GET(type, get_func, len, cast) \
{ \
type amin, amax; \
get_func(amin, a); \
a += len; \
get_func(amax, a); \
a += len; \
*res++ = (double)amin; \
*res++ = (double)amax; \
*res++ = cast(amin); \
*res++ = cast(amax); \
break; \
}
......@@ -296,27 +296,27 @@ int rtree_d_mbr(HA_KEYSEG *keyseg, uchar *a, uint key_length, double *res)
break;
}
case HA_KEYTYPE_SHORT_INT:
RT_D_MBR_KORR(int16, mi_sint2korr, 2);
RT_D_MBR_KORR(int16, mi_sint2korr, 2, (double));
case HA_KEYTYPE_USHORT_INT:
RT_D_MBR_KORR(uint16, mi_uint2korr, 2);
RT_D_MBR_KORR(uint16, mi_uint2korr, 2, (double));
case HA_KEYTYPE_INT24:
RT_D_MBR_KORR(int32, mi_sint3korr, 3);
RT_D_MBR_KORR(int32, mi_sint3korr, 3, (double));
case HA_KEYTYPE_UINT24:
RT_D_MBR_KORR(uint32, mi_uint3korr, 3);
RT_D_MBR_KORR(uint32, mi_uint3korr, 3, (double));
case HA_KEYTYPE_LONG_INT:
RT_D_MBR_KORR(int32, mi_sint4korr, 4);
RT_D_MBR_KORR(int32, mi_sint4korr, 4, (double));
case HA_KEYTYPE_ULONG_INT:
RT_D_MBR_KORR(uint32, mi_uint4korr, 4);
RT_D_MBR_KORR(uint32, mi_uint4korr, 4, (double));
#ifdef HAVE_LONG_LONG
case HA_KEYTYPE_LONGLONG:
RT_D_MBR_KORR(longlong, mi_sint8korr, 8);
RT_D_MBR_KORR(longlong, mi_sint8korr, 8, (double));
case HA_KEYTYPE_ULONGLONG:
RT_D_MBR_KORR(ulonglong, mi_uint8korr, 8);
RT_D_MBR_KORR(ulonglong, mi_uint8korr, 8, ulonglong2double);
#endif
case HA_KEYTYPE_FLOAT:
RT_D_MBR_GET(float, mi_float4get, 4);
RT_D_MBR_GET(float, mi_float4get, 4, (double));
case HA_KEYTYPE_DOUBLE:
RT_D_MBR_GET(double, mi_float8get, 8);
RT_D_MBR_GET(double, mi_float8get, 8, (double));
case HA_KEYTYPE_END:
key_length = 0;
break;
......@@ -362,12 +362,13 @@ int rtree_d_mbr(HA_KEYSEG *keyseg, uchar *a, uint key_length, double *res)
}
/*
Creates common minimal bounding rectungle
for two input rectagnles a and b
Result is written to c
Creates common minimal bounding rectungle
for two input rectagnles a and b
Result is written to c
*/
int rtree_combine_rect(HA_KEYSEG *keyseg, uchar* a, uchar* b, uchar* c,
uint key_length)
uint key_length)
{
for ( ; (int) key_length > 0 ; keyseg += 2)
......
slave stop;
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
slave start;
start slave;
create table t1(a int not null auto_increment, b int, primary key(a) );
load data infile '../../std_data/rpl_loaddata.dat' into table t1;
select * from t1;
......
......@@ -1274,8 +1274,13 @@ String *Item_func_trim::val_str(String *str)
return &tmp_value;
}
void Item_func_password::fix_length_and_dec()
{
max_length= get_password_length(use_old_passwords);
}
/*
Password() function can have 2 args now. Second argument can be used
Password() function has 2 arguments. Second argument can be used
to make results repeatable
*/
......@@ -1292,9 +1297,9 @@ String *Item_func_password::val_str(String *str)
{
if (res->length() == 0)
return &empty_string;
make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords,
make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
&current_thd->rand);
str->set(tmp_value,get_password_length(opt_old_passwords),res->charset());
str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
return str;
}
else
......@@ -1323,9 +1328,9 @@ String *Item_func_password::val_str(String *str)
/* Use constants which allow nice random values even with small seed */
randominit(&rand_st,seed*111111+33333333L,seed*1111+55555555L);
make_scrambled_password(tmp_value,res->c_ptr(),opt_old_passwords,
make_scrambled_password(tmp_value,res->c_ptr(),use_old_passwords,
&rand_st);
str->set(tmp_value,get_password_length(opt_old_passwords),res->charset());
str->set(tmp_value,get_password_length(use_old_passwords),res->charset());
return str;
}
}
......
......@@ -21,9 +21,6 @@
#pragma interface /* gcc class implementation */
#endif
extern my_bool opt_old_passwords; /* Need this variable for some functions */
class Item_str_func :public Item_func
{
public:
......@@ -264,7 +261,7 @@ class Item_func_password :public Item_str_func
Item_func_password(Item *a) :Item_str_func(a) {}
Item_func_password(Item *a, Item *b) :Item_str_func(a,b) {}
String *val_str(String *);
void fix_length_and_dec() { max_length = get_password_length(opt_old_passwords); }
void fix_length_and_dec();
const char *func_name() const { return "password"; }
};
......
......@@ -718,6 +718,7 @@ extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
extern my_bool opt_safe_show_db, opt_local_infile, lower_case_table_names;
extern my_bool opt_slave_compressed_protocol, use_temp_pool;
extern my_bool opt_enable_named_pipe;
extern my_bool opt_old_passwords, use_old_passwords;
extern char *shared_memory_base_name;
extern bool opt_enable_shared_memory;
extern char f_fyllchar;
......
......@@ -288,7 +288,7 @@ static my_bool opt_noacl=0, opt_bootstrap=0, opt_myisam_log=0;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool lower_case_table_names, opt_old_rpl_compat;
my_bool opt_show_slave_auth_info, opt_sql_bin_update = 0;
my_bool opt_log_slave_updates= 0, opt_old_passwords=0;
my_bool opt_log_slave_updates= 0, opt_old_passwords=0, use_old_passwords=0;
volatile bool mqh_used = 0;
FILE *bootstrap_file=0;
......@@ -3560,7 +3560,7 @@ struct my_option my_long_options[] =
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"safe-mode", OPT_SAFE, "Skip some optimize stages (for testing).",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for old clients)",
{"old-passwords", OPT_OLD_PASSWORDS, "Use old password encryption method (needed for 4.0 and older clients)",
(gptr*) &opt_old_passwords, (gptr*) &opt_old_passwords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
#ifndef TO_BE_DELETED
{"safe-show-database", OPT_SAFE_SHOW_DB,
......
......@@ -55,7 +55,7 @@ static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
static MEM_ROOT mem, memex;
static bool initialized=0;
static bool allow_all_hosts=1;
static HASH acl_check_hosts, hash_tables;
static HASH acl_check_hosts, column_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache;
static uint grant_version=0;
......@@ -104,7 +104,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
DBUG_RETURN(0); /* purecov: tested */
}
priv_version++; /* Priveleges updated */
priv_version++; /* Privileges updated */
/*
To be able to run this from boot, we allocate a temporary THD
......@@ -112,6 +112,8 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (!(thd=new THD))
DBUG_RETURN(1); /* purecov: inspected */
thd->store_globals();
/* Use passwords according to command line option */
use_old_passwords= opt_old_passwords;
acl_cache->clear(1); // Clear locked hostname cache
thd->db= my_strdup("mysql",MYF(0));
......@@ -176,7 +178,14 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
protocol_version=9; /* purecov: tested */
}
DBUG_PRINT("info",("user table fields: %d",table->fields));
DBUG_PRINT("info",("user table fields: %d, password length: %d",
table->fields, table->field[2]->field_length));
if (table->field[2]->field_length < 45 && !use_old_passwords)
{
sql_print_error("mysql.user table is not updated to new password format; Disabling new password usage until mysql_fix_privilege_tables is run");
use_old_passwords= 1;
}
allow_all_hosts=0;
while (!(read_record_info.read_record(&read_record_info)))
{
......@@ -192,7 +201,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
"Found old style password for user '%s'. Ignoring user. (You may want to restart mysqld using --old-protocol)",
user.user ? user.user : ""); /* purecov: tested */
}
else /* non emptpy and not short passwords */
else /* non empty and not short passwords */
{
user.pversion=get_password_version(user.password);
/* Only passwords of specific lengths depending on version are allowed */
......@@ -358,6 +367,7 @@ void acl_reload(THD *thd)
if (acl_init(thd, 0))
{ // Error. Revert to old list
DBUG_PRINT("error",("Reverting to old privileges"));
acl_free(); /* purecov: inspected */
acl_hosts=old_acl_hosts;
acl_users=old_acl_users;
......@@ -1733,10 +1743,12 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
GRANT_TABLE *grant_table,*found=0;
len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1;
for (grant_table=(GRANT_TABLE*) hash_search(&hash_tables,(byte*) helping,
for (grant_table=(GRANT_TABLE*) hash_search(&column_priv_hash,
(byte*) helping,
len) ;
grant_table ;
grant_table= (GRANT_TABLE*) hash_next(&hash_tables,(byte*) helping,len))
grant_table= (GRANT_TABLE*) hash_next(&column_priv_hash,(byte*) helping,
len))
{
if (exact)
{
......@@ -2033,7 +2045,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
else
{
hash_delete(&hash_tables,(byte*) grant_table);
hash_delete(&column_priv_hash,(byte*) grant_table);
}
DBUG_RETURN(0);
......@@ -2179,7 +2191,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list,
result= -1; /* purecov: deadcode */
continue; /* purecov: deadcode */
}
hash_insert(&hash_tables,(byte*) grant_table);
hash_insert(&column_priv_hash,(byte*) grant_table);
}
/* If revoke_grant, calculate the new column privilege for tables_priv */
......@@ -2334,7 +2346,7 @@ void grant_free(void)
{
DBUG_ENTER("grant_free");
grant_option = FALSE;
hash_free(&hash_tables);
hash_free(&column_priv_hash);
free_root(&memex,MYF(0));
DBUG_VOID_RETURN;
}
......@@ -2352,7 +2364,7 @@ my_bool grant_init(THD *org_thd)
DBUG_ENTER("grant_init");
grant_option = FALSE;
(void) hash_init(&hash_tables,my_charset_latin1,
(void) hash_init(&column_priv_hash,my_charset_latin1,
0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
init_sql_alloc(&memex,1024,0);
......@@ -2387,6 +2399,7 @@ my_bool grant_init(THD *org_thd)
if (t_table->file->index_first(t_table->record[0]))
{
t_table->file->index_end();
return_val= 0;
goto end_unlock;
}
grant_option= TRUE;
......@@ -2398,7 +2411,7 @@ my_bool grant_init(THD *org_thd)
{
GRANT_TABLE *mem_check;
if (!(mem_check=new GRANT_TABLE(t_table,c_table)) ||
mem_check->ok() && hash_insert(&hash_tables,(byte*) mem_check))
mem_check->ok() && hash_insert(&column_priv_hash,(byte*) mem_check))
{
/* This could only happen if we are out memory */
grant_option = FALSE; /* purecov: deadcode */
......@@ -2427,11 +2440,12 @@ my_bool grant_init(THD *org_thd)
}
/* Reload grant array if possible */
/* Reload grant array (table and column privileges) if possible */
void grant_reload(THD *thd)
{
HASH old_hash_tables;bool old_grant_option;
HASH old_column_priv_hash;
bool old_grant_option;
MEM_ROOT old_mem;
DBUG_ENTER("grant_reload");
......@@ -2439,20 +2453,21 @@ void grant_reload(THD *thd)
rw_wrlock(&LOCK_grant);
grant_version++;
old_hash_tables=hash_tables;
old_column_priv_hash= column_priv_hash;
old_grant_option = grant_option;
old_mem = memex;
if (grant_init(thd))
{ // Error. Revert to old hash
DBUG_PRINT("error",("Reverting to old privileges"));
grant_free(); /* purecov: deadcode */
hash_tables=old_hash_tables; /* purecov: deadcode */
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
grant_option = old_grant_option; /* purecov: deadcode */
memex = old_mem; /* purecov: deadcode */
}
else
{
hash_free(&old_hash_tables);
hash_free(&old_column_priv_hash);
free_root(&old_mem,MYF(0));
}
rw_unlock(&LOCK_grant);
......@@ -2676,9 +2691,10 @@ bool check_grant_db(THD *thd,const char *db)
len = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1;
rw_rdlock(&LOCK_grant);
for (uint idx=0 ; idx < hash_tables.records ; idx++)
for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
{
GRANT_TABLE *grant_table = (GRANT_TABLE*) hash_element(&hash_tables,idx);
GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
idx);
if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) &&
(thd->host && !wild_case_compare(my_charset_latin1,
......@@ -3000,10 +3016,11 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
/* Add column access */
for (index=0 ; index < hash_tables.records ; index++)
for (index=0 ; index < column_priv_hash.records ; index++)
{
const char *user,*host;
GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index);
GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&column_priv_hash,
index);
if (!(user=grant_table->user))
user="";
......
......@@ -430,7 +430,7 @@ class THD :public ilink {
/* points to host if host is available, otherwise points to ip */
const char *host_or_ip;
uint client_capabilities; /* What the client supports */
ulong client_capabilities; /* What the client supports */
/* Determines if which non-standard SQL behaviour should be enabled */
ulong max_client_packet_length;
ulong master_access; /* Global privileges from mysql.user */
......
......@@ -206,10 +206,11 @@ static int check_user(THD *thd,enum_server_command command, const char *user,
}
thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user,
passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 ||
!(thd->client_capabilities &
CLIENT_LONG_PASSWORD),&ur,crypted_scramble,
cur_priv_version,hint_user);
(protocol_version == 9 ||
!(thd->client_capabilities &
CLIENT_LONG_PASSWORD)),
&ur,crypted_scramble,
cur_priv_version,hint_user);
DBUG_PRINT("info",
("Capabilities: %d packet_length: %ld Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
......@@ -493,11 +494,11 @@ check_connections(THD *thd)
{
uint connect_errors=0;
NET *net= &thd->net;
/* Store the connection details */
char *end;
DBUG_PRINT("info", (("check_connections called by thread %d"),
thd->thread_id));
thd->thread_id));
DBUG_PRINT("info",("New connection received on %s",
vio_description(net->vio)));
vio_description(net->vio)));
if (!thd->host) // If TCP/IP connection
{
char ip[30];
......@@ -542,8 +543,7 @@ check_connections(THD *thd)
ulong pkt_len=0;
{
/* buff[] needs to big enough to hold the server_version variable */
char buff[SERVER_VERSION_LENGTH +
SCRAMBLE_LENGTH+64],*end;
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+64];
int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB |
CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION;
......@@ -587,6 +587,18 @@ check_connections(THD *thd)
return(ER_OUT_OF_RESOURCES);
thd->client_capabilities=uint2korr(net->read_pos);
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
thd->max_client_packet_length= uint4korr(net->read_pos+4);
end= (char*) net->read_pos+8;
}
else
{
thd->max_client_packet_length= uint3korr(net->read_pos+2);
end= (char*) net->read_pos+5;
}
if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
thd->variables.sql_mode|= MODE_IGNORE_SPACE;
#ifdef HAVE_OPENSSL
......@@ -612,19 +624,15 @@ check_connections(THD *thd)
return(ER_HANDSHAKE_ERROR);
}
}
else
#endif
if (end >= (char*) net->read_pos+ pkt_len +2)
{
DBUG_PRINT("info", ("Leaving IO layer intact"));
if (pkt_len < NORMAL_HANDSHAKE_SIZE)
{
inc_host_errors(&thd->remote.sin_addr);
return ER_HANDSHAKE_ERROR;
}
inc_host_errors(&thd->remote.sin_addr);
return(ER_HANDSHAKE_ERROR);
}
#endif
thd->max_client_packet_length=uint3korr(net->read_pos+2);
char *user= (char*) net->read_pos+5;
char *user= end;
char *passwd= strend(user)+1;
char *db=0;
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
......
......@@ -4108,7 +4108,8 @@ text_or_password:
else
{
char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
make_scrambled_password(buff,$3.str,opt_old_passwords,&current_thd->rand);
make_scrambled_password(buff,$3.str,use_old_passwords,
&YYTHD->rand);
$$=buff;
}
}
......@@ -4410,7 +4411,8 @@ grant_user:
char *buff=(char*) YYTHD->alloc(HASH_PASSWORD_LENGTH+1);
if (buff)
{
make_scrambled_password(buff,$4.str,opt_old_passwords,&current_thd->rand);
make_scrambled_password(buff,$4.str,use_old_passwords,
&YYTHD->rand);
$1->password.str=buff;
$1->password.length=HASH_PASSWORD_LENGTH;
}
......
......@@ -2460,9 +2460,9 @@ long my_strntol_ucs2(CHARSET_INFO *cs,
register unsigned int cutlim;
register ulong cutoff;
register ulong res;
register const char *s=nptr;
register const char *e=nptr+l;
const char *save;
register const uchar *s= (const uchar*) nptr;
register const uchar *e= (const uchar*) nptr+l;
const uchar *save;
*err= 0;
do
......@@ -2490,7 +2490,7 @@ long my_strntol_ucs2(CHARSET_INFO *cs,
bs:
#if 0
#ifdef NOT_USED
if (base <= 0 || base == 1 || base > 36)
base = 10;
#endif
......@@ -2575,9 +2575,9 @@ ulong my_strntoul_ucs2(CHARSET_INFO *cs,
register unsigned int cutlim;
register ulong cutoff;
register ulong res;
register const char *s=nptr;
register const char *e=nptr+l;
const char *save;
register const uchar *s= (const uchar*) nptr;
register const uchar *e= (const uchar*) nptr+l;
const uchar *save;
*err= 0;
do
......@@ -2605,7 +2605,7 @@ ulong my_strntoul_ucs2(CHARSET_INFO *cs,
bs:
#if 0
#ifdef NOT_USED
if (base <= 0 || base == 1 || base > 36)
base = 10;
#endif
......@@ -2616,7 +2616,8 @@ ulong my_strntoul_ucs2(CHARSET_INFO *cs,
cutoff = ((ulong)~0L) / (unsigned long int) base;
cutlim = (uint) (((ulong)~0L) % (unsigned long int) base);
do {
do
{
if ((cnv=cs->mb_wc(cs,&wc,s,e))>0)
{
s+=cnv;
......@@ -2684,9 +2685,9 @@ longlong my_strntoll_ucs2(CHARSET_INFO *cs,
register ulonglong cutoff;
register unsigned int cutlim;
register ulonglong res;
register const char *s=nptr;
register const char *e=nptr+l;
const char *save;
register const uchar *s= (const uchar*) nptr;
register const uchar *e= (const uchar*) nptr+l;
const uchar *save;
*err= 0;
do
......@@ -2714,7 +2715,7 @@ longlong my_strntoll_ucs2(CHARSET_INFO *cs,
bs:
#if 0
#ifdef NOT_USED
if (base <= 0 || base == 1 || base > 36)
base = 10;
#endif
......@@ -2801,9 +2802,9 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs,
register ulonglong cutoff;
register unsigned int cutlim;
register ulonglong res;
register const char *s=nptr;
register const char *e=nptr+l;
const char *save;
register const uchar *s= (const uchar*) nptr;
register const uchar *e= (const uchar*) nptr+l;
const uchar *save;
*err= 0;
do
......@@ -2831,7 +2832,7 @@ ulonglong my_strntoull_ucs2(CHARSET_INFO *cs,
bs:
#if 0
#ifdef NOT_USED
if (base <= 0 || base == 1 || base > 36)
base = 10;
#endif
......@@ -2905,8 +2906,8 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
char buf[256];
double res;
register char *b=buf;
register const char *s=nptr;
register const char *end;
register const uchar *s= (const uchar*) nptr;
register const uchar *end;
my_wc_t wc;
int cnv;
......@@ -2914,7 +2915,7 @@ double my_strntod_ucs2(CHARSET_INFO *cs __attribute__((unused)),
/* Cut too long strings */
if (length >= sizeof(buf))
length= sizeof(buf)-1;
end=nptr+length;
end= s+length;
while ((cnv=cs->mb_wc(cs,&wc,s,end)) > 0)
{
......@@ -2976,7 +2977,7 @@ int my_l10tostr_ucs2(CHARSET_INFO *cs,
for ( db=dst, de=dst+len ; (dst<de) && *p ; p++)
{
int cnvres=cs->wc_mb(cs,(my_wc_t)p[0],dst,de);
int cnvres=cs->wc_mb(cs,(my_wc_t)p[0],(uchar*) dst, (uchar*) de);
if (cnvres>0)
dst+=cnvres;
else
......@@ -3035,7 +3036,7 @@ int my_ll10tostr_ucs2(CHARSET_INFO *cs __attribute__((unused)),
for ( db=dst, de=dst+len ; (dst<de) && *p ; p++)
{
int cnvres=cs->wc_mb(cs,(my_wc_t)p[0],dst,de);
int cnvres=cs->wc_mb(cs, (my_wc_t) p[0], (uchar*) dst, (uchar*) de);
if (cnvres>0)
dst+=cnvres;
else
......
/*
File strings/ctype-win1250ch.c for MySQL.
/* Copyright (C) 2003 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Copyright: (C) 2001 Jan Pazdziora.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
This software is released under the terms of GNU General
Public License.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
Development of this software was supported by Neocortex, s.r.o.
/*
Shared, independent copyright: (C) 2001 Jan Pazdziora.
Bug reports and suggestions are always welcome.
Development of this software was supported by Neocortex, s.r.o.
MySQL AB expresses its gratitude to Jan for for giving us this software.
This file implements the collating sequence for Windows-1250
character set. It merely extends the binary sorting of US-ASCII
by adding characters with diacritical marks into proper places.
In addition, it sorts 'ch' between 'h' and 'i', and the sorting
is case sensitive, with uppercase being sorted first, in the
second pass.
Bug reports and suggestions are always welcome.
Bug reports and suggestions are always welcome.
This file implements the collating sequence for Windows-1250
character set. It merely extends the binary sorting of US-ASCII
by adding characters with diacritical marks into proper places.
In addition, it sorts 'ch' between 'h' and 'i', and the sorting
is case sensitive, with uppercase being sorted first, in the
second pass.
*/
/*
......@@ -388,16 +398,16 @@ static uchar NEAR _sort_order_win1250ch2[] = {
};
struct wordvalue {
const char * word;
const uchar * word;
uchar pass1;
uchar pass2;
};
static struct wordvalue doubles[] = {
{ "ch", 0xad, 0x03 },
{ "c", 0xa6, 0x02 },
{ "Ch", 0xad, 0x02 },
{ "CH", 0xad, 0x01 },
{ "C", 0xa6, 0x01 },
{ (uchar*) "ch", 0xad, 0x03 },
{ (uchar*) "c", 0xa6, 0x02 },
{ (uchar*) "Ch", 0xad, 0x02 },
{ (uchar*) "CH", 0xad, 0x01 },
{ (uchar*) "C", 0xa6, 0x01 },
};
#define NEXT_CMP_VALUE(src, p, pass, value, len) \
......@@ -412,7 +422,7 @@ static struct wordvalue doubles[] = {
int i; \
for (i = 0; i < (int) sizeof(doubles); i++) { \
const uchar * patt = doubles[i].word; \
const uchar * q = (const char *) p; \
const uchar * q = (const uchar *) p; \
while (*patt \
&& !(IS_END(q, src, len)) \
&& (*patt == *q)) { \
......
......@@ -27,11 +27,11 @@ show grants for grant_user@localhost
GRANT SELECT ON *.* TO 'grant_user'@'localhost'
insert into mysql.user (host,user) values ('error','grant_user')
Error in execute: insert command denied to user: 'grant_user@localhost' for table 'user'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
update mysql.user set host='error' WHERE user='grant_user'
Error in execute: update command denied to user: 'grant_user@localhost' for table 'user'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
create table grant_test.test (a int,b int)
Error in execute: create command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
grant select on *.* to grant_user2@localhost
Error in execute: Access denied for user: 'grant_user@localhost' (Using password: NO)
revoke select on grant_test.test from grant_user@opt_host
......@@ -106,21 +106,21 @@ select count(*) from grant_test.test
2
select * from mysql.user where user = 'grant_user'
Error in execute: select command denied to user: 'grant_user@localhost' for table 'user'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
insert into grant_test.test values (4,0)
Error in execute: insert command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
update grant_test.test set a=1
Error in execute: update command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
delete from grant_test.test
Error in execute: delete command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
create table grant_test.test2 (a int)
Error in execute: create command denied to user: 'grant_user@localhost' for table 'test2'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
ALTER TABLE grant_test.test add c int
Error in execute: alter command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
CREATE INDEX dummy ON grant_test.test (a)
Error in execute: index command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
drop table grant_test.test
Error in execute: drop command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
grant ALL PRIVILEGES on grant_test.* to grant_user2@localhost
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
grant ALL PRIVILEGES on grant_test.* to grant_user@localhost WITH GRANT OPTION
......@@ -133,14 +133,14 @@ REVOKE ALL PRIVILEGES on grant_test.* from grant_user@localhost
REVOKE ALL PRIVILEGES on grant_test.* from grant_user@localhost
Connecting grant_user
insert into grant_test.test values (6,0)
Error in execute: insert command denied to user: 'grant_user@localhost' for table 'test'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'grant_test'
REVOKE GRANT OPTION on grant_test.* from grant_user@localhost
Connecting grant_user
Access denied for user: 'grant_user@localhost' to database 'grant_test'
grant ALL PRIVILEGES on grant_test.* to grant_user@localhost
Connecting grant_user
select * from mysql.user where user = 'grant_user'
Error in execute: select command denied to user: 'grant_user@localhost' for table 'user'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
insert into grant_test.test values (7,0)
update grant_test.test set a=3 where a=2
delete from grant_test.test where a=3
......@@ -152,7 +152,7 @@ show tables from grant_test
test
insert into mysql.user (host,user) values ('error','grant_user',0)
Error in execute: insert command denied to user: 'grant_user@localhost' for table 'user'
Error in execute: Access denied for user: 'grant_user@localhost' to database 'mysql'
revoke ALL PRIVILEGES on grant_test.* from grant_user@localhost
select * from mysql.user where user = 'grant_user'
localhost grant_user N N N N N N N N N N N N N N N N N N N N N 0 0 0
......@@ -171,7 +171,7 @@ Error in execute: select command denied to user: 'grant_user@localhost' for tabl
show keys from test
Error in execute: select command denied to user: 'grant_user@localhost' for table 'test'
show columns from test2
a int(11) 0
a int(11) binary 0
show keys from test2
select * from test
......@@ -228,7 +228,7 @@ Error in execute: select command denied to user: 'grant_user@localhost' for tabl
select count(*) from test,test2
Error in execute: select command denied to user: 'grant_user@localhost' for table 'test2'
replace into test2 SELECT a from test
Error in execute: update command denied to user: 'grant_user@localhost' for table 'test2'
Error in execute: delete command denied to user: 'grant_user@localhost' for table 'test2'
grant update on grant_test.test2 to grant_user@localhost
replace into test2 SELECT a,a from test
Error in execute: delete command denied to user: 'grant_user@localhost' for table 'test2'
......@@ -314,8 +314,8 @@ revoke GRANT OPTION on grant_test.test from grant_user@localhost
Error in execute: There is no such grant defined for user 'grant_user' on host 'localhost' on table 'test'
grant select(a) on grant_test.test to grant_user@localhost
show full columns from test
a int(11) YES NULL select
b int(11) YES NULL
a int(11) binary YES NULL select
b int(11) binary YES NULL
grant insert (b), update (b) on grant_test.test to grant_user@localhost
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