mirror of
https://github.com/MariaDB/server.git
synced 2025-07-27 18:02:13 +03:00
merge
This commit is contained in:
@ -311,4 +311,5 @@
|
|||||||
#define ER_TRUNCATED_WRONG_VALUE 1292
|
#define ER_TRUNCATED_WRONG_VALUE 1292
|
||||||
#define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293
|
#define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293
|
||||||
#define ER_INVALID_ON_UPDATE 1294
|
#define ER_INVALID_ON_UPDATE 1294
|
||||||
#define ER_ERROR_MESSAGES 295
|
#define ER_UNSUPPORTED_PS 1295
|
||||||
|
#define ER_ERROR_MESSAGES 296
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
drop table if exists t1,t2,t3;
|
drop table if exists t1,t2,t3;
|
||||||
|
drop database if exists mysqltest;
|
||||||
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));
|
||||||
@ -402,7 +403,7 @@ DELETE t1 FROM t1, t2 AS t3;
|
|||||||
DELETE t4 FROM t1, t1 AS t4;
|
DELETE t4 FROM t1, t1 AS t4;
|
||||||
DELETE t3 FROM t1 AS t3, t1 AS t4;
|
DELETE t3 FROM t1 AS t3, t1 AS t4;
|
||||||
DELETE t1 FROM t1 AS t3, t2 AS t4;
|
DELETE t1 FROM t1 AS t3, t2 AS t4;
|
||||||
ERROR 42000: Not unique table/alias: 't1'
|
ERROR 42S02: Unknown table 't1' in MULTI DELETE
|
||||||
INSERT INTO t1 values (1),(2);
|
INSERT INTO t1 values (1),(2);
|
||||||
INSERT INTO t2 values (1),(2);
|
INSERT INTO t2 values (1),(2);
|
||||||
DELETE t1 FROM t1 AS t2, t2 AS t1 where t1.a=t2.a and t1.a=1;
|
DELETE t1 FROM t1 AS t2, t2 AS t1 where t1.a=t2.a and t1.a=1;
|
||||||
@ -435,3 +436,20 @@ select * from t2;
|
|||||||
c2_id c2_p_id c2_note c2_active
|
c2_id c2_p_id c2_note c2_active
|
||||||
1 1 A Note 1
|
1 1 A Note 1
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
create database mysqltest;
|
||||||
|
create table mysqltest.t1 (a int, b int, primary key (a));
|
||||||
|
create table mysqltest.t2 (a int, b int, primary key (a));
|
||||||
|
create table mysqltest.t3 (a int, b int, primary key (a));
|
||||||
|
grant select on mysqltest.* to mysqltest_1@localhost;
|
||||||
|
grant update on mysqltest.t1 to mysqltest_1@localhost;
|
||||||
|
update t1, t2 set t1.b=1 where t1.a=t2.a;
|
||||||
|
update t1, t2 set t1.b=(select t3.b from t3 where t1.a=t3.a) where t1.a=t2.a;
|
||||||
|
revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
|
||||||
|
delete from mysql.user where user='mysqltest_1';
|
||||||
|
drop database mysqltest;
|
||||||
|
create table t1 (a int, primary key (a));
|
||||||
|
create table t2 (a int, primary key (a));
|
||||||
|
create table t3 (a int, primary key (a));
|
||||||
|
delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a);
|
||||||
|
ERROR 42S02: Unknown table 't3' in MULTI DELETE
|
||||||
|
drop table t1, t2, t3;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop table if exists t1,t2,t3;
|
drop table if exists t1,t2,t3;
|
||||||
|
drop database if exists mysqltest;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
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));
|
||||||
@ -354,7 +355,7 @@ CREATE TABLE t2 ( a int );
|
|||||||
DELETE t1 FROM t1, t2 AS t3;
|
DELETE t1 FROM t1, t2 AS t3;
|
||||||
DELETE t4 FROM t1, t1 AS t4;
|
DELETE t4 FROM t1, t1 AS t4;
|
||||||
DELETE t3 FROM t1 AS t3, t1 AS t4;
|
DELETE t3 FROM t1 AS t3, t1 AS t4;
|
||||||
--error 1066
|
--error 1109
|
||||||
DELETE t1 FROM t1 AS t3, t2 AS t4;
|
DELETE t1 FROM t1 AS t3, t2 AS t4;
|
||||||
INSERT INTO t1 values (1),(2);
|
INSERT INTO t1 values (1),(2);
|
||||||
INSERT INTO t2 values (1),(2);
|
INSERT INTO t2 values (1),(2);
|
||||||
@ -369,7 +370,6 @@ DROP TABLE t1,t2;
|
|||||||
#
|
#
|
||||||
# Test update with const tables
|
# Test update with const tables
|
||||||
#
|
#
|
||||||
|
|
||||||
create table `t1` (`p_id` int(10) unsigned NOT NULL auto_increment, `p_code` varchar(20) NOT NULL default '', `p_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`p_id`) );
|
create table `t1` (`p_id` int(10) unsigned NOT NULL auto_increment, `p_code` varchar(20) NOT NULL default '', `p_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`p_id`) );
|
||||||
create table `t2` (`c2_id` int(10) unsigned NULL auto_increment, `c2_p_id` int(10) unsigned NOT NULL default '0', `c2_note` text NOT NULL, `c2_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`c2_id`), KEY `c2_p_id` (`c2_p_id`) );
|
create table `t2` (`c2_id` int(10) unsigned NULL auto_increment, `c2_p_id` int(10) unsigned NOT NULL default '0', `c2_note` text NOT NULL, `c2_active` tinyint(1) unsigned NOT NULL default '1', PRIMARY KEY (`c2_id`), KEY `c2_p_id` (`c2_p_id`) );
|
||||||
insert into t1 values (0,'A01-Comp',1);
|
insert into t1 values (0,'A01-Comp',1);
|
||||||
@ -379,3 +379,36 @@ update t1 left join t2 on p_id = c2_p_id set c2_note = 'asdf-1' where p_id = 2;
|
|||||||
select * from t1;
|
select * from t1;
|
||||||
select * from t2;
|
select * from t2;
|
||||||
drop table t1, t2;
|
drop table t1, t2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# prevelege chexk for multiupdate with other tables
|
||||||
|
#
|
||||||
|
|
||||||
|
connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock);
|
||||||
|
connection root;
|
||||||
|
--disable_warnings
|
||||||
|
create database mysqltest;
|
||||||
|
--enable_warnings
|
||||||
|
create table mysqltest.t1 (a int, b int, primary key (a));
|
||||||
|
create table mysqltest.t2 (a int, b int, primary key (a));
|
||||||
|
create table mysqltest.t3 (a int, b int, primary key (a));
|
||||||
|
grant select on mysqltest.* to mysqltest_1@localhost;
|
||||||
|
grant update on mysqltest.t1 to mysqltest_1@localhost;
|
||||||
|
connect (user1,localhost,mysqltest_1,,mysqltest,$MASTER_MYPORT,master.sock);
|
||||||
|
connection user1;
|
||||||
|
update t1, t2 set t1.b=1 where t1.a=t2.a;
|
||||||
|
update t1, t2 set t1.b=(select t3.b from t3 where t1.a=t3.a) where t1.a=t2.a;
|
||||||
|
connection root;
|
||||||
|
revoke all privileges on mysqltest.t1 from mysqltest_1@localhost;
|
||||||
|
delete from mysql.user where user='mysqltest_1';
|
||||||
|
drop database mysqltest;
|
||||||
|
|
||||||
|
#
|
||||||
|
# multi delete wrong table check
|
||||||
|
#
|
||||||
|
create table t1 (a int, primary key (a));
|
||||||
|
create table t2 (a int, primary key (a));
|
||||||
|
create table t3 (a int, primary key (a));
|
||||||
|
-- error 1109
|
||||||
|
delete t1,t3 from t1,t2 where t1.a=t2.a and t2.a=(select t3.a from t3 where t1.a=t3.a);
|
||||||
|
drop table t1, t2, t3;
|
||||||
|
@ -477,9 +477,11 @@ bool Item_in_optimizer::fix_left(THD *thd,
|
|||||||
struct st_table_list *tables,
|
struct st_table_list *tables,
|
||||||
Item **ref)
|
Item **ref)
|
||||||
{
|
{
|
||||||
if (args[0]->fix_fields(thd, tables, ref) ||
|
if ((!args[0]->fixed && args[0]->fix_fields(thd, tables, args)))
|
||||||
(!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))))
|
|
||||||
return 1;
|
return 1;
|
||||||
|
if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
|
||||||
|
return 1;
|
||||||
|
|
||||||
cache->setup(args[0]);
|
cache->setup(args[0]);
|
||||||
cache->store(args[0]);
|
cache->store(args[0]);
|
||||||
if (cache->cols() == 1)
|
if (cache->cols() == 1)
|
||||||
@ -512,12 +514,12 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
|
|||||||
Item ** ref)
|
Item ** ref)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed == 0);
|
DBUG_ASSERT(fixed == 0);
|
||||||
if (!args[0]->fixed && fix_left(thd, tables, ref))
|
if (fix_left(thd, tables, ref))
|
||||||
return 1;
|
return 1;
|
||||||
if (args[0]->maybe_null)
|
if (args[0]->maybe_null)
|
||||||
maybe_null=1;
|
maybe_null=1;
|
||||||
|
|
||||||
if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args))
|
if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args+1))
|
||||||
return 1;
|
return 1;
|
||||||
Item_in_subselect * sub= (Item_in_subselect *)args[1];
|
Item_in_subselect * sub= (Item_in_subselect *)args[1];
|
||||||
if (args[0]->cols() != sub->engine->cols())
|
if (args[0]->cols() != sub->engine->cols())
|
||||||
|
@ -347,6 +347,13 @@ void free_items(Item *item);
|
|||||||
void cleanup_items(Item *item);
|
void cleanup_items(Item *item);
|
||||||
class THD;
|
class THD;
|
||||||
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
|
void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0);
|
||||||
|
int check_one_table_access(THD *thd, ulong privilege,
|
||||||
|
TABLE_LIST *tables, bool no_errors);
|
||||||
|
bool check_merge_table_access(THD *thd, char *db,
|
||||||
|
TABLE_LIST *table_list);
|
||||||
|
int multi_update_precheck(THD *thd, TABLE_LIST *tables);
|
||||||
|
int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
|
||||||
|
int insert_select_precheck(THD *thd, TABLE_LIST *tables);
|
||||||
#include "sql_class.h"
|
#include "sql_class.h"
|
||||||
#include "opt_range.h"
|
#include "opt_range.h"
|
||||||
|
|
||||||
|
@ -2529,6 +2529,24 @@ int set_var::check(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int set_var::light_check(THD *thd)
|
||||||
|
{
|
||||||
|
if (var->check_type(type))
|
||||||
|
{
|
||||||
|
my_error(type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE,
|
||||||
|
MYF(0),
|
||||||
|
var->name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if ((type == OPT_GLOBAL && check_global_access(thd, SUPER_ACL)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (value && (value->fix_fields(thd, 0, &value) || value->check_cols(1)))
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int set_var::update(THD *thd)
|
int set_var::update(THD *thd)
|
||||||
{
|
{
|
||||||
if (!value)
|
if (!value)
|
||||||
@ -2556,6 +2574,16 @@ int set_var_user::check(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int set_var_user::light_check(THD *thd)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Item_func_set_user_var can't substitute something else on its place =>
|
||||||
|
0 can be passed as last argument (reference on item)
|
||||||
|
*/
|
||||||
|
return (user_var_item->fix_fields(thd, 0, (Item**) 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int set_var_user::update(THD *thd)
|
int set_var_user::update(THD *thd)
|
||||||
{
|
{
|
||||||
if (user_var_item->update())
|
if (user_var_item->update())
|
||||||
|
@ -688,6 +688,8 @@ public:
|
|||||||
virtual ~set_var_base() {}
|
virtual ~set_var_base() {}
|
||||||
virtual int check(THD *thd)=0; /* To check privileges etc. */
|
virtual int check(THD *thd)=0; /* To check privileges etc. */
|
||||||
virtual int update(THD *thd)=0; /* To set the value */
|
virtual int update(THD *thd)=0; /* To set the value */
|
||||||
|
/* light check for PS */
|
||||||
|
virtual int light_check(THD *thd) { return check(thd); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -728,6 +730,7 @@ public:
|
|||||||
}
|
}
|
||||||
int check(THD *thd);
|
int check(THD *thd);
|
||||||
int update(THD *thd);
|
int update(THD *thd);
|
||||||
|
int light_check(THD *thd);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -742,6 +745,7 @@ public:
|
|||||||
{}
|
{}
|
||||||
int check(THD *thd);
|
int check(THD *thd);
|
||||||
int update(THD *thd);
|
int update(THD *thd);
|
||||||
|
int light_check(THD *thd);
|
||||||
};
|
};
|
||||||
|
|
||||||
/* For SET PASSWORD */
|
/* For SET PASSWORD */
|
||||||
|
@ -307,3 +307,4 @@ character-set=latin2
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -301,3 +301,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -309,3 +309,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -298,3 +298,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -303,3 +303,4 @@ character-set=latin7
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -298,3 +298,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -310,3 +310,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -298,3 +298,4 @@ character-set=greek
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -300,3 +300,4 @@ character-set=latin2
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -298,3 +298,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -300,3 +300,4 @@ character-set=ujis
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -298,3 +298,4 @@ character-set=euckr
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -300,3 +300,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -300,3 +300,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -302,3 +302,4 @@ character-set=latin2
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -299,3 +299,4 @@ character-set=latin1
|
|||||||
"Truncado errado %-.32s valor: '%-.128s'"
|
"Truncado errado %-.32s valor: '%-.128s'"
|
||||||
"Incorreta defini<6E><69>o de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cl<63>usula"
|
"Incorreta defini<6E><69>o de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cl<63>usula"
|
||||||
"Inv<6E>lida cl<63>usula ON UPDATE para campo '%-.64s'",
|
"Inv<6E>lida cl<63>usula ON UPDATE para campo '%-.64s'",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -302,3 +302,4 @@ character-set=latin2
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -300,3 +300,4 @@ character-set=koi8r
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -292,3 +292,4 @@ character-set=cp1250
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -306,3 +306,4 @@ character-set=latin2
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -300,3 +300,4 @@ character-set=latin1
|
|||||||
"Equivocado truncado %-.32s valor: '%-.128s'"
|
"Equivocado truncado %-.32s valor: '%-.128s'"
|
||||||
"Incorrecta definici<63>n de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cl<63>usula"
|
"Incorrecta definici<63>n de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cl<63>usula"
|
||||||
"Inv<6E>lido ON UPDATE cl<63>usula para campo '%-.64s'",
|
"Inv<6E>lido ON UPDATE cl<63>usula para campo '%-.64s'",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -298,3 +298,4 @@ character-set=latin1
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -303,3 +303,4 @@ character-set=koi8u
|
|||||||
"Truncated wrong %-.32s value: '%-.128s'"
|
"Truncated wrong %-.32s value: '%-.128s'"
|
||||||
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
"Incorrect table definition; There can only be one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause"
|
||||||
"Invalid ON UPDATE clause for '%-.64s' field",
|
"Invalid ON UPDATE clause for '%-.64s' field",
|
||||||
|
"This command is not supported in the prepared statement protocol yet",
|
||||||
|
@ -1634,6 +1634,66 @@ void st_select_lex::print_limit(THD *thd, String *str)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
unlink first table from table lists
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
unlink_first_table()
|
||||||
|
tables - global table list
|
||||||
|
global_first - save first global table passed using this parameter
|
||||||
|
local_first - save first local table passed using this parameter
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
global list without first table
|
||||||
|
*/
|
||||||
|
TABLE_LIST *st_lex::unlink_first_table(TABLE_LIST *tables,
|
||||||
|
TABLE_LIST **global_first,
|
||||||
|
TABLE_LIST **local_first)
|
||||||
|
{
|
||||||
|
*global_first= tables;
|
||||||
|
*local_first= (TABLE_LIST*)select_lex.table_list.first;
|
||||||
|
// exclude from global table list
|
||||||
|
tables= tables->next;
|
||||||
|
// and from local list if it is not the same
|
||||||
|
if (&select_lex != all_selects_list)
|
||||||
|
select_lex.table_list.first= (gptr)(*local_first)->next;
|
||||||
|
else
|
||||||
|
select_lex.table_list.first= (gptr)tables;
|
||||||
|
(*global_first)->next= 0;
|
||||||
|
return tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
link unlinked first table back
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
link_first_table_back()
|
||||||
|
tables - global table list
|
||||||
|
global_first - save first global table
|
||||||
|
local_first - save first local table
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
global list
|
||||||
|
*/
|
||||||
|
TABLE_LIST *st_lex::link_first_table_back(TABLE_LIST *tables,
|
||||||
|
TABLE_LIST *global_first,
|
||||||
|
TABLE_LIST *local_first)
|
||||||
|
{
|
||||||
|
global_first->next= tables;
|
||||||
|
tables= global_first;
|
||||||
|
if (&select_lex != all_selects_list)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
we do not touch local table 'next' field => we need just
|
||||||
|
put the table in the list
|
||||||
|
*/
|
||||||
|
select_lex.table_list.first= (gptr) local_first;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
select_lex.table_list.first= (gptr) tables;
|
||||||
|
return tables;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
There are st_select_lex::add_table_to_list &
|
There are st_select_lex::add_table_to_list &
|
||||||
st_select_lex::set_lock_for_tables are in sql_parse.cc
|
st_select_lex::set_lock_for_tables are in sql_parse.cc
|
||||||
|
@ -612,6 +612,12 @@ typedef struct st_lex
|
|||||||
un->uncacheable|= cause;
|
un->uncacheable|= cause;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
TABLE_LIST *unlink_first_table(TABLE_LIST *tables,
|
||||||
|
TABLE_LIST **global_first,
|
||||||
|
TABLE_LIST **local_first);
|
||||||
|
TABLE_LIST *link_first_table_back(TABLE_LIST *tables,
|
||||||
|
TABLE_LIST *global_first,
|
||||||
|
TABLE_LIST *local_first);
|
||||||
} LEX;
|
} LEX;
|
||||||
|
|
||||||
|
|
||||||
|
348
sql/sql_parse.cc
348
sql/sql_parse.cc
@ -53,13 +53,10 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
|
|||||||
#endif
|
#endif
|
||||||
static void decrease_user_connections(USER_CONN *uc);
|
static void decrease_user_connections(USER_CONN *uc);
|
||||||
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 void remove_escape(char *name);
|
static void remove_escape(char *name);
|
||||||
static void refresh_status(void);
|
static void refresh_status(void);
|
||||||
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
|
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
|
||||||
const char *table_name);
|
const char *table_name);
|
||||||
static int check_one_table_access(THD *thd, ulong privilege,
|
|
||||||
TABLE_LIST *tables, bool no_errors);
|
|
||||||
|
|
||||||
const char *any_db="*any*"; // Special symbol for check_access
|
const char *any_db="*any*"; // Special symbol for check_access
|
||||||
|
|
||||||
@ -2168,17 +2165,9 @@ mysql_execute_command(THD *thd)
|
|||||||
case SQLCOM_CREATE_TABLE:
|
case SQLCOM_CREATE_TABLE:
|
||||||
{
|
{
|
||||||
/* Skip first table, which is the table we are creating */
|
/* Skip first table, which is the table we are creating */
|
||||||
TABLE_LIST *create_table= tables;
|
TABLE_LIST *create_table, *create_table_local;
|
||||||
TABLE_LIST *create_table_local=
|
tables= lex->unlink_first_table(tables, &create_table,
|
||||||
(TABLE_LIST*)lex->select_lex.table_list.first;
|
&create_table_local);
|
||||||
// exclude from global table list
|
|
||||||
tables= tables->next;
|
|
||||||
// and from local list if it is not the same
|
|
||||||
if (&lex->select_lex != lex->all_selects_list)
|
|
||||||
lex->select_lex.table_list.first= (gptr)create_table_local->next;
|
|
||||||
else
|
|
||||||
lex->select_lex.table_list.first= (gptr)tables;
|
|
||||||
create_table->next= 0;
|
|
||||||
|
|
||||||
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
|
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
|
||||||
CREATE_TMP_ACL : CREATE_ACL);
|
CREATE_TMP_ACL : CREATE_ACL);
|
||||||
@ -2188,10 +2177,10 @@ mysql_execute_command(THD *thd)
|
|||||||
check_merge_table_access(thd, create_table->db,
|
check_merge_table_access(thd, create_table->db,
|
||||||
(TABLE_LIST *)
|
(TABLE_LIST *)
|
||||||
lex->create_info.merge_list.first))
|
lex->create_info.merge_list.first))
|
||||||
goto create_eror; /* purecov: inspected */
|
goto create_error; /* purecov: inspected */
|
||||||
if (grant_option && want_priv != CREATE_TMP_ACL &&
|
if (grant_option && want_priv != CREATE_TMP_ACL &&
|
||||||
check_grant(thd, want_priv, create_table,0,0))
|
check_grant(thd, want_priv, create_table,0,0))
|
||||||
goto create_eror;
|
goto create_error;
|
||||||
#ifndef HAVE_READLINK
|
#ifndef HAVE_READLINK
|
||||||
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
|
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
|
||||||
#else
|
#else
|
||||||
@ -2227,10 +2216,10 @@ mysql_execute_command(THD *thd)
|
|||||||
create_table->real_name))
|
create_table->real_name))
|
||||||
{
|
{
|
||||||
net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
|
net_printf(thd,ER_UPDATE_TABLE_USED, create_table->real_name);
|
||||||
goto create_eror;
|
goto create_error;
|
||||||
}
|
}
|
||||||
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
|
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
|
||||||
goto create_eror; // Error message is given
|
goto create_error; // Error message is given
|
||||||
select_lex->options|= SELECT_NO_UNLOCK;
|
select_lex->options|= SELECT_NO_UNLOCK;
|
||||||
unit->offset_limit_cnt= select_lex->offset_limit;
|
unit->offset_limit_cnt= select_lex->offset_limit;
|
||||||
unit->select_limit_cnt= select_lex->select_limit+
|
unit->select_limit_cnt= select_lex->select_limit+
|
||||||
@ -2248,6 +2237,9 @@ mysql_execute_command(THD *thd)
|
|||||||
lex->key_list,
|
lex->key_list,
|
||||||
select_lex->item_list,lex->duplicates)))
|
select_lex->item_list,lex->duplicates)))
|
||||||
res=handle_select(thd, lex, result);
|
res=handle_select(thd, lex, result);
|
||||||
|
//reset for PS
|
||||||
|
lex->create_list.empty();
|
||||||
|
lex->key_list.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // regular create
|
else // regular create
|
||||||
@ -2265,35 +2257,18 @@ mysql_execute_command(THD *thd)
|
|||||||
if (!res)
|
if (!res)
|
||||||
send_ok(thd);
|
send_ok(thd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// put tables back for PS rexecuting
|
// put tables back for PS rexecuting
|
||||||
create_table->next= tables;
|
tables= lex->link_first_table_back(tables, create_table,
|
||||||
tables= create_table;
|
create_table_local);
|
||||||
if (&lex->select_lex != lex->all_selects_list)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
we do not touch local table 'next' field => we need just
|
|
||||||
put the table in the list
|
|
||||||
*/
|
|
||||||
lex->select_lex.table_list.first= (gptr) create_table_local;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
lex->select_lex.table_list.first= (gptr) tables;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
create_eror:
|
create_error:
|
||||||
res= 1; //error reported
|
res= 1; //error reported
|
||||||
unsent_create_error:
|
unsent_create_error:
|
||||||
// put tables back for PS rexecuting
|
// put tables back for PS rexecuting
|
||||||
create_table->next= tables;
|
tables= lex->link_first_table_back(tables, create_table,
|
||||||
tables= create_table;
|
create_table_local);
|
||||||
if (&lex->select_lex != lex->all_selects_list)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
we do not touch local table 'next' field => we need just
|
|
||||||
put the table in the list
|
|
||||||
*/
|
|
||||||
lex->select_lex.table_list.first= (gptr) create_table_local;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SQLCOM_CREATE_INDEX:
|
case SQLCOM_CREATE_INDEX:
|
||||||
@ -2582,39 +2557,8 @@ unsent_create_error:
|
|||||||
break;
|
break;
|
||||||
case SQLCOM_UPDATE_MULTI:
|
case SQLCOM_UPDATE_MULTI:
|
||||||
{
|
{
|
||||||
const char *msg= 0;
|
if ((res= multi_update_precheck(thd, tables)))
|
||||||
TABLE_LIST *table;
|
|
||||||
|
|
||||||
if (select_lex->item_list.elements != lex->value_list.elements)
|
|
||||||
{
|
|
||||||
send_error(thd,ER_WRONG_VALUE_COUNT);
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
Ensure that we have UPDATE or SELECT privilege for each table
|
|
||||||
The exact privilege is checked in mysql_multi_update()
|
|
||||||
*/
|
|
||||||
for (table= tables ; table ; table= table->next)
|
|
||||||
{
|
|
||||||
TABLE_LIST *save= table->next;
|
|
||||||
table->next= 0;
|
|
||||||
if (check_one_table_access(thd, UPDATE_ACL, table, 1) &&
|
|
||||||
check_one_table_access(thd, SELECT_ACL, table, 0))
|
|
||||||
goto error;
|
|
||||||
table->next= save;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (select_lex->order_list.elements)
|
|
||||||
msg= "ORDER BY";
|
|
||||||
else if (select_lex->select_limit && select_lex->select_limit !=
|
|
||||||
HA_POS_ERROR)
|
|
||||||
msg= "LIMIT";
|
|
||||||
if (msg)
|
|
||||||
{
|
|
||||||
net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg);
|
|
||||||
res= 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
res= mysql_multi_update(thd,tables,
|
res= mysql_multi_update(thd,tables,
|
||||||
&select_lex->item_list,
|
&select_lex->item_list,
|
||||||
&lex->value_list,
|
&lex->value_list,
|
||||||
@ -2647,16 +2591,9 @@ unsent_create_error:
|
|||||||
case SQLCOM_REPLACE_SELECT:
|
case SQLCOM_REPLACE_SELECT:
|
||||||
case SQLCOM_INSERT_SELECT:
|
case SQLCOM_INSERT_SELECT:
|
||||||
{
|
{
|
||||||
/*
|
TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
|
||||||
Check that we have modify privileges for the first table and
|
if ((res= insert_select_precheck(thd, tables)))
|
||||||
select privileges for the rest
|
break;
|
||||||
*/
|
|
||||||
{
|
|
||||||
ulong privilege= (lex->duplicates == DUP_REPLACE ?
|
|
||||||
INSERT_ACL | DELETE_ACL : INSERT_ACL);
|
|
||||||
if (check_one_table_access(thd, privilege, tables, 0))
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Fix lock for first table */
|
/* Fix lock for first table */
|
||||||
if (tables->lock_type == TL_WRITE_DELAYED)
|
if (tables->lock_type == TL_WRITE_DELAYED)
|
||||||
@ -2677,16 +2614,18 @@ unsent_create_error:
|
|||||||
select_lex->options |= OPTION_BUFFER_RESULT;
|
select_lex->options |= OPTION_BUFFER_RESULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip first table, which is the table we are inserting in */
|
|
||||||
lex->select_lex.table_list.first=
|
|
||||||
(byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
|
|
||||||
lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
|
|
||||||
|
|
||||||
if (!(res=open_and_lock_tables(thd, tables)))
|
if (!(res=open_and_lock_tables(thd, tables)))
|
||||||
{
|
{
|
||||||
if ((result=new select_insert(tables->table,&lex->field_list,
|
if ((result=new select_insert(tables->table,&lex->field_list,
|
||||||
lex->duplicates)))
|
lex->duplicates)))
|
||||||
|
/* Skip first table, which is the table we are inserting in */
|
||||||
|
lex->select_lex.table_list.first= (gptr) first_local_table->next;
|
||||||
|
lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
|
||||||
res=handle_select(thd,lex,result);
|
res=handle_select(thd,lex,result);
|
||||||
|
/* revert changes for SP */
|
||||||
|
lex->select_lex.table_list.first= (gptr) first_local_table;
|
||||||
|
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
|
||||||
if (thd->net.report_error)
|
if (thd->net.report_error)
|
||||||
res= -1;
|
res= -1;
|
||||||
}
|
}
|
||||||
@ -2723,51 +2662,25 @@ unsent_create_error:
|
|||||||
}
|
}
|
||||||
case SQLCOM_DELETE_MULTI:
|
case SQLCOM_DELETE_MULTI:
|
||||||
{
|
{
|
||||||
TABLE_LIST *aux_tables= (TABLE_LIST *)thd->lex->auxilliary_table_list.first;
|
TABLE_LIST *aux_tables=
|
||||||
|
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
|
||||||
|
TABLE_LIST *delete_tables= (TABLE_LIST*)select_lex->table_list.first;
|
||||||
|
|
||||||
TABLE_LIST *auxi;
|
TABLE_LIST *auxi;
|
||||||
uint table_count=0;
|
uint table_count= 0;
|
||||||
multi_delete *result;
|
multi_delete *result;
|
||||||
|
if ((res= multi_delete_precheck(thd, tables, &table_count)))
|
||||||
|
break;
|
||||||
|
|
||||||
/* sql_yacc guarantees that tables and aux_tables are not zero */
|
// condition will be TRUE on SP re esexcuting
|
||||||
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
|
if (select_lex->item_list.elements != 0)
|
||||||
check_table_access(thd,SELECT_ACL, tables,0) ||
|
select_lex->item_list.empty();
|
||||||
check_table_access(thd,DELETE_ACL, aux_tables,0))
|
|
||||||
goto error;
|
|
||||||
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
|
|
||||||
{
|
|
||||||
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next)
|
|
||||||
{
|
|
||||||
table_count++;
|
|
||||||
/* All tables in aux_tables must be found in FROM PART */
|
|
||||||
TABLE_LIST *walk;
|
|
||||||
for (walk= (TABLE_LIST*) tables; walk; walk= walk->next)
|
|
||||||
{
|
|
||||||
if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) &&
|
|
||||||
!strcmp(walk->db, auxi->db))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!walk)
|
|
||||||
{
|
|
||||||
net_printf(thd, ER_NONUNIQ_TABLE, auxi->real_name);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (walk->derived)
|
|
||||||
{
|
|
||||||
net_printf(thd, ER_NON_UPDATABLE_TABLE,
|
|
||||||
auxi->real_name, "DELETE");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
walk->lock_type= auxi->lock_type;
|
|
||||||
auxi->table_list= walk; // Remember corresponding table
|
|
||||||
}
|
|
||||||
if (add_item_to_list(thd, new Item_null()))
|
if (add_item_to_list(thd, new Item_null()))
|
||||||
{
|
{
|
||||||
res= -1;
|
res= -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
thd->proc_info="init";
|
thd->proc_info="init";
|
||||||
if ((res=open_and_lock_tables(thd,tables)))
|
if ((res=open_and_lock_tables(thd,tables)))
|
||||||
break;
|
break;
|
||||||
@ -3499,9 +3412,8 @@ error:
|
|||||||
0 - OK
|
0 - OK
|
||||||
1 - access denied, error is sent to client
|
1 - access denied, error is sent to client
|
||||||
*/
|
*/
|
||||||
|
int check_one_table_access(THD *thd, ulong privilege,
|
||||||
static int check_one_table_access(THD *thd, ulong privilege,
|
TABLE_LIST *tables, bool no_errors)
|
||||||
TABLE_LIST *tables, bool no_errors)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
|
if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
|
||||||
@ -3702,8 +3614,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_merge_table_access(THD *thd, char *db,
|
bool check_merge_table_access(THD *thd, char *db,
|
||||||
TABLE_LIST *table_list)
|
TABLE_LIST *table_list)
|
||||||
{
|
{
|
||||||
int error=0;
|
int error=0;
|
||||||
if (table_list)
|
if (table_list)
|
||||||
@ -4993,3 +4905,181 @@ Item * all_any_subquery_creator(Item *left_expr,
|
|||||||
|
|
||||||
return it; /* ANY/SOME */
|
return it; /* ANY/SOME */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Multi update query pre-check
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
multi_update_precheck()
|
||||||
|
thd - thread handler
|
||||||
|
tables - global table list
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 - OK
|
||||||
|
1 - error (message is sent to user)
|
||||||
|
-1 - error (message is not sent to user)
|
||||||
|
*/
|
||||||
|
int multi_update_precheck(THD *thd, TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("multi_update_precheck");
|
||||||
|
const char *msg= 0;
|
||||||
|
TABLE_LIST *table;
|
||||||
|
LEX *lex= thd->lex;
|
||||||
|
SELECT_LEX *select_lex= &lex->select_lex;
|
||||||
|
TABLE_LIST *update_list= (TABLE_LIST*)select_lex->table_list.first;
|
||||||
|
|
||||||
|
if (select_lex->item_list.elements != lex->value_list.elements)
|
||||||
|
{
|
||||||
|
my_error(ER_WRONG_VALUE_COUNT, MYF(0));
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Ensure that we have UPDATE or SELECT privilege for each table
|
||||||
|
The exact privilege is checked in mysql_multi_update()
|
||||||
|
*/
|
||||||
|
for (table= update_list; table; table= table->next)
|
||||||
|
{
|
||||||
|
TABLE_LIST *save= table->next;
|
||||||
|
table->next= 0;
|
||||||
|
if ((check_access(thd, UPDATE_ACL, table->db,
|
||||||
|
&table->grant.privilege, 0, 1) ||
|
||||||
|
grant_option && check_grant(thd, UPDATE_ACL, table, 0, 1)) &&
|
||||||
|
(check_access(thd, SELECT_ACL, table->db,
|
||||||
|
&table->grant.privilege, 0, 0) ||
|
||||||
|
grant_option && check_grant(thd, SELECT_ACL, table, 0, 0)))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
table->next= save;
|
||||||
|
if (table->table_list)
|
||||||
|
table->table_list->checked= 1;
|
||||||
|
}
|
||||||
|
// tables of subqueries
|
||||||
|
if (&lex->select_lex != lex->all_selects_list)
|
||||||
|
{
|
||||||
|
for (table= tables; table; table= table->next)
|
||||||
|
{
|
||||||
|
if (table->checked)
|
||||||
|
{
|
||||||
|
table->checked= 0;
|
||||||
|
/*
|
||||||
|
If we check table by local TABLE_LIST copy then we should copy
|
||||||
|
grants to global table list, because it will be used for table
|
||||||
|
opening.
|
||||||
|
*/
|
||||||
|
if (table->table_list)
|
||||||
|
table->grant= table->table_list->grant;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TABLE_LIST *save= table->next;
|
||||||
|
table->next= 0;
|
||||||
|
if (check_access(thd, SELECT_ACL, table->db,
|
||||||
|
&table->grant.privilege, 0, 0) ||
|
||||||
|
grant_option && check_grant(thd, SELECT_ACL, table, 0, 0))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
table->next= save;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (select_lex->order_list.elements)
|
||||||
|
msg= "ORDER BY";
|
||||||
|
else if (select_lex->select_limit && select_lex->select_limit !=
|
||||||
|
HA_POS_ERROR)
|
||||||
|
msg= "LIMIT";
|
||||||
|
if (msg)
|
||||||
|
{
|
||||||
|
my_error(ER_WRONG_USAGE, MYF(0), "UPDATE", msg);
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Multi delete query pre-check
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
multi_delete_precheck()
|
||||||
|
thd - thread handler
|
||||||
|
tables - global table list
|
||||||
|
table_count - pointer to table counter
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 - OK
|
||||||
|
1 - error (message is sent to user)
|
||||||
|
-1 - error (message is not sent to user)
|
||||||
|
*/
|
||||||
|
int multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("multi_delete_precheck");
|
||||||
|
SELECT_LEX *select_lex= &thd->lex->select_lex;
|
||||||
|
TABLE_LIST *aux_tables=
|
||||||
|
(TABLE_LIST *)thd->lex->auxilliary_table_list.first;
|
||||||
|
TABLE_LIST *delete_tables= (TABLE_LIST *)select_lex->table_list.first;
|
||||||
|
TABLE_LIST *auxi;
|
||||||
|
|
||||||
|
/* sql_yacc guarantees that tables and aux_tables are not zero */
|
||||||
|
DBUG_ASSERT(aux_tables != 0);
|
||||||
|
if (check_db_used(thd, tables) || check_db_used(thd,aux_tables) ||
|
||||||
|
check_table_access(thd,SELECT_ACL, tables,0) ||
|
||||||
|
check_table_access(thd,DELETE_ACL, aux_tables,0))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where)
|
||||||
|
{
|
||||||
|
my_error(ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE, MYF(0));
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
for (auxi= aux_tables; auxi; auxi= auxi->next)
|
||||||
|
{
|
||||||
|
(*table_count)++;
|
||||||
|
/* All tables in aux_tables must be found in FROM PART */
|
||||||
|
TABLE_LIST *walk;
|
||||||
|
for (walk= delete_tables; walk; walk= walk->next)
|
||||||
|
{
|
||||||
|
if (!my_strcasecmp(table_alias_charset, auxi->alias, walk->alias) &&
|
||||||
|
!strcmp(walk->db, auxi->db))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!walk)
|
||||||
|
{
|
||||||
|
my_error(ER_UNKNOWN_TABLE, MYF(0), auxi->real_name, "MULTI DELETE");
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
if (walk->derived)
|
||||||
|
{
|
||||||
|
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), auxi->real_name, "DELETE");
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
}
|
||||||
|
walk->lock_type= auxi->lock_type;
|
||||||
|
auxi->table_list= walk; // Remember corresponding table
|
||||||
|
}
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
INSERT ... SELECT query pre-check
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
multi_delete_precheck()
|
||||||
|
thd - thread handler
|
||||||
|
tables - global table list
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 - OK
|
||||||
|
1 - error (message is sent to user)
|
||||||
|
-1 - error (message is not sent to user)
|
||||||
|
*/
|
||||||
|
int insert_select_precheck(THD *thd, TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("insert_select_precheck");
|
||||||
|
/*
|
||||||
|
Check that we have modify privileges for the first table and
|
||||||
|
select privileges for the rest
|
||||||
|
*/
|
||||||
|
ulong privilege= (thd->lex->duplicates == DUP_REPLACE ?
|
||||||
|
INSERT_ACL | DELETE_ACL : INSERT_ACL);
|
||||||
|
if (check_one_table_access(thd, privilege, tables, 0))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
@ -646,26 +646,29 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
|
|||||||
static int mysql_test_insert_fields(Prepared_statement *stmt,
|
static int mysql_test_insert_fields(Prepared_statement *stmt,
|
||||||
TABLE_LIST *table_list,
|
TABLE_LIST *table_list,
|
||||||
List<Item> &fields,
|
List<Item> &fields,
|
||||||
List<List_item> &values_list)
|
List<List_item> &values_list,
|
||||||
|
List<Item> &update_fields,
|
||||||
|
List<Item> &update_values,
|
||||||
|
enum_duplicates duplic)
|
||||||
{
|
{
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
|
LEX *lex= stmt->lex;
|
||||||
TABLE *table;
|
TABLE *table;
|
||||||
List_iterator_fast<List_item> its(values_list);
|
List_iterator_fast<List_item> its(values_list);
|
||||||
List_item *values;
|
List_item *values;
|
||||||
|
TABLE_LIST *insert_table_list=
|
||||||
|
(TABLE_LIST*) lex->select_lex.table_list.first;
|
||||||
|
|
||||||
DBUG_ENTER("mysql_test_insert_fields");
|
DBUG_ENTER("mysql_test_insert_fields");
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
my_bool update=(stmt->lex->value_list.elements ? UPDATE_ACL : 0);
|
ulong privilege= (lex->duplicates == DUP_REPLACE ?
|
||||||
ulong privilege= (stmt->lex->duplicates == DUP_REPLACE ?
|
INSERT_ACL | DELETE_ACL : INSERT_ACL);
|
||||||
INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
|
if (check_one_table_access(thd, privilege, table_list, 0))
|
||||||
if (check_access(thd,privilege,table_list->db,
|
DBUG_RETURN(1);
|
||||||
&table_list->grant.privilege,0,0) ||
|
|
||||||
(grant_option && check_grant(thd,privilege,table_list,0,0)))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
open temporary memory pool for temporary data allocated by derived
|
open temporary memory pool for temporary data allocated by derived
|
||||||
tables & preparation procedure
|
tables & preparation procedure
|
||||||
*/
|
*/
|
||||||
@ -683,12 +686,19 @@ static int mysql_test_insert_fields(Prepared_statement *stmt,
|
|||||||
uint value_count;
|
uint value_count;
|
||||||
ulong counter= 0;
|
ulong counter= 0;
|
||||||
|
|
||||||
if (check_insert_fields(thd,table,fields,*values,1))
|
if (check_insert_fields(thd, table, fields, *values, 1) ||
|
||||||
|
setup_tables(insert_table_list) ||
|
||||||
|
setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) ||
|
||||||
|
(duplic == DUP_UPDATE &&
|
||||||
|
(setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) ||
|
||||||
|
setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0))))
|
||||||
|
goto error;
|
||||||
|
if (find_real_table_in_list(table_list->next,
|
||||||
|
table_list->db, table_list->real_name))
|
||||||
{
|
{
|
||||||
thd->free_temporary_memory_pool_for_ps_preparing();
|
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
|
||||||
DBUG_RETURN(-1);
|
goto error;
|
||||||
}
|
}
|
||||||
thd->free_temporary_memory_pool_for_ps_preparing();
|
|
||||||
|
|
||||||
value_count= values->elements;
|
value_count= values->elements;
|
||||||
its.rewind();
|
its.rewind();
|
||||||
@ -701,15 +711,20 @@ static int mysql_test_insert_fields(Prepared_statement *stmt,
|
|||||||
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
|
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
|
||||||
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
|
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
|
||||||
MYF(0), counter);
|
MYF(0), counter);
|
||||||
DBUG_RETURN(-1);
|
goto error;
|
||||||
}
|
}
|
||||||
|
if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0))
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
lex->unit.cleanup();
|
||||||
{
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
thd->free_temporary_memory_pool_for_ps_preparing();
|
|
||||||
}
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
error:
|
||||||
|
lex->unit.cleanup();
|
||||||
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
|
DBUG_RETURN(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -728,19 +743,26 @@ static int mysql_test_insert_fields(Prepared_statement *stmt,
|
|||||||
static int mysql_test_upd_fields(Prepared_statement *stmt,
|
static int mysql_test_upd_fields(Prepared_statement *stmt,
|
||||||
TABLE_LIST *table_list,
|
TABLE_LIST *table_list,
|
||||||
List<Item> &fields, List<Item> &values,
|
List<Item> &fields, List<Item> &values,
|
||||||
COND *conds)
|
COND *conds, ulong privelege)
|
||||||
{
|
{
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
|
SELECT_LEX *select_lex= &stmt->lex->select_lex;
|
||||||
|
TABLE_LIST *upd_table_list=
|
||||||
|
(TABLE_LIST*) select_lex->table_list.first;
|
||||||
|
List<Item> all_fields;
|
||||||
|
uint order_num= select_lex->order_list.elements;
|
||||||
|
ORDER *order= (ORDER *) select_lex->order_list.first;
|
||||||
|
|
||||||
DBUG_ENTER("mysql_test_upd_fields");
|
DBUG_ENTER("mysql_test_upd_fields");
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (check_access(thd,UPDATE_ACL,table_list->db,
|
if (check_one_table_access(thd, privelege, table_list, 0))
|
||||||
&table_list->grant.privilege,0,0) ||
|
|
||||||
(grant_option && check_grant(thd,UPDATE_ACL,table_list,0,0)))
|
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
// Set privilege for the WHERE clause
|
||||||
|
table_list->grant.want_privilege= (SELECT_ACL &
|
||||||
|
~table_list->grant.privilege);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
open temporary memory pool for temporary data allocated by derived
|
open temporary memory pool for temporary data allocated by derived
|
||||||
tables & preparation procedure
|
tables & preparation procedure
|
||||||
*/
|
*/
|
||||||
@ -748,11 +770,19 @@ static int mysql_test_upd_fields(Prepared_statement *stmt,
|
|||||||
|
|
||||||
if (open_and_lock_tables(thd, table_list))
|
if (open_and_lock_tables(thd, table_list))
|
||||||
goto err;
|
goto err;
|
||||||
if (setup_tables(table_list) ||
|
if (setup_tables(upd_table_list) ||
|
||||||
setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
|
setup_conds(thd, upd_table_list, &conds) ||
|
||||||
setup_conds(thd, table_list, &conds) || thd->net.report_error)
|
thd->lex->select_lex.setup_ref_array(thd, order_num) ||
|
||||||
|
setup_fields(thd, 0, upd_table_list, fields, 1, 0, 0) ||
|
||||||
|
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
|
||||||
|
upd_table_list, all_fields, all_fields, order) ||
|
||||||
|
thd->net.report_error)
|
||||||
|
{
|
||||||
|
stmt->lex->unit.cleanup();
|
||||||
goto err;
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt->lex->unit.cleanup();
|
||||||
thd->free_temporary_memory_pool_for_ps_preparing();
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
|
|
||||||
/* TODO: here we should send types of placeholders to the client. */
|
/* TODO: here we should send types of placeholders to the client. */
|
||||||
@ -782,16 +812,12 @@ err:
|
|||||||
|
|
||||||
static int mysql_test_select_fields(Prepared_statement *stmt,
|
static int mysql_test_select_fields(Prepared_statement *stmt,
|
||||||
TABLE_LIST *tables,
|
TABLE_LIST *tables,
|
||||||
uint wild_num,
|
List<Item> &fields)
|
||||||
List<Item> &fields, COND *conds,
|
|
||||||
uint og_num, ORDER *order, ORDER *group,
|
|
||||||
Item *having, ORDER *proc,
|
|
||||||
ulong select_options,
|
|
||||||
SELECT_LEX_UNIT *unit,
|
|
||||||
SELECT_LEX *select_lex)
|
|
||||||
{
|
{
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
LEX *lex= stmt->lex;
|
LEX *lex= stmt->lex;
|
||||||
|
SELECT_LEX_UNIT *unit= &lex->unit;
|
||||||
|
|
||||||
|
|
||||||
DBUG_ENTER("mysql_test_select_fields");
|
DBUG_ENTER("mysql_test_select_fields");
|
||||||
|
|
||||||
@ -805,11 +831,8 @@ static int mysql_test_select_fields(Prepared_statement *stmt,
|
|||||||
else if (check_access(thd, privilege, any_db,0,0,0))
|
else if (check_access(thd, privilege, any_db,0,0,0))
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
#endif
|
#endif
|
||||||
if ((&lex->select_lex != lex->all_selects_list &&
|
|
||||||
lex->unit.create_total_list(thd, lex, &tables)))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
open temporary memory pool for temporary data allocated by derived
|
open temporary memory pool for temporary data allocated by derived
|
||||||
tables & preparation procedure
|
tables & preparation procedure
|
||||||
*/
|
*/
|
||||||
@ -825,18 +848,11 @@ static int mysql_test_select_fields(Prepared_statement *stmt,
|
|||||||
if (send_prep_stmt(stmt, 0))
|
if (send_prep_stmt(stmt, 0))
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
select_result *result= lex->result;
|
|
||||||
if (!result && !(result= new select_send()))
|
|
||||||
{
|
|
||||||
send_error(thd, ER_OUT_OF_RESOURCES);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
thd->used_tables= 0; // Updated by setup_fields
|
thd->used_tables= 0; // Updated by setup_fields
|
||||||
|
|
||||||
if (unit->prepare(thd, result, 0))
|
if (unit->prepare(thd, 0, 0))
|
||||||
{
|
{
|
||||||
send_error(thd);
|
send_error(thd);
|
||||||
goto err_prep;
|
goto err_prep;
|
||||||
@ -863,6 +879,277 @@ err:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate and prepare for execution DO statement expressions
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_test_do_fields()
|
||||||
|
stmt prepared statemen handler
|
||||||
|
tables list of tables queries
|
||||||
|
values list of expressions
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 success
|
||||||
|
1 error, sent to client
|
||||||
|
-1 error, not sent to client
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int mysql_test_do_fields(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables,
|
||||||
|
List<Item> *values)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mysql_test_do_fields");
|
||||||
|
THD *thd= stmt->thd;
|
||||||
|
int res= 0;
|
||||||
|
if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0)))
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
/*
|
||||||
|
open temporary memory pool for temporary data allocated by derived
|
||||||
|
tables & preparation procedure
|
||||||
|
*/
|
||||||
|
thd->allocate_temporary_memory_pool_for_ps_preparing();
|
||||||
|
if (tables && (res= open_and_lock_tables(thd, tables)))
|
||||||
|
{
|
||||||
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
}
|
||||||
|
res= setup_fields(thd, 0, 0, *values, 0, 0, 0);
|
||||||
|
stmt->lex->unit.cleanup();
|
||||||
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
|
if (res)
|
||||||
|
DBUG_RETURN(-1);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate and prepare for execution SET statement expressions
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_test_set_fields()
|
||||||
|
stmt prepared statemen handler
|
||||||
|
tables list of tables queries
|
||||||
|
values list of expressions
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 success
|
||||||
|
1 error, sent to client
|
||||||
|
-1 error, not sent to client
|
||||||
|
*/
|
||||||
|
static int mysql_test_set_fields(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables,
|
||||||
|
List<set_var_base> *var_list)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mysql_test_set_fields");
|
||||||
|
List_iterator_fast<set_var_base> it(*var_list);
|
||||||
|
THD *thd= stmt->thd;
|
||||||
|
set_var_base *var;
|
||||||
|
int res= 0;
|
||||||
|
|
||||||
|
if (tables && (res= check_table_access(thd, SELECT_ACL, tables, 0)))
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
/*
|
||||||
|
open temporary memory pool for temporary data allocated by derived
|
||||||
|
tables & preparation procedure
|
||||||
|
*/
|
||||||
|
thd->allocate_temporary_memory_pool_for_ps_preparing();
|
||||||
|
if (tables && (res= open_and_lock_tables(thd, tables)))
|
||||||
|
goto error;
|
||||||
|
while ((var= it++))
|
||||||
|
{
|
||||||
|
if (var->light_check(thd))
|
||||||
|
{
|
||||||
|
stmt->lex->unit.cleanup();
|
||||||
|
res= -1;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt->lex->unit.cleanup();
|
||||||
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
error:
|
||||||
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check internal SELECT of the prepared command
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
select_like_statement_test()
|
||||||
|
stmt - prepared table handler
|
||||||
|
tables - global list of tables
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
0 success
|
||||||
|
1 error, sent to client
|
||||||
|
-1 error, not sent to client
|
||||||
|
*/
|
||||||
|
static int select_like_statement_test(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("select_like_statement_test");
|
||||||
|
THD *thd= stmt->thd;
|
||||||
|
LEX *lex= stmt->lex;
|
||||||
|
int res= 0;
|
||||||
|
/*
|
||||||
|
open temporary memory pool for temporary data allocated by derived
|
||||||
|
tables & preparation procedure
|
||||||
|
*/
|
||||||
|
thd->allocate_temporary_memory_pool_for_ps_preparing();
|
||||||
|
if (tables && (res= open_and_lock_tables(thd, tables)))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
thd->used_tables= 0; // Updated by setup_fields
|
||||||
|
|
||||||
|
if (lex->unit.prepare(thd, 0, 0))
|
||||||
|
{
|
||||||
|
res= thd->net.report_error ? -1 : 1;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
lex->unit.cleanup();
|
||||||
|
thd->free_temporary_memory_pool_for_ps_preparing();
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate and prepare for execution CRETE TABLE statement
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_test_create_table()
|
||||||
|
stmt prepared statemen handler
|
||||||
|
tables list of tables queries
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 success
|
||||||
|
1 error, sent to client
|
||||||
|
-1 error, not sent to client
|
||||||
|
*/
|
||||||
|
static int mysql_test_create_table(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("mysql_test_create_table");
|
||||||
|
THD *thd= stmt->thd;
|
||||||
|
LEX *lex= stmt->lex;
|
||||||
|
int res= 0;
|
||||||
|
|
||||||
|
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
|
||||||
|
CREATE_TMP_ACL : CREATE_ACL);
|
||||||
|
if (check_one_table_access(thd, want_priv, tables, 0) ||
|
||||||
|
check_merge_table_access(thd, tables->db,
|
||||||
|
(TABLE_LIST *)
|
||||||
|
lex->create_info.merge_list.first))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
/* Skip first table, which is the table we are creating */
|
||||||
|
TABLE_LIST *create_table, *create_table_local;
|
||||||
|
tables= lex->unlink_first_table(tables, &create_table,
|
||||||
|
&create_table_local);
|
||||||
|
|
||||||
|
if (grant_option && want_priv != CREATE_TMP_ACL &&
|
||||||
|
check_grant(thd, want_priv, create_table,0,0))
|
||||||
|
{
|
||||||
|
res= 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tables)
|
||||||
|
res= select_like_statement_test(stmt, tables);
|
||||||
|
|
||||||
|
end:
|
||||||
|
// put tables back for PS rexecuting
|
||||||
|
tables= lex->link_first_table_back(tables, create_table,
|
||||||
|
create_table_local);
|
||||||
|
DBUG_RETURN(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate and prepare for execution multy update statement
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_test_multiupdate()
|
||||||
|
stmt prepared statemen handler
|
||||||
|
tables list of tables queries
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 success
|
||||||
|
1 error, sent to client
|
||||||
|
-1 error, not sent to client
|
||||||
|
*/
|
||||||
|
static int mysql_test_multiupdate(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
if ((res= multi_update_precheck(stmt->thd, tables)))
|
||||||
|
return res;
|
||||||
|
return select_like_statement_test(stmt, tables);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate and prepare for execution multy delete statement
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_test_multidelete()
|
||||||
|
stmt prepared statemen handler
|
||||||
|
tables list of tables queries
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 success
|
||||||
|
1 error, sent to client
|
||||||
|
-1 error, not sent to client
|
||||||
|
*/
|
||||||
|
static int mysql_test_multidelete(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
stmt->thd->lex->current_select= &stmt->thd->lex->select_lex;
|
||||||
|
if (add_item_to_list(stmt->thd, new Item_null()))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
uint fake_counter= 0;
|
||||||
|
if ((res= multi_delete_precheck(stmt->thd, tables, &fake_counter)))
|
||||||
|
return res;
|
||||||
|
return select_like_statement_test(stmt, tables);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Validate and prepare for execution INSERT ... SELECT statement
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
mysql_test_insert_select()
|
||||||
|
stmt prepared statemen handler
|
||||||
|
tables list of tables queries
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 success
|
||||||
|
1 error, sent to client
|
||||||
|
-1 error, not sent to client
|
||||||
|
*/
|
||||||
|
static int mysql_test_insert_select(Prepared_statement *stmt,
|
||||||
|
TABLE_LIST *tables)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
LEX *lex= stmt->lex;
|
||||||
|
if ((res= insert_select_precheck(stmt->thd, tables)))
|
||||||
|
return res;
|
||||||
|
TABLE_LIST *first_local_table=
|
||||||
|
(TABLE_LIST *)lex->select_lex.table_list.first;
|
||||||
|
/* Skip first table, which is the table we are inserting in */
|
||||||
|
lex->select_lex.table_list.first= (gptr) first_local_table->next;
|
||||||
|
lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
|
||||||
|
res= select_like_statement_test(stmt, tables);
|
||||||
|
/* revert changes*/
|
||||||
|
lex->select_lex.table_list.first= (gptr) first_local_table;
|
||||||
|
lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Send the prepare query results back to client
|
Send the prepare query results back to client
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
@ -872,25 +1159,33 @@ err:
|
|||||||
0 success
|
0 success
|
||||||
1 error, sent to client
|
1 error, sent to client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int send_prepare_results(Prepared_statement *stmt)
|
static int send_prepare_results(Prepared_statement *stmt)
|
||||||
{
|
{
|
||||||
|
DBUG_ENTER("send_prepare_results");
|
||||||
THD *thd= stmt->thd;
|
THD *thd= stmt->thd;
|
||||||
LEX *lex= stmt->lex;
|
LEX *lex= stmt->lex;
|
||||||
SELECT_LEX *select_lex= &lex->select_lex;
|
SELECT_LEX *select_lex= &lex->select_lex;
|
||||||
TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
|
TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
|
||||||
enum enum_sql_command sql_command= lex->sql_command;
|
enum enum_sql_command sql_command= lex->sql_command;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
DBUG_ENTER("send_prepare_results");
|
|
||||||
DBUG_PRINT("enter",("command: %d, param_count: %ld",
|
DBUG_PRINT("enter",("command: %d, param_count: %ld",
|
||||||
sql_command, stmt->param_count));
|
sql_command, stmt->param_count));
|
||||||
|
|
||||||
|
if (&lex->select_lex != lex->all_selects_list &&
|
||||||
|
lex->unit.create_total_list(thd, lex, &tables))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
|
||||||
switch (sql_command) {
|
switch (sql_command) {
|
||||||
|
|
||||||
|
case SQLCOM_REPLACE:
|
||||||
case SQLCOM_INSERT:
|
case SQLCOM_INSERT:
|
||||||
if ((res= mysql_test_insert_fields(stmt, tables, lex->field_list,
|
if ((res=
|
||||||
lex->many_values)))
|
mysql_test_insert_fields(stmt, tables, lex->field_list,
|
||||||
|
lex->many_values,
|
||||||
|
select_lex->item_list, lex->value_list,
|
||||||
|
(lex->value_list.elements ?
|
||||||
|
DUP_UPDATE : lex->duplicates))))
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -898,32 +1193,75 @@ static int send_prepare_results(Prepared_statement *stmt)
|
|||||||
/* XXX: fallthrough */
|
/* XXX: fallthrough */
|
||||||
case SQLCOM_DELETE:
|
case SQLCOM_DELETE:
|
||||||
if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list,
|
if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list,
|
||||||
lex->value_list, select_lex->where)))
|
lex->value_list, select_lex->where,
|
||||||
|
((sql_command == SQLCOM_DELETE)?
|
||||||
|
DELETE_ACL : UPDATE_ACL))))
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SQLCOM_SELECT:
|
case SQLCOM_SELECT:
|
||||||
if ((res= mysql_test_select_fields(stmt, tables, select_lex->with_wild,
|
if ((res= mysql_test_select_fields(stmt, tables, select_lex->item_list)))
|
||||||
select_lex->item_list,
|
|
||||||
select_lex->where,
|
|
||||||
select_lex->order_list.elements +
|
|
||||||
select_lex->group_list.elements,
|
|
||||||
(ORDER*) select_lex->order_list.first,
|
|
||||||
(ORDER*) select_lex->group_list.first,
|
|
||||||
select_lex->having,
|
|
||||||
(ORDER*)lex->proc_list.first,
|
|
||||||
select_lex->options | thd->options,
|
|
||||||
&(lex->unit), select_lex)))
|
|
||||||
goto error;
|
goto error;
|
||||||
/* Statement and field info has already been sent */
|
/* Statement and field info has already been sent */
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
default:
|
case SQLCOM_CREATE_TABLE:
|
||||||
/*
|
if ((res= mysql_test_create_table(stmt, tables)))
|
||||||
Rest fall through to default category, no parsing
|
goto error;
|
||||||
for non-DML statements
|
|
||||||
*/
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_DO:
|
||||||
|
if ((res= mysql_test_do_fields(stmt, tables, lex->insert_list)))
|
||||||
|
goto error;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_SET_OPTION:
|
||||||
|
if ((res= mysql_test_set_fields(stmt, tables, &lex->var_list)))
|
||||||
|
goto error;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_DELETE_MULTI:
|
||||||
|
if ((res= mysql_test_multidelete(stmt, tables)))
|
||||||
|
goto error;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_UPDATE_MULTI:
|
||||||
|
if ((res= mysql_test_multiupdate(stmt, tables)))
|
||||||
|
goto error;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_INSERT_SELECT:
|
||||||
|
if ((res= mysql_test_insert_select(stmt, tables)))
|
||||||
|
goto error;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SQLCOM_SHOW_DATABASES:
|
||||||
|
case SQLCOM_SHOW_PROCESSLIST:
|
||||||
|
case SQLCOM_SHOW_STORAGE_ENGINES:
|
||||||
|
case SQLCOM_SHOW_PRIVILEGES:
|
||||||
|
case SQLCOM_SHOW_COLUMN_TYPES:
|
||||||
|
case SQLCOM_SHOW_STATUS:
|
||||||
|
case SQLCOM_SHOW_VARIABLES:
|
||||||
|
case SQLCOM_SHOW_LOGS:
|
||||||
|
case SQLCOM_SHOW_TABLES:
|
||||||
|
case SQLCOM_SHOW_OPEN_TABLES:
|
||||||
|
case SQLCOM_SHOW_CHARSETS:
|
||||||
|
case SQLCOM_SHOW_COLLATIONS:
|
||||||
|
case SQLCOM_SHOW_FIELDS:
|
||||||
|
case SQLCOM_SHOW_KEYS:
|
||||||
|
case SQLCOM_SHOW_CREATE_DB:
|
||||||
|
case SQLCOM_SHOW_GRANTS:
|
||||||
|
case SQLCOM_DROP_TABLE:
|
||||||
|
case SQLCOM_RENAME_TABLE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/*
|
||||||
|
All other is not supported yet
|
||||||
|
*/
|
||||||
|
res= -1;
|
||||||
|
my_error(ER_UNSUPPORTED_PS, MYF(0));
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
DBUG_RETURN(send_prep_stmt(stmt, 0));
|
DBUG_RETURN(send_prep_stmt(stmt, 0));
|
||||||
|
|
||||||
@ -1177,6 +1515,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
|
|||||||
*/
|
*/
|
||||||
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
|
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
|
||||||
mysql_execute_command(thd);
|
mysql_execute_command(thd);
|
||||||
|
thd->lex->unit.cleanup();
|
||||||
thd->protocol= &thd->protocol_simple; // Use normal protocol
|
thd->protocol= &thd->protocol_simple; // Use normal protocol
|
||||||
|
|
||||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||||
|
@ -434,7 +434,7 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!procedure && result->prepare(fields_list, unit_arg))
|
if (!procedure && result && result->prepare(fields_list, unit_arg))
|
||||||
goto err; /* purecov: inspected */
|
goto err; /* purecov: inspected */
|
||||||
|
|
||||||
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
|
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
|
||||||
|
@ -460,13 +460,24 @@ int st_select_lex_unit::cleanup()
|
|||||||
table= 0; // Safety
|
table= 0; // Safety
|
||||||
}
|
}
|
||||||
JOIN *join;
|
JOIN *join;
|
||||||
for (SELECT_LEX *sl= first_select_in_union(); sl; sl= sl->next_select())
|
SELECT_LEX *sl= first_select_in_union();
|
||||||
|
for (; sl; sl= sl->next_select())
|
||||||
{
|
{
|
||||||
if ((join= sl->join))
|
if ((join= sl->join))
|
||||||
{
|
{
|
||||||
error|= sl->join->cleanup();
|
error|= sl->join->cleanup();
|
||||||
delete join;
|
delete join;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// it can be DO/SET with subqueries
|
||||||
|
for (SELECT_LEX_UNIT *lex_unit= sl->first_inner_unit();
|
||||||
|
lex_unit != 0;
|
||||||
|
lex_unit= lex_unit->next_unit())
|
||||||
|
{
|
||||||
|
error|= lex_unit->cleanup();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (fake_select_lex && (join= fake_select_lex->join))
|
if (fake_select_lex && (join= fake_select_lex->join))
|
||||||
{
|
{
|
||||||
|
@ -99,7 +99,7 @@ int mysql_update(THD *thd,
|
|||||||
setup_conds(thd,update_table_list,&conds) ||
|
setup_conds(thd,update_table_list,&conds) ||
|
||||||
thd->lex->select_lex.setup_ref_array(thd, order_num) ||
|
thd->lex->select_lex.setup_ref_array(thd, order_num) ||
|
||||||
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
|
setup_order(thd, thd->lex->select_lex.ref_pointer_array,
|
||||||
&tables, all_fields, all_fields, order) ||
|
update_table_list, all_fields, all_fields, order) ||
|
||||||
setup_ftfuncs(&thd->lex->select_lex))
|
setup_ftfuncs(&thd->lex->select_lex))
|
||||||
DBUG_RETURN(-1); /* purecov: inspected */
|
DBUG_RETURN(-1); /* purecov: inspected */
|
||||||
|
|
||||||
@ -427,6 +427,9 @@ int mysql_multi_update(THD *thd,
|
|||||||
int res;
|
int res;
|
||||||
multi_update *result;
|
multi_update *result;
|
||||||
TABLE_LIST *tl;
|
TABLE_LIST *tl;
|
||||||
|
TABLE_LIST *update_list=
|
||||||
|
(TABLE_LIST*)thd->lex->select_lex.table_list.first;
|
||||||
|
|
||||||
table_map item_tables= 0, derived_tables= 0;
|
table_map item_tables= 0, derived_tables= 0;
|
||||||
DBUG_ENTER("mysql_multi_update");
|
DBUG_ENTER("mysql_multi_update");
|
||||||
|
|
||||||
@ -439,7 +442,7 @@ int mysql_multi_update(THD *thd,
|
|||||||
Ensure that we have update privilege for all tables and columns in the
|
Ensure that we have update privilege for all tables and columns in the
|
||||||
SET part
|
SET part
|
||||||
*/
|
*/
|
||||||
for (tl= table_list ; tl ; tl=tl->next)
|
for (tl= update_list; tl; tl= tl->next)
|
||||||
{
|
{
|
||||||
TABLE *table= tl->table;
|
TABLE *table= tl->table;
|
||||||
/*
|
/*
|
||||||
@ -456,14 +459,14 @@ int mysql_multi_update(THD *thd,
|
|||||||
{
|
{
|
||||||
// Assign table map values to check updatability of derived tables
|
// Assign table map values to check updatability of derived tables
|
||||||
uint tablenr=0;
|
uint tablenr=0;
|
||||||
for (TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
|
for (TABLE_LIST *table_list= update_list;
|
||||||
table_list;
|
table_list;
|
||||||
table_list= table_list->next, tablenr++)
|
table_list= table_list->next, tablenr++)
|
||||||
{
|
{
|
||||||
table_list->table->map= (table_map) 1 << tablenr;
|
table_list->table->map= (table_map) 1 << tablenr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
|
if (setup_fields(thd, 0, update_list, *fields, 1, 0, 0))
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
if (thd->lex->derived_tables)
|
if (thd->lex->derived_tables)
|
||||||
{
|
{
|
||||||
@ -479,7 +482,7 @@ int mysql_multi_update(THD *thd,
|
|||||||
/*
|
/*
|
||||||
Count tables and setup timestamp handling
|
Count tables and setup timestamp handling
|
||||||
*/
|
*/
|
||||||
for (tl= select_lex->get_table_list() ; tl ; tl= tl->next)
|
for (tl= update_list; tl; tl= tl->next)
|
||||||
{
|
{
|
||||||
TABLE *table= tl->table;
|
TABLE *table= tl->table;
|
||||||
|
|
||||||
@ -496,7 +499,7 @@ int mysql_multi_update(THD *thd,
|
|||||||
if (thd->lex->derived_tables && (item_tables & derived_tables))
|
if (thd->lex->derived_tables && (item_tables & derived_tables))
|
||||||
{
|
{
|
||||||
// find derived table which cause error
|
// find derived table which cause error
|
||||||
for (tl= select_lex->get_table_list() ; tl ; tl= tl->next)
|
for (tl= update_list; tl; tl= tl->next)
|
||||||
{
|
{
|
||||||
if (tl->derived && (item_tables & tl->table->map))
|
if (tl->derived && (item_tables & tl->table->map))
|
||||||
{
|
{
|
||||||
|
@ -194,6 +194,7 @@ typedef struct st_table_list
|
|||||||
bool force_index; /* Prefer index over table scan */
|
bool force_index; /* Prefer index over table scan */
|
||||||
bool ignore_leaves; /* Preload only non-leaf nodes */
|
bool ignore_leaves; /* Preload only non-leaf nodes */
|
||||||
bool cacheable_table; /* stop PS caching */
|
bool cacheable_table; /* stop PS caching */
|
||||||
|
bool checked; /* used in multi-upd privelege check */
|
||||||
} TABLE_LIST;
|
} TABLE_LIST;
|
||||||
|
|
||||||
typedef struct st_changed_table_list
|
typedef struct st_changed_table_list
|
||||||
|
@ -925,14 +925,6 @@ static void test_prepare_simple()
|
|||||||
rc = mysql_query(mysql,"CREATE TABLE test_prepare_simple(id int, name varchar(50))");
|
rc = mysql_query(mysql,"CREATE TABLE test_prepare_simple(id int, name varchar(50))");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
/* alter table */
|
|
||||||
strmov(query,"ALTER TABLE test_prepare_simple ADD new char(20)");
|
|
||||||
stmt = mysql_simple_prepare(mysql, query);
|
|
||||||
mystmt_init(stmt);
|
|
||||||
|
|
||||||
verify_param_count(stmt,0);
|
|
||||||
mysql_stmt_close(stmt);
|
|
||||||
|
|
||||||
/* insert */
|
/* insert */
|
||||||
strmov(query,"INSERT INTO test_prepare_simple VALUES(?,?)");
|
strmov(query,"INSERT INTO test_prepare_simple VALUES(?,?)");
|
||||||
stmt = mysql_simple_prepare(mysql, query);
|
stmt = mysql_simple_prepare(mysql, query);
|
||||||
@ -1541,22 +1533,25 @@ static void test_select_version()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************
|
/********************************************************
|
||||||
* to test simple select *
|
* to test simple show *
|
||||||
*********************************************************/
|
*********************************************************/
|
||||||
static void test_select_simple()
|
static void test_select_show_table()
|
||||||
{
|
{
|
||||||
MYSQL_STMT *stmt;
|
MYSQL_STMT *stmt;
|
||||||
int rc;
|
int rc, i;
|
||||||
|
|
||||||
myheader("test_select_simple");
|
myheader("test_select_show_table");
|
||||||
|
|
||||||
stmt = mysql_simple_prepare(mysql, "SHOW TABLES FROM mysql");
|
stmt = mysql_simple_prepare(mysql, "SHOW TABLES FROM mysql");
|
||||||
mystmt_init(stmt);
|
mystmt_init(stmt);
|
||||||
|
|
||||||
verify_param_count(stmt,0);
|
verify_param_count(stmt,0);
|
||||||
|
|
||||||
rc = mysql_execute(stmt);
|
for (i= 1; i < 3; i++)
|
||||||
mystmt(stmt, rc);
|
{
|
||||||
|
rc = mysql_execute(stmt);
|
||||||
|
mystmt(stmt, rc);
|
||||||
|
}
|
||||||
|
|
||||||
my_process_stmt_result(stmt);
|
my_process_stmt_result(stmt);
|
||||||
mysql_stmt_close(stmt);
|
mysql_stmt_close(stmt);
|
||||||
@ -4048,7 +4043,7 @@ static void test_stmt_close()
|
|||||||
rc = mysql_query(lmysql,"CREATE TABLE test_stmt_close(id int)");
|
rc = mysql_query(lmysql,"CREATE TABLE test_stmt_close(id int)");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
strmov(query,"ALTER TABLE test_stmt_close ADD name varchar(20)");
|
strmov(query,"DO \"nothing\"");
|
||||||
stmt1= mysql_simple_prepare(lmysql, query);
|
stmt1= mysql_simple_prepare(lmysql, query);
|
||||||
mystmt_init(stmt1);
|
mystmt_init(stmt1);
|
||||||
|
|
||||||
@ -6452,14 +6447,10 @@ static void test_prepare_grant()
|
|||||||
myquery_r(rc);
|
myquery_r(rc);
|
||||||
|
|
||||||
stmt= mysql_simple_prepare(mysql,"DELETE FROM test_grant");
|
stmt= mysql_simple_prepare(mysql,"DELETE FROM test_grant");
|
||||||
mystmt_init(stmt);
|
mystmt_init_r(stmt);
|
||||||
|
|
||||||
rc = mysql_execute(stmt);
|
|
||||||
myquery_r(rc);
|
|
||||||
|
|
||||||
assert(4 == my_stmt_result("SELECT * FROM test_grant"));
|
assert(4 == my_stmt_result("SELECT * FROM test_grant"));
|
||||||
|
|
||||||
mysql_stmt_close(stmt);
|
|
||||||
mysql_close(lmysql);
|
mysql_close(lmysql);
|
||||||
mysql= org_mysql;
|
mysql= org_mysql;
|
||||||
|
|
||||||
@ -8214,6 +8205,7 @@ static void test_subqueries()
|
|||||||
MYSQL_STMT *stmt;
|
MYSQL_STMT *stmt;
|
||||||
int rc, i;
|
int rc, i;
|
||||||
const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1,b-1) in (select a,b from t2) as in_row_s FROM t1, (select a x, b y from t2) tt WHERE x=a";
|
const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s, (a-1,b-1) in (select a,b from t2) as in_row_s FROM t1, (select a x, b y from t2) tt WHERE x=a";
|
||||||
|
/* const char *query= "SELECT (SELECT SUM(a+b) FROM t2 where t1.b=t2.b GROUP BY t1.a LIMIT 1) as scalar_s, exists (select 1 from t2 where t2.a/2=t1.a) as exists_s, a in (select a+3 from t2) as in_s FROM t1, (select a x, b y from t2) tt WHERE x=a"; */
|
||||||
|
|
||||||
myheader("test_subquery");
|
myheader("test_subquery");
|
||||||
|
|
||||||
@ -8594,13 +8586,22 @@ static void test_selecttmp()
|
|||||||
|
|
||||||
static void test_create_drop()
|
static void test_create_drop()
|
||||||
{
|
{
|
||||||
MYSQL_STMT *stmt_create, *stmt_drop;
|
MYSQL_STMT *stmt_create, *stmt_drop, *stmt_select, *stmt_create_select;
|
||||||
char *query;
|
char *query;
|
||||||
int rc, i;
|
int rc, i;
|
||||||
myheader("test_table_manipulation");
|
myheader("test_table_manipulation");
|
||||||
|
|
||||||
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2");
|
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2");
|
||||||
myquery(rc);
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"create table t2 (a int);");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"create table t1 (a int);");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "insert into t2 values (3), (2), (1);");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
query= (char*)"create table t1 (a int)";
|
query= (char*)"create table t1 (a int)";
|
||||||
stmt_create= mysql_prepare(mysql, query, strlen(query));
|
stmt_create= mysql_prepare(mysql, query, strlen(query));
|
||||||
@ -8610,18 +8611,51 @@ static void test_create_drop()
|
|||||||
stmt_drop= mysql_prepare(mysql, query, strlen(query));
|
stmt_drop= mysql_prepare(mysql, query, strlen(query));
|
||||||
mystmt_init(stmt_drop);
|
mystmt_init(stmt_drop);
|
||||||
|
|
||||||
|
query= (char*)"select a in (select a from t2) from t1";
|
||||||
|
stmt_select= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_select);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "DROP TABLE t1");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
query= (char*)"create table t1 select a from t2";
|
||||||
|
stmt_create_select= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_create_select);
|
||||||
|
|
||||||
for (i= 0; i < 3; i++)
|
for (i= 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
rc= mysql_execute(stmt_create);
|
rc= mysql_execute(stmt_create);
|
||||||
mystmt(stmt_create, rc);
|
mystmt(stmt_create, rc);
|
||||||
fprintf(stdout, "created %i\n", i);
|
fprintf(stdout, "created %i\n", i);
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_select);
|
||||||
|
mystmt(stmt_select, rc);
|
||||||
|
assert(0 == my_process_stmt_result(stmt_select));
|
||||||
|
|
||||||
rc= mysql_execute(stmt_drop);
|
rc= mysql_execute(stmt_drop);
|
||||||
mystmt(stmt_drop, rc);
|
mystmt(stmt_drop, rc);
|
||||||
fprintf(stdout, "droped %i\n", i);
|
fprintf(stdout, "droped %i\n", i);
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_create_select);
|
||||||
|
mystmt(stmt_create, rc);
|
||||||
|
fprintf(stdout, "created select %i\n", i);
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_select);
|
||||||
|
mystmt(stmt_select, rc);
|
||||||
|
assert(3 == my_process_stmt_result(stmt_select));
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_drop);
|
||||||
|
mystmt(stmt_drop, rc);
|
||||||
|
fprintf(stdout, "droped %i\n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
mysql_stmt_close(stmt_create);
|
mysql_stmt_close(stmt_create);
|
||||||
mysql_stmt_close(stmt_drop);
|
mysql_stmt_close(stmt_drop);
|
||||||
|
mysql_stmt_close(stmt_select);
|
||||||
|
mysql_stmt_close(stmt_create_select);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql, "DROP TABLE t2");
|
||||||
|
myquery(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -8669,6 +8703,166 @@ static void test_rename()
|
|||||||
myquery(rc);
|
myquery(rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void test_do_set()
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt_do, *stmt_set;
|
||||||
|
char *query;
|
||||||
|
int rc, i;
|
||||||
|
myheader("test_do_set");
|
||||||
|
|
||||||
|
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"create table t1 (a int)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
query= (char*)"do @var:=(1 in (select * from t1))";
|
||||||
|
stmt_do= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_do);
|
||||||
|
|
||||||
|
query= (char*)"set @var=(1 in (select * from t1))";
|
||||||
|
stmt_set= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_set);
|
||||||
|
|
||||||
|
for (i= 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
rc= mysql_execute(stmt_do);
|
||||||
|
mystmt(stmt_do, rc);
|
||||||
|
fprintf(stdout, "do %i\n", i);
|
||||||
|
rc= mysql_execute(stmt_set);
|
||||||
|
mystmt(stmt_set, rc);
|
||||||
|
fprintf(stdout, "set %i\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt_do);
|
||||||
|
mysql_stmt_close(stmt_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_multi()
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt_delete, *stmt_update, *stmt_select1, *stmt_select2;
|
||||||
|
char *query;
|
||||||
|
MYSQL_BIND bind[1];
|
||||||
|
int rc, i;
|
||||||
|
long param= 1, length= 1;
|
||||||
|
myheader("test_multi");
|
||||||
|
|
||||||
|
bind[0].buffer_type= MYSQL_TYPE_LONG;
|
||||||
|
bind[0].buffer= (char *)¶m;
|
||||||
|
bind[0].buffer_length= 0;
|
||||||
|
bind[0].is_null= 0;
|
||||||
|
bind[0].length= &length;
|
||||||
|
|
||||||
|
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"create table t1 (a int, b int)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"create table t2 (a int, b int)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"insert into t1 values (3,3), (2,2), (1,1)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"insert into t2 values (3,3), (2,2), (1,1)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
query= (char*)"delete t1,t2 from t1,t2 where t1.a=t2.a and t1.b=10";
|
||||||
|
stmt_delete= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_delete);
|
||||||
|
|
||||||
|
query= (char*)"update t1,t2 set t1.b=10,t2.b=10 where t1.a=t2.a and t1.b=?";
|
||||||
|
stmt_update= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_update);
|
||||||
|
|
||||||
|
query= (char*)"select * from t1";
|
||||||
|
stmt_select1= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_select1);
|
||||||
|
|
||||||
|
query= (char*)"select * from t2";
|
||||||
|
stmt_select2= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_select2);
|
||||||
|
|
||||||
|
for(i= 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
rc= mysql_bind_param(stmt_update, bind);
|
||||||
|
mystmt(stmt_update,rc);
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_update);
|
||||||
|
mystmt(stmt_update, rc);
|
||||||
|
fprintf(stdout, "update %ld\n", param);
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_delete);
|
||||||
|
mystmt(stmt_delete, rc);
|
||||||
|
fprintf(stdout, "delete %ld\n", param);
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_select1);
|
||||||
|
mystmt(stmt_select1, rc);
|
||||||
|
assert((uint)(3-param) == my_process_stmt_result(stmt_select1));
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_select2);
|
||||||
|
mystmt(stmt_select2, rc);
|
||||||
|
assert((uint)(3-param) == my_process_stmt_result(stmt_select2));
|
||||||
|
|
||||||
|
param++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt_delete);
|
||||||
|
mysql_stmt_close(stmt_update);
|
||||||
|
mysql_stmt_close(stmt_select1);
|
||||||
|
mysql_stmt_close(stmt_select2);
|
||||||
|
rc= mysql_query(mysql,"drop table t1,t2");
|
||||||
|
myquery(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void test_insert_select()
|
||||||
|
{
|
||||||
|
MYSQL_STMT *stmt_insert, *stmt_select;
|
||||||
|
char *query;
|
||||||
|
int rc, i;
|
||||||
|
myheader("test_insert_select");
|
||||||
|
|
||||||
|
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1, t2");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"create table t1 (a int)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"create table t2 (a int)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
rc= mysql_query(mysql,"insert into t2 values (1)");
|
||||||
|
myquery(rc);
|
||||||
|
|
||||||
|
query= (char*)"insert into t1 select a from t2";
|
||||||
|
stmt_insert= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_insert);
|
||||||
|
|
||||||
|
query= (char*)"select * from t1";
|
||||||
|
stmt_select= mysql_prepare(mysql, query, strlen(query));
|
||||||
|
mystmt_init(stmt_select);
|
||||||
|
|
||||||
|
for(i= 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
rc= mysql_execute(stmt_insert);
|
||||||
|
mystmt(stmt_insert, rc);
|
||||||
|
fprintf(stdout, "insert %u\n", i);
|
||||||
|
|
||||||
|
rc= mysql_execute(stmt_select);
|
||||||
|
mystmt(stmt_select, rc);
|
||||||
|
assert((i+1) == my_process_stmt_result(stmt_select));
|
||||||
|
}
|
||||||
|
|
||||||
|
mysql_stmt_close(stmt_insert);
|
||||||
|
mysql_stmt_close(stmt_select);
|
||||||
|
rc= mysql_query(mysql,"drop table t1,t2");
|
||||||
|
myquery(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read and parse arguments and MySQL options from my.cnf
|
Read and parse arguments and MySQL options from my.cnf
|
||||||
*/
|
*/
|
||||||
@ -8831,7 +9025,7 @@ int main(int argc, char **argv)
|
|||||||
test_select_prepare(); /* prepare select - protocol_prep debug */
|
test_select_prepare(); /* prepare select - protocol_prep debug */
|
||||||
test_select(); /* simple select test */
|
test_select(); /* simple select test */
|
||||||
test_select_version(); /* select with variables */
|
test_select_version(); /* select with variables */
|
||||||
test_select_simple(); /* simple select prepare */
|
test_select_show_table();/* simple show prepare */
|
||||||
#if NOT_USED
|
#if NOT_USED
|
||||||
/*
|
/*
|
||||||
Enable this tests from 4.1.1 when mysql_param_result() is
|
Enable this tests from 4.1.1 when mysql_param_result() is
|
||||||
@ -8932,6 +9126,9 @@ int main(int argc, char **argv)
|
|||||||
test_selecttmp(); /* temporary table used in select execution */
|
test_selecttmp(); /* temporary table used in select execution */
|
||||||
test_create_drop(); /* some table manipulation BUG#2811 */
|
test_create_drop(); /* some table manipulation BUG#2811 */
|
||||||
test_rename(); /* rename test */
|
test_rename(); /* rename test */
|
||||||
|
test_do_set(); /* DO & SET commands test BUG#3393 */
|
||||||
|
test_multi(); /* test of multi delete & update */
|
||||||
|
test_insert_select(); /* test INSERT ... SELECT */
|
||||||
|
|
||||||
end_time= time((time_t *)0);
|
end_time= time((time_t *)0);
|
||||||
total_time+= difftime(end_time, start_time);
|
total_time+= difftime(end_time, start_time);
|
||||||
|
Reference in New Issue
Block a user