mirror of
https://github.com/MariaDB/server.git
synced 2025-01-29 18:20:07 +01:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.1-runtime
into bodhi.(none):/opt/local/work/mysql-5.1-27430 mysql-test/r/grant.result: Auto merged mysql-test/t/disabled.def: Auto merged mysql-test/t/grant.test: Auto merged sql/set_var.cc: Auto merged sql/sql_acl.cc: Auto merged sql/sql_parse.cc: Auto merged storage/myisam/mi_create.c: Auto merged
This commit is contained in:
commit
fd8253afbb
30 changed files with 3472 additions and 172 deletions
|
@ -570,7 +570,7 @@ typedef unsigned short ushort;
|
|||
|
||||
#define CMP_NUM(a,b) (((a) < (b)) ? -1 : ((a) == (b)) ? 0 : 1)
|
||||
#define sgn(a) (((a) < 0) ? -1 : ((a) > 0) ? 1 : 0)
|
||||
#define swap_variables(t, a, b) { register t dummy; dummy= a; a= b; b= dummy; }
|
||||
#define swap_variables(t, a, b) { t dummy; dummy= a; a= b; b= dummy; }
|
||||
#define test(a) ((a) ? 1 : 0)
|
||||
#define set_if_bigger(a,b) do { if ((a) < (b)) (a)=(b); } while(0)
|
||||
#define set_if_smaller(a,b) do { if ((a) > (b)) (a)=(b); } while(0)
|
||||
|
|
|
@ -1309,6 +1309,7 @@ SELECT * FROM t1;
|
|||
|
||||
--echo # Switch to connection con2
|
||||
connection con2;
|
||||
--reap
|
||||
SELECT * FROM t1;
|
||||
|
||||
--echo # Switch to connection con1
|
||||
|
|
|
@ -143,32 +143,32 @@ b char(30)
|
|||
);
|
||||
insert into t5( a, b, c) values( 9, 'recreated table', 9);
|
||||
execute stmt2 ;
|
||||
a b c
|
||||
9 recreated table 9
|
||||
a c b
|
||||
9 9 recreated table
|
||||
drop table t5 ;
|
||||
create table t5
|
||||
(
|
||||
a int primary key,
|
||||
b char(30),
|
||||
c int,
|
||||
d timestamp default current_timestamp
|
||||
d timestamp default '2008-02-23 09:23:45'
|
||||
);
|
||||
insert into t5( a, b, c) values( 9, 'recreated table', 9);
|
||||
execute stmt2 ;
|
||||
a b c
|
||||
9 recreated table 9
|
||||
a b c d
|
||||
9 recreated table 9 2008-02-23 09:23:45
|
||||
drop table t5 ;
|
||||
create table t5
|
||||
(
|
||||
a int primary key,
|
||||
d timestamp default current_timestamp,
|
||||
d timestamp default '2008-02-23 09:23:45',
|
||||
b char(30),
|
||||
c int
|
||||
);
|
||||
insert into t5( a, b, c) values( 9, 'recreated table', 9);
|
||||
execute stmt2 ;
|
||||
a b c
|
||||
9 recreated table 9
|
||||
a d b c
|
||||
9 2008-02-23 09:23:45 recreated table 9
|
||||
drop table t5 ;
|
||||
create table t5
|
||||
(
|
||||
|
@ -189,7 +189,8 @@ f3 int
|
|||
);
|
||||
insert into t5( f1, f2, f3) values( 9, 'recreated table', 9);
|
||||
execute stmt2 ;
|
||||
ERROR 42S22: Unknown column 'test.t5.a' in 'field list'
|
||||
f1 f2 f3
|
||||
9 recreated table 9
|
||||
drop table t5 ;
|
||||
prepare stmt1 from ' select * from t1 where a <= 2 ' ;
|
||||
execute stmt1 ;
|
||||
|
|
|
@ -35,6 +35,7 @@ Part 3: NOTHING -> VIEW transitions
|
|||
=====================================================================
|
||||
Part 4: TABLE -> NOTHING transitions
|
||||
=====================================================================
|
||||
# Test 4-a: select ... from <table>
|
||||
create table t1 (a int);
|
||||
prepare stmt from "select * from t1";
|
||||
execute stmt;
|
||||
|
@ -59,6 +60,32 @@ call p_verify_reprepare_count(0);
|
|||
SUCCESS
|
||||
|
||||
deallocate prepare stmt;
|
||||
# Test 4-b: TABLE -> NOTHING by renaming the table
|
||||
create table t1 (a int);
|
||||
prepare stmt from "select * from t1";
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
rename table t1 to t2;
|
||||
execute stmt;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop table t2;
|
||||
=====================================================================
|
||||
Part 5: TABLE -> TABLE (DDL) transitions
|
||||
=====================================================================
|
||||
|
@ -192,6 +219,7 @@ SUCCESS
|
|||
select @message;
|
||||
@message
|
||||
new trigger: 11
|
||||
Test 6-e: removing a relevant trigger
|
||||
drop trigger t1_bi;
|
||||
set @val=12;
|
||||
execute stmt using @val;
|
||||
|
@ -338,7 +366,7 @@ SUCCESS
|
|||
#
|
||||
# Sic: the insert went into t3, even though the view now
|
||||
# points at t2. This is because neither the merged view
|
||||
# nor its prelocking list are affected by view DDL
|
||||
# nor its prelocking list are affected by view DDL
|
||||
# The binary log is of course wrong, since it is not
|
||||
# using prepared statements
|
||||
#
|
||||
|
@ -380,7 +408,7 @@ set @var=2;
|
|||
# Since the dependent table is tracked in the prelocked
|
||||
# list of the prepared statement, invalidation happens
|
||||
# and the statement is re-prepared. This is an unnecessary
|
||||
# side effect, since the statement that *is* dependent
|
||||
# side effect, since the statement that *is* dependent
|
||||
# on t2 definition is inside the trigger, and it is currently
|
||||
# not reprepared (see the previous test case).
|
||||
execute stmt using @var;
|
||||
|
@ -398,7 +426,7 @@ a comment
|
|||
drop table t1,t2;
|
||||
# Test 7-e: dependent TABLE TRIGGER has changed
|
||||
create table t1 (a int);
|
||||
create trigger t1_ai after insert on t1 for each row
|
||||
create trigger t1_ai after insert on t1 for each row
|
||||
insert into t2 (a) values (new.a);
|
||||
create table t2 (a int unique);
|
||||
create trigger t2_ai after insert on t2 for each row
|
||||
|
@ -444,6 +472,7 @@ deallocate prepare stmt;
|
|||
=====================================================================
|
||||
Part 8: TABLE -> TEMPORARY TABLE transitions
|
||||
=====================================================================
|
||||
# Test 8-a: base table used recreated as temporary table
|
||||
create table t1 (a int);
|
||||
prepare stmt from "select * from t1";
|
||||
execute stmt;
|
||||
|
@ -462,6 +491,37 @@ SUCCESS
|
|||
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
# Test 8-b: temporary table has precedence over base table with same name
|
||||
create table t1 (a int);
|
||||
prepare stmt from 'select count(*) from t1';
|
||||
execute stmt;
|
||||
count(*)
|
||||
0
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
count(*)
|
||||
0
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
create temporary table t1 AS SELECT 1;
|
||||
execute stmt;
|
||||
count(*)
|
||||
1
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
count(*)
|
||||
1
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop temporary table t1;
|
||||
drop table t1;
|
||||
=====================================================================
|
||||
Part 9: TABLE -> VIEW transitions
|
||||
=====================================================================
|
||||
|
@ -503,6 +563,7 @@ deallocate prepare stmt;
|
|||
=====================================================================
|
||||
Part 11: TEMPORARY TABLE -> TABLE transitions
|
||||
=====================================================================
|
||||
# Test 11-a: temporary table replaced by base table
|
||||
create table t1 (a int);
|
||||
insert into t1 (a) value (1);
|
||||
create temporary table t1 (a int);
|
||||
|
@ -524,6 +585,38 @@ a
|
|||
1
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
# Test 11-b: temporary table has precedence over base table with same name
|
||||
# temporary table disappears
|
||||
create table t1 (a int);
|
||||
create temporary table t1 as select 1 as a;
|
||||
prepare stmt from "select count(*) from t1";
|
||||
execute stmt;
|
||||
count(*)
|
||||
1
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
count(*)
|
||||
1
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop temporary table t1;
|
||||
execute stmt;
|
||||
count(*)
|
||||
0
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
count(*)
|
||||
0
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
=====================================================================
|
||||
Part 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions
|
||||
=====================================================================
|
||||
|
@ -663,6 +756,8 @@ a b c
|
|||
# Currently a different result from conventional statements.
|
||||
# A view is inlined once at prepare, later on view DDL
|
||||
# does not affect prepared statement and it is not re-prepared.
|
||||
# This is reported in Bug#36002 Prepared statements: if a view
|
||||
# used in a statement is replaced, bad data
|
||||
execute stmt;
|
||||
a b c
|
||||
10 20 30
|
||||
|
@ -738,6 +833,7 @@ drop procedure p1;
|
|||
create procedure p1(out x int) select max(a) from t2 into x;
|
||||
# XXX: bug. The prelocked list is not invalidated
|
||||
# and we keep opening table t1, whereas the procedure
|
||||
# is now referring to table t2
|
||||
execute stmt;
|
||||
ERROR HY000: View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||
call p_verify_reprepare_count(0);
|
||||
|
@ -1005,7 +1101,7 @@ prepare stmt from "alter table t1 add column b int";
|
|||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (a1 int, a2 int);
|
||||
# t1 has changed, and it's does not lead to reprepare
|
||||
# t1 has changed, and it's does not lead to reprepare
|
||||
execute stmt;
|
||||
alter table t1 drop column b;
|
||||
execute stmt;
|
||||
|
@ -1028,7 +1124,7 @@ test.t1 repair status OK
|
|||
drop table t1;
|
||||
create table t1 (a1 int, a2 int);
|
||||
insert into t1 values (1, 10), (2, 20), (3, 30);
|
||||
# t1 has changed, and it's does not lead to reprepare
|
||||
# t1 has changed, and it's does not lead to reprepare
|
||||
execute stmt;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 repair status OK
|
||||
|
@ -1331,7 +1427,7 @@ insert into t_27430_2 values
|
|||
(2, 2),
|
||||
(1234, 3),
|
||||
(1234, 4);
|
||||
prepare stmt from
|
||||
prepare stmt from
|
||||
"select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2";
|
||||
execute stmt;
|
||||
oref a Z
|
||||
|
@ -1344,7 +1440,7 @@ SUCCESS
|
|||
|
||||
drop table t_27430_1, t_27430_2;
|
||||
create table t_27430_1 (a int, oref int, key(a));
|
||||
insert into t_27430_1 values
|
||||
insert into t_27430_1 values
|
||||
(1, 1),
|
||||
(1, NULL),
|
||||
(2, 3),
|
||||
|
@ -1497,8 +1593,617 @@ drop function f_12093;
|
|||
drop procedure p_12093;
|
||||
deallocate prepare stmt_sf;
|
||||
deallocate prepare stmt_sp;
|
||||
=====================================================================
|
||||
Ensure that metadata validation is performed for every type of
|
||||
SQL statement where it is needed.
|
||||
=====================================================================
|
||||
#
|
||||
# SQLCOM_SELECT
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "select 1 as res from dual where (1) in (select * from t1)";
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
res
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
#
|
||||
# SQLCOM_CREATE_TABLE
|
||||
#
|
||||
drop table if exists t1;
|
||||
drop table if exists t2;
|
||||
create table t1 (a int);
|
||||
prepare stmt from 'create table t2 as select * from t1';
|
||||
execute stmt;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
ERROR 42S01: Table 't2' already exists
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
ERROR 42S01: Table 't2' already exists
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
create temporary table t2 (a int);
|
||||
execute stmt;
|
||||
ERROR 42S01: Table 't2' already exists
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
ERROR 42S01: Table 't2' already exists
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop temporary table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
create view t2 as select 1;
|
||||
execute stmt;
|
||||
Got one of the listed errors
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
Got one of the listed errors
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop view t2;
|
||||
drop table t1;
|
||||
create table t1 (x varchar(20));
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
select * from t2;
|
||||
x
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
alter table t1 add column y decimal(10,3);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
select * from t2;
|
||||
x y
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
# XXX: no validation of the first table in case of
|
||||
# CREATE TEMPORARY TABLE. This is a shortcoming of the current code,
|
||||
# but since validation is not strictly necessary, nothing is done
|
||||
# about it.
|
||||
# Will be fixed as part of work on Bug#21431 "Incomplete support of
|
||||
# temporary tables"
|
||||
create table t1 (a int);
|
||||
insert into t1 (a) values (1);
|
||||
prepare stmt from "create temporary table if not exists t2 as select * from t1";
|
||||
execute stmt;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
Warnings:
|
||||
Note 1050 Table 't2' already exists
|
||||
select * from t2;
|
||||
a
|
||||
1
|
||||
1
|
||||
execute stmt;
|
||||
Warnings:
|
||||
Note 1050 Table 't2' already exists
|
||||
select * from t2;
|
||||
a
|
||||
1
|
||||
1
|
||||
1
|
||||
drop table t2;
|
||||
create temporary table t2 (a varchar(10));
|
||||
execute stmt;
|
||||
Warnings:
|
||||
Note 1050 Table 't2' already exists
|
||||
select * from t2;
|
||||
a
|
||||
1
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Warnings:
|
||||
Note 1050 Table 't2' already exists
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
Warnings:
|
||||
Note 1050 Table 't2' already exists
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t1;
|
||||
drop temporary table t2;
|
||||
drop table t2;
|
||||
deallocate prepare stmt;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "create table t2 like t1";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
drop table t1;
|
||||
execute stmt;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
create table t1 (x char(17));
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t2;
|
||||
alter table t1 add column y time;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
select * from t2;
|
||||
x y
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_UPDATE
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "update t2 set a=a+1 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_INSERT
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "insert into t2 set a=((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_INSERT_SELECT
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "insert into t2 select * from t1";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_REPLACE
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "replace t2 set a=((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_REPLACE_SELECT
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "replace t2 select * from t1";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_DELETE
|
||||
#
|
||||
drop table if exists t1, t2;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "delete from t2 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_DELETE_MULTI
|
||||
#
|
||||
drop table if exists t1, t2, t3;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
create table t3 (a int);
|
||||
prepare stmt from "delete t2, t3 from t2, t3 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2, t3;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_UPDATE_MULTI
|
||||
#
|
||||
drop table if exists t1, t2, t3;
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
create table t3 (a int);
|
||||
prepare stmt from "update t2, t3 set t3.a=t2.a, t2.a=null where (1) in (select * from t1)";
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2, t3;
|
||||
deallocate prepare stmt;
|
||||
# Intermediate results: 8 SQLCOMs tested, 8 automatic reprepares
|
||||
call p_verify_reprepare_count(8);
|
||||
SUCCESS
|
||||
|
||||
#
|
||||
# SQLCOM_LOAD
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a varchar(20));
|
||||
prepare stmt from "load data infile '../std_data_ln/words.dat' into table t1";
|
||||
ERROR HY000: This command is not supported in the prepared statement protocol yet
|
||||
drop table t1;
|
||||
#
|
||||
# SQLCOM_SHOW_DATABASES
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show databases where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Database
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Database
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_TABLES
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show tables where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Tables_in_test
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Tables_in_test
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_FIELDS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show fields from t1 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Field Type Null Key Default Extra
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Field Type Null Key Default Extra
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_KEYS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show keys from t1 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_VARIABLES
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show variables where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Variable_name Value
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Variable_name Value
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_STATUS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Variable_name Value
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Variable_name Value
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_LOGS,
|
||||
# SQLCOM_SHOW_ENGINE_MUTEX, SQLCOM_SHOW_PROCESSLIST
|
||||
#
|
||||
# Currently can not have a where clause, need to be covered
|
||||
# with tests
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show engine all status where (1) in (select * from t1)";
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1
|
||||
prepare stmt from "show engine all logs where (1) in (select * from t1)";
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1
|
||||
prepare stmt from "show engine all mutex where (1) in (select * from t1)";
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1
|
||||
prepare stmt from "show processlist where (1) in (select * from t1)";
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where (1) in (select * from t1)' at line 1
|
||||
drop table t1;
|
||||
#
|
||||
# SQLCOM_SHOW_CHARSETS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show charset where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Charset Description Default collation Maxlen
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Charset Description Default collation Maxlen
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_COLLATIONS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show collation where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Collation Charset Id Default Compiled Sortlen
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Collation Charset Id Default Compiled Sortlen
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_TABLE_STATUS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show table status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_TRIGGERS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show triggers where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Trigger Event Table Statement Timing Created sql_mode Definer character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_OPEN_TABLES
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show open tables where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Database Table In_use Name_locked
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Database Table In_use Name_locked
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_STATUS_PROC
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show procedure status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_STATUS_FUNC
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show function status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Db Name Type Definer Modified Created Security_type Comment character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SHOW_EVENTS
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show events where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_SET_OPTION
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "set @a=((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_DO
|
||||
#
|
||||
drop table if exists t1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "do ((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_CALL
|
||||
#
|
||||
drop table if exists t1;
|
||||
drop procedure if exists p1;
|
||||
create procedure p1(a int) begin end;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "call p1((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
drop procedure p1;
|
||||
deallocate prepare stmt;
|
||||
#
|
||||
# SQLCOM_CREATE_VIEW
|
||||
#
|
||||
drop table if exists t1;
|
||||
drop view if exists v1;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "create view v1 as select * from t1";
|
||||
execute stmt;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
# Intermediate result: number of reprepares matches the number
|
||||
# of tests
|
||||
call p_verify_reprepare_count(18);
|
||||
SUCCESS
|
||||
|
||||
#
|
||||
# SQLCOM_ALTER_VIEW
|
||||
#
|
||||
drop view if exists v1;
|
||||
create view v1 as select 1;
|
||||
prepare stmt from "alter view v1 as select 2";
|
||||
ERROR HY000: This command is not supported in the prepared statement protocol yet
|
||||
drop view v1;
|
||||
# Cleanup
|
||||
#
|
||||
#
|
||||
drop temporary table if exists t1, t2, t3;
|
||||
drop table if exists t1, t2, t3, v1, v2;
|
||||
drop procedure if exists p_verify_reprepare_count;
|
||||
|
|
482
mysql-test/r/ps_ddl1.result
Normal file
482
mysql-test/r/ps_ddl1.result
Normal file
|
@ -0,0 +1,482 @@
|
|||
drop temporary table if exists t1;
|
||||
drop table if exists t1, t2;
|
||||
drop procedure if exists p_verify_reprepare_count;
|
||||
drop procedure if exists p1;
|
||||
drop function if exists f1;
|
||||
drop view if exists t1;
|
||||
drop schema if exists mysqltest;
|
||||
create procedure p_verify_reprepare_count(expected int)
|
||||
begin
|
||||
declare old_reprepare_count int default @reprepare_count;
|
||||
select variable_value from
|
||||
information_schema.session_status where
|
||||
variable_name='com_stmt_reprepare'
|
||||
into @reprepare_count;
|
||||
if old_reprepare_count + expected <> @reprepare_count then
|
||||
select concat("Expected: ", expected,
|
||||
", actual: ", @reprepare_count - old_reprepare_count)
|
||||
as "ERROR";
|
||||
else
|
||||
select '' as "SUCCESS";
|
||||
end if;
|
||||
end|
|
||||
set @reprepare_count= 0;
|
||||
flush status;
|
||||
drop table if exists t1;
|
||||
# Column added or dropped is not within the list of selected columns
|
||||
# or table comment has changed.
|
||||
# A reprepare is probably not needed.
|
||||
create table t1 (a int, b int);
|
||||
prepare stmt from "select a from t1";
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
alter table t1 add column c int;
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
alter table t1 drop column b;
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
alter table t1 comment "My best table";
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
a
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
# Selects using the table at various positions, inser,update ...
|
||||
# + the table disappears
|
||||
create table t1 (a int);
|
||||
prepare stmt1 from "truncate t1";
|
||||
prepare stmt2 from "select 1 as my_column from t1";
|
||||
prepare stmt3 from "select 1 as my_column from (select * from t1) as t2";
|
||||
prepare stmt4 from
|
||||
"select 1 as my_column from (select 1) as t2 where exists (select 1 from t1)";
|
||||
prepare stmt5 from "select * from (select 1 as b) as t2, t1";
|
||||
prepare stmt6 from "select * from t1 union all select 1.5";
|
||||
prepare stmt7 from "select 1 as my_column union all select 1 from t1";
|
||||
prepare stmt8 from "insert into t1 values(1),(2)";
|
||||
prepare stmt9 from "update t1 set a = 3 where a = 2";
|
||||
prepare stmt10 from "delete from t1 where a = 1";
|
||||
# Attention: Result logging is disabled.
|
||||
execute stmt10;
|
||||
execute stmt9;
|
||||
execute stmt8;
|
||||
execute stmt7;
|
||||
execute stmt6;
|
||||
execute stmt5;
|
||||
execute stmt4;
|
||||
execute stmt3;
|
||||
execute stmt2;
|
||||
execute stmt1;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t1;
|
||||
execute stmt10;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt9;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt8;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt7;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt6;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt5;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt4;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt3;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt2;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
execute stmt1;
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
deallocate prepare stmt10;
|
||||
deallocate prepare stmt9;
|
||||
deallocate prepare stmt8;
|
||||
deallocate prepare stmt7;
|
||||
deallocate prepare stmt6;
|
||||
deallocate prepare stmt5;
|
||||
deallocate prepare stmt4;
|
||||
deallocate prepare stmt3;
|
||||
deallocate prepare stmt2;
|
||||
deallocate prepare stmt1;
|
||||
# Selects using the table at various positions, inser,update ...
|
||||
# + layout change (drop column) which must cause a reprepare
|
||||
create table t1 (a int, b int);
|
||||
insert into t1 values(1,1),(2,2),(3,3);
|
||||
create table t2 like t1;
|
||||
insert into t1 values(2,2);
|
||||
prepare stmt1 from "select a,b from t1";
|
||||
prepare stmt2 from "select a,b from (select * from t1) as t1";
|
||||
prepare stmt3 from "select * from t1 where a = 2 and b = 2";
|
||||
prepare stmt4 from "select * from t2 where (a,b) in (select * from t1)";
|
||||
prepare stmt5 from "select * from t1 union select * from t2";
|
||||
prepare stmt6 from "select * from t1 union all select * from t2";
|
||||
prepare stmt7 from "insert into t1 set a = 4, b = 4";
|
||||
prepare stmt8 from "insert into t1 select * from t2";
|
||||
# Attention: Result logging is disabled.
|
||||
execute stmt8;
|
||||
execute stmt7;
|
||||
execute stmt6;
|
||||
execute stmt5;
|
||||
execute stmt4;
|
||||
execute stmt3;
|
||||
execute stmt2;
|
||||
execute stmt1;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
alter table t1 drop column b;
|
||||
execute stmt8;
|
||||
ERROR 21S01: Column count doesn't match value count at row 1
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt7;
|
||||
ERROR 42S22: Unknown column 'b' in 'field list'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt6;
|
||||
ERROR 21000: The used SELECT statements have a different number of columns
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt5;
|
||||
ERROR 21000: The used SELECT statements have a different number of columns
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt4;
|
||||
ERROR 21000: Operand should contain 2 column(s)
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt3;
|
||||
ERROR 42S22: Unknown column 'b' in 'where clause'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt2;
|
||||
ERROR 42S22: Unknown column 'b' in 'field list'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt1;
|
||||
ERROR 42S22: Unknown column 'b' in 'field list'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt8;
|
||||
ERROR 21S01: Column count doesn't match value count at row 1
|
||||
call p_verify_reprepare_count(1);
|
||||
ERROR
|
||||
Expected: 1, actual: 0
|
||||
execute stmt7;
|
||||
ERROR 42S22: Unknown column 'b' in 'field list'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt6;
|
||||
ERROR 21000: The used SELECT statements have a different number of columns
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt5;
|
||||
ERROR 21000: The used SELECT statements have a different number of columns
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt4;
|
||||
ERROR 21000: Operand should contain 2 column(s)
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt3;
|
||||
ERROR 42S22: Unknown column 'b' in 'where clause'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt2;
|
||||
ERROR 42S22: Unknown column 'b' in 'field list'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt1;
|
||||
ERROR 42S22: Unknown column 'b' in 'field list'
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
# Why does the INSERT ... SELECT does not get a reprepare or is
|
||||
# only the counter not incremented?
|
||||
execute stmt8;
|
||||
ERROR 21S01: Column count doesn't match value count at row 1
|
||||
call p_verify_reprepare_count(1);
|
||||
ERROR
|
||||
Expected: 1, actual: 0
|
||||
alter table t2 add column c int;
|
||||
execute stmt8;
|
||||
ERROR 21S01: Column count doesn't match value count at row 1
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
deallocate prepare stmt8;
|
||||
deallocate prepare stmt7;
|
||||
deallocate prepare stmt6;
|
||||
deallocate prepare stmt5;
|
||||
deallocate prepare stmt4;
|
||||
deallocate prepare stmt3;
|
||||
deallocate prepare stmt2;
|
||||
deallocate prepare stmt1;
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
# select AVG(<col>) + optimizer uses index meets loss of the index
|
||||
create table t1 (a int, b int, primary key(b),unique index t1_unq_idx(a));
|
||||
insert into t1 set a = 0, b = 0;
|
||||
insert into t1 select a + 1, b + 1 from t1;
|
||||
insert into t1 select a + 2, b + 2 from t1;
|
||||
insert into t1 select a + 4, b + 4 from t1;
|
||||
insert into t1 select a + 8, b + 8 from t1;
|
||||
# Optimizer strategy: Possible keys = NULL , Extra = Using index
|
||||
prepare stmt from "select avg(a) from t1";
|
||||
execute stmt;
|
||||
avg(a)
|
||||
7.5000
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
avg(a)
|
||||
7.5000
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
alter table t1 drop index t1_unq_idx;
|
||||
# Optimizer strategy: Possible keys = NULL , Extra =
|
||||
execute stmt;
|
||||
avg(a)
|
||||
7.5000
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
avg(a)
|
||||
7.5000
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
# select AVG(<col>) + optimizer uses table scan meets a new index
|
||||
alter table t1 add unique index t1_unq_idx(a);
|
||||
# Optimizer strategy: Possible keys = NULL , Extra = Using index
|
||||
execute stmt;
|
||||
avg(a)
|
||||
7.5000
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
avg(a)
|
||||
7.5000
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
# table replaced by not updatable view - Insert
|
||||
create table t1 (a int);
|
||||
prepare stmt from "insert into t1 values(1)";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop table t1;
|
||||
create view t1 as select 1;
|
||||
execute stmt;
|
||||
ERROR HY000: The target table t1 of the INSERT is not insertable-into
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
drop view t1;
|
||||
create table t2 (a int);
|
||||
create view t1 as select * from t2 with check option;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
1
|
||||
deallocate prepare stmt;
|
||||
drop view t1;
|
||||
drop table t2;
|
||||
=====================================================================
|
||||
Some freestyle tests
|
||||
=====================================================================
|
||||
create temporary table t1 as select 1 as a;
|
||||
create procedure p1()
|
||||
begin
|
||||
drop temporary table t1;
|
||||
end|
|
||||
create function f1() returns int
|
||||
begin
|
||||
call p1();
|
||||
return 1;
|
||||
end|
|
||||
prepare stmt from "select f1() as my_column, a from t1";
|
||||
execute stmt;
|
||||
ERROR HY000: Can't reopen table: 't1'
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
prepare stmt from "select a, f1() as my_column from t1";
|
||||
execute stmt;
|
||||
ERROR HY000: Can't reopen table: 't1'
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
prepare stmt from "select f1() as my_column, count(*) from t1";
|
||||
execute stmt;
|
||||
ERROR HY000: Can't reopen table: 't1'
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
prepare stmt from "select count(*), f1() as my_column from t1";
|
||||
execute stmt;
|
||||
ERROR HY000: Can't reopen table: 't1'
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
# Execute fails, no drop of temporary table
|
||||
prepare stmt from "select 1 as my_column from (select 1) as t2
|
||||
where exists (select f1() from t1)";
|
||||
execute stmt;
|
||||
my_column
|
||||
1
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
my_column
|
||||
1
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
# Execute drops temporary table
|
||||
prepare stmt from "select f1()";
|
||||
execute stmt;
|
||||
f1()
|
||||
1
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
ERROR 42S02: Unknown table 't1'
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
drop function f1;
|
||||
drop procedure p1;
|
||||
deallocate prepare stmt;
|
||||
# Execute fails, temporary table is not replaced by another
|
||||
create temporary table t1 as select 1 as a;
|
||||
create procedure p1()
|
||||
begin
|
||||
drop temporary table t1;
|
||||
create temporary table t1 as select 'abc' as a;
|
||||
end|
|
||||
create function f1() returns int
|
||||
begin
|
||||
call p1();
|
||||
return 1;
|
||||
end|
|
||||
prepare stmt from "select count(*), f1() as my_column from t1";
|
||||
execute stmt;
|
||||
ERROR HY000: Can't reopen table: 't1'
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from "call p1";
|
||||
execute stmt;
|
||||
drop procedure p1;
|
||||
create schema mysqltest;
|
||||
create procedure mysqltest.p1()
|
||||
begin
|
||||
drop schema mysqltest;
|
||||
create schema mysqltest;
|
||||
end|
|
||||
execute stmt;
|
||||
ERROR 42000: PROCEDURE test.p1 does not exist
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
execute stmt;
|
||||
ERROR 42000: PROCEDURE test.p1 does not exist
|
||||
call p_verify_reprepare_count(0);
|
||||
SUCCESS
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop schema mysqltest;
|
||||
drop temporary table t1;
|
||||
# Cleanup
|
||||
#
|
||||
drop temporary table if exists t1;
|
||||
drop table if exists t1, t2;
|
||||
drop procedure if exists p_verify_reprepare_count;
|
||||
drop procedure if exists p1;
|
||||
drop function if exists f1;
|
||||
drop view if exists t1;
|
||||
drop schema if exists mysqltest;
|
|
@ -18,3 +18,4 @@ Variable_name Value
|
|||
Qcache_queries_in_cache 0
|
||||
drop table t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t257,t00;
|
||||
SET @@global.query_cache_size=0;
|
||||
set @@global.table_definition_cache=@save_table_definition_cache;
|
||||
|
|
|
@ -820,7 +820,6 @@ call p1();
|
|||
drop trigger t1_bi;
|
||||
create trigger t1_bi after insert on t1 for each row insert into t3 values (new.id);
|
||||
execute stmt1;
|
||||
ERROR 42S02: Table 'test.t3' doesn't exist
|
||||
call p1();
|
||||
ERROR 42S02: Table 'test.t3' doesn't exist
|
||||
deallocate prepare stmt1;
|
||||
|
|
|
@ -16,6 +16,5 @@ federated_transactions : Bug#29523 Transactions do not work
|
|||
lowercase_table3 : Bug#32667 lowercase_table3.test reports to error log
|
||||
ctype_create : Bug#32965 main.ctype_create fails
|
||||
status : Bug#32966 main.status fails
|
||||
ps_ddl : Bug#12093 2007-12-14 pending WL#4165 / WL#4166
|
||||
csv_alter_table : Bug#33696 2008-01-21 pcrews no .result file - bug allows NULL columns in CSV tables
|
||||
cast : Bug#35594 2008-03-27 main.cast fails on Windows2003-64
|
||||
|
|
|
@ -181,7 +181,7 @@ create table t5
|
|||
a int primary key,
|
||||
b char(30),
|
||||
c int,
|
||||
d timestamp default current_timestamp
|
||||
d timestamp default '2008-02-23 09:23:45'
|
||||
);
|
||||
insert into t5( a, b, c) values( 9, 'recreated table', 9);
|
||||
execute stmt2 ;
|
||||
|
@ -191,7 +191,7 @@ drop table t5 ;
|
|||
create table t5
|
||||
(
|
||||
a int primary key,
|
||||
d timestamp default current_timestamp,
|
||||
d timestamp default '2008-02-23 09:23:45',
|
||||
b char(30),
|
||||
c int
|
||||
);
|
||||
|
@ -218,7 +218,6 @@ create table t5
|
|||
f3 int
|
||||
);
|
||||
insert into t5( f1, f2, f3) values( 9, 'recreated table', 9);
|
||||
--error 1054
|
||||
execute stmt2 ;
|
||||
drop table t5 ;
|
||||
|
||||
|
|
|
@ -104,6 +104,7 @@ prepare stmt from "select * from t1";
|
|||
--echo Part 4: TABLE -> NOTHING transitions
|
||||
--echo =====================================================================
|
||||
|
||||
--echo # Test 4-a: select ... from <table>
|
||||
create table t1 (a int);
|
||||
|
||||
prepare stmt from "select * from t1";
|
||||
|
@ -121,6 +122,25 @@ execute stmt;
|
|||
call p_verify_reprepare_count(0);
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo # Test 4-b: TABLE -> NOTHING by renaming the table
|
||||
create table t1 (a int);
|
||||
prepare stmt from "select * from t1";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
rename table t1 to t2;
|
||||
--error ER_NO_SUCH_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
--error ER_NO_SUCH_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop table t2;
|
||||
|
||||
--echo =====================================================================
|
||||
--echo Part 5: TABLE -> TABLE (DDL) transitions
|
||||
--echo =====================================================================
|
||||
|
@ -143,11 +163,11 @@ call p_verify_reprepare_count(0);
|
|||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
|
||||
--echo =====================================================================
|
||||
--echo Part 6: TABLE -> TABLE (TRIGGER) transitions
|
||||
--echo =====================================================================
|
||||
|
||||
|
||||
--echo # Test 6-a: adding a relevant trigger
|
||||
|
||||
create table t1 (a int);
|
||||
|
@ -181,7 +201,7 @@ select @message;
|
|||
# Unrelated trigger: reprepare may or may not happen, implementation dependent
|
||||
create trigger t1_bd before delete on t1 for each row
|
||||
set @message= old.a;
|
||||
|
||||
|
||||
set @val=5;
|
||||
execute stmt using @val;
|
||||
call p_verify_reprepare_count(1);
|
||||
|
@ -229,7 +249,7 @@ execute stmt using @val;
|
|||
call p_verify_reprepare_count(1);
|
||||
select @message;
|
||||
|
||||
--ehco Test 6-e: removing a relevant trigger
|
||||
--echo Test 6-e: removing a relevant trigger
|
||||
|
||||
drop trigger t1_bi;
|
||||
|
||||
|
@ -338,7 +358,7 @@ call p_verify_reprepare_count(0);
|
|||
--echo #
|
||||
--echo # Sic: the insert went into t3, even though the view now
|
||||
--echo # points at t2. This is because neither the merged view
|
||||
--echo # nor its prelocking list are affected by view DDL
|
||||
--echo # nor its prelocking list are affected by view DDL
|
||||
--echo # The binary log is of course wrong, since it is not
|
||||
--echo # using prepared statements
|
||||
--echo #
|
||||
|
@ -367,7 +387,7 @@ set @var=2;
|
|||
--echo # Since the dependent table is tracked in the prelocked
|
||||
--echo # list of the prepared statement, invalidation happens
|
||||
--echo # and the statement is re-prepared. This is an unnecessary
|
||||
--echo # side effect, since the statement that *is* dependent
|
||||
--echo # side effect, since the statement that *is* dependent
|
||||
--echo # on t2 definition is inside the trigger, and it is currently
|
||||
--echo # not reprepared (see the previous test case).
|
||||
execute stmt using @var;
|
||||
|
@ -378,7 +398,7 @@ drop table t1,t2;
|
|||
|
||||
--echo # Test 7-e: dependent TABLE TRIGGER has changed
|
||||
create table t1 (a int);
|
||||
create trigger t1_ai after insert on t1 for each row
|
||||
create trigger t1_ai after insert on t1 for each row
|
||||
insert into t2 (a) values (new.a);
|
||||
create table t2 (a int unique);
|
||||
create trigger t2_ai after insert on t2 for each row
|
||||
|
@ -414,6 +434,7 @@ deallocate prepare stmt;
|
|||
--echo Part 8: TABLE -> TEMPORARY TABLE transitions
|
||||
--echo =====================================================================
|
||||
|
||||
--echo # Test 8-a: base table used recreated as temporary table
|
||||
create table t1 (a int);
|
||||
|
||||
prepare stmt from "select * from t1";
|
||||
|
@ -430,6 +451,25 @@ call p_verify_reprepare_count(0);
|
|||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo # Test 8-b: temporary table has precedence over base table with same name
|
||||
create table t1 (a int);
|
||||
prepare stmt from 'select count(*) from t1';
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
create temporary table t1 AS SELECT 1;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop temporary table t1;
|
||||
drop table t1;
|
||||
|
||||
|
||||
--echo =====================================================================
|
||||
--echo Part 9: TABLE -> VIEW transitions
|
||||
--echo =====================================================================
|
||||
|
@ -471,6 +511,7 @@ deallocate prepare stmt;
|
|||
--echo Part 11: TEMPORARY TABLE -> TABLE transitions
|
||||
--echo =====================================================================
|
||||
|
||||
--echo # Test 11-a: temporary table replaced by base table
|
||||
create table t1 (a int);
|
||||
insert into t1 (a) value (1);
|
||||
create temporary table t1 (a int);
|
||||
|
@ -488,6 +529,27 @@ select * from t1;
|
|||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
|
||||
--echo # Test 11-b: temporary table has precedence over base table with same name
|
||||
--echo # temporary table disappears
|
||||
create table t1 (a int);
|
||||
create temporary table t1 as select 1 as a;
|
||||
prepare stmt from "select count(*) from t1";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
drop temporary table t1;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
|
||||
|
||||
--echo =====================================================================
|
||||
--echo Part 12: TEMPORARY TABLE -> TEMPORARY TABLE (DDL) transitions
|
||||
--echo =====================================================================
|
||||
|
@ -614,6 +676,8 @@ select * from t1;
|
|||
--echo # Currently a different result from conventional statements.
|
||||
--echo # A view is inlined once at prepare, later on view DDL
|
||||
--echo # does not affect prepared statement and it is not re-prepared.
|
||||
--echo # This is reported in Bug#36002 Prepared statements: if a view
|
||||
--echo # used in a statement is replaced, bad data
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
flush table t2;
|
||||
|
@ -672,7 +736,7 @@ drop procedure p1;
|
|||
create procedure p1(out x int) select max(a) from t2 into x;
|
||||
--echo # XXX: bug. The prelocked list is not invalidated
|
||||
--echo # and we keep opening table t1, whereas the procedure
|
||||
--ehco # is now referring to table t2
|
||||
--echo # is now referring to table t2
|
||||
--error ER_VIEW_INVALID
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
@ -700,7 +764,7 @@ execute stmt;
|
|||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
--echo # Test 18-d: dependent TABLE has changed
|
||||
drop view v2;
|
||||
drop view v2;
|
||||
create table v2 as select * from t1;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
|
@ -852,7 +916,7 @@ execute stmt;
|
|||
drop table t1;
|
||||
create table t1 (a1 int, a2 int);
|
||||
|
||||
--echo # t1 has changed, and it's does not lead to reprepare
|
||||
--echo # t1 has changed, and it's does not lead to reprepare
|
||||
execute stmt;
|
||||
|
||||
alter table t1 drop column b;
|
||||
|
@ -879,7 +943,7 @@ drop table t1;
|
|||
create table t1 (a1 int, a2 int);
|
||||
insert into t1 values (1, 10), (2, 20), (3, 30);
|
||||
|
||||
--echo # t1 has changed, and it's does not lead to reprepare
|
||||
--echo # t1 has changed, and it's does not lead to reprepare
|
||||
execute stmt;
|
||||
|
||||
alter table t1 add column b varchar(50) default NULL;
|
||||
|
@ -1188,16 +1252,16 @@ insert into t_27430_2 values
|
|||
(1234, 3),
|
||||
(1234, 4);
|
||||
|
||||
prepare stmt from
|
||||
prepare stmt from
|
||||
"select oref, a, a in (select a from t_27430_1 where oref=t_27430_2.oref) Z from t_27430_2";
|
||||
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
drop table t_27430_1, t_27430_2;
|
||||
|
||||
create table t_27430_1 (a int, oref int, key(a));
|
||||
insert into t_27430_1 values
|
||||
insert into t_27430_1 values
|
||||
(1, 1),
|
||||
(1, NULL),
|
||||
(2, 3),
|
||||
|
@ -1235,7 +1299,7 @@ insert into t_27690_1 values (1,1),(2,2);
|
|||
create table v_27690_1 as select * from t_27690_1;
|
||||
create table v_27690_2 as select * from t_27690_1;
|
||||
|
||||
prepare stmt from "select * from v_27690_1, v_27690_2";
|
||||
prepare stmt from "select * from v_27690_1, v_27690_2";
|
||||
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
|
@ -1325,17 +1389,17 @@ drop procedure p_12093_unrelated;
|
|||
connection default;
|
||||
|
||||
--echo # XXX: bug
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
execute stmt_sf;
|
||||
--echo # XXX: bug
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
execute stmt_sp;
|
||||
|
||||
--echo # XXX: bug
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
execute stmt_sf;
|
||||
--echo # XXX: bug
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
execute stmt_sp;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
|
@ -1347,8 +1411,656 @@ drop procedure p_12093;
|
|||
deallocate prepare stmt_sf;
|
||||
deallocate prepare stmt_sp;
|
||||
|
||||
|
||||
--echo =====================================================================
|
||||
--echo Ensure that metadata validation is performed for every type of
|
||||
--echo SQL statement where it is needed.
|
||||
--echo =====================================================================
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SELECT
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "select 1 as res from dual where (1) in (select * from t1)";
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_CREATE_TABLE
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
drop table if exists t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from 'create table t2 as select * from t1';
|
||||
execute stmt;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
# Base table with name of table to be created exists
|
||||
--error ER_TABLE_EXISTS_ERROR
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
--error ER_TABLE_EXISTS_ERROR
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t2;
|
||||
# Temporary table with name of table to be created exists
|
||||
create temporary table t2 (a int);
|
||||
--error ER_TABLE_EXISTS_ERROR
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
--error ER_TABLE_EXISTS_ERROR
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop temporary table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t2;
|
||||
# View with name of table to be created exists
|
||||
# Attention:
|
||||
# We cannot print the error message because it contains a random filename.
|
||||
# Example: 1050: Table '<some_path>/var/tmp/#sql_6979_0' already exists
|
||||
# Therefore we mangle it via
|
||||
# "--error ER_TABLE_EXISTS_ERROR,9999" (9999 is currently not used)
|
||||
# to "Got one of the listed errors".
|
||||
create view t2 as select 1;
|
||||
--error ER_TABLE_EXISTS_ERROR,9999
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
--error ER_TABLE_EXISTS_ERROR,9999
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop view t2;
|
||||
drop table t1;
|
||||
# Table to be used recreated (drop,create) with different layout
|
||||
create table t1 (x varchar(20));
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
select * from t2;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t2;
|
||||
# Table to be used has a modified (alter table) layout
|
||||
alter table t1 add column y decimal(10,3);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
select * from t2;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
--echo # XXX: no validation of the first table in case of
|
||||
--echo # CREATE TEMPORARY TABLE. This is a shortcoming of the current code,
|
||||
--echo # but since validation is not strictly necessary, nothing is done
|
||||
--echo # about it.
|
||||
--echo # Will be fixed as part of work on Bug#21431 "Incomplete support of
|
||||
--echo # temporary tables"
|
||||
create table t1 (a int);
|
||||
insert into t1 (a) values (1);
|
||||
prepare stmt from "create temporary table if not exists t2 as select * from t1";
|
||||
execute stmt;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
execute stmt;
|
||||
select * from t2;
|
||||
execute stmt;
|
||||
select * from t2;
|
||||
drop table t2;
|
||||
create temporary table t2 (a varchar(10));
|
||||
execute stmt;
|
||||
select * from t2;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t1;
|
||||
drop temporary table t2;
|
||||
drop table t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
create table t1 (a int);
|
||||
prepare stmt from "create table t2 like t1";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t2;
|
||||
# Table to be used does not exist
|
||||
drop table t1;
|
||||
--error ER_NO_SUCH_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
--error ER_NO_SUCH_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
# Table to be used recreated (drop,create) with different layout
|
||||
create table t1 (x char(17));
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t2;
|
||||
# Table to be used has a modified (alter table) layout
|
||||
alter table t1 add column y time;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
select * from t2;
|
||||
drop table t2;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_UPDATE
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "update t2 set a=a+1 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_INSERT
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "insert into t2 set a=((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_INSERT_SELECT
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "insert into t2 select * from t1";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_REPLACE
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "replace t2 set a=((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_REPLACE_SELECT
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "replace t2 select * from t1";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_DELETE
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
prepare stmt from "delete from t2 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_DELETE_MULTI
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2, t3;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
create table t3 (a int);
|
||||
prepare stmt from "delete t2, t3 from t2, t3 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2, t3;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_UPDATE_MULTI
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1, t2, t3;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
create table t2 (a int);
|
||||
create table t3 (a int);
|
||||
prepare stmt from "update t2, t3 set t3.a=t2.a, t2.a=null where (1) in (select * from t1)";
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1, t2, t3;
|
||||
deallocate prepare stmt;
|
||||
--echo # Intermediate results: 8 SQLCOMs tested, 8 automatic reprepares
|
||||
call p_verify_reprepare_count(8);
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_LOAD
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a varchar(20));
|
||||
--error ER_UNSUPPORTED_PS
|
||||
prepare stmt from "load data infile '../std_data_ln/words.dat' into table t1";
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_DATABASES
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show databases where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_TABLES
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show tables where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_FIELDS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show fields from t1 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_KEYS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show keys from t1 where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_VARIABLES
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show variables where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_STATUS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_ENGINE_STATUS, SQLCOM_SHOW_ENGINE_LOGS,
|
||||
--echo # SQLCOM_SHOW_ENGINE_MUTEX, SQLCOM_SHOW_PROCESSLIST
|
||||
--echo #
|
||||
|
||||
--echo # Currently can not have a where clause, need to be covered
|
||||
--echo # with tests
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
--error ER_PARSE_ERROR
|
||||
prepare stmt from "show engine all status where (1) in (select * from t1)";
|
||||
--error ER_PARSE_ERROR
|
||||
prepare stmt from "show engine all logs where (1) in (select * from t1)";
|
||||
--error ER_PARSE_ERROR
|
||||
prepare stmt from "show engine all mutex where (1) in (select * from t1)";
|
||||
--error ER_PARSE_ERROR
|
||||
prepare stmt from "show processlist where (1) in (select * from t1)";
|
||||
drop table t1;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_CHARSETS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show charset where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_COLLATIONS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show collation where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_TABLE_STATUS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show table status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_TRIGGERS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show triggers where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_OPEN_TABLES
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show open tables where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_STATUS_PROC
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show procedure status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_STATUS_FUNC
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show function status where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SHOW_EVENTS
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "show events where (1) in (select * from t1)";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_SET_OPTION
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "set @a=((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_DO
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "do ((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_CALL
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
drop procedure if exists p1;
|
||||
--enable_warnings
|
||||
create procedure p1(a int) begin end;
|
||||
create table t1 (a int);
|
||||
prepare stmt from "call p1((1) in (select * from t1))";
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop table t1;
|
||||
drop procedure p1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_CREATE_VIEW
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
drop view if exists v1;
|
||||
--enable_warnings
|
||||
create table t1 (a int);
|
||||
prepare stmt from "create view v1 as select * from t1";
|
||||
execute stmt;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
create table t1 (x int);
|
||||
execute stmt;
|
||||
drop view v1;
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
--echo # Intermediate result: number of reprepares matches the number
|
||||
--echo # of tests
|
||||
call p_verify_reprepare_count(18);
|
||||
|
||||
--echo #
|
||||
--echo # SQLCOM_ALTER_VIEW
|
||||
--echo #
|
||||
|
||||
--disable_warnings
|
||||
drop view if exists v1;
|
||||
--enable_warnings
|
||||
create view v1 as select 1;
|
||||
--error ER_UNSUPPORTED_PS
|
||||
prepare stmt from "alter view v1 as select 2";
|
||||
drop view v1;
|
||||
|
||||
--echo # Cleanup
|
||||
--echo #
|
||||
--echo #
|
||||
--disable_warnings
|
||||
drop temporary table if exists t1, t2, t3;
|
||||
drop table if exists t1, t2, t3, v1, v2;
|
||||
|
|
398
mysql-test/t/ps_ddl1.test
Normal file
398
mysql-test/t/ps_ddl1.test
Normal file
|
@ -0,0 +1,398 @@
|
|||
#
|
||||
# Testing the behavior of 'PREPARE', 'DDL', 'EXECUTE' scenarios
|
||||
#
|
||||
# There are several subtests which are probably "superfluous" because a DDL
|
||||
# statement before the EXECUTE <prepared stmt handle> contained a keyword
|
||||
# or action (Example: Alter) which causes that all prepared statements using
|
||||
# the modified object are reprepared before execution.
|
||||
# Please do not delete these subtests if they disturb. Just disable them by
|
||||
# if (0)
|
||||
# {
|
||||
# <tests to disable>
|
||||
# }.
|
||||
# There might be future optimisations of the server which decrease the amount
|
||||
# of unneeded reprepares or skip unneeded prepare steps and than these subtests
|
||||
# might become valuable.
|
||||
# Example:
|
||||
# Every preceding ALTER TABLE seems to cause a reprepare.
|
||||
# But if the ALTER only changed the table comment ...
|
||||
#
|
||||
# Created: 2008-04-18 mleich
|
||||
#
|
||||
|
||||
--disable_warnings
|
||||
drop temporary table if exists t1;
|
||||
drop table if exists t1, t2;
|
||||
drop procedure if exists p_verify_reprepare_count;
|
||||
drop procedure if exists p1;
|
||||
drop function if exists f1;
|
||||
drop view if exists t1;
|
||||
drop schema if exists mysqltest;
|
||||
--enable_warnings
|
||||
|
||||
delimiter |;
|
||||
create procedure p_verify_reprepare_count(expected int)
|
||||
begin
|
||||
declare old_reprepare_count int default @reprepare_count;
|
||||
|
||||
select variable_value from
|
||||
information_schema.session_status where
|
||||
variable_name='com_stmt_reprepare'
|
||||
into @reprepare_count;
|
||||
|
||||
if old_reprepare_count + expected <> @reprepare_count then
|
||||
select concat("Expected: ", expected,
|
||||
", actual: ", @reprepare_count - old_reprepare_count)
|
||||
as "ERROR";
|
||||
else
|
||||
select '' as "SUCCESS";
|
||||
end if;
|
||||
end|
|
||||
delimiter ;|
|
||||
set @reprepare_count= 0;
|
||||
flush status;
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--disable_warnings
|
||||
|
||||
--echo # Column added or dropped is not within the list of selected columns
|
||||
--echo # or table comment has changed.
|
||||
--echo # A reprepare is probably not needed.
|
||||
create table t1 (a int, b int);
|
||||
prepare stmt from "select a from t1";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
alter table t1 add column c int;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
alter table t1 drop column b;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
alter table t1 comment "My best table";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo # Selects using the table at various positions, inser,update ...
|
||||
--echo # + the table disappears
|
||||
create table t1 (a int);
|
||||
# Attention:
|
||||
# "truncate" must have the first position (= executed as last prepared
|
||||
# statement), because it recreates the table which has leads to reprepare
|
||||
# (is this really needed) of all statements.
|
||||
prepare stmt1 from "truncate t1";
|
||||
prepare stmt2 from "select 1 as my_column from t1";
|
||||
prepare stmt3 from "select 1 as my_column from (select * from t1) as t2";
|
||||
prepare stmt4 from
|
||||
"select 1 as my_column from (select 1) as t2 where exists (select 1 from t1)";
|
||||
prepare stmt5 from "select * from (select 1 as b) as t2, t1";
|
||||
prepare stmt6 from "select * from t1 union all select 1.5";
|
||||
prepare stmt7 from "select 1 as my_column union all select 1 from t1";
|
||||
prepare stmt8 from "insert into t1 values(1),(2)";
|
||||
prepare stmt9 from "update t1 set a = 3 where a = 2";
|
||||
prepare stmt10 from "delete from t1 where a = 1";
|
||||
let ps_stmt_count= 10;
|
||||
--echo # Attention: Result logging is disabled.
|
||||
# Checks of correct results of statements are not the goal of this test.
|
||||
let $num= $ps_stmt_count;
|
||||
while ($num)
|
||||
{
|
||||
--disable_result_log
|
||||
eval execute stmt$num;
|
||||
--enable_result_log
|
||||
dec $num;
|
||||
}
|
||||
# There was no reprepare needed, because none of the objects has changed.
|
||||
call p_verify_reprepare_count(0);
|
||||
drop table t1;
|
||||
let $num= $ps_stmt_count;
|
||||
while ($num)
|
||||
{
|
||||
--error ER_NO_SUCH_TABLE
|
||||
eval execute stmt$num;
|
||||
dec $num;
|
||||
}
|
||||
# There was no reprepare needed, because the statement is no more applicable.
|
||||
call p_verify_reprepare_count(0);
|
||||
let $num= $ps_stmt_count;
|
||||
while ($num)
|
||||
{
|
||||
eval deallocate prepare stmt$num;
|
||||
dec $num;
|
||||
}
|
||||
|
||||
--echo # Selects using the table at various positions, inser,update ...
|
||||
--echo # + layout change (drop column) which must cause a reprepare
|
||||
create table t1 (a int, b int);
|
||||
insert into t1 values(1,1),(2,2),(3,3);
|
||||
create table t2 like t1;
|
||||
insert into t1 values(2,2);
|
||||
prepare stmt1 from "select a,b from t1";
|
||||
prepare stmt2 from "select a,b from (select * from t1) as t1";
|
||||
prepare stmt3 from "select * from t1 where a = 2 and b = 2";
|
||||
prepare stmt4 from "select * from t2 where (a,b) in (select * from t1)";
|
||||
prepare stmt5 from "select * from t1 union select * from t2";
|
||||
prepare stmt6 from "select * from t1 union all select * from t2";
|
||||
prepare stmt7 from "insert into t1 set a = 4, b = 4";
|
||||
prepare stmt8 from "insert into t1 select * from t2";
|
||||
let ps_stmt_count= 8;
|
||||
--echo # Attention: Result logging is disabled.
|
||||
# Checks of correct results of statements are not the goal of this test.
|
||||
let $num= $ps_stmt_count;
|
||||
while ($num)
|
||||
{
|
||||
--disable_result_log
|
||||
eval execute stmt$num;
|
||||
--enable_result_log
|
||||
dec $num;
|
||||
}
|
||||
call p_verify_reprepare_count(0);
|
||||
alter table t1 drop column b;
|
||||
--disable_abort_on_error
|
||||
let $num= $ps_stmt_count;
|
||||
while ($num)
|
||||
{
|
||||
eval execute stmt$num;
|
||||
# A reprepare is needed, because layout change of t1 affects statement.
|
||||
call p_verify_reprepare_count(1);
|
||||
dec $num;
|
||||
}
|
||||
let $num= $ps_stmt_count;
|
||||
while ($num)
|
||||
{
|
||||
eval execute stmt$num;
|
||||
call p_verify_reprepare_count(1);
|
||||
dec $num;
|
||||
}
|
||||
--echo # Why does the INSERT ... SELECT does not get a reprepare or is
|
||||
--echo # only the counter not incremented?
|
||||
eval execute stmt8;
|
||||
call p_verify_reprepare_count(1);
|
||||
--enable_abort_on_error
|
||||
alter table t2 add column c int;
|
||||
--error ER_WRONG_VALUE_COUNT_ON_ROW
|
||||
eval execute stmt8;
|
||||
call p_verify_reprepare_count(1);
|
||||
let $num= $ps_stmt_count;
|
||||
while ($num)
|
||||
{
|
||||
eval deallocate prepare stmt$num;
|
||||
dec $num;
|
||||
}
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
|
||||
|
||||
--echo # select AVG(<col>) + optimizer uses index meets loss of the index
|
||||
create table t1 (a int, b int, primary key(b),unique index t1_unq_idx(a));
|
||||
# We need an index which is not converted to PRIMARY KEY (becomes in
|
||||
# case of InnoDB the key used for table clustering).
|
||||
insert into t1 set a = 0, b = 0;
|
||||
insert into t1 select a + 1, b + 1 from t1;
|
||||
insert into t1 select a + 2, b + 2 from t1;
|
||||
insert into t1 select a + 4, b + 4 from t1;
|
||||
insert into t1 select a + 8, b + 8 from t1;
|
||||
# "using index" optimizer strategy is intended
|
||||
let $possible_keys=
|
||||
query_get_value(explain select avg(a) from t1, possible_keys, 1);
|
||||
let $extra=
|
||||
query_get_value(explain select avg(a) from t1, Extra, 1);
|
||||
--echo # Optimizer strategy: Possible keys = $possible_keys , Extra = $extra
|
||||
prepare stmt from "select avg(a) from t1";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
alter table t1 drop index t1_unq_idx;
|
||||
let $possible_keys=
|
||||
query_get_value(explain select avg(a) from t1, possible_keys, 1);
|
||||
let $extra=
|
||||
query_get_value(explain select avg(a) from t1, Extra, 1);
|
||||
--echo # Optimizer strategy: Possible keys = $possible_keys , Extra = $extra
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
|
||||
--echo # select AVG(<col>) + optimizer uses table scan meets a new index
|
||||
alter table t1 add unique index t1_unq_idx(a);
|
||||
let $possible_keys=
|
||||
query_get_value(explain select avg(a) from t1, possible_keys, 1);
|
||||
let $extra=
|
||||
query_get_value(explain select avg(a) from t1, Extra, 1);
|
||||
--echo # Optimizer strategy: Possible keys = $possible_keys , Extra = $extra
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop table t1;
|
||||
|
||||
|
||||
--echo # table replaced by not updatable view - Insert
|
||||
create table t1 (a int);
|
||||
prepare stmt from "insert into t1 values(1)";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
drop table t1;
|
||||
create view t1 as select 1;
|
||||
--error ER_NON_INSERTABLE_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
|
||||
drop view t1;
|
||||
create table t2 (a int);
|
||||
create view t1 as select * from t2 with check option;
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(1);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
select * from t1;
|
||||
|
||||
deallocate prepare stmt;
|
||||
drop view t1;
|
||||
drop table t2;
|
||||
|
||||
|
||||
--echo =====================================================================
|
||||
--echo Some freestyle tests
|
||||
--echo =====================================================================
|
||||
|
||||
create temporary table t1 as select 1 as a;
|
||||
delimiter |;
|
||||
create procedure p1()
|
||||
begin
|
||||
drop temporary table t1;
|
||||
end|
|
||||
create function f1() returns int
|
||||
begin
|
||||
call p1();
|
||||
return 1;
|
||||
end|
|
||||
delimiter ;|
|
||||
|
||||
prepare stmt from "select f1() as my_column, a from t1";
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
select * from t1;
|
||||
|
||||
prepare stmt from "select a, f1() as my_column from t1";
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
select * from t1;
|
||||
|
||||
prepare stmt from "select f1() as my_column, count(*) from t1";
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
select * from t1;
|
||||
|
||||
prepare stmt from "select count(*), f1() as my_column from t1";
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
select * from t1;
|
||||
|
||||
|
||||
--echo # Execute fails, no drop of temporary table
|
||||
prepare stmt from "select 1 as my_column from (select 1) as t2
|
||||
where exists (select f1() from t1)";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
select * from t1;
|
||||
|
||||
--echo # Execute drops temporary table
|
||||
prepare stmt from "select f1()";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
--error ER_BAD_TABLE_ERROR
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
|
||||
drop function f1;
|
||||
drop procedure p1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
--echo # Execute fails, temporary table is not replaced by another
|
||||
create temporary table t1 as select 1 as a;
|
||||
delimiter |;
|
||||
create procedure p1()
|
||||
begin
|
||||
drop temporary table t1;
|
||||
create temporary table t1 as select 'abc' as a;
|
||||
end|
|
||||
create function f1() returns int
|
||||
begin
|
||||
call p1();
|
||||
return 1;
|
||||
end|
|
||||
delimiter ;|
|
||||
prepare stmt from "select count(*), f1() as my_column from t1";
|
||||
--error ER_CANT_REOPEN_TABLE
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
select * from t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
prepare stmt from "call p1";
|
||||
execute stmt;
|
||||
drop procedure p1;
|
||||
create schema mysqltest;
|
||||
delimiter |;
|
||||
create procedure mysqltest.p1()
|
||||
begin
|
||||
drop schema mysqltest;
|
||||
create schema mysqltest;
|
||||
end|
|
||||
delimiter ;|
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
deallocate prepare stmt;
|
||||
drop schema mysqltest;
|
||||
drop temporary table t1;
|
||||
|
||||
|
||||
# Bug#36089 drop temp table in SP called by function, crash
|
||||
# Note: A non prepared "select 1 from t1 having count(*) = f1();" is sufficient.
|
||||
if (0)
|
||||
{
|
||||
create temporary table t1 as select 1 as a;
|
||||
prepare stmt from "select 1 from t1 having count(*) = f1()";
|
||||
execute stmt;
|
||||
call p_verify_reprepare_count(0);
|
||||
deallocate prepare stmt;
|
||||
drop temporary table t1;
|
||||
}
|
||||
|
||||
|
||||
--echo # Cleanup
|
||||
--echo #
|
||||
--disable_warnings
|
||||
drop temporary table if exists t1;
|
||||
drop table if exists t1, t2;
|
||||
drop procedure if exists p_verify_reprepare_count;
|
||||
drop procedure if exists p1;
|
||||
drop function if exists f1;
|
||||
drop view if exists t1;
|
||||
drop schema if exists mysqltest;
|
||||
--enable_warnings
|
|
@ -25,6 +25,15 @@ while ($1)
|
|||
}
|
||||
--enable_warnings
|
||||
|
||||
#
|
||||
# In order for the test to pass in --ps-protocol, we must
|
||||
# set table_definition_cache size to at least 258 elements.
|
||||
# Otherwise table versions are bound to change between
|
||||
# prepare and execute, and we will get a constant validation
|
||||
# error. See WL#4165 for details.
|
||||
#
|
||||
set @save_table_definition_cache= @@global.table_definition_cache;
|
||||
set @@global.table_definition_cache=512;
|
||||
create table t00 (a int) engine=MERGE UNION=(t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t257) INSERT_METHOD=FIRST;
|
||||
enable_query_log;
|
||||
select count(*) from t00;
|
||||
|
@ -36,5 +45,6 @@ show status like "Qcache_queries_in_cache";
|
|||
drop table t1,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14,t15,t16,t17,t18,t19,t20,t21,t22,t23,t24,t25,t26,t27,t28,t29,t30,t31,t32,t33,t34,t35,t36,t37,t38,t39,t40,t41,t42,t43,t44,t45,t46,t47,t48,t49,t50,t51,t52,t53,t54,t55,t56,t57,t58,t59,t60,t61,t62,t63,t64,t65,t66,t67,t68,t69,t70,t71,t72,t73,t74,t75,t76,t77,t78,t79,t80,t81,t82,t83,t84,t85,t86,t87,t88,t89,t90,t91,t92,t93,t94,t95,t96,t97,t98,t99,t100,t101,t102,t103,t104,t105,t106,t107,t108,t109,t110,t111,t112,t113,t114,t115,t116,t117,t118,t119,t120,t121,t122,t123,t124,t125,t126,t127,t128,t129,t130,t131,t132,t133,t134,t135,t136,t137,t138,t139,t140,t141,t142,t143,t144,t145,t146,t147,t148,t149,t150,t151,t152,t153,t154,t155,t156,t157,t158,t159,t160,t161,t162,t163,t164,t165,t166,t167,t168,t169,t170,t171,t172,t173,t174,t175,t176,t177,t178,t179,t180,t181,t182,t183,t184,t185,t186,t187,t188,t189,t190,t191,t192,t193,t194,t195,t196,t197,t198,t199,t200,t201,t202,t203,t204,t205,t206,t207,t208,t209,t210,t211,t212,t213,t214,t215,t216,t217,t218,t219,t220,t221,t222,t223,t224,t225,t226,t227,t228,t229,t230,t231,t232,t233,t234,t235,t236,t237,t238,t239,t240,t241,t242,t243,t244,t245,t246,t247,t248,t249,t250,t251,t252,t253,t254,t255,t256,t257,t00;
|
||||
|
||||
SET @@global.query_cache_size=0;
|
||||
set @@global.table_definition_cache=@save_table_definition_cache;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
|
|
@ -997,11 +997,10 @@ call p1();
|
|||
# Altering trigger forcing it use different set of tables
|
||||
drop trigger t1_bi;
|
||||
create trigger t1_bi after insert on t1 for each row insert into t3 values (new.id);
|
||||
# Until we implement proper mechanism for invalidation of PS/SP when table
|
||||
# or SP's are changed these two statements will fail with 'Table ... was
|
||||
# not locked' error (this mechanism should be based on the new TDC).
|
||||
--error ER_NO_SUCH_TABLE
|
||||
execute stmt1;
|
||||
# Until we implement proper mechanism for invalidation of SP statements
|
||||
# invoked whenever a table used in SP changes, this statement will fail with
|
||||
# 'Table ... does not exist' error.
|
||||
--error ER_NO_SUCH_TABLE
|
||||
call p1();
|
||||
deallocate prepare stmt1;
|
||||
|
|
39
sql/item.cc
39
sql/item.cc
|
@ -3161,6 +3161,45 @@ void Item_param::print(String *str, enum_query_type query_type)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Preserve the original parameter types and values
|
||||
when re-preparing a prepared statement.
|
||||
|
||||
Copy parameter type information and conversion function
|
||||
pointers from a parameter of the old statement to the
|
||||
corresponding parameter of the new one.
|
||||
|
||||
Move parameter values from the old parameters to the new
|
||||
one. We simply "exchange" the values, which allows
|
||||
to save on allocation and character set conversion in
|
||||
case a parameter is a string or a blob/clob.
|
||||
|
||||
@param[in] src parameter item of the original
|
||||
prepared statement
|
||||
*/
|
||||
|
||||
void
|
||||
Item_param::set_param_type_and_swap_value(Item_param *src)
|
||||
{
|
||||
unsigned_flag= src->unsigned_flag;
|
||||
param_type= src->param_type;
|
||||
set_param_func= src->set_param_func;
|
||||
item_type= src->item_type;
|
||||
item_result_type= src->item_result_type;
|
||||
|
||||
collation.set(src->collation.collation);
|
||||
maybe_null= src->maybe_null;
|
||||
null_value= src->null_value;
|
||||
max_length= src->max_length;
|
||||
decimals= src->decimals;
|
||||
state= src->state;
|
||||
value= src->value;
|
||||
|
||||
decimal_value.swap(src->decimal_value);
|
||||
str_value.swap(src->str_value);
|
||||
str_value_ptr.swap(src->str_value_ptr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Item_copy_string
|
||||
****************************************************************************/
|
||||
|
|
|
@ -1684,6 +1684,7 @@ public:
|
|||
bool eq(const Item *item, bool binary_cmp) const;
|
||||
/** Item is a argument to a limit clause. */
|
||||
bool limit_clause_param;
|
||||
void set_param_type_and_swap_value(Item_param *from);
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -114,6 +114,14 @@ public:
|
|||
bool sign() const { return decimal_t::sign; }
|
||||
void sign(bool s) { decimal_t::sign= s; }
|
||||
uint precision() const { return intg + frac; }
|
||||
|
||||
/** Swap two my_decimal values */
|
||||
void swap(my_decimal &rhs)
|
||||
{
|
||||
swap_variables(my_decimal, *this, rhs);
|
||||
/* Swap the buffer pointers back */
|
||||
swap_variables(decimal_digit_t *, buf, rhs.buf);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -259,6 +259,21 @@ protected:
|
|||
#define USER_VARS_HASH_SIZE 16
|
||||
#define TABLE_OPEN_CACHE_MIN 64
|
||||
#define TABLE_OPEN_CACHE_DEFAULT 64
|
||||
#define TABLE_DEF_CACHE_DEFAULT 256
|
||||
/**
|
||||
We must have room for at least 256 table definitions in the table
|
||||
cache, since otherwise there is no chance prepared
|
||||
statements that use these many tables can work.
|
||||
Prepared statements use table definition cache ids (table_map_id)
|
||||
as table version identifiers. If the table definition
|
||||
cache size is less than the number of tables used in a statement,
|
||||
the contents of the table definition cache is guaranteed to rotate
|
||||
between a prepare and execute. This leads to stable validation
|
||||
errors. In future we shall use more stable version identifiers,
|
||||
for now the only solution is to ensure that the table definition
|
||||
cache can contain at least all tables of a given statement.
|
||||
*/
|
||||
#define TABLE_DEF_CACHE_MIN 256
|
||||
|
||||
/*
|
||||
Value of 9236 discovered through binary search 2006-09-26 on Ubuntu Dapper
|
||||
|
@ -670,6 +685,31 @@ const char *set_thd_proc_info(THD *thd, const char *info,
|
|||
const char *calling_file,
|
||||
const unsigned int calling_line);
|
||||
|
||||
/**
|
||||
Enumerate possible types of a table from re-execution
|
||||
standpoint.
|
||||
TABLE_LIST class has a member of this type.
|
||||
At prepared statement prepare, this member is assigned a value
|
||||
as of the current state of the database. Before (re-)execution
|
||||
of a prepared statement, we check that the value recorded at
|
||||
prepare matches the type of the object we obtained from the
|
||||
table definition cache.
|
||||
|
||||
@sa check_and_update_table_version()
|
||||
@sa Execute_observer
|
||||
@sa Prepared_statement::reprepare()
|
||||
*/
|
||||
|
||||
enum enum_metadata_type
|
||||
{
|
||||
/** Initial value set by the parser */
|
||||
METADATA_NULL= 0,
|
||||
METADATA_VIEW,
|
||||
METADATA_BASE_TABLE,
|
||||
METADATA_I_S_TABLE,
|
||||
METADATA_TMP_TABLE
|
||||
};
|
||||
|
||||
/*
|
||||
External variables
|
||||
*/
|
||||
|
|
|
@ -3090,6 +3090,7 @@ SHOW_VAR com_status_vars[]= {
|
|||
{"stmt_execute", (char*) offsetof(STATUS_VAR, com_stmt_execute), SHOW_LONG_STATUS},
|
||||
{"stmt_fetch", (char*) offsetof(STATUS_VAR, com_stmt_fetch), SHOW_LONG_STATUS},
|
||||
{"stmt_prepare", (char*) offsetof(STATUS_VAR, com_stmt_prepare), SHOW_LONG_STATUS},
|
||||
{"stmt_reprepare", (char*) offsetof(STATUS_VAR, com_stmt_reprepare), SHOW_LONG_STATUS},
|
||||
{"stmt_reset", (char*) offsetof(STATUS_VAR, com_stmt_reset), SHOW_LONG_STATUS},
|
||||
{"stmt_send_long_data", (char*) offsetof(STATUS_VAR, com_stmt_send_long_data), SHOW_LONG_STATUS},
|
||||
{"truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS},
|
||||
|
@ -3178,7 +3179,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
|
|||
We have few debug-only commands in com_status_vars, only visible in debug
|
||||
builds. for simplicity we enable the assert only in debug builds
|
||||
|
||||
There are 7 Com_ variables which don't have corresponding SQLCOM_ values:
|
||||
There are 8 Com_ variables which don't have corresponding SQLCOM_ values:
|
||||
(TODO strictly speaking they shouldn't be here, should not have Com_ prefix
|
||||
that is. Perhaps Stmt_ ? Comstmt_ ? Prepstmt_ ?)
|
||||
|
||||
|
@ -3187,6 +3188,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
|
|||
Com_stmt_execute => com_stmt_execute
|
||||
Com_stmt_fetch => com_stmt_fetch
|
||||
Com_stmt_prepare => com_stmt_prepare
|
||||
Com_stmt_reprepare => com_stmt_reprepare
|
||||
Com_stmt_reset => com_stmt_reset
|
||||
Com_stmt_send_long_data => com_stmt_send_long_data
|
||||
|
||||
|
@ -3195,7 +3197,7 @@ static int init_common_variables(const char *conf_file_name, int argc,
|
|||
of SQLCOM_ constants.
|
||||
*/
|
||||
compile_time_assert(sizeof(com_status_vars)/sizeof(com_status_vars[0]) - 1 ==
|
||||
SQLCOM_END + 7);
|
||||
SQLCOM_END + 8);
|
||||
#endif
|
||||
|
||||
load_defaults(conf_file_name, groups, &argc, &argv);
|
||||
|
@ -6762,7 +6764,8 @@ The minimum value for this variable is 4096.",
|
|||
{"table_definition_cache", OPT_TABLE_DEF_CACHE,
|
||||
"The number of cached table definitions.",
|
||||
(uchar**) &table_def_size, (uchar**) &table_def_size,
|
||||
0, GET_ULONG, REQUIRED_ARG, 128, 1, 512*1024L, 0, 1, 0},
|
||||
0, GET_ULONG, REQUIRED_ARG, TABLE_DEF_CACHE_DEFAULT, TABLE_DEF_CACHE_MIN,
|
||||
512*1024L, 0, 1, 0},
|
||||
{"table_open_cache", OPT_TABLE_OPEN_CACHE,
|
||||
"The number of cached open tables.",
|
||||
(uchar**) &table_cache_size, (uchar**) &table_cache_size, 0, GET_ULONG,
|
||||
|
|
|
@ -6121,8 +6121,15 @@ ER_NO_FORMAT_DESCRIPTION_EVENT_BEFORE_BINLOG_STATEMENT
|
|||
eng "The BINLOG statement of type `%s` was not preceded by a format description BINLOG statement."
|
||||
ER_SLAVE_CORRUPT_EVENT
|
||||
eng "Corrupted replication event was detected"
|
||||
|
||||
ER_LOAD_DATA_INVALID_COLUMN
|
||||
eng "Invalid column reference (%-.64s) in LOAD DATA"
|
||||
|
||||
ER_LOG_PURGE_NO_FILE
|
||||
eng "Being purged log %s was not found"
|
||||
|
||||
ER_NEED_REPREPARE
|
||||
eng "Prepared statement needs to be re-prepared"
|
||||
|
||||
ER_PS_REBIND
|
||||
eng "Prepared statement result set has changed, a rebind needed"
|
||||
|
|
|
@ -1068,6 +1068,7 @@ sp_head::execute(THD *thd)
|
|||
LEX *old_lex;
|
||||
Item_change_list old_change_list;
|
||||
String old_packet;
|
||||
Metadata_version_observer *save_metadata_observer= thd->m_metadata_observer;
|
||||
|
||||
Object_creation_ctx *saved_creation_ctx;
|
||||
|
||||
|
@ -1135,6 +1136,25 @@ sp_head::execute(THD *thd)
|
|||
thd->variables.sql_mode= m_sql_mode;
|
||||
save_abort_on_warning= thd->abort_on_warning;
|
||||
thd->abort_on_warning= 0;
|
||||
/**
|
||||
When inside a substatement (a stored function or trigger
|
||||
statement), clear the metadata observer in THD, if any.
|
||||
Remember the value of the observer here, to be able
|
||||
to restore it when leaving the substatement.
|
||||
|
||||
We reset the observer to suppress errors when a substatement
|
||||
uses temporary tables. If a temporary table does not exist
|
||||
at start of the main statement, it's not prelocked
|
||||
and thus is not validated with other prelocked tables.
|
||||
|
||||
Later on, when the temporary table is opened, metadata
|
||||
versions mismatch, expectedly.
|
||||
|
||||
The proper solution for the problem is to re-validate tables
|
||||
of substatements (Bug#12257, Bug#27011, Bug#32868, Bug#33000),
|
||||
but it's not implemented yet.
|
||||
*/
|
||||
thd->m_metadata_observer= 0;
|
||||
|
||||
/*
|
||||
It is also more efficient to save/restore current thd->lex once when
|
||||
|
@ -1297,6 +1317,7 @@ sp_head::execute(THD *thd)
|
|||
thd->derived_tables= old_derived_tables;
|
||||
thd->variables.sql_mode= save_sql_mode;
|
||||
thd->abort_on_warning= save_abort_on_warning;
|
||||
thd->m_metadata_observer= save_metadata_observer;
|
||||
|
||||
thd->stmt_arena= old_arena;
|
||||
state= EXECUTED;
|
||||
|
|
110
sql/sql_base.cc
110
sql/sql_base.cc
|
@ -3717,6 +3717,72 @@ void assign_new_table_id(TABLE_SHARE *share)
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Compare metadata versions of an element obtained from the table
|
||||
definition cache and its corresponding node in the parse tree.
|
||||
|
||||
If the new and the old values mismatch, invoke
|
||||
Metadata_version_observer.
|
||||
|
||||
At prepared statement prepare, all TABLE_LIST version values are
|
||||
NULL and we always have a mismatch. But there is no observer set
|
||||
in THD, and therefore no error is reported. Instead, we update
|
||||
the value in the parse tree, effectively recording the original
|
||||
version.
|
||||
At prepared statement execute, an observer may be installed. If
|
||||
there is a version mismatch, we push an error and return TRUE.
|
||||
|
||||
For conventional execution (no prepared statements), the
|
||||
observer is never installed.
|
||||
|
||||
@sa Execute_observer
|
||||
@sa check_prepared_statement() to see cases when an observer is installed
|
||||
@sa TABLE_LIST::is_metadata_version_equal()
|
||||
@sa TABLE_SHARE::get_metadata_version()
|
||||
|
||||
@param[in] thd used to report errors
|
||||
@param[in,out] tables TABLE_LIST instance created by the parser
|
||||
Metadata version information in this object
|
||||
is updated upon success.
|
||||
@param[in] table_share an element from the table definition cache
|
||||
|
||||
@retval TRUE an error, which has been reported
|
||||
@retval FALSE success, version in TABLE_LIST has been updated
|
||||
*/
|
||||
|
||||
bool
|
||||
check_and_update_table_version(THD *thd,
|
||||
TABLE_LIST *tables, TABLE_SHARE *table_share)
|
||||
{
|
||||
if (! tables->is_metadata_version_equal(table_share))
|
||||
{
|
||||
if (thd->m_metadata_observer &&
|
||||
thd->m_metadata_observer->check_metadata_change(thd))
|
||||
{
|
||||
/*
|
||||
Version of the table share is different from the
|
||||
previous execution of the prepared statement, and it is
|
||||
unacceptable for this SQLCOM. Error has been reported.
|
||||
*/
|
||||
return TRUE;
|
||||
}
|
||||
/* Always maintain the latest version */
|
||||
tables->set_metadata_version(table_share);
|
||||
}
|
||||
#if 0
|
||||
#ifndef DBUG_OFF
|
||||
/* Spuriously reprepare each statement. */
|
||||
if (thd->m_metadata_observer && thd->stmt_arena->is_reprepared == FALSE)
|
||||
{
|
||||
thd->m_metadata_observer->check_metadata_change(thd);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
Load a table definition from file and open unireg table
|
||||
|
||||
|
@ -3762,6 +3828,8 @@ retry:
|
|||
|
||||
if (share->is_view)
|
||||
{
|
||||
if (check_and_update_table_version(thd, table_list, share))
|
||||
goto err;
|
||||
if (table_list->i_s_requested_object & OPEN_TABLE_ONLY)
|
||||
goto err;
|
||||
|
||||
|
@ -3779,6 +3847,26 @@ retry:
|
|||
release_table_share(share, RELEASE_NORMAL);
|
||||
DBUG_RETURN((flags & OPEN_VIEW_NO_PARSE)? -1 : 0);
|
||||
}
|
||||
else if (table_list->view)
|
||||
{
|
||||
/*
|
||||
We're trying to open a table for what was a view.
|
||||
This can only happen during (re-)execution.
|
||||
At prepared statement prepare the view has been opened and
|
||||
merged into the statement parse tree. After that, someone
|
||||
performed a DDL and replaced the view with a base table.
|
||||
Don't try to open the table inside a prepared statement,
|
||||
invalidate it instead.
|
||||
|
||||
Note, the assert below is known to fail inside stored
|
||||
procedures (Bug#27011).
|
||||
*/
|
||||
DBUG_ASSERT(thd->m_metadata_observer);
|
||||
check_and_update_table_version(thd, table_list, share);
|
||||
/* Always an error. */
|
||||
DBUG_ASSERT(thd->is_error());
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (table_list->i_s_requested_object & OPEN_VIEW_ONLY)
|
||||
goto err;
|
||||
|
@ -4375,8 +4463,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||
*/
|
||||
if (tables->schema_table)
|
||||
{
|
||||
if (!mysql_schema_table(thd, thd->lex, tables))
|
||||
/*
|
||||
If this information_schema table is merged into a mergeable
|
||||
view, ignore it for now -- it will be filled when its respective
|
||||
TABLE_LIST is processed. This code works only during re-execution.
|
||||
*/
|
||||
if (tables->view)
|
||||
goto process_view_routines;
|
||||
if (!mysql_schema_table(thd, thd->lex, tables) &&
|
||||
!check_and_update_table_version(thd, tables, tables->table->s))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
(*counter)++;
|
||||
|
@ -4524,6 +4622,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
|||
}
|
||||
tables->table->grant= tables->grant;
|
||||
|
||||
if (check_and_update_table_version(thd, tables, tables->table->s))
|
||||
{
|
||||
result= -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Attach MERGE children if not locked already. */
|
||||
DBUG_PRINT("tcache", ("is parent: %d is child: %d",
|
||||
test(tables->table->child_l),
|
||||
|
@ -4582,7 +4686,11 @@ process_view_routines:
|
|||
error happens on a MERGE child, clear the parents TABLE reference.
|
||||
*/
|
||||
if (tables->parent_l)
|
||||
{
|
||||
if (tables->parent_l->next_global == tables->parent_l->table->child_l)
|
||||
tables->parent_l->next_global= *tables->parent_l->table->child_last_l;
|
||||
tables->parent_l->table= NULL;
|
||||
}
|
||||
tables->table= NULL;
|
||||
}
|
||||
DBUG_PRINT("tcache", ("returning: %d", result));
|
||||
|
|
|
@ -360,6 +360,10 @@ char *thd_security_context(THD *thd, char *buffer, unsigned int length,
|
|||
return thd->strmake(str.ptr(), str.length());
|
||||
}
|
||||
|
||||
Metadata_version_observer::~Metadata_version_observer()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
Clear this diagnostics area.
|
||||
|
||||
|
@ -2769,7 +2773,8 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup)
|
|||
DBUG_ASSERT(open_tables == 0 && temporary_tables == 0 &&
|
||||
handler_tables == 0 && derived_tables == 0 &&
|
||||
lock == 0 && locked_tables == 0 &&
|
||||
prelocked_mode == NON_PRELOCKED);
|
||||
prelocked_mode == NON_PRELOCKED &&
|
||||
m_metadata_observer == NULL);
|
||||
set_open_tables_state(backup);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
|
|
@ -23,6 +23,53 @@
|
|||
#include "log.h"
|
||||
#include "rpl_tblmap.h"
|
||||
|
||||
/**
|
||||
An abstract interface that can be used to take an action when
|
||||
the locking module notices that a table version has changed
|
||||
since the last execution. "Table" here may refer to any kind of
|
||||
table -- a base table, a temporary table, a view or an
|
||||
information schema table.
|
||||
|
||||
When we open and lock tables for execution of a prepared
|
||||
statement, we must verify that they did not change
|
||||
since statement prepare. If some table did change, the statement
|
||||
parse tree *may* be no longer valid, e.g. in case it contains
|
||||
optimizations that depend on table metadata.
|
||||
|
||||
This class provides an abstract interface (a method) that is
|
||||
invoked when such a situation takes place.
|
||||
The implementation of the interface in most cases simply
|
||||
reports an error, but the exact details depend on the nature of
|
||||
the SQL statement.
|
||||
|
||||
At most 1 instance of this class is active at a time, in which
|
||||
case THD::m_metadata_observer is not NULL.
|
||||
|
||||
@sa check_and_update_table_version() for details of the
|
||||
version tracking algorithm
|
||||
|
||||
@sa Execute_observer for details of how we detect that
|
||||
a metadata change is fatal and a re-prepare is necessary
|
||||
|
||||
@sa Open_tables_state::m_metadata_observer for the life cycle
|
||||
of metadata observers.
|
||||
*/
|
||||
|
||||
class Metadata_version_observer
|
||||
{
|
||||
protected:
|
||||
virtual ~Metadata_version_observer();
|
||||
public:
|
||||
/**
|
||||
Check if a change of metadata is OK. In future
|
||||
the signature of this method may be extended to accept the old
|
||||
and the new versions, but since currently the check is very
|
||||
simple, we only need the THD to report an error.
|
||||
*/
|
||||
virtual bool check_metadata_change(THD *thd)= 0;
|
||||
};
|
||||
|
||||
|
||||
class Relay_log_info;
|
||||
|
||||
class Query_log_event;
|
||||
|
@ -406,6 +453,7 @@ typedef struct system_status_var
|
|||
ulong filesort_scan_count;
|
||||
/* Prepared statements and binary protocol */
|
||||
ulong com_stmt_prepare;
|
||||
ulong com_stmt_reprepare;
|
||||
ulong com_stmt_execute;
|
||||
ulong com_stmt_send_long_data;
|
||||
ulong com_stmt_fetch;
|
||||
|
@ -436,7 +484,7 @@ void free_tmp_table(THD *thd, TABLE *entry);
|
|||
|
||||
/* The following macro is to make init of Query_arena simpler */
|
||||
#ifndef DBUG_OFF
|
||||
#define INIT_ARENA_DBUG_INFO is_backup_arena= 0
|
||||
#define INIT_ARENA_DBUG_INFO is_backup_arena= 0; is_reprepared= FALSE;
|
||||
#else
|
||||
#define INIT_ARENA_DBUG_INFO
|
||||
#endif
|
||||
|
@ -452,6 +500,7 @@ public:
|
|||
MEM_ROOT *mem_root; // Pointer to current memroot
|
||||
#ifndef DBUG_OFF
|
||||
bool is_backup_arena; /* True if this arena is used for backup. */
|
||||
bool is_reprepared;
|
||||
#endif
|
||||
/*
|
||||
The states relfects three diffrent life cycles for three
|
||||
|
@ -788,6 +837,20 @@ enum prelocked_mode_type {NON_PRELOCKED= 0, PRELOCKED= 1,
|
|||
class Open_tables_state
|
||||
{
|
||||
public:
|
||||
/**
|
||||
As part of class THD, this member is set during execution
|
||||
of a prepared statement. When it is set, it is used
|
||||
by the locking subsystem to report a change in table metadata.
|
||||
|
||||
When Open_tables_state part of THD is reset to open
|
||||
a system or INFORMATION_SCHEMA table, the member is cleared
|
||||
to avoid spurious ER_NEED_REPREPARE errors -- system and
|
||||
INFORMATION_SCHEMA tables are not subject to metadata version
|
||||
tracking.
|
||||
@sa check_and_update_table_version()
|
||||
*/
|
||||
Metadata_version_observer *m_metadata_observer;
|
||||
|
||||
/**
|
||||
List of regular tables in use by this thread. Contains temporary and
|
||||
base tables that were opened with @see open_tables().
|
||||
|
@ -891,6 +954,7 @@ public:
|
|||
extra_lock= lock= locked_tables= 0;
|
||||
prelocked_mode= NON_PRELOCKED;
|
||||
state_flags= 0U;
|
||||
m_metadata_observer= NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -2778,6 +2842,7 @@ public:
|
|||
#define CF_STATUS_COMMAND 4
|
||||
#define CF_SHOW_TABLE_COMMAND 8
|
||||
#define CF_WRITE_LOGS_COMMAND 16
|
||||
#define CF_REEXECUTION_FRAGILE 32
|
||||
|
||||
/* Functions in sql_class.cc */
|
||||
|
||||
|
|
|
@ -111,7 +111,8 @@ class Select_materialize: public select_union
|
|||
select_result *result; /**< the result object of the caller (PS or SP) */
|
||||
public:
|
||||
Materialized_cursor *materialized_cursor;
|
||||
Select_materialize(select_result *result_arg) :result(result_arg) {}
|
||||
Select_materialize(select_result *result_arg)
|
||||
:result(result_arg), materialized_cursor(0) {}
|
||||
virtual bool send_fields(List<Item> &list, uint flags);
|
||||
};
|
||||
|
||||
|
|
|
@ -200,45 +200,56 @@ void init_update_queries(void)
|
|||
{
|
||||
bzero((uchar*) &sql_command_flags, sizeof(sql_command_flags));
|
||||
|
||||
sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_CREATE_TABLE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_CREATE_INDEX]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_ALTER_TABLE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
|
||||
sql_command_flags[SQLCOM_TRUNCATE]= CF_CHANGES_DATA | CF_WRITE_LOGS_COMMAND;
|
||||
sql_command_flags[SQLCOM_DROP_TABLE]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_LOAD]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_CREATE_DB]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_DROP_DB]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_RENAME_TABLE]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_BACKUP_TABLE]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_RESTORE_TABLE]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_DROP_INDEX]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_CREATE_VIEW]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_DROP_VIEW]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_CREATE_EVENT]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_ALTER_EVENT]= CF_CHANGES_DATA;
|
||||
sql_command_flags[SQLCOM_DROP_EVENT]= CF_CHANGES_DATA;
|
||||
|
||||
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
|
||||
CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE;
|
||||
|
||||
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_STATUS_PROC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_STATUS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_DATABASES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_TRIGGERS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_EVENTS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_OPEN_TABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_PLUGINS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_FIELDS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_KEYS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_VARIABLES]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_CHARSETS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_COLLATIONS]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_NEW_MASTER]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_BINLOGS]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_SLAVE_HOSTS]= CF_STATUS_COMMAND;
|
||||
|
@ -262,7 +273,7 @@ void init_update_queries(void)
|
|||
sql_command_flags[SQLCOM_SHOW_CREATE_PROC]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_CREATE_FUNC]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_CREATE_TRIGGER]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_STATUS_FUNC]= CF_STATUS_COMMAND | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_SHOW_PROC_CODE]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_FUNC_CODE]= CF_STATUS_COMMAND;
|
||||
sql_command_flags[SQLCOM_SHOW_CREATE_EVENT]= CF_STATUS_COMMAND;
|
||||
|
@ -270,9 +281,11 @@ void init_update_queries(void)
|
|||
sql_command_flags[SQLCOM_SHOW_PROFILE]= CF_STATUS_COMMAND;
|
||||
|
||||
sql_command_flags[SQLCOM_SHOW_TABLES]= (CF_STATUS_COMMAND |
|
||||
CF_SHOW_TABLE_COMMAND);
|
||||
CF_SHOW_TABLE_COMMAND |
|
||||
CF_REEXECUTION_FRAGILE);
|
||||
sql_command_flags[SQLCOM_SHOW_TABLE_STATUS]= (CF_STATUS_COMMAND |
|
||||
CF_SHOW_TABLE_COMMAND);
|
||||
CF_SHOW_TABLE_COMMAND |
|
||||
CF_REEXECUTION_FRAGILE);
|
||||
|
||||
/*
|
||||
The following is used to preserver CF_ROW_COUNT during the
|
||||
|
@ -280,7 +293,7 @@ void init_update_queries(void)
|
|||
last called (or executed) statement is preserved.
|
||||
See mysql_execute_command() for how CF_ROW_COUNT is used.
|
||||
*/
|
||||
sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT;
|
||||
sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE;
|
||||
sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT;
|
||||
|
||||
/*
|
||||
|
|
|
@ -116,6 +116,39 @@ public:
|
|||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
If a metadata changed, report a respective error to trigger
|
||||
re-prepare of a prepared statement.
|
||||
*/
|
||||
|
||||
class Execute_observer: public Metadata_version_observer
|
||||
{
|
||||
public:
|
||||
virtual bool check_metadata_change(THD *thd);
|
||||
/** Set to TRUE if metadata of some used table has changed since prepare */
|
||||
bool m_invalidated;
|
||||
};
|
||||
|
||||
/**
|
||||
Push an error to the error stack and return TRUE for now.
|
||||
In future we must take special care of statements like CREATE
|
||||
TABLE ... SELECT. Should we re-prepare such statements every
|
||||
time?
|
||||
*/
|
||||
|
||||
bool
|
||||
Execute_observer::check_metadata_change(THD *thd)
|
||||
{
|
||||
bool save_thd_no_warnings_for_error= thd->no_warnings_for_error;
|
||||
DBUG_ENTER("Execute_observer::notify_about_metadata_change");
|
||||
|
||||
thd->no_warnings_for_error= TRUE;
|
||||
my_error(ER_NEED_REPREPARE, MYF(0));
|
||||
thd->no_warnings_for_error= save_thd_no_warnings_for_error;
|
||||
m_invalidated= TRUE;
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/**
|
||||
|
@ -156,20 +189,27 @@ public:
|
|||
bool set_name(LEX_STRING *name);
|
||||
inline void close_cursor() { delete cursor; cursor= 0; }
|
||||
inline bool is_in_use() { return flags & (uint) IS_IN_USE; }
|
||||
inline bool is_protocol_text() const { return protocol == &thd->protocol_text; }
|
||||
bool prepare(const char *packet, uint packet_length);
|
||||
bool execute(String *expanded_query, bool open_cursor);
|
||||
bool execute_loop(String *expanded_query,
|
||||
bool open_cursor,
|
||||
uchar *packet_arg, uchar *packet_end_arg);
|
||||
/* Destroy this statement */
|
||||
void deallocate();
|
||||
private:
|
||||
/**
|
||||
Store the parsed tree of a prepared statement here.
|
||||
*/
|
||||
LEX main_lex;
|
||||
/**
|
||||
The memory root to allocate parsed tree elements (instances of Item,
|
||||
SELECT_LEX and other classes).
|
||||
*/
|
||||
MEM_ROOT main_mem_root;
|
||||
private:
|
||||
bool set_db(const char *db, uint db_length);
|
||||
bool set_parameters(String *expanded_query,
|
||||
uchar *packet, uchar *packet_end);
|
||||
bool execute(String *expanded_query, bool open_cursor);
|
||||
bool reprepare();
|
||||
bool validate_metadata(Prepared_statement *copy);
|
||||
void swap_prepared_statement(Prepared_statement *copy);
|
||||
};
|
||||
|
||||
|
||||
|
@ -941,6 +981,55 @@ static bool emb_insert_params_with_log(Prepared_statement *stmt,
|
|||
|
||||
#endif /*!EMBEDDED_LIBRARY*/
|
||||
|
||||
/**
|
||||
Setup data conversion routines using an array of parameter
|
||||
markers from the original prepared statement.
|
||||
Move the parameter data of the original prepared
|
||||
statement to the new one.
|
||||
|
||||
Used only when we re-prepare a prepared statement.
|
||||
There are two reasons for this function to exist:
|
||||
|
||||
1) In the binary client/server protocol, parameter metadata
|
||||
is sent only at first execute. Consequently, if we need to
|
||||
reprepare a prepared statement at a subsequent execution,
|
||||
we may not have metadata information in the packet.
|
||||
In that case we use the parameter array of the original
|
||||
prepared statement to setup parameter types of the new
|
||||
prepared statement.
|
||||
|
||||
2) In the binary client/server protocol, we may supply
|
||||
long data in pieces. When the last piece is supplied,
|
||||
we assemble the pieces and convert them from client
|
||||
character set to the connection character set. After
|
||||
that the parameter value is only available inside
|
||||
the parameter, the original pieces are lost, and thus
|
||||
we can only assign the corresponding parameter of the
|
||||
reprepared statement from the original value.
|
||||
|
||||
@param[out] param_array_dst parameter markers of the new statement
|
||||
@param[in] param_array_src parameter markers of the original
|
||||
statement
|
||||
@param[in] param_count total number of parameters. Is the
|
||||
same in src and dst arrays, since
|
||||
the statement query is the same
|
||||
|
||||
@return this function never fails
|
||||
*/
|
||||
|
||||
static void
|
||||
swap_parameter_array(Item_param **param_array_dst,
|
||||
Item_param **param_array_src,
|
||||
uint param_count)
|
||||
{
|
||||
Item_param **dst= param_array_dst;
|
||||
Item_param **src= param_array_src;
|
||||
Item_param **end= param_array_dst + param_count;
|
||||
|
||||
for (; dst < end; ++src, ++dst)
|
||||
(*dst)->set_param_type_and_swap_value(*src);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Assign prepared statement parameters from user variables.
|
||||
|
@ -1264,7 +1353,7 @@ error:
|
|||
*/
|
||||
|
||||
static int mysql_test_select(Prepared_statement *stmt,
|
||||
TABLE_LIST *tables, bool text_protocol)
|
||||
TABLE_LIST *tables)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
LEX *lex= stmt->lex;
|
||||
|
@ -1300,7 +1389,7 @@ static int mysql_test_select(Prepared_statement *stmt,
|
|||
*/
|
||||
if (unit->prepare(thd, 0, 0))
|
||||
goto error;
|
||||
if (!lex->describe && !text_protocol)
|
||||
if (!lex->describe && !stmt->is_protocol_text())
|
||||
{
|
||||
/* Make copy of item list, as change_columns may change it */
|
||||
List<Item> fields(lex->select_lex.item_list);
|
||||
|
@ -1391,6 +1480,43 @@ error:
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Validate and prepare for execution CALL statement expressions.
|
||||
|
||||
@param stmt prepared statement
|
||||
@param tables list of tables used in this query
|
||||
@param value_list list of expressions
|
||||
|
||||
@retval FALSE success
|
||||
@retval TRUE error, error message is set in THD
|
||||
*/
|
||||
|
||||
static bool mysql_test_call_fields(Prepared_statement *stmt,
|
||||
TABLE_LIST *tables,
|
||||
List<Item> *value_list)
|
||||
{
|
||||
DBUG_ENTER("mysql_test_call_fields");
|
||||
|
||||
List_iterator<Item> it(*value_list);
|
||||
THD *thd= stmt->thd;
|
||||
Item *item;
|
||||
|
||||
if (tables && check_table_access(thd, SELECT_ACL, tables, UINT_MAX, FALSE) ||
|
||||
open_normal_and_derived_tables(thd, tables, 0))
|
||||
goto err;
|
||||
|
||||
while ((item= it++))
|
||||
{
|
||||
if (!item->fixed && item->fix_fields(thd, it.ref()) ||
|
||||
item->check_cols(1))
|
||||
goto err;
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
err:
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check internal SELECT of the prepared command.
|
||||
|
||||
|
@ -1512,6 +1638,17 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
|
|||
|
||||
res= select_like_stmt_test(stmt, 0, 0);
|
||||
}
|
||||
else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
|
||||
{
|
||||
/*
|
||||
Check that the source table exist, and also record
|
||||
its metadata version. Even though not strictly necessary,
|
||||
we validate metadata of all CREATE TABLE statements,
|
||||
which keeps metadata validation code simple.
|
||||
*/
|
||||
if (open_normal_and_derived_tables(stmt->thd, lex->query_tables, 0))
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
/* put tables back for PS rexecuting */
|
||||
lex->link_first_table_back(create_table, link_to_local);
|
||||
|
@ -1708,8 +1845,7 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
|
|||
TRUE error, error message is set in THD (but not sent)
|
||||
*/
|
||||
|
||||
static bool check_prepared_statement(Prepared_statement *stmt,
|
||||
bool text_protocol)
|
||||
static bool check_prepared_statement(Prepared_statement *stmt)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
LEX *lex= stmt->lex;
|
||||
|
@ -1750,9 +1886,23 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
|||
case SQLCOM_DELETE:
|
||||
res= mysql_test_delete(stmt, tables);
|
||||
break;
|
||||
|
||||
/* The following allow WHERE clause, so they must be tested like SELECT */
|
||||
case SQLCOM_SHOW_DATABASES:
|
||||
case SQLCOM_SHOW_TABLES:
|
||||
case SQLCOM_SHOW_TRIGGERS:
|
||||
case SQLCOM_SHOW_EVENTS:
|
||||
case SQLCOM_SHOW_OPEN_TABLES:
|
||||
case SQLCOM_SHOW_FIELDS:
|
||||
case SQLCOM_SHOW_KEYS:
|
||||
case SQLCOM_SHOW_COLLATIONS:
|
||||
case SQLCOM_SHOW_CHARSETS:
|
||||
case SQLCOM_SHOW_VARIABLES:
|
||||
case SQLCOM_SHOW_STATUS:
|
||||
case SQLCOM_SHOW_TABLE_STATUS:
|
||||
case SQLCOM_SHOW_STATUS_PROC:
|
||||
case SQLCOM_SHOW_STATUS_FUNC:
|
||||
case SQLCOM_SELECT:
|
||||
res= mysql_test_select(stmt, tables, text_protocol);
|
||||
res= mysql_test_select(stmt, tables);
|
||||
if (res == 2)
|
||||
{
|
||||
/* Statement and field info has already been sent */
|
||||
|
@ -1775,6 +1925,9 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
|||
res= mysql_test_do_fields(stmt, tables, lex->insert_list);
|
||||
break;
|
||||
|
||||
case SQLCOM_CALL:
|
||||
res= mysql_test_call_fields(stmt, tables, &lex->value_list);
|
||||
break;
|
||||
case SQLCOM_SET_OPTION:
|
||||
res= mysql_test_set_fields(stmt, tables, &lex->var_list);
|
||||
break;
|
||||
|
@ -1824,7 +1977,6 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
|||
case SQLCOM_DROP_INDEX:
|
||||
case SQLCOM_ROLLBACK:
|
||||
case SQLCOM_TRUNCATE:
|
||||
case SQLCOM_CALL:
|
||||
case SQLCOM_DROP_VIEW:
|
||||
case SQLCOM_REPAIR:
|
||||
case SQLCOM_ANALYZE:
|
||||
|
@ -1867,8 +2019,8 @@ static bool check_prepared_statement(Prepared_statement *stmt,
|
|||
break;
|
||||
}
|
||||
if (res == 0)
|
||||
DBUG_RETURN(text_protocol? FALSE : (send_prep_stmt(stmt, 0) ||
|
||||
thd->protocol->flush()));
|
||||
DBUG_RETURN(stmt->is_protocol_text() ?
|
||||
FALSE : (send_prep_stmt(stmt, 0) || thd->protocol->flush()));
|
||||
error:
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
@ -2309,11 +2461,9 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
|
|||
ulong flags= (ulong) packet[4];
|
||||
/* Query text for binary, general or slow log, if any of them is open */
|
||||
String expanded_query;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
uchar *packet_end= packet + packet_length;
|
||||
#endif
|
||||
Prepared_statement *stmt;
|
||||
bool error;
|
||||
bool open_cursor;
|
||||
DBUG_ENTER("mysql_stmt_execute");
|
||||
|
||||
packet+= 9; /* stmt_id + 5 bytes of flags */
|
||||
|
@ -2338,44 +2488,12 @@ void mysql_stmt_execute(THD *thd, char *packet_arg, uint packet_length)
|
|||
sp_cache_flush_obsolete(&thd->sp_proc_cache);
|
||||
sp_cache_flush_obsolete(&thd->sp_func_cache);
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (stmt->param_count)
|
||||
{
|
||||
uchar *null_array= packet;
|
||||
if (setup_conversion_functions(stmt, &packet, packet_end) ||
|
||||
stmt->set_params(stmt, null_array, packet, packet_end,
|
||||
&expanded_query))
|
||||
goto set_params_data_err;
|
||||
}
|
||||
#else
|
||||
/*
|
||||
In embedded library we re-install conversion routines each time
|
||||
we set params, and also we don't need to parse packet.
|
||||
So we do it in one function.
|
||||
*/
|
||||
if (stmt->param_count && stmt->set_params_data(stmt, &expanded_query))
|
||||
goto set_params_data_err;
|
||||
#endif
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
||||
open_cursor= test(flags & (ulong) CURSOR_TYPE_READ_ONLY);
|
||||
|
||||
/*
|
||||
If the free_list is not empty, we'll wrongly free some externally
|
||||
allocated items when cleaning up after validation of the prepared
|
||||
statement.
|
||||
*/
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
stmt->execute_loop(&expanded_query, open_cursor, packet, packet_end);
|
||||
|
||||
error= stmt->execute(&expanded_query,
|
||||
test(flags & (ulong) CURSOR_TYPE_READ_ONLY));
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
set_params_data_err:
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_execute");
|
||||
reset_stmt_params(stmt);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2421,24 +2539,8 @@ void mysql_sql_stmt_execute(THD *thd)
|
|||
|
||||
DBUG_PRINT("info",("stmt: 0x%lx", (long) stmt));
|
||||
|
||||
/*
|
||||
If the free_list is not empty, we'll wrongly free some externally
|
||||
allocated items when cleaning up after validation of the prepared
|
||||
statement.
|
||||
*/
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
(void) stmt->execute_loop(&expanded_query, FALSE, NULL, NULL);
|
||||
|
||||
if (stmt->set_params_from_vars(stmt, lex->prepared_stmt_params,
|
||||
&expanded_query))
|
||||
goto set_params_data_err;
|
||||
|
||||
(void) stmt->execute(&expanded_query, FALSE);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
set_params_data_err:
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "EXECUTE");
|
||||
reset_stmt_params(stmt);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -2742,7 +2844,7 @@ Select_fetch_protocol_binary::send_data(List<Item> &fields)
|
|||
****************************************************************************/
|
||||
|
||||
Prepared_statement::Prepared_statement(THD *thd_arg, Protocol *protocol_arg)
|
||||
:Statement(&main_lex, &main_mem_root,
|
||||
:Statement(0, &main_mem_root,
|
||||
INITIALIZED, ++thd_arg->statement_id_counter),
|
||||
thd(thd_arg),
|
||||
result(thd_arg),
|
||||
|
@ -2813,7 +2915,11 @@ Prepared_statement::~Prepared_statement()
|
|||
like Item_param, don't free everything until free_items()
|
||||
*/
|
||||
free_items();
|
||||
delete lex->result;
|
||||
if (lex)
|
||||
{
|
||||
delete lex->result;
|
||||
delete (st_lex_local *) lex;
|
||||
}
|
||||
free_root(&main_mem_root, MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
@ -2849,6 +2955,34 @@ bool Prepared_statement::set_name(LEX_STRING *name_arg)
|
|||
return name.str == 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Remember the current database.
|
||||
|
||||
We must reset/restore the current database during execution of
|
||||
a prepared statement since it affects execution environment:
|
||||
privileges, @@character_set_database, and other.
|
||||
|
||||
@return Returns an error if out of memory.
|
||||
*/
|
||||
|
||||
bool
|
||||
Prepared_statement::set_db(const char *db_arg, uint db_length_arg)
|
||||
{
|
||||
/* Remember the current database. */
|
||||
if (db_arg && db_length_arg)
|
||||
{
|
||||
db= this->strmake(db_arg, db_length_arg);
|
||||
db_length= db_length_arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
db= NULL;
|
||||
db_length= 0;
|
||||
}
|
||||
return db_arg != NULL && db == NULL;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Common parts of mysql_[sql]_stmt_prepare, mysql_[sql]_stmt_execute.
|
||||
Essentially, these functions do all the magic of preparing/executing
|
||||
|
@ -2890,6 +3024,12 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||
*/
|
||||
status_var_increment(thd->status_var.com_stmt_prepare);
|
||||
|
||||
if (! (lex= new (mem_root) st_lex_local))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
if (set_db(thd->db, thd->db_length))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
/*
|
||||
alloc_query() uses thd->memroot && thd->query, so we should call
|
||||
both of backup_statement() and backup_query_arena() here.
|
||||
|
@ -2917,19 +3057,6 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||
|
||||
lex->set_trg_event_type_for_tables();
|
||||
|
||||
/* Remember the current database. */
|
||||
|
||||
if (thd->db && thd->db_length)
|
||||
{
|
||||
db= this->strmake(thd->db, thd->db_length);
|
||||
db_length= thd->db_length;
|
||||
}
|
||||
else
|
||||
{
|
||||
db= NULL;
|
||||
db_length= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
While doing context analysis of the query (in check_prepared_statement)
|
||||
we allocate a lot of additional memory: for open tables, JOINs, derived
|
||||
|
@ -2953,7 +3080,7 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||
*/
|
||||
|
||||
if (error == 0)
|
||||
error= check_prepared_statement(this, name.str != 0);
|
||||
error= check_prepared_statement(this);
|
||||
|
||||
/*
|
||||
Currently CREATE PROCEDURE/TRIGGER/EVENT are prohibited in prepared
|
||||
|
@ -3000,6 +3127,310 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Assign parameter values either from variables, in case of SQL PS
|
||||
or from the execute packet.
|
||||
|
||||
@param expanded_query a container with the original SQL statement.
|
||||
'?' placeholders will be replaced with
|
||||
their values in case of success.
|
||||
The result is used for logging and replication
|
||||
@param packet pointer to execute packet.
|
||||
NULL in case of SQL PS
|
||||
@param packet_end end of the packet. NULL in case of SQL PS
|
||||
|
||||
@todo Use a paremeter source class family instead of 'if's, and
|
||||
support stored procedure variables.
|
||||
|
||||
@retval TRUE an error occurred when assigning a parameter (likely
|
||||
a conversion error or out of memory, or malformed packet)
|
||||
@retval FALSE success
|
||||
*/
|
||||
|
||||
bool
|
||||
Prepared_statement::set_parameters(String *expanded_query,
|
||||
uchar *packet, uchar *packet_end)
|
||||
{
|
||||
bool is_sql_ps= packet == NULL;
|
||||
|
||||
if (is_sql_ps)
|
||||
{
|
||||
/* SQL prepared statement */
|
||||
if (set_params_from_vars(this, thd->lex->prepared_stmt_params,
|
||||
expanded_query))
|
||||
goto set_params_data_err;
|
||||
}
|
||||
else if (param_count)
|
||||
{
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
uchar *null_array= packet;
|
||||
if (setup_conversion_functions(this, &packet, packet_end) ||
|
||||
set_params(this, null_array, packet, packet_end,
|
||||
expanded_query))
|
||||
goto set_params_data_err;
|
||||
#else
|
||||
/*
|
||||
In embedded library we re-install conversion routines each time
|
||||
we set params, and also we don't need to parse packet.
|
||||
So we do it in one function.
|
||||
*/
|
||||
if (set_params_data(this, expanded_query))
|
||||
goto set_params_data_err;
|
||||
#endif
|
||||
}
|
||||
return FALSE;
|
||||
set_params_data_err:
|
||||
my_error(ER_WRONG_ARGUMENTS, MYF(0),
|
||||
is_sql_ps ? "EXECUTE" : "mysql_stmt_execute");
|
||||
reset_stmt_params(this);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Execute a prepared statement. Re-prepare it a limited number
|
||||
of times if necessary.
|
||||
|
||||
Try to execute a prepared statement. If there is a metadata
|
||||
validation error, prepare a new copy of the prepared statement,
|
||||
swap the old and the new statements, and try again.
|
||||
If there is a validation error again, repeat the above, but
|
||||
perform no more than MAX_REPREPARE_ATTEMPTS.
|
||||
|
||||
@note We have to try several times in a loop since we
|
||||
release metadata locks on tables after prepared statement
|
||||
prepare. Therefore, a DDL statement may sneak in between prepare
|
||||
and execute of a new statement. If this happens repeatedly
|
||||
more than MAX_REPREPARE_ATTEMPTS times, we give up.
|
||||
|
||||
In future we need to be able to keep the metadata locks between
|
||||
prepare and execute, but right now open_and_lock_tables(), as
|
||||
well as close_thread_tables() are buried deep inside
|
||||
execution code (mysql_execute_command()).
|
||||
|
||||
@return TRUE if an error, FALSE if success
|
||||
@retval TRUE either MAX_REPREPARE_ATTEMPTS has been reached,
|
||||
or some general error
|
||||
@retval FALSE successfully executed the statement, perhaps
|
||||
after having reprepared it a few times.
|
||||
*/
|
||||
|
||||
bool
|
||||
Prepared_statement::execute_loop(String *expanded_query,
|
||||
bool open_cursor,
|
||||
uchar *packet,
|
||||
uchar *packet_end)
|
||||
{
|
||||
const int MAX_REPREPARE_ATTEMPTS= 3;
|
||||
Execute_observer execute_observer;
|
||||
bool error;
|
||||
int reprepare_attempt= 0;
|
||||
|
||||
if (set_parameters(expanded_query, packet, packet_end))
|
||||
return TRUE;
|
||||
|
||||
reexecute:
|
||||
execute_observer.m_invalidated= FALSE;
|
||||
|
||||
/*
|
||||
If the free_list is not empty, we'll wrongly free some externally
|
||||
allocated items when cleaning up after validation of the prepared
|
||||
statement.
|
||||
*/
|
||||
DBUG_ASSERT(thd->free_list == NULL);
|
||||
|
||||
/*
|
||||
Install the metadata observer. If some metadata version is
|
||||
different from prepare time and an observer is installed,
|
||||
the observer method will be invoked to push an error into
|
||||
the error stack.
|
||||
*/
|
||||
if (sql_command_flags[lex->sql_command] &
|
||||
CF_REEXECUTION_FRAGILE)
|
||||
{
|
||||
thd->m_metadata_observer= &execute_observer;
|
||||
}
|
||||
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(),QUERY_PRIOR);
|
||||
|
||||
error= execute(expanded_query, open_cursor) || thd->is_error();
|
||||
|
||||
if (!(specialflag & SPECIAL_NO_PRIOR))
|
||||
my_pthread_setprio(pthread_self(), WAIT_PRIOR);
|
||||
|
||||
thd->m_metadata_observer= 0;
|
||||
|
||||
if (error && !thd->is_fatal_error && !thd->killed &&
|
||||
execute_observer.m_invalidated &&
|
||||
reprepare_attempt++ < MAX_REPREPARE_ATTEMPTS)
|
||||
{
|
||||
thd->clear_error();
|
||||
|
||||
error= reprepare();
|
||||
|
||||
if (! error) /* Success */
|
||||
goto reexecute;
|
||||
}
|
||||
reset_stmt_params(this);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Reprepare this prepared statement.
|
||||
|
||||
Currently this is implemented by creating a new prepared
|
||||
statement, preparing it with the original query and then
|
||||
swapping the new statement and the original one.
|
||||
|
||||
@retval TRUE an error occurred. Possible errors include
|
||||
incompatibility of new and old result set
|
||||
metadata
|
||||
@retval FALSE success, the statement has been reprepared
|
||||
*/
|
||||
|
||||
bool
|
||||
Prepared_statement::reprepare()
|
||||
{
|
||||
char saved_cur_db_name_buf[NAME_LEN+1];
|
||||
LEX_STRING saved_cur_db_name=
|
||||
{ saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
|
||||
LEX_STRING stmt_db_name= { db, db_length };
|
||||
Prepared_statement *copy;
|
||||
bool cur_db_changed;
|
||||
bool error= TRUE;
|
||||
|
||||
status_var_increment(thd->status_var.com_stmt_reprepare);
|
||||
|
||||
copy= new Prepared_statement(thd, &thd->protocol_text);
|
||||
|
||||
if (! copy)
|
||||
return TRUE;
|
||||
|
||||
if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE,
|
||||
&cur_db_changed))
|
||||
goto end;
|
||||
|
||||
error= (name.str && copy->set_name(&name) ||
|
||||
copy->prepare(query, query_length) ||
|
||||
validate_metadata(copy));
|
||||
|
||||
if (cur_db_changed)
|
||||
mysql_change_db(thd, &saved_cur_db_name, TRUE);
|
||||
|
||||
if (! error)
|
||||
{
|
||||
swap_prepared_statement(copy);
|
||||
swap_parameter_array(param_array, copy->param_array, param_count);
|
||||
#ifndef DBUG_OFF
|
||||
is_reprepared= TRUE;
|
||||
#endif
|
||||
/*
|
||||
Clear possible warnigns during re-prepare, it has to be completely
|
||||
transparent to the user. We use mysql_reset_errors() since
|
||||
there were no separate query id issued for re-prepare.
|
||||
*/
|
||||
mysql_reset_errors(thd, TRUE);
|
||||
}
|
||||
end:
|
||||
delete copy;
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Validate statement result set metadata (if the statement returns
|
||||
a result set).
|
||||
|
||||
Currently we only check that the number of columns of the result
|
||||
set did not change.
|
||||
This is a helper method used during re-prepare.
|
||||
|
||||
@param[in] copy the re-prepared prepared statement to verify
|
||||
the metadata of
|
||||
|
||||
@retval TRUE error, ER_PS_NEED_REBIND is reported
|
||||
@retval FALSE statement return no or compatible metadata
|
||||
*/
|
||||
|
||||
|
||||
bool Prepared_statement::validate_metadata(Prepared_statement *copy)
|
||||
{
|
||||
/**
|
||||
If this is an SQL prepared statement or EXPLAIN,
|
||||
return FALSE -- the metadata of the original SELECT,
|
||||
if any, has not been sent to the client.
|
||||
*/
|
||||
if (is_protocol_text() || lex->describe)
|
||||
return FALSE;
|
||||
|
||||
if (lex->select_lex.item_list.elements !=
|
||||
copy->lex->select_lex.item_list.elements)
|
||||
{
|
||||
/** Column counts mismatch. */
|
||||
my_error(ER_PS_REBIND, MYF(0));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Replace the original prepared statement with a prepared copy.
|
||||
|
||||
This is a private helper that is used as part of statement
|
||||
reprepare
|
||||
|
||||
@return This function does not return any errors.
|
||||
*/
|
||||
|
||||
void
|
||||
Prepared_statement::swap_prepared_statement(Prepared_statement *copy)
|
||||
{
|
||||
Statement tmp_stmt;
|
||||
|
||||
/* Swap memory roots. */
|
||||
swap_variables(MEM_ROOT, main_mem_root, copy->main_mem_root);
|
||||
|
||||
/* Swap the arenas */
|
||||
tmp_stmt.set_query_arena(this);
|
||||
set_query_arena(copy);
|
||||
copy->set_query_arena(&tmp_stmt);
|
||||
|
||||
/* Swap the statement parent classes */
|
||||
tmp_stmt.set_statement(this);
|
||||
set_statement(copy);
|
||||
copy->set_statement(&tmp_stmt);
|
||||
|
||||
/* Swap ids back, we need the original id */
|
||||
swap_variables(ulong, id, copy->id);
|
||||
/* Swap mem_roots back, they must continue pointing at the main_mem_roots */
|
||||
swap_variables(MEM_ROOT *, mem_root, copy->mem_root);
|
||||
/*
|
||||
Swap the old and the new parameters array. The old array
|
||||
is allocated in the old arena.
|
||||
*/
|
||||
swap_variables(Item_param **, param_array, copy->param_array);
|
||||
/* Swap flags: this is perhaps unnecessary */
|
||||
swap_variables(uint, flags, copy->flags);
|
||||
/* Swap names, the old name is allocated in the wrong memory root */
|
||||
swap_variables(LEX_STRING, name, copy->name);
|
||||
/* Ditto */
|
||||
swap_variables(char *, db, copy->db);
|
||||
|
||||
DBUG_ASSERT(db_length == copy->db_length);
|
||||
DBUG_ASSERT(param_count == copy->param_count);
|
||||
DBUG_ASSERT(thd == copy->thd);
|
||||
last_error[0]= '\0';
|
||||
last_errno= 0;
|
||||
/* Do not swap protocols, the copy always has protocol_text */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Execute a prepared statement.
|
||||
|
||||
|
@ -3162,10 +3593,7 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||
DBUG_ASSERT(! (error && cursor));
|
||||
|
||||
if (! cursor)
|
||||
{
|
||||
cleanup_stmt();
|
||||
reset_stmt_params(this);
|
||||
}
|
||||
|
||||
thd->set_statement(&stmt_backup);
|
||||
thd->stmt_arena= old_stmt_arena;
|
||||
|
|
|
@ -4776,9 +4776,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
|||
DBUG_ENTER("mysql_create_like_table");
|
||||
|
||||
|
||||
/* CREATE TABLE ... LIKE is not allowed for views. */
|
||||
src_table->required_type= FRMTYPE_TABLE;
|
||||
|
||||
/*
|
||||
By opening source table we guarantee that it exists and no concurrent
|
||||
DDL operation will mess with it. Later we also take an exclusive
|
||||
|
|
|
@ -3582,20 +3582,30 @@ create2:
|
|||
| LIKE table_ident
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
TABLE_LIST *src_table;
|
||||
LEX *lex= thd->lex;
|
||||
|
||||
lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
|
||||
if (!lex->select_lex.add_table_to_list(thd, $2, NULL, 0, TL_READ))
|
||||
src_table= lex->select_lex.add_table_to_list(thd, $2, NULL, 0,
|
||||
TL_READ);
|
||||
if (! src_table)
|
||||
MYSQL_YYABORT;
|
||||
/* CREATE TABLE ... LIKE is not allowed for views. */
|
||||
src_table->required_type= FRMTYPE_TABLE;
|
||||
}
|
||||
| '(' LIKE table_ident ')'
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
TABLE_LIST *src_table;
|
||||
LEX *lex= thd->lex;
|
||||
|
||||
lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
|
||||
if (!lex->select_lex.add_table_to_list(thd, $3, NULL, 0, TL_READ))
|
||||
src_table= lex->select_lex.add_table_to_list(thd, $3, NULL, 0,
|
||||
TL_READ);
|
||||
if (! src_table)
|
||||
MYSQL_YYABORT;
|
||||
/* CREATE TABLE ... LIKE is not allowed for views. */
|
||||
src_table->required_type= FRMTYPE_TABLE;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
130
sql/table.h
130
sql/table.h
|
@ -438,6 +438,105 @@ typedef struct st_table_share
|
|||
return table_map_id;
|
||||
}
|
||||
|
||||
/**
|
||||
Convert unrelated members of TABLE_SHARE to one enum
|
||||
representing its metadata type.
|
||||
|
||||
@todo perhaps we need to have a member instead of a function.
|
||||
*/
|
||||
enum enum_metadata_type get_metadata_type() const
|
||||
{
|
||||
if (is_view)
|
||||
return METADATA_VIEW;
|
||||
switch (tmp_table) {
|
||||
case NO_TMP_TABLE:
|
||||
return METADATA_BASE_TABLE;
|
||||
case SYSTEM_TMP_TABLE:
|
||||
return METADATA_I_S_TABLE;
|
||||
default:
|
||||
return METADATA_TMP_TABLE;
|
||||
}
|
||||
}
|
||||
/**
|
||||
Return a table metadata version.
|
||||
* for base tables, we return table_map_id.
|
||||
It is assigned from a global counter incremented for each
|
||||
new table loaded into the table definition cache (TDC).
|
||||
* for temporary tables it's table_map_id again. But for
|
||||
temporary tables table_map_id is assigned from
|
||||
thd->query_id. The latter is assigned from a thread local
|
||||
counter incremented for every new SQL statement. Since
|
||||
temporary tables are thread-local, each temporary table
|
||||
gets a unique id.
|
||||
* for everything else (views, information schema tables),
|
||||
the version id is zero.
|
||||
|
||||
This choice of version id is a large compromise
|
||||
to have a working prepared statement validation in 5.1. In
|
||||
future version ids will be persistent, as described in WL#4180.
|
||||
|
||||
Let's try to explain why and how this limited solution allows
|
||||
to validate prepared statements.
|
||||
|
||||
Firstly, spaces (in mathematical sense) of version numbers
|
||||
never intersect for different metadata types. Therefore,
|
||||
version id of a temporary table is never compared with
|
||||
a version id of a view or a temporary table, and vice versa.
|
||||
|
||||
Secondly, for base tables, we know that each DDL flushes the
|
||||
respective share from the TDC. This ensures that whenever
|
||||
a table is altered or dropped and recreated, it gets a new
|
||||
version id.
|
||||
Unfortunately, since elements of the TDC are also flushed on
|
||||
LRU basis, this choice of version ids leads to false positives.
|
||||
E.g. when the TDC size is too small, we may have a SELECT
|
||||
* FROM INFORMATION_SCHEMA.TABLES flush all its elements, which
|
||||
in turn will lead to a validation error and a subsequent
|
||||
reprepare of all prepared statements. This is
|
||||
considered acceptable, since as long as prepared statements are
|
||||
automatically reprepared, spurious invalidation is only
|
||||
a performance hit. Besides, no better simple solution exists.
|
||||
|
||||
For temporary tables, using thd->query_id ensures that if
|
||||
a temporary table was altered or recreated, a new version id is
|
||||
assigned. This suits validation needs very well and will perhaps
|
||||
never change.
|
||||
|
||||
Metadata of information schema tables never changes.
|
||||
Thus we can safely assume 0 for a good enough version id.
|
||||
|
||||
Views are a special and tricky case. A view is always inlined
|
||||
into the parse tree of a prepared statement at prepare.
|
||||
Thus, when we execute a prepared statement, the parse tree
|
||||
will not get modified even if the view is replaced with another
|
||||
view. Therefore, we can safely choose 0 for version id of
|
||||
views and effectively never invalidate a prepared statement
|
||||
when a view definition is altered. Note, that this leads to
|
||||
wrong binary log in statement-based replication, since we log
|
||||
prepared statement execution in form Query_log_events
|
||||
containing conventional statements. But since there is no
|
||||
metadata locking for views, the very same problem exists for
|
||||
conventional statements alone, as reported in Bug#25144. The only
|
||||
difference between prepared and conventional execution is,
|
||||
effectively, that for prepared statements the race condition
|
||||
window is much wider.
|
||||
In 6.0 we plan to support view metadata locking (WL#3726) and
|
||||
extend table definition cache to cache views (WL#4298).
|
||||
When this is done, views will be handled in the same fashion
|
||||
as the base tables.
|
||||
|
||||
Finally, by taking into account metadata type, we always
|
||||
track that a change has taken place when a view is replaced
|
||||
with a base table, a base table is replaced with a temporary
|
||||
table and so on.
|
||||
|
||||
@sa TABLE_LIST::is_metadata_version_equal()
|
||||
*/
|
||||
ulong get_metadata_version() const
|
||||
{
|
||||
return tmp_table == SYSTEM_TMP_TABLE || is_view ? 0 : table_map_id;
|
||||
}
|
||||
|
||||
} TABLE_SHARE;
|
||||
|
||||
|
||||
|
@ -1233,6 +1332,33 @@ struct TABLE_LIST
|
|||
child_def_version= ~0UL;
|
||||
}
|
||||
|
||||
/**
|
||||
Compare the version of metadata from the previous execution
|
||||
(if any) with values obtained from the current table
|
||||
definition cache element.
|
||||
|
||||
@sa check_and_update_table_version()
|
||||
*/
|
||||
inline
|
||||
bool is_metadata_version_equal(TABLE_SHARE *s) const
|
||||
{
|
||||
return (m_metadata_type == s->get_metadata_type() &&
|
||||
m_metadata_version == s->get_metadata_version());
|
||||
}
|
||||
|
||||
/**
|
||||
Record the value of metadata version of the corresponding
|
||||
table definition cache element in this parse tree node.
|
||||
|
||||
@sa check_and_update_table_version()
|
||||
*/
|
||||
inline
|
||||
void set_metadata_version(TABLE_SHARE *s)
|
||||
{
|
||||
m_metadata_type= s->get_metadata_type();
|
||||
m_metadata_version= s->get_metadata_version();
|
||||
}
|
||||
|
||||
private:
|
||||
bool prep_check_option(THD *thd, uint8 check_opt_type);
|
||||
bool prep_where(THD *thd, Item **conds, bool no_where_clause);
|
||||
|
@ -1243,6 +1369,10 @@ private:
|
|||
|
||||
/* Remembered MERGE child def version. See top comment in ha_myisammrg.cc */
|
||||
ulong child_def_version;
|
||||
/** See comments for set_metadata_version() */
|
||||
enum enum_metadata_type m_metadata_type;
|
||||
/** See comments for set_metadata_version() */
|
||||
ulong m_metadata_version;
|
||||
};
|
||||
|
||||
class Item;
|
||||
|
|
|
@ -11132,7 +11132,7 @@ static void test_bug4236()
|
|||
int rc;
|
||||
MYSQL_STMT backup;
|
||||
|
||||
myheader("test_bug4296");
|
||||
myheader("test_bug4236");
|
||||
|
||||
stmt= mysql_stmt_init(mysql);
|
||||
|
||||
|
@ -17383,6 +17383,123 @@ static void test_bug28386()
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
static void test_wl4166()
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
int int_data;
|
||||
char str_data[50];
|
||||
char tiny_data;
|
||||
short small_data;
|
||||
longlong big_data;
|
||||
float real_data;
|
||||
double double_data;
|
||||
ulong length[7];
|
||||
my_bool is_null[7];
|
||||
MYSQL_BIND my_bind[7];
|
||||
int rc;
|
||||
int i;
|
||||
|
||||
myheader("test_wl4166");
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS table_4166");
|
||||
myquery(rc);
|
||||
|
||||
rc= mysql_query(mysql, "CREATE TABLE table_4166(col1 tinyint NOT NULL, "
|
||||
"col2 varchar(15), col3 int, "
|
||||
"col4 smallint, col5 bigint, "
|
||||
"col6 float, col7 double, "
|
||||
"colX varchar(10) default NULL)");
|
||||
myquery(rc);
|
||||
|
||||
stmt= mysql_simple_prepare(mysql,
|
||||
"INSERT INTO table_4166(col1, col2, col3, col4, col5, col6, col7) "
|
||||
"VALUES(?, ?, ?, ?, ?, ?, ?)");
|
||||
check_stmt(stmt);
|
||||
|
||||
verify_param_count(stmt, 7);
|
||||
|
||||
/* tinyint */
|
||||
my_bind[0].buffer_type= MYSQL_TYPE_TINY;
|
||||
my_bind[0].buffer= (void *)&tiny_data;
|
||||
/* string */
|
||||
my_bind[1].buffer_type= MYSQL_TYPE_STRING;
|
||||
my_bind[1].buffer= (void *)str_data;
|
||||
my_bind[1].buffer_length= 1000; /* Max string length */
|
||||
/* integer */
|
||||
my_bind[2].buffer_type= MYSQL_TYPE_LONG;
|
||||
my_bind[2].buffer= (void *)&int_data;
|
||||
/* short */
|
||||
my_bind[3].buffer_type= MYSQL_TYPE_SHORT;
|
||||
my_bind[3].buffer= (void *)&small_data;
|
||||
/* bigint */
|
||||
my_bind[4].buffer_type= MYSQL_TYPE_LONGLONG;
|
||||
my_bind[4].buffer= (void *)&big_data;
|
||||
/* float */
|
||||
my_bind[5].buffer_type= MYSQL_TYPE_FLOAT;
|
||||
my_bind[5].buffer= (void *)&real_data;
|
||||
/* double */
|
||||
my_bind[6].buffer_type= MYSQL_TYPE_DOUBLE;
|
||||
my_bind[6].buffer= (void *)&double_data;
|
||||
|
||||
for (i= 0; i < (int) array_elements(my_bind); i++)
|
||||
{
|
||||
my_bind[i].length= &length[i];
|
||||
my_bind[i].is_null= &is_null[i];
|
||||
is_null[i]= 0;
|
||||
}
|
||||
|
||||
rc= mysql_stmt_bind_param(stmt, my_bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
int_data= 320;
|
||||
small_data= 1867;
|
||||
big_data= 1000;
|
||||
real_data= 2;
|
||||
double_data= 6578.001;
|
||||
|
||||
/* now, execute the prepared statement to insert 10 records.. */
|
||||
for (tiny_data= 0; tiny_data < 10; tiny_data++)
|
||||
{
|
||||
length[1]= my_sprintf(str_data, (str_data, "MySQL%d", int_data));
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
int_data += 25;
|
||||
small_data += 10;
|
||||
big_data += 100;
|
||||
real_data += 1;
|
||||
double_data += 10.09;
|
||||
}
|
||||
|
||||
/* force a re-prepare with some DDL */
|
||||
|
||||
rc= mysql_query(mysql,
|
||||
"ALTER TABLE table_4166 change colX colX varchar(20) default NULL");
|
||||
myquery(rc);
|
||||
|
||||
/*
|
||||
execute the prepared statement again,
|
||||
without changing the types of parameters already bound.
|
||||
*/
|
||||
|
||||
for (tiny_data= 50; tiny_data < 60; tiny_data++)
|
||||
{
|
||||
length[1]= my_sprintf(str_data, (str_data, "MySQL%d", int_data));
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
int_data += 25;
|
||||
small_data += 10;
|
||||
big_data += 100;
|
||||
real_data += 1;
|
||||
double_data += 10.09;
|
||||
}
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE table_4166");
|
||||
myquery(rc);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
Read and parse arguments and MySQL options from my.cnf
|
||||
*/
|
||||
|
@ -17689,6 +17806,7 @@ static struct my_tests_st my_tests[]= {
|
|||
{ "test_bug31418", test_bug31418 },
|
||||
{ "test_bug31669", test_bug31669 },
|
||||
{ "test_bug28386", test_bug28386 },
|
||||
{ "test_wl4166", test_wl4166 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue