This is a large push. Included are :

* multi-table updates
* new paid feature for limiting number of queries per hour for users
* optional syntax for multi-table deletes
* optimization for SQL_CALC_FOUND_ROWS
* a small addition for CREATE .. SELECT that will be of future use

I know that all this will require many additions to documentation, 
which I have not done, but I am at Arjen's disposal to help him document
all this.
parent ec761d57
...@@ -425,3 +425,5 @@ vio/test-sslclient ...@@ -425,3 +425,5 @@ vio/test-sslclient
vio/test-sslserver vio/test-sslserver
vio/viotest-ssl vio/viotest-ssl
libmysqld/mf_iocache.cc libmysqld/mf_iocache.cc
50
sql/new.cc
...@@ -228,11 +228,11 @@ check_connections2(THD * thd) ...@@ -228,11 +228,11 @@ check_connections2(THD * thd)
return 0; return 0;
} }
static bool check_user(THD *thd,enum_server_command command, const char *user, static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count) const char *passwd, const char *db, bool check_count)
{ {
NET *net= &thd->net; NET *net= &thd->net;
uint max=0;
thd->db=0; thd->db=0;
if (!(thd->user = my_strdup(user, MYF(0)))) if (!(thd->user = my_strdup(user, MYF(0))))
...@@ -244,7 +244,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, ...@@ -244,7 +244,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
passwd, thd->scramble, &thd->priv_user, passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 || protocol_version == 9 ||
!(thd->client_capabilities & !(thd->client_capabilities &
CLIENT_LONG_PASSWORD)); CLIENT_LONG_PASSWORD),&max);
DBUG_PRINT("general", DBUG_PRINT("general",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_packet_length, thd->client_capabilities, thd->max_packet_length,
......
...@@ -2,32 +2,33 @@ drop table if exists t1,t2,t3; ...@@ -2,32 +2,33 @@ drop table if exists t1,t2,t3;
create table t1(id1 int not null auto_increment primary key, t char(12)); create table t1(id1 int not null auto_increment primary key, t char(12));
create table t2(id2 int not null, t char(12)); create table t2(id2 int not null, t char(12));
create table t3(id3 int not null, t char(12), index(id3)); create table t3(id3 int not null, t char(12), index(id3));
delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 9500; update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90;
delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95;
check table t1, t2, t3; check table t1, t2, t3;
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 check status OK test.t1 check status OK
test.t2 check status OK test.t2 check status OK
test.t3 check status OK test.t3 check status OK
select count(*) from t1 where id1 > 9500; select count(*) from t1 where id1 > 95;
count(*) count(*)
0 0
select count(*) from t2 where id2 > 9500; select count(*) from t2 where id2 > 95;
count(*) count(*)
0 0
select count(*) from t3 where id3 > 9500; select count(*) from t3 where id3 > 95;
count(*) count(*)
0 0
delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 500; delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 5;
select count(*) from t1 where id1 > 500; select count(*) from t1 where id1 > 5;
count(*) count(*)
0 0
select count(*) from t2 where id2 > 500; select count(*) from t2 where id2 > 5;
count(*) count(*)
0 0
select count(*) from t3 where id3 > 500; select count(*) from t3 where id3 > 5;
count(*) count(*)
0 0
delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0; delete from t1, t2, t3 using t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0;
select count(*) from t1 where id1; select count(*) from t1 where id1;
count(*) count(*)
0 0
......
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
# Only run the test if we are using --big-test, because this test takes a # Only run the test if we are using --big-test, because this test takes a
# long time # long time
# #
-- require r/big_test.require #-- require r/big_test.require
eval select $BIG_TEST as using_big_test; #eval select $BIG_TEST as using_big_test;
drop table if exists t1,t2,t3; drop table if exists t1,t2,t3;
create table t1(id1 int not null auto_increment primary key, t char(12)); create table t1(id1 int not null auto_increment primary key, t char(12));
create table t2(id2 int not null, t char(12)); create table t2(id2 int not null, t char(12));
create table t3(id3 int not null, t char(12), index(id3)); create table t3(id3 int not null, t char(12), index(id3));
disable_query_log; disable_query_log;
let $1 = 10000; let $1 = 100;
while ($1) while ($1)
{ {
let $2 = 5; let $2 = 5;
...@@ -29,20 +29,21 @@ while ($1) ...@@ -29,20 +29,21 @@ while ($1)
dec $1; dec $1;
} }
enable_query_log; enable_query_log;
delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 9500; update t1,t2,t3 set t1.t="aaa", t2.t="bbb", t3.t="cc" where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 90;
delete t1.*, t2.*, t3.* from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 95;
check table t1, t2, t3; check table t1, t2, t3;
select count(*) from t1 where id1 > 9500; select count(*) from t1 where id1 > 95;
select count(*) from t2 where id2 > 9500; select count(*) from t2 where id2 > 95;
select count(*) from t3 where id3 > 9500; select count(*) from t3 where id3 > 95;
delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 500; delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 5;
select count(*) from t1 where id1 > 500; select count(*) from t1 where id1 > 5;
select count(*) from t2 where id2 > 500; select count(*) from t2 where id2 > 5;
select count(*) from t3 where id3 > 500; select count(*) from t3 where id3 > 5;
delete t1, t2, t3 from t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0; delete from t1, t2, t3 using t1,t2,t3 where t1.id1 = t2.id2 and t2.id2 = t3.id3 and t1.id1 > 0;
# These queries will force a scan of the table # These queries will force a scan of the table
select count(*) from t1 where id1; select count(*) from t1 where id1;
......
...@@ -228,18 +228,21 @@ then ...@@ -228,18 +228,21 @@ then
c_u="$c_u ssl_cipher BLOB NOT NULL," c_u="$c_u ssl_cipher BLOB NOT NULL,"
c_u="$c_u x509_issuer BLOB NOT NULL," c_u="$c_u x509_issuer BLOB NOT NULL,"
c_u="$c_u x509_subject BLOB NOT NULL," c_u="$c_u x509_subject BLOB NOT NULL,"
c_u="$c_u max_questions int(11) unsigned DEFAULT 0 NOT NULL,"
c_u="$c_u max_updates int(11) unsigned DEFAULT 0 NOT NULL,"
c_u="$c_u max_connections int(11) unsigned DEFAULT 0 NOT NULL,"
c_u="$c_u PRIMARY KEY Host (Host,User)" c_u="$c_u PRIMARY KEY Host (Host,User)"
c_u="$c_u )" c_u="$c_u )"
c_u="$c_u comment='Users and global privileges';" c_u="$c_u comment='Users and global privileges';"
i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','',''); i_u="INSERT INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','',''); INSERT INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
REPLACE INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','',''); REPLACE INTO user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
REPLACE INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','',''); REPLACE INTO user VALUES ('$hostname','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','NONE','','','',0,0,0);
INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','NONE','','',''); INSERT INTO user VALUES ('localhost','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','NONE','','','',0,0,0);
INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','NONE','','','');" INSERT INTO user VALUES ('$hostname','','','N','N','N','N','N','N','N','N','N','N','N','N','N','N','NONE','','','',0,0,0);"
fi fi
if test ! -f $mdata/func.frm if test ! -f $mdata/func.frm
......
#!/bin/sh
echo "This scripts updates the mysql.user, mysql.db, mysql.host and the"
echo "mysql.func table to MySQL 3.22.14 and above."
echo ""
echo "This is needed if you want to use the new GRANT functions,"
echo "CREATE AGGREAGATE FUNCTION or want to use the more secure passwords in 3.23"
echo ""
echo "If you get Access denied errors, you should run this script again"
echo "and give the MySQL root user password as a argument!"
root_password="$1"
host="localhost"
# Fix old password format, add File_priv and func table
echo ""
echo "If your tables are already up to date or partially up to date you will"
echo "get some warnings about 'Duplicated column name'. You can safely ignore these!"
@bindir@/mysql -f --user=root --password="$root_password" --host="$host" mysql <<END_OF_DATA
alter table user add max_questions int(11) unsigned DEFAULT 0 NOT NULL;
alter table user add max_updates int(11) unsigned DEFAULT 0 NOT NULL;
alter table user add max_connections int(11) unsigned DEFAULT 0 NOT NULL;
END_OF_DATA
...@@ -229,6 +229,23 @@ public: ...@@ -229,6 +229,23 @@ public:
const char *func_name() const { return "date"; } const char *func_name() const { return "date"; }
void fix_length_and_dec() { decimals=0; max_length=10; } void fix_length_and_dec() { decimals=0; max_length=10; }
bool save_in_field(Field *to); bool save_in_field(Field *to);
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,FIELD_TYPE_DATE);
}
};
class Item_date_func :public Item_str_func
{
public:
Item_date_func() :Item_str_func() {}
Item_date_func(Item *a) :Item_str_func(a) {}
Item_date_func(Item *a,Item *b) :Item_str_func(a,b) {}
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,FIELD_TYPE_DATETIME);
}
}; };
...@@ -247,6 +264,10 @@ public: ...@@ -247,6 +264,10 @@ public:
{ str_value.set(buff,buff_length); return &str_value; } { str_value.set(buff,buff_length); return &str_value; }
const char *func_name() const { return "curtime"; } const char *func_name() const { return "curtime"; }
void fix_length_and_dec(); void fix_length_and_dec();
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,FIELD_TYPE_TIME);
}
}; };
...@@ -263,15 +284,15 @@ public: ...@@ -263,15 +284,15 @@ public:
}; };
class Item_func_now :public Item_func class Item_func_now :public Item_date_func
{ {
longlong value; longlong value;
char buff[20]; char buff[20];
uint buff_length; uint buff_length;
TIME ltime; TIME ltime;
public: public:
Item_func_now() :Item_func() {} Item_func_now() :Item_date_func() {}
Item_func_now(Item *a) :Item_func(a) {} Item_func_now(Item *a) :Item_date_func(a) {}
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
double val() { return (double) value; } double val() { return (double) value; }
longlong val_int() { return value; } longlong val_int() { return value; }
...@@ -307,16 +328,16 @@ public: ...@@ -307,16 +328,16 @@ public:
}; };
class Item_func_from_unixtime :public Item_func class Item_func_from_unixtime :public Item_date_func
{ {
public: public:
Item_func_from_unixtime(Item *a) :Item_func(a) {} Item_func_from_unixtime(Item *a) :Item_date_func(a) {}
double val() { return (double) Item_func_from_unixtime::val_int(); } double val() { return (double) Item_func_from_unixtime::val_int(); }
longlong val_int(); longlong val_int();
String *val_str(String *str); String *val_str(String *str);
const char *func_name() const { return "from_unixtime"; } const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec() { decimals=0; max_length=19; } void fix_length_and_dec() { decimals=0; max_length=19; }
enum Item_result result_type () const { return STRING_RESULT; } // enum Item_result result_type () const { return STRING_RESULT; }
bool get_date(TIME *res,bool fuzzy_date); bool get_date(TIME *res,bool fuzzy_date);
}; };
...@@ -330,6 +351,10 @@ public: ...@@ -330,6 +351,10 @@ public:
String *val_str(String *); String *val_str(String *);
void fix_length_and_dec() { maybe_null=1; max_length=13; } void fix_length_and_dec() { maybe_null=1; max_length=13; }
const char *func_name() const { return "sec_to_time"; } const char *func_name() const { return "sec_to_time"; }
void make_field(Send_field *tmp_field)
{
init_make_field(tmp_field,FIELD_TYPE_TIME);
}
}; };
enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
...@@ -339,7 +364,7 @@ enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY, ...@@ -339,7 +364,7 @@ enum interval_type { INTERVAL_YEAR, INTERVAL_MONTH, INTERVAL_DAY,
INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND, INTERVAL_HOUR_MINUTE, INTERVAL_HOUR_SECOND,
INTERVAL_MINUTE_SECOND}; INTERVAL_MINUTE_SECOND};
class Item_date_add_interval :public Item_str_func class Item_date_add_interval :public Item_date_func
{ {
const interval_type int_type; const interval_type int_type;
String value; String value;
...@@ -347,7 +372,7 @@ class Item_date_add_interval :public Item_str_func ...@@ -347,7 +372,7 @@ class Item_date_add_interval :public Item_str_func
public: public:
Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg) Item_date_add_interval(Item *a,Item *b,interval_type type_arg,bool neg_arg)
:Item_str_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} :Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {}
String *val_str(String *); String *val_str(String *);
const char *func_name() const { return "date_add_interval"; } const char *func_name() const { return "date_add_interval"; }
void fix_length_and_dec() { maybe_null=1; max_length=19; value.alloc(32);} void fix_length_and_dec() { maybe_null=1; max_length=19; value.alloc(32);}
......
...@@ -224,6 +224,7 @@ static SYMBOL symbols[] = { ...@@ -224,6 +224,7 @@ static SYMBOL symbols[] = {
{ "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0}, { "MASTER_SERVER_ID", SYM(MASTER_SERVER_ID_SYM),0,0},
{ "MASTER_USER", SYM(MASTER_USER_SYM),0,0}, { "MASTER_USER", SYM(MASTER_USER_SYM),0,0},
{ "MAX_ROWS", SYM(MAX_ROWS),0,0}, { "MAX_ROWS", SYM(MAX_ROWS),0,0},
{ "MAXIMUM", SYM(MAXIMUM),0,0},
{ "MATCH", SYM(MATCH),0,0}, { "MATCH", SYM(MATCH),0,0},
{ "MEDIUMBLOB", SYM(MEDIUMBLOB),0,0}, { "MEDIUMBLOB", SYM(MEDIUMBLOB),0,0},
{ "MEDIUMTEXT", SYM(MEDIUMTEXT),0,0}, { "MEDIUMTEXT", SYM(MEDIUMTEXT),0,0},
...@@ -237,6 +238,7 @@ static SYMBOL symbols[] = { ...@@ -237,6 +238,7 @@ static SYMBOL symbols[] = {
{ "MODE", SYM(MODE_SYM),0,0}, { "MODE", SYM(MODE_SYM),0,0},
{ "MODIFY", SYM(MODIFY_SYM),0,0}, { "MODIFY", SYM(MODIFY_SYM),0,0},
{ "MONTH", SYM(MONTH_SYM),0,0}, { "MONTH", SYM(MONTH_SYM),0,0},
{ "MQH", SYM(MQH_SYM),0,0},
{ "MRG_MYISAM", SYM(MERGE_SYM),0,0}, { "MRG_MYISAM", SYM(MERGE_SYM),0,0},
{ "MYISAM", SYM(MYISAM_SYM),0,0}, { "MYISAM", SYM(MYISAM_SYM),0,0},
{ "NATURAL", SYM(NATURAL),0,0}, { "NATURAL", SYM(NATURAL),0,0},
...@@ -260,6 +262,7 @@ static SYMBOL symbols[] = { ...@@ -260,6 +262,7 @@ static SYMBOL symbols[] = {
{ "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0}, { "PACK_KEYS", SYM(PACK_KEYS_SYM),0,0},
{ "PARTIAL", SYM(PARTIAL),0,0}, { "PARTIAL", SYM(PARTIAL),0,0},
{ "PASSWORD", SYM(PASSWORD),0,0}, { "PASSWORD", SYM(PASSWORD),0,0},
{ "PER", SYM(PER_SYM),0,0},
{ "PURGE", SYM(PURGE),0,0}, { "PURGE", SYM(PURGE),0,0},
{ "PRECISION", SYM(PRECISION),0,0}, { "PRECISION", SYM(PRECISION),0,0},
{ "PREV", SYM(PREV_SYM),0,0}, { "PREV", SYM(PREV_SYM),0,0},
...@@ -268,6 +271,7 @@ static SYMBOL symbols[] = { ...@@ -268,6 +271,7 @@ static SYMBOL symbols[] = {
{ "PROCESS" , SYM(PROCESS),0,0}, { "PROCESS" , SYM(PROCESS),0,0},
{ "PROCESSLIST", SYM(PROCESSLIST_SYM),0,0}, { "PROCESSLIST", SYM(PROCESSLIST_SYM),0,0},
{ "PRIVILEGES", SYM(PRIVILEGES),0,0}, { "PRIVILEGES", SYM(PRIVILEGES),0,0},
{ "QUERIES", SYM(QUERIES),0,0},
{ "QUICK", SYM(QUICK),0,0}, { "QUICK", SYM(QUICK),0,0},
{ "RAID0", SYM(RAID_0_SYM),0,0}, { "RAID0", SYM(RAID_0_SYM),0,0},
{ "READ", SYM(READ_SYM),0,0}, { "READ", SYM(READ_SYM),0,0},
......
...@@ -492,7 +492,7 @@ int write_record(TABLE *table,COPY_INFO *info); ...@@ -492,7 +492,7 @@ int write_record(TABLE *table,COPY_INFO *info);
/* bits set in manager_status */ /* bits set in manager_status */
#define MANAGER_BERKELEY_LOG_CLEANUP (1L << 0) #define MANAGER_BERKELEY_LOG_CLEANUP (1L << 0)
extern ulong volatile manager_status; extern ulong volatile manager_status;
extern bool volatile manager_thread_in_use; extern bool volatile manager_thread_in_use, mqh_used;
extern pthread_t manager_thread; extern pthread_t manager_thread;
extern pthread_mutex_t LOCK_manager; extern pthread_mutex_t LOCK_manager;
extern pthread_cond_t COND_manager; extern pthread_cond_t COND_manager;
......
...@@ -219,6 +219,7 @@ static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl, ...@@ -219,6 +219,7 @@ static bool opt_log,opt_update_log,opt_bin_log,opt_slow_log,opt_noacl,
bool opt_sql_bin_update = 0, opt_log_slave_updates = 0, opt_safe_show_db=0, bool opt_sql_bin_update = 0, opt_log_slave_updates = 0, opt_safe_show_db=0,
opt_show_slave_auth_info = 0, opt_old_rpl_compat = 0, opt_show_slave_auth_info = 0, opt_old_rpl_compat = 0,
opt_safe_user_create = 0, opt_no_mix_types = 0; opt_safe_user_create = 0, opt_no_mix_types = 0;
volatile bool mqh_used = 0;
FILE *bootstrap_file=0; FILE *bootstrap_file=0;
int segfaulted = 0; // ensure we do not enter SIGSEGV handler twice int segfaulted = 0; // ensure we do not enter SIGSEGV handler twice
extern MASTER_INFO glob_mi; extern MASTER_INFO glob_mi;
...@@ -1900,7 +1901,7 @@ The server will not act as a slave."); ...@@ -1900,7 +1901,7 @@ The server will not act as a slave.");
} }
if (!opt_noacl) if (!opt_noacl)
(void) grant_init(); (void) grant_init();
if (max_user_connections) if (max_user_connections || mqh_used)
init_max_user_conn(); init_max_user_conn();
#ifdef HAVE_DLOPEN #ifdef HAVE_DLOPEN
......
...@@ -58,7 +58,7 @@ class ACL_USER :public ACL_ACCESS ...@@ -58,7 +58,7 @@ class ACL_USER :public ACL_ACCESS
{ {
public: public:
acl_host_and_ip host; acl_host_and_ip host;
uint hostname_length; uint hostname_length, questions, updates;
char *user,*password; char *user,*password;
ulong salt[2]; ulong salt[2];
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
...@@ -240,6 +240,15 @@ int acl_init(bool dont_read_acl_tables) ...@@ -240,6 +240,15 @@ int acl_init(bool dont_read_acl_tables)
user.access=get_access(table,3); user.access=get_access(table,3);
user.sort=get_sort(2,user.host.hostname,user.user); user.sort=get_sort(2,user.host.hostname,user.user);
user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0; user.hostname_length=user.host.hostname ? (uint) strlen(user.host.hostname) : 0;
if (table->fields >=23)
{
char *ptr = get_field(&mem, table, 21);
user.questions=atoi(ptr);
ptr = get_field(&mem, table, 22);
user.updates=atoi(ptr);
if (user.questions)
mqh_used=true;
}
#ifndef TO_BE_REMOVED #ifndef TO_BE_REMOVED
if (table->fields <= 13) if (table->fields <= 13)
{ // Without grant { // Without grant
...@@ -423,7 +432,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) ...@@ -423,7 +432,7 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
/* Get master privilges for user (priviliges for all tables). Required to connect */ /* Get master privilges for user (priviliges for all tables). Required to connect */
uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user, uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message,char **priv_user, const char *password,const char *message,char **priv_user,
bool old_ver) bool old_ver, uint *max)
{ {
uint user_access=NO_ACCESS; uint user_access=NO_ACCESS;
*priv_user=(char*) user; *priv_user=(char*) user;
...@@ -536,6 +545,7 @@ uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user, ...@@ -536,6 +545,7 @@ uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
#else /* HAVE_OPENSSL */ #else /* HAVE_OPENSSL */
user_access=acl_user->access; user_access=acl_user->access;
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
*max=acl_user->questions;
if (!acl_user->user) if (!acl_user->user)
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */ *priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
break; break;
...@@ -569,6 +579,7 @@ static void acl_update_user(const char *user, const char *host, ...@@ -569,6 +579,7 @@ static void acl_update_user(const char *user, const char *host,
const char *ssl_cipher, const char *ssl_cipher,
const char *x509_issuer, const char *x509_issuer,
const char *x509_subject, const char *x509_subject,
unsigned int mqh,
uint privileges) uint privileges)
{ {
for (uint i=0 ; i < acl_users.elements ; i++) for (uint i=0 ; i < acl_users.elements ; i++)
...@@ -582,6 +593,7 @@ static void acl_update_user(const char *user, const char *host, ...@@ -582,6 +593,7 @@ static void acl_update_user(const char *user, const char *host,
acl_user->host.hostname && !strcmp(host,acl_user->host.hostname)) acl_user->host.hostname && !strcmp(host,acl_user->host.hostname))
{ {
acl_user->access=privileges; acl_user->access=privileges;
acl_user->questions=mqh;
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
acl_user->ssl_type=ssl_type; acl_user->ssl_type=ssl_type;
acl_user->ssl_cipher=ssl_cipher; acl_user->ssl_cipher=ssl_cipher;
...@@ -611,6 +623,7 @@ static void acl_insert_user(const char *user, const char *host, ...@@ -611,6 +623,7 @@ static void acl_insert_user(const char *user, const char *host,
const char *ssl_cipher, const char *ssl_cipher,
const char *x509_issuer, const char *x509_issuer,
const char *x509_subject, const char *x509_subject,
unsigned int mqh,
uint privileges) uint privileges)
{ {
ACL_USER acl_user; ACL_USER acl_user;
...@@ -618,6 +631,7 @@ static void acl_insert_user(const char *user, const char *host, ...@@ -618,6 +631,7 @@ static void acl_insert_user(const char *user, const char *host,
update_hostname(&acl_user.host,strdup_root(&mem,host)); update_hostname(&acl_user.host,strdup_root(&mem,host));
acl_user.password=0; acl_user.password=0;
acl_user.access=privileges; acl_user.access=privileges;
acl_user.questions=mqh;
acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user); acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
acl_user.hostname_length=(uint) strlen(acl_user.host.hostname); acl_user.hostname_length=(uint) strlen(acl_user.host.hostname);
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
...@@ -1192,6 +1206,13 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, ...@@ -1192,6 +1206,13 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
} }
} }
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
if (table->fields>=23 && thd->lex.mqh)
{
char buff[33];
int len =int2str((long)thd->lex.mqh,buff,10) - buff;
table->field[21]->store(buff,len);
mqh_used=true;
}
if (old_row_exists) if (old_row_exists)
{ {
/* /*
...@@ -1230,6 +1251,7 @@ end: ...@@ -1230,6 +1251,7 @@ end:
thd->lex.ssl_cipher, thd->lex.ssl_cipher,
thd->lex.x509_issuer, thd->lex.x509_issuer,
thd->lex.x509_subject, thd->lex.x509_subject,
thd->lex.mqh,
rights); rights);
else else
acl_insert_user(combo.user.str,combo.host.str,password, acl_insert_user(combo.user.str,combo.host.str,password,
...@@ -1237,6 +1259,7 @@ end: ...@@ -1237,6 +1259,7 @@ end:
thd->lex.ssl_cipher, thd->lex.ssl_cipher,
thd->lex.x509_issuer, thd->lex.x509_issuer,
thd->lex.x509_subject, thd->lex.x509_subject,
thd->lex.mqh,
rights); rights);
} }
table->file->index_end(); table->file->index_end();
......
...@@ -61,7 +61,7 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip, ...@@ -61,7 +61,7 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db); const char *user, const char *db);
uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user, uint acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,char **priv_user, const char *password,const char *scramble,char **priv_user,
bool old_ver); bool old_ver, uint *max);
bool acl_check_host(const char *host, const char *ip); bool acl_check_host(const char *host, const char *ip);
bool change_password(THD *thd, const char *host, const char *user, bool change_password(THD *thd, const char *host, const char *user,
char *password); char *password);
......
...@@ -652,4 +652,33 @@ public: ...@@ -652,4 +652,33 @@ public:
bool send_eof(); bool send_eof();
}; };
class multi_update : public select_result {
TABLE_LIST *update_tables, *table_being_updated;
// Unique **tempfiles;
COPY_INFO *infos;
TABLE **tmp_tables;
THD *thd;
ha_rows updated, found;
List<Item> fields;
List <Item> **fields_by_tables;
thr_lock_type lock_option;
enum enum_duplicates dupl;
uint num_of_tables, num_fields, num_updated, *save_time_stamps, *field_sequence;
int error;
bool do_update;
public:
multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs,
enum enum_duplicates handle_duplicates,
thr_lock_type lock_option_arg, uint num);
~multi_update();
int prepare(List<Item> &list);
bool send_fields(List<Item> &list,
uint flag) { return 0; }
bool send_data(List<Item> &items);
void initialize_tables (JOIN *join);
void send_error(uint errcode,const char *err);
int do_updates (bool from_send_error);
bool send_eof();
};
...@@ -55,7 +55,7 @@ enum enum_sql_command { ...@@ -55,7 +55,7 @@ enum enum_sql_command {
SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS, SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_SHOW_BINLOGS,
SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA, SQLCOM_SHOW_OPEN_TABLES, SQLCOM_LOAD_MASTER_DATA,
SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ,
SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_MULTI_DELETE, SQLCOM_MULTI_UPDATE,
SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER
}; };
...@@ -181,7 +181,7 @@ typedef struct st_lex { ...@@ -181,7 +181,7 @@ typedef struct st_lex {
enum enum_ha_read_modes ha_read_mode; enum enum_ha_read_modes ha_read_mode;
enum ha_rkey_function ha_rkey_mode; enum ha_rkey_function ha_rkey_mode;
enum enum_enable_or_disable alter_keys_onoff; enum enum_enable_or_disable alter_keys_onoff;
uint grant,grant_tot_col,which_columns, union_option; uint grant,grant_tot_col,which_columns, union_option, mqh;
thr_lock_type lock_option; thr_lock_type lock_option;
bool drop_primary,drop_if_exists,local_file; bool drop_primary,drop_if_exists,local_file;
bool in_comment,ignore_space,verbose,simple_alter, option_type; bool in_comment,ignore_space,verbose,simple_alter, option_type;
......
...@@ -37,7 +37,7 @@ extern "C" int gethostname(char *name, int namelen); ...@@ -37,7 +37,7 @@ extern "C" int gethostname(char *name, int namelen);
#endif #endif
static int check_for_max_user_connections(const char *user, int u_length, static int check_for_max_user_connections(const char *user, int u_length,
const char *host); const char *host, uint max);
static void decrease_user_connections(const char *user, const char *host); static void decrease_user_connections(const char *user, const char *host);
static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_db_used(THD *thd,TABLE_LIST *tables);
static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables);
...@@ -98,6 +98,95 @@ inline bool end_active_trans(THD *thd) ...@@ -98,6 +98,95 @@ inline bool end_active_trans(THD *thd)
} }
static HASH hash_user_connections;
extern pthread_mutex_t LOCK_user_conn;
struct user_conn {
char *user;
uint len, connections, questions, max;
time_t intime;
};
static byte* get_key_conn(user_conn *buff, uint *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->len;
return (byte*) buff->user;
}
#define DEF_USER_COUNT 50
static void free_user(struct user_conn *uc)
{
my_free((char*) uc,MYF(0));
}
/*
** Check if maximum queries per hour limit has been reached
** returns 0 if OK.
*/
static bool check_mqh(THD *thd, const char *user, const char *host,uint max)
{
uint temp_len;
char temp_user[USERNAME_LENGTH+HOSTNAME_LENGTH+2];
struct user_conn *uc;
if (!user)
user="";
if (!host)
host="";
temp_len= (uint) (strxnmov(temp_user, sizeof(temp_user), user, "@", host,
NullS) - temp_user);
//This would be MUCH faster if there was already temp_user made in THD !!! May I ??
(void) pthread_mutex_lock(&LOCK_user_conn);
uc = (struct user_conn *) hash_search(&hash_user_connections,
(byte*) temp_user, temp_len);
if (uc) /* user found ; check for no. of queries */
{
bool my_start = thd->start_time != 0;
time_t check_time = (my_start) ? thd->start_time : time(NULL);
if (check_time - uc->intime >= 3600)
{
uc->questions=(uint)my_start;
uc->intime=check_time;
}
else if (uc->max && ++(uc->questions) > uc->max)
{
(void) pthread_mutex_unlock(&LOCK_user_conn);
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); // change this to appropriate message
return 1;
}
}
else
{
struct user_conn *uc= ((struct user_conn*)
my_malloc(sizeof(struct user_conn) + temp_len+1,
MYF(MY_WME)));
if (!uc)
{
send_error(&current_thd->net, 0, NullS); // Out of memory
(void) pthread_mutex_unlock(&LOCK_user_conn);
return 1;
}
uc->user=(char*) (uc+1);
memcpy(uc->user,temp_user,temp_len+1);
uc->len = temp_len;
uc->connections = 1;
uc->questions=0;
uc->max=max;
uc->intime=current_thd->thr_create_time;
if (hash_insert(&hash_user_connections, (byte*) uc))
{
my_free((char*) uc,0);
send_error(&current_thd->net, 0, NullS); // Out of memory
(void) pthread_mutex_unlock(&LOCK_user_conn);
return 1;
}
}
(void) pthread_mutex_unlock(&LOCK_user_conn);
return 0;
}
/* /*
** Check if user is ok ** Check if user is ok
** Updates: ** Updates:
...@@ -108,6 +197,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, ...@@ -108,6 +197,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
const char *passwd, const char *db, bool check_count) const char *passwd, const char *db, bool check_count)
{ {
NET *net= &thd->net; NET *net= &thd->net;
uint max=0;
thd->db=0; thd->db=0;
if (!(thd->user = my_strdup(user, MYF(0)))) if (!(thd->user = my_strdup(user, MYF(0))))
...@@ -119,7 +209,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, ...@@ -119,7 +209,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
passwd, thd->scramble, &thd->priv_user, passwd, thd->scramble, &thd->priv_user,
protocol_version == 9 || protocol_version == 9 ||
!(thd->client_capabilities & !(thd->client_capabilities &
CLIENT_LONG_PASSWORD)); CLIENT_LONG_PASSWORD),&max);
DBUG_PRINT("info", DBUG_PRINT("info",
("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'", ("Capabilities: %d packet_length: %d Host: '%s' User: '%s' Using password: %s Access: %u db: '%s'",
thd->client_capabilities, thd->max_packet_length, thd->client_capabilities, thd->max_packet_length,
...@@ -150,6 +240,8 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, ...@@ -150,6 +240,8 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
return(1); return(1);
} }
} }
if (mqh_used && max && check_mqh(thd,user,thd->host,max))
return -1;
mysql_log.write(thd,command, mysql_log.write(thd,command,
(thd->priv_user == thd->user ? (thd->priv_user == thd->user ?
(char*) "%s@%s on %s" : (char*) "%s@%s on %s" :
...@@ -159,7 +251,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, ...@@ -159,7 +251,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
db ? db : (char*) ""); db ? db : (char*) "");
thd->db_access=0; thd->db_access=0;
if (max_user_connections && if (max_user_connections &&
check_for_max_user_connections(user, strlen(user), thd->host)) check_for_max_user_connections(user, strlen(user), thd->host, max))
return -1; return -1;
if (db && db[0]) if (db && db[0])
{ {
...@@ -179,28 +271,6 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, ...@@ -179,28 +271,6 @@ static bool check_user(THD *thd,enum_server_command command, const char *user,
** variable that is greater then 0 ** variable that is greater then 0
*/ */
static HASH hash_user_connections;
extern pthread_mutex_t LOCK_user_conn;
struct user_conn {
char *user;
uint len, connections;
};
static byte* get_key_conn(user_conn *buff, uint *length,
my_bool not_used __attribute__((unused)))
{
*length=buff->len;
return (byte*) buff->user;
}
#define DEF_USER_COUNT 50
static void free_user(struct user_conn *uc)
{
my_free((char*) uc,MYF(0));
}
void init_max_user_conn(void) void init_max_user_conn(void)
{ {
(void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0, (void) hash_init(&hash_user_connections,DEF_USER_COUNT,0,0,
...@@ -210,7 +280,7 @@ void init_max_user_conn(void) ...@@ -210,7 +280,7 @@ void init_max_user_conn(void)
static int check_for_max_user_connections(const char *user, int u_length, static int check_for_max_user_connections(const char *user, int u_length,
const char *host) const char *host, uint max)
{ {
int error=1; int error=1;
uint temp_len; uint temp_len;
...@@ -251,7 +321,10 @@ static int check_for_max_user_connections(const char *user, int u_length, ...@@ -251,7 +321,10 @@ static int check_for_max_user_connections(const char *user, int u_length,
uc->user=(char*) (uc+1); uc->user=(char*) (uc+1);
memcpy(uc->user,temp_user,temp_len+1); memcpy(uc->user,temp_user,temp_len+1);
uc->len = temp_len; uc->len = temp_len;
uc->connections = 1; uc->connections = 1;
uc->questions=0;
uc->max=max;
uc->intime=current_thd->thr_create_time;
if (hash_insert(&hash_user_connections, (byte*) uc)) if (hash_insert(&hash_user_connections, (byte*) uc))
{ {
my_free((char*) uc,0); my_free((char*) uc,0);
...@@ -290,7 +363,7 @@ static void decrease_user_connections(const char *user, const char *host) ...@@ -290,7 +363,7 @@ static void decrease_user_connections(const char *user, const char *host)
dbug_assert(uc != 0); // We should always find the user dbug_assert(uc != 0); // We should always find the user
if (!uc) if (!uc)
goto end; // Safety; Something went wrong goto end; // Safety; Something went wrong
if (! --uc->connections) if (! --uc->connections && !mqh_used)
{ {
/* Last connection for user; Delete it */ /* Last connection for user; Delete it */
(void) hash_delete(&hash_user_connections,(byte*) uc); (void) hash_delete(&hash_user_connections,(byte*) uc);
...@@ -306,7 +379,6 @@ void free_max_user_conn(void) ...@@ -306,7 +379,6 @@ void free_max_user_conn(void)
hash_free(&hash_user_connections); hash_free(&hash_user_connections);
} }
/* /*
** check connnetion and get priviliges ** check connnetion and get priviliges
** returns 0 on ok, -1 < if error is given > 0 on error. ** returns 0 on ok, -1 < if error is given > 0 on error.
...@@ -849,6 +921,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -849,6 +921,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
my_pthread_setprio(pthread_self(),QUERY_PRIOR); my_pthread_setprio(pthread_self(),QUERY_PRIOR);
mysql_log.write(thd,command,"%s",thd->query); mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%s",thd->query)); DBUG_PRINT("query",("%s",thd->query));
if (mqh_used && check_mqh(thd,thd->user,thd->host,0))
{
error = TRUE;
net->error = 0;
break;
}
mysql_parse(thd,thd->query,packet_length-1); mysql_parse(thd,thd->query,packet_length-1);
if (!(specialflag & SPECIAL_NO_PRIOR)) if (!(specialflag & SPECIAL_NO_PRIOR))
my_pthread_setprio(pthread_self(),WAIT_PRIOR); my_pthread_setprio(pthread_self(),WAIT_PRIOR);
...@@ -959,6 +1037,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -959,6 +1037,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
send_error(net,0); send_error(net,0);
else else
send_eof(net); send_eof(net);
if (mqh_used && hash_user_connections.array.buffer == 0)
init_max_user_conn();
break; break;
} }
case COM_SHUTDOWN: case COM_SHUTDOWN:
...@@ -1092,6 +1172,8 @@ mysql_execute_command(void) ...@@ -1092,6 +1172,8 @@ mysql_execute_command(void)
(table_rules_on && tables && thd->slave_thread && (table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables))) !tables_ok(thd,tables)))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
if (lex->sql_command==SQLCOM_UPDATE && select_lex->table_list.elements > 1)
lex->sql_command=SQLCOM_MULTI_UPDATE;
switch (lex->sql_command) { switch (lex->sql_command) {
case SQLCOM_SELECT: case SQLCOM_SELECT:
...@@ -1727,6 +1809,59 @@ mysql_execute_command(void) ...@@ -1727,6 +1809,59 @@ mysql_execute_command(void)
close_thread_tables(thd); close_thread_tables(thd);
break; break;
} }
case SQLCOM_MULTI_UPDATE:
multi_update *result;
uint table_count;
TABLE_LIST *auxi;
if (check_access(thd,UPDATE_ACL,tables->db,&tables->grant.privilege))
goto error;
if (grant_option && check_grant(thd,UPDATE_ACL,tables))
goto error;
if (select_lex->item_list.elements != lex->value_list.elements)
{
send_error(&thd->net,ER_WRONG_VALUE_COUNT);
DBUG_VOID_RETURN;
}
for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next)
{
table_count++;
auxi->lock_type=TL_WRITE;
}
if (select_lex->order_list.elements || (select_lex->select_limit && select_lex->select_limit < INT_MAX))
{
send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /// will have to come up with something better eventually
DBUG_VOID_RETURN;
}
tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege);
if ((res=open_and_lock_tables(thd,tables)))
break;
if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) &&
!setup_fields(thd,tables,lex->value_list,0,0,0) && ! thd->fatal_error &&
(result=new multi_update(thd,tables,select_lex->item_list,lex->duplicates,
lex->lock_option, table_count)))
{
List <Item> total_list;
List_iterator <Item> field_list(select_lex->item_list);
List_iterator <Item> value_list(lex->value_list);
Item *item;
while ((item=field_list++))
total_list.push_back(item);
while ((item=value_list++))
total_list.push_back(item);
res=mysql_select(thd,tables,total_list,
select_lex->where,select_lex->ftfunc_list,
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
result);
delete result;
}
else
res= -1; // Error is not sent
close_thread_tables(thd);
break;
case SQLCOM_DROP_TABLE: case SQLCOM_DROP_TABLE:
{ {
if (check_table_access(thd,DROP_ACL,tables)) if (check_table_access(thd,DROP_ACL,tables))
...@@ -2080,6 +2215,8 @@ mysql_execute_command(void) ...@@ -2080,6 +2215,8 @@ mysql_execute_command(void)
} }
} }
} }
if (mqh_used && hash_user_connections.array.buffer == 0)
init_max_user_conn();
break; break;
} }
case SQLCOM_FLUSH: case SQLCOM_FLUSH:
......
...@@ -4731,9 +4731,18 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), ...@@ -4731,9 +4731,18 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)),
{ {
if (join->select_options & OPTION_FOUND_ROWS) if (join->select_options & OPTION_FOUND_ROWS)
{ {
join->do_send_rows=0; JOIN_TAB *jt=join->join_tab;
join->thd->select_limit = HA_POS_ERROR; if ((join->tables == 1) && !join->tmp_table && !join->sort_and_group && !join->send_group_parts && !join->having && !jt->select_cond )
DBUG_RETURN(0); {
join->select_options ^= OPTION_FOUND_ROWS;
join->send_records = jt->records;
}
else
{
join->do_send_rows=0;
join->thd->select_limit = HA_POS_ERROR;
DBUG_RETURN(0);
}
} }
DBUG_RETURN(-3); // Abort nicely DBUG_RETURN(-3); // Abort nicely
} }
......
This diff is collapsed.
...@@ -80,6 +80,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -80,6 +80,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token NEXT_SYM %token NEXT_SYM
%token PREV_SYM %token PREV_SYM
%token SQL_CALC_FOUND_ROWS %token SQL_CALC_FOUND_ROWS
%token QUERIES
%token MQH_SYM
%token PER_SYM
%token MAXIMUM
%token EQ %token EQ
%token EQUAL_SYM %token EQUAL_SYM
...@@ -556,7 +561,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -556,7 +561,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
opt_outer table_list table_name opt_option opt_place opt_low_priority opt_outer table_list table_name opt_option opt_place opt_low_priority
opt_attribute opt_attribute_list attribute column_list column_list_id opt_attribute opt_attribute_list attribute column_list column_list_id
opt_column_list grant_privileges opt_table user_list grant_option opt_column_list grant_privileges opt_table user_list grant_option
grant_privilege grant_privilege_list grant_privilege grant_privilege_list mqh_option
flush_options flush_option insert_lock_option replace_lock_option flush_options flush_option insert_lock_option replace_lock_option
equal optional_braces opt_key_definition key_usage_list2 equal optional_braces opt_key_definition key_usage_list2
opt_mi_check_type opt_to mi_check_types normal_join opt_mi_check_type opt_to mi_check_types normal_join
...@@ -2025,7 +2030,12 @@ opt_order_clause: ...@@ -2025,7 +2030,12 @@ opt_order_clause:
| order_clause | order_clause
order_clause: order_clause:
ORDER_SYM BY { Select->sort_default=1; } order_list ORDER_SYM BY
{
if (Lex->sql_command==SQLCOM_MULTI_UPDATE)
YYABORT;
Select->sort_default=1;
} order_list
order_list: order_list:
order_list ',' order_ident order_dir order_list ',' order_ident order_dir
...@@ -2061,6 +2071,8 @@ limit_clause: ...@@ -2061,6 +2071,8 @@ limit_clause:
delete_limit_clause: delete_limit_clause:
/* empty */ /* empty */
{ {
if (Lex->sql_command==SQLCOM_MULTI_UPDATE)
YYABORT;
Select->select_limit= HA_POS_ERROR; Select->select_limit= HA_POS_ERROR;
} }
| LIMIT ulonglong_num | LIMIT ulonglong_num
...@@ -2290,11 +2302,7 @@ values: ...@@ -2290,11 +2302,7 @@ values:
/* Update rows in a table */ /* Update rows in a table */
update: update:
UPDATE_SYM opt_low_priority opt_ignore table_name UPDATE_SYM
SET update_list
where_clause
opt_order_clause
delete_limit_clause
{ {
LEX *lex=Lex; LEX *lex=Lex;
lex->sql_command = SQLCOM_UPDATE; lex->sql_command = SQLCOM_UPDATE;
...@@ -2302,6 +2310,7 @@ update: ...@@ -2302,6 +2310,7 @@ update:
lex->select->order_list.first=0; lex->select->order_list.first=0;
lex->select->order_list.next= (byte**) &lex->select->order_list.first; lex->select->order_list.next= (byte**) &lex->select->order_list.first;
} }
opt_low_priority opt_ignore join_table_list SET update_list where_clause opt_order_clause delete_limit_clause
update_list: update_list:
update_list ',' simple_ident equal expr update_list ',' simple_ident equal expr
...@@ -2353,6 +2362,24 @@ single_multi: ...@@ -2353,6 +2362,24 @@ single_multi:
lex->select->table_list.first=0; lex->select->table_list.first=0;
lex->select->table_list.next= (byte**) &(lex->select->table_list.first); lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
} join_table_list where_clause } join_table_list where_clause
| FROM table_wild_list
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_MULTI_DELETE;
mysql_init_select(lex);
lex->select->select_limit=HA_POS_ERROR;
lex->auxilliary_table_list.elements=0;
lex->auxilliary_table_list.first=0;
lex->auxilliary_table_list.next= (byte**) &(lex->auxilliary_table_list.first);
}
USING
{
LEX *lex=Lex;
lex->auxilliary_table_list=lex->select_lex.table_list;
lex->select->table_list.elements=0;
lex->select->table_list.first=0;
lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
} join_table_list where_clause
table_wild_list: table_wild_list:
...@@ -3267,9 +3294,10 @@ grant: ...@@ -3267,9 +3294,10 @@ grant:
lex->select->db=0; lex->select->db=0;
lex->ssl_type=SSL_TYPE_NONE; lex->ssl_type=SSL_TYPE_NONE;
lex->ssl_cipher=lex->x509_subject=lex->x509_issuer=0; lex->ssl_cipher=lex->x509_subject=lex->x509_issuer=0;
lex->mqh=0;
} }
grant_privileges ON opt_table TO_SYM user_list grant_privileges ON opt_table TO_SYM user_list
require_clause grant_option require_clause grant_option mqh_option
grant_privileges: grant_privileges:
grant_privilege_list {} grant_privilege_list {}
...@@ -3460,6 +3488,19 @@ grant_option: ...@@ -3460,6 +3488,19 @@ grant_option:
/* empty */ {} /* empty */ {}
| WITH GRANT OPTION { Lex->grant |= GRANT_ACL;} | WITH GRANT OPTION { Lex->grant |= GRANT_ACL;}
mqh_option:
/* empty */ {}
| AND WITH short_or_long_one EQ NUM
{
Lex->mqh=atoi($5.str);
if (Lex->mqh > 65535)
YYABORT;
}
short_or_long_one:
MQH_SYM
| MAXIMUM QUERIES PER_SYM HOUR_SYM
begin: begin:
BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work
......
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