summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mysqld_error.h3
-rw-r--r--mysql-test/r/multi_update.result20
-rw-r--r--mysql-test/t/multi_update.test37
-rw-r--r--sql/item_cmpfunc.cc10
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/set_var.cc28
-rw-r--r--sql/set_var.h4
-rw-r--r--sql/share/czech/errmsg.txt1
-rw-r--r--sql/share/danish/errmsg.txt1
-rw-r--r--sql/share/dutch/errmsg.txt1
-rw-r--r--sql/share/english/errmsg.txt1
-rw-r--r--sql/share/estonian/errmsg.txt1
-rw-r--r--sql/share/french/errmsg.txt1
-rw-r--r--sql/share/german/errmsg.txt1
-rw-r--r--sql/share/greek/errmsg.txt1
-rw-r--r--sql/share/hungarian/errmsg.txt1
-rw-r--r--sql/share/italian/errmsg.txt1
-rw-r--r--sql/share/japanese/errmsg.txt1
-rw-r--r--sql/share/korean/errmsg.txt1
-rw-r--r--sql/share/norwegian-ny/errmsg.txt1
-rw-r--r--sql/share/norwegian/errmsg.txt1
-rw-r--r--sql/share/polish/errmsg.txt1
-rw-r--r--sql/share/portuguese/errmsg.txt1
-rw-r--r--sql/share/romanian/errmsg.txt1
-rw-r--r--sql/share/russian/errmsg.txt1
-rw-r--r--sql/share/serbian/errmsg.txt1
-rw-r--r--sql/share/slovak/errmsg.txt1
-rw-r--r--sql/share/spanish/errmsg.txt1
-rw-r--r--sql/share/swedish/errmsg.txt1
-rw-r--r--sql/share/ukrainian/errmsg.txt1
-rw-r--r--sql/sql_lex.cc60
-rw-r--r--sql/sql_lex.h6
-rw-r--r--sql/sql_parse.cc348
-rw-r--r--sql/sql_prepare.cc473
-rw-r--r--sql/sql_select.cc2
-rw-r--r--sql/sql_union.cc13
-rw-r--r--sql/sql_update.cc15
-rw-r--r--sql/table.h1
-rw-r--r--tests/client_test.c243
39 files changed, 1058 insertions, 235 deletions
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index 6ae6111a8bb..3dabd226ae6 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -311,4 +311,5 @@
#define ER_TRUNCATED_WRONG_VALUE 1292
#define ER_TOO_MUCH_AUTO_TIMESTAMP_COLS 1293
#define ER_INVALID_ON_UPDATE 1294
-#define ER_ERROR_MESSAGES 295
+#define ER_UNSUPPORTED_PS 1295
+#define ER_ERROR_MESSAGES 296
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index fc5ef88f045..f0975b6fa10 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -1,4 +1,5 @@
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 t2(id2 int not null, t char(12));
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 t3 FROM t1 AS t3, t1 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 t2 values (1),(2);
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
1 1 A Note 1
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;
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index 27fd80e781b..8b6941c4a94 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -4,6 +4,7 @@
--disable_warnings
drop table if exists t1,t2,t3;
+drop database if exists mysqltest;
--enable_warnings
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 t4 FROM t1, 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;
INSERT INTO t1 values (1),(2);
INSERT INTO t2 values (1),(2);
@@ -369,7 +370,6 @@ DROP TABLE t1,t2;
#
# 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 `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);
@@ -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 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;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 24d60b51eab..d5842189f07 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -477,9 +477,11 @@ bool Item_in_optimizer::fix_left(THD *thd,
struct st_table_list *tables,
Item **ref)
{
- if (args[0]->fix_fields(thd, tables, ref) ||
- (!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))))
+ if ((!args[0]->fixed && args[0]->fix_fields(thd, tables, args)))
return 1;
+ if (!cache && !(cache= Item_cache::get_cache(args[0]->result_type())))
+ return 1;
+
cache->setup(args[0]);
cache->store(args[0]);
if (cache->cols() == 1)
@@ -512,12 +514,12 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref)
{
DBUG_ASSERT(fixed == 0);
- if (!args[0]->fixed && fix_left(thd, tables, ref))
+ if (fix_left(thd, tables, ref))
return 1;
if (args[0]->maybe_null)
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;
Item_in_subselect * sub= (Item_in_subselect *)args[1];
if (args[0]->cols() != sub->engine->cols())
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 29db2ceda49..44e241b9d4c 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -347,6 +347,13 @@ void free_items(Item *item);
void cleanup_items(Item *item);
class THD;
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 "opt_range.h"
diff --git a/sql/set_var.cc b/sql/set_var.cc
index e3ed2a4cbd8..b357c0c96f2 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2528,6 +2528,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)
{
if (!value)
@@ -2555,6 +2573,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)
{
if (user_var_item->update())
diff --git a/sql/set_var.h b/sql/set_var.h
index 1cac2953a21..699f320bbd9 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -688,6 +688,8 @@ public:
virtual ~set_var_base() {}
virtual int check(THD *thd)=0; /* To check privileges etc. */
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 update(THD *thd);
+ int light_check(THD *thd);
};
@@ -742,6 +745,7 @@ public:
{}
int check(THD *thd);
int update(THD *thd);
+ int light_check(THD *thd);
};
/* For SET PASSWORD */
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 339c693bb38..f3a0c5e0eec 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -307,3 +307,4 @@ character-set=latin2
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 9c870ecb67c..195e48faf82 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -301,3 +301,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 18f11253fb5..9d9dfb14a89 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -309,3 +309,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 2d7f82e36ef..14a854fbafb 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -298,3 +298,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index c96f5d1e40c..5d0f34fd4b2 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -303,3 +303,4 @@ character-set=latin7
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index bb5f48cab56..adc9f66e96b 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -298,3 +298,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index ccc9eace98e..0b732ba48f8 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -310,3 +310,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index ff49f887d95..f96c10b0e65 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -298,3 +298,4 @@ character-set=greek
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 63925213da2..a26790a4ef9 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -300,3 +300,4 @@ character-set=latin2
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 76e572fd71b..7c519e4e4bf 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -298,3 +298,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index f7df183269d..f973f84d2a4 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -300,3 +300,4 @@ character-set=ujis
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index e63a5d64c2b..8b5d318ab19 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -298,3 +298,4 @@ character-set=euckr
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 2d28db39a3c..c0a7d736e1f 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -300,3 +300,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 231bcc89822..fc9b5d2f6da 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -300,3 +300,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 0b5269cce80..36b7d67d134 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -302,3 +302,4 @@ character-set=latin2
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 9549d8f530d..d4ffa2d5ef5 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -299,3 +299,4 @@ character-set=latin1
"Truncado errado %-.32s valor: '%-.128s'"
"Incorreta definição de tabela; Pode ter somente uma coluna TIMESTAMP com CURRENT_TIMESTAMP em DEFAULT ou ON UPDATE cláusula"
"Inválida cláusula ON UPDATE para campo '%-.64s'",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 3e1993d8018..4918a6e1a10 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -302,3 +302,4 @@ character-set=latin2
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 943a64ad711..dbc93306a38 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -300,3 +300,4 @@ character-set=koi8r
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 74cc1c9f2e1..df157566aea 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -292,3 +292,4 @@ character-set=cp1250
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 79fe55c1ff1..80d21f8e31f 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -306,3 +306,4 @@ character-set=latin2
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 36d8bac986e..512f06c8c50 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -300,3 +300,4 @@ character-set=latin1
"Equivocado truncado %-.32s valor: '%-.128s'"
"Incorrecta definición de tabla; Solamente debe haber una columna TIMESTAMP con CURRENT_TIMESTAMP en DEFAULT o ON UPDATE cláusula"
"Inválido ON UPDATE cláusula para campo '%-.64s'",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 2643e726db8..22e7cb786b5 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -298,3 +298,4 @@ character-set=latin1
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index e61e479aa66..3149d58b413 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -303,3 +303,4 @@ character-set=koi8u
"Truncated wrong %-.32s value: '%-.128s'"
"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",
+"This command is not supported in the prepared statement protocol yet",
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index df7d487194a..7ff2fb4643a 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1635,6 +1635,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 &
st_select_lex::set_lock_for_tables are in sql_parse.cc
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index c86c7d4a81d..d5fbbd8803e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -603,6 +603,12 @@ typedef struct st_lex
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;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 2b8720abebb..147f576d03e 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -51,13 +51,10 @@ extern "C" int gethostname(char *name, int namelen);
static int check_for_max_user_connections(THD *thd, USER_CONN *uc);
static void decrease_user_connections(USER_CONN *uc);
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 refresh_status(void);
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
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
@@ -2164,17 +2161,9 @@ mysql_execute_command(THD *thd)
case SQLCOM_CREATE_TABLE:
{
/* Skip first table, which is the table we are creating */
- TABLE_LIST *create_table= tables;
- TABLE_LIST *create_table_local=
- (TABLE_LIST*)lex->select_lex.table_list.first;
- // 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;
+ TABLE_LIST *create_table, *create_table_local;
+ tables= lex->unlink_first_table(tables, &create_table,
+ &create_table_local);
ulong want_priv= ((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) ?
CREATE_TMP_ACL : CREATE_ACL);
@@ -2184,10 +2173,10 @@ mysql_execute_command(THD *thd)
check_merge_table_access(thd, create_table->db,
(TABLE_LIST *)
lex->create_info.merge_list.first))
- goto create_eror; /* purecov: inspected */
+ goto create_error; /* purecov: inspected */
if (grant_option && want_priv != CREATE_TMP_ACL &&
check_grant(thd, want_priv, create_table,0,0))
- goto create_eror;
+ goto create_error;
#ifndef HAVE_READLINK
lex->create_info.data_file_name=lex->create_info.index_file_name=0;
#else
@@ -2223,10 +2212,10 @@ mysql_execute_command(THD *thd)
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))
- goto create_eror; // Error message is given
+ goto create_error; // Error message is given
select_lex->options|= SELECT_NO_UNLOCK;
unit->offset_limit_cnt= select_lex->offset_limit;
unit->select_limit_cnt= select_lex->select_limit+
@@ -2244,6 +2233,9 @@ mysql_execute_command(THD *thd)
lex->key_list,
select_lex->item_list,lex->duplicates)))
res=handle_select(thd, lex, result);
+ //reset for PS
+ lex->create_list.empty();
+ lex->key_list.empty();
}
}
else // regular create
@@ -2261,35 +2253,18 @@ mysql_execute_command(THD *thd)
if (!res)
send_ok(thd);
}
+
// put tables back for PS rexecuting
- create_table->next= tables;
- tables= create_table;
- 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;
+ tables= lex->link_first_table_back(tables, create_table,
+ create_table_local);
break;
-create_eror:
+create_error:
res= 1; //error reported
unsent_create_error:
// put tables back for PS rexecuting
- create_table->next= tables;
- tables= create_table;
- 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;
- }
+ tables= lex->link_first_table_back(tables, create_table,
+ create_table_local);
break;
}
case SQLCOM_CREATE_INDEX:
@@ -2577,39 +2552,8 @@ unsent_create_error:
break;
case SQLCOM_UPDATE_MULTI:
{
- const char *msg= 0;
- 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;
+ if ((res= multi_update_precheck(thd, tables)))
break;
- }
res= mysql_multi_update(thd,tables,
&select_lex->item_list,
&lex->value_list,
@@ -2642,16 +2586,9 @@ unsent_create_error:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
{
- /*
- Check that we have modify privileges for the first table and
- select privileges for the rest
- */
- {
- ulong privilege= (lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL);
- if (check_one_table_access(thd, privilege, tables, 0))
- goto error;
- }
+ TABLE_LIST *first_local_table= (TABLE_LIST *) select_lex->table_list.first;
+ if ((res= insert_select_precheck(thd, tables)))
+ break;
/* Fix lock for first table */
if (tables->lock_type == TL_WRITE_DELAYED)
@@ -2672,16 +2609,18 @@ unsent_create_error:
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 ((result=new select_insert(tables->table,&lex->field_list,
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);
+ /* 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)
res= -1;
}
@@ -2718,51 +2657,25 @@ unsent_create_error:
}
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;
- uint table_count=0;
+ uint table_count= 0;
multi_delete *result;
+ if ((res= multi_delete_precheck(thd, tables, &table_count)))
+ break;
- /* sql_yacc guarantees that tables and aux_tables are not zero */
- 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))
- 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
- }
+ // condition will be TRUE on SP re esexcuting
+ if (select_lex->item_list.elements != 0)
+ select_lex->item_list.empty();
if (add_item_to_list(thd, new Item_null()))
{
res= -1;
break;
}
+
thd->proc_info="init";
if ((res=open_and_lock_tables(thd,tables)))
break;
@@ -3494,9 +3407,8 @@ error:
0 - OK
1 - access denied, error is sent to client
*/
-
-static int check_one_table_access(THD *thd, ulong privilege,
- TABLE_LIST *tables, bool no_errors)
+int check_one_table_access(THD *thd, ulong privilege,
+ TABLE_LIST *tables, bool no_errors)
{
if (check_access(thd, privilege, tables->db, &tables->grant.privilege,0,0))
@@ -3694,8 +3606,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
return FALSE;
}
-static bool check_merge_table_access(THD *thd, char *db,
- TABLE_LIST *table_list)
+bool check_merge_table_access(THD *thd, char *db,
+ TABLE_LIST *table_list)
{
int error=0;
if (table_list)
@@ -4977,3 +4889,181 @@ Item * all_any_subquery_creator(Item *left_expr,
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);
+}
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index bdbdcb28d3a..b4580ca5a60 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -646,26 +646,29 @@ static bool emb_insert_params_withlog(Prepared_statement *stmt)
static int mysql_test_insert_fields(Prepared_statement *stmt,
TABLE_LIST *table_list,
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;
+ LEX *lex= stmt->lex;
TABLE *table;
List_iterator_fast<List_item> its(values_list);
List_item *values;
+ TABLE_LIST *insert_table_list=
+ (TABLE_LIST*) lex->select_lex.table_list.first;
DBUG_ENTER("mysql_test_insert_fields");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- my_bool update=(stmt->lex->value_list.elements ? UPDATE_ACL : 0);
- ulong privilege= (stmt->lex->duplicates == DUP_REPLACE ?
- INSERT_ACL | DELETE_ACL : INSERT_ACL | update);
- if (check_access(thd,privilege,table_list->db,
- &table_list->grant.privilege,0,0) ||
- (grant_option && check_grant(thd,privilege,table_list,0,0)))
- DBUG_RETURN(1);
+ ulong privilege= (lex->duplicates == DUP_REPLACE ?
+ INSERT_ACL | DELETE_ACL : INSERT_ACL);
+ if (check_one_table_access(thd, privilege, table_list, 0))
+ DBUG_RETURN(1);
#endif
- /*
+ /*
open temporary memory pool for temporary data allocated by derived
tables & preparation procedure
*/
@@ -683,12 +686,19 @@ static int mysql_test_insert_fields(Prepared_statement *stmt,
uint value_count;
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();
- DBUG_RETURN(-1);
+ my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
+ goto error;
}
- thd->free_temporary_memory_pool_for_ps_preparing();
value_count= values->elements;
its.rewind();
@@ -701,15 +711,20 @@ static int mysql_test_insert_fields(Prepared_statement *stmt,
my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW,
ER(ER_WRONG_VALUE_COUNT_ON_ROW),
MYF(0), counter);
- DBUG_RETURN(-1);
+ goto error;
}
+ if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0))
+ goto error;
}
}
- else
- {
- thd->free_temporary_memory_pool_for_ps_preparing();
- }
+ lex->unit.cleanup();
+ thd->free_temporary_memory_pool_for_ps_preparing();
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,
TABLE_LIST *table_list,
List<Item> &fields, List<Item> &values,
- COND *conds)
+ COND *conds, ulong privelege)
{
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");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (check_access(thd,UPDATE_ACL,table_list->db,
- &table_list->grant.privilege,0,0) ||
- (grant_option && check_grant(thd,UPDATE_ACL,table_list,0,0)))
+ if (check_one_table_access(thd, privelege, table_list, 0))
DBUG_RETURN(1);
+ // Set privilege for the WHERE clause
+ table_list->grant.want_privilege= (SELECT_ACL &
+ ~table_list->grant.privilege);
#endif
- /*
+ /*
open temporary memory pool for temporary data allocated by derived
tables & preparation procedure
*/
@@ -748,11 +770,19 @@ static int mysql_test_upd_fields(Prepared_statement *stmt,
if (open_and_lock_tables(thd, table_list))
goto err;
- if (setup_tables(table_list) ||
- setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
- setup_conds(thd, table_list, &conds) || thd->net.report_error)
+ if (setup_tables(upd_table_list) ||
+ setup_conds(thd, upd_table_list, &conds) ||
+ 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;
+ }
+ stmt->lex->unit.cleanup();
thd->free_temporary_memory_pool_for_ps_preparing();
/* 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,
TABLE_LIST *tables,
- uint wild_num,
- 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)
+ List<Item> &fields)
{
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
+ SELECT_LEX_UNIT *unit= &lex->unit;
+
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*",0,0,0))
DBUG_RETURN(1);
#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
tables & preparation procedure
*/
@@ -825,18 +848,11 @@ static int mysql_test_select_fields(Prepared_statement *stmt,
if (send_prep_stmt(stmt, 0))
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
- if (unit->prepare(thd, result, 0))
+ if (unit->prepare(thd, 0, 0))
{
send_error(thd);
goto err_prep;
@@ -864,6 +880,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
SYNOPSIS
send_prepare_results()
@@ -872,25 +1159,33 @@ err:
0 success
1 error, sent to client
*/
-
static int send_prepare_results(Prepared_statement *stmt)
{
+ DBUG_ENTER("send_prepare_results");
THD *thd= stmt->thd;
LEX *lex= stmt->lex;
SELECT_LEX *select_lex= &lex->select_lex;
TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first;
enum enum_sql_command sql_command= lex->sql_command;
int res;
-
- DBUG_ENTER("send_prepare_results");
DBUG_PRINT("enter",("command: %d, param_count: %ld",
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) {
+ case SQLCOM_REPLACE:
case SQLCOM_INSERT:
- if ((res= mysql_test_insert_fields(stmt, tables, lex->field_list,
- lex->many_values)))
+ if ((res=
+ 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;
break;
@@ -898,32 +1193,75 @@ static int send_prepare_results(Prepared_statement *stmt)
/* XXX: fallthrough */
case SQLCOM_DELETE:
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;
break;
case SQLCOM_SELECT:
- if ((res= mysql_test_select_fields(stmt, tables, select_lex->with_wild,
- 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)))
+ if ((res= mysql_test_select_fields(stmt, tables, select_lex->item_list)))
goto error;
/* Statement and field info has already been sent */
DBUG_RETURN(0);
+ case SQLCOM_CREATE_TABLE:
+ if ((res= mysql_test_create_table(stmt, tables)))
+ goto error;
+ 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:
- /*
- Rest fall through to default category, no parsing
- for non-DML statements
+ /*
+ All other is not supported yet
*/
- break;
+ res= -1;
+ my_error(ER_UNSUPPORTED_PS, MYF(0));
+ goto error;
}
DBUG_RETURN(send_prep_stmt(stmt, 0));
@@ -1176,6 +1514,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length)
*/
thd->protocol= &thd->protocol_prep; // Switch to binary protocol
mysql_execute_command(thd);
+ thd->lex->unit.cleanup();
thd->protocol= &thd->protocol_simple; // Use normal protocol
if (!(specialflag & SPECIAL_NO_PRIOR))
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 598b53fe7dd..03b6d9b6bbb 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -434,7 +434,7 @@ JOIN::prepare(Item ***rref_pointer_array,
goto err;
}
#endif
- if (!procedure && result->prepare(fields_list, unit_arg))
+ if (!procedure && result && result->prepare(fields_list, unit_arg))
goto err; /* purecov: inspected */
if (select_lex->olap == ROLLUP_TYPE && rollup_init())
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 7265a99d6e5..468bdab9119 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -460,13 +460,24 @@ int st_select_lex_unit::cleanup()
table= 0; // Safety
}
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))
{
error|= sl->join->cleanup();
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))
{
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 1a9906be0cc..c7c87a488fd 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -99,7 +99,7 @@ int mysql_update(THD *thd,
setup_conds(thd,update_table_list,&conds) ||
thd->lex->select_lex.setup_ref_array(thd, order_num) ||
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))
DBUG_RETURN(-1); /* purecov: inspected */
@@ -427,6 +427,9 @@ int mysql_multi_update(THD *thd,
int res;
multi_update *result;
TABLE_LIST *tl;
+ TABLE_LIST *update_list=
+ (TABLE_LIST*)thd->lex->select_lex.table_list.first;
+
table_map item_tables= 0, derived_tables= 0;
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
SET part
*/
- for (tl= table_list ; tl ; tl=tl->next)
+ for (tl= update_list; tl; tl= tl->next)
{
TABLE *table= tl->table;
/*
@@ -456,14 +459,14 @@ int mysql_multi_update(THD *thd,
{
// Assign table map values to check updatability of derived tables
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->next, 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);
if (thd->lex->derived_tables)
{
@@ -479,7 +482,7 @@ int mysql_multi_update(THD *thd,
/*
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;
@@ -496,7 +499,7 @@ int mysql_multi_update(THD *thd,
if (thd->lex->derived_tables && (item_tables & derived_tables))
{
// 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))
{
diff --git a/sql/table.h b/sql/table.h
index 0bae880a89f..bbf22ae6725 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -193,6 +193,7 @@ typedef struct st_table_list
bool updating; /* for replicate-do/ignore table */
bool force_index; /* Prefer index over table scan */
bool ignore_leaves; /* Preload only non-leaf nodes */
+ bool checked; /* used in multi-upd privelege check */
bool non_cachable_table; /* stop PS caching */
} TABLE_LIST;
diff --git a/tests/client_test.c b/tests/client_test.c
index eaa9c6d7acd..795dbd26769 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -925,14 +925,6 @@ static void test_prepare_simple()
rc = mysql_query(mysql,"CREATE TABLE test_prepare_simple(id int, name varchar(50))");
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 */
strmov(query,"INSERT INTO test_prepare_simple VALUES(?,?)");
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;
- int rc;
+ int rc, i;
- myheader("test_select_simple");
+ myheader("test_select_show_table");
stmt = mysql_simple_prepare(mysql, "SHOW TABLES FROM mysql");
mystmt_init(stmt);
verify_param_count(stmt,0);
- rc = mysql_execute(stmt);
- mystmt(stmt, rc);
+ for (i= 1; i < 3; i++)
+ {
+ rc = mysql_execute(stmt);
+ mystmt(stmt, rc);
+ }
my_process_stmt_result(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)");
myquery(rc);
- strmov(query,"ALTER TABLE test_stmt_close ADD name varchar(20)");
+ strmov(query,"DO \"nothing\"");
stmt1= mysql_simple_prepare(lmysql, query);
mystmt_init(stmt1);
@@ -6452,14 +6447,10 @@ static void test_prepare_grant()
myquery_r(rc);
stmt= mysql_simple_prepare(mysql,"DELETE FROM test_grant");
- mystmt_init(stmt);
-
- rc = mysql_execute(stmt);
- myquery_r(rc);
+ mystmt_init_r(stmt);
assert(4 == my_stmt_result("SELECT * FROM test_grant"));
- mysql_stmt_close(stmt);
mysql_close(lmysql);
mysql= org_mysql;
@@ -8214,6 +8205,7 @@ static void test_subqueries()
MYSQL_STMT *stmt;
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 FROM t1, (select a x, b y from t2) tt WHERE x=a"; */
myheader("test_subquery");
@@ -8594,13 +8586,22 @@ static void test_selecttmp()
static void test_create_drop()
{
- MYSQL_STMT *stmt_create, *stmt_drop;
+ MYSQL_STMT *stmt_create, *stmt_drop, *stmt_select, *stmt_create_select;
char *query;
int rc, i;
myheader("test_table_manipulation");
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1,t2");
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)";
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));
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++)
{
rc= mysql_execute(stmt_create);
mystmt(stmt_create, rc);
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);
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_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);
}
+
+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 *)&param;
+ 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
*/
@@ -8831,7 +9025,7 @@ int main(int argc, char **argv)
test_select_prepare(); /* prepare select - protocol_prep debug */
test_select(); /* simple select test */
test_select_version(); /* select with variables */
- test_select_simple(); /* simple select prepare */
+ test_select_show_table();/* simple show prepare */
#if NOT_USED
/*
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_create_drop(); /* some table manipulation BUG#2811 */
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);
total_time+= difftime(end_time, start_time);