Merge bk-internal.mysql.com:/home/bk/mysql-5.1-runtime
into ibm.opbmk:/home/alik/Documents/MySQL/devel/5.1-rt-bug25843 sql/mysql_priv.h: Auto merged sql/sp.cc: Auto merged sql/sp_head.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_db.cc: Auto merged
This commit is contained in:
commit
d7463b5e1b
@ -275,5 +275,223 @@ drop table t1;
|
|||||||
--echo ---- disconnect connection con1 ----
|
--echo ---- disconnect connection con1 ----
|
||||||
disconnect con1;
|
disconnect con1;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #25843 Changing default database between PREPARE and EXECUTE of statement
|
||||||
|
# breaks binlog.
|
||||||
|
#
|
||||||
|
# There were actually two problems discovered by this bug:
|
||||||
|
#
|
||||||
|
# 1. Default (current) database is not fixed at the creation time.
|
||||||
|
# That leads to wrong output of DATABASE() function.
|
||||||
|
#
|
||||||
|
# 2. Database attributes (@@collation_database) are not fixed at the creation
|
||||||
|
# time. That leads to wrong resultset.
|
||||||
|
#
|
||||||
|
# Binlog breakage and Query Cache wrong output happened because of the first
|
||||||
|
# problem.
|
||||||
|
#
|
||||||
|
|
||||||
|
--echo ########################################################################
|
||||||
|
--echo #
|
||||||
|
--echo # BUG#25843: Changing default database between PREPARE and EXECUTE of
|
||||||
|
--echo # statement breaks binlog.
|
||||||
|
--echo #
|
||||||
|
--echo ########################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo #
|
||||||
|
--echo # Check that default database and its attributes are fixed at the
|
||||||
|
--echo # creation time.
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
# Prepare data structures.
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--disable_warnings
|
||||||
|
DROP DATABASE IF EXISTS mysqltest1;
|
||||||
|
DROP DATABASE IF EXISTS mysqltest2;
|
||||||
|
--enable_warnings
|
||||||
|
|
||||||
|
--echo
|
||||||
|
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
|
||||||
|
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
CREATE TABLE mysqltest1.t1(msg VARCHAR(255));
|
||||||
|
CREATE TABLE mysqltest2.t1(msg VARCHAR(255));
|
||||||
|
|
||||||
|
# - Create a prepared statement with mysqltest1 as default database;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
PREPARE stmt_a_1 FROM 'INSERT INTO t1 VALUES(DATABASE())';
|
||||||
|
PREPARE stmt_a_2 FROM 'INSERT INTO t1 VALUES(@@collation_database)';
|
||||||
|
|
||||||
|
# - Execute on mysqltest1.
|
||||||
|
|
||||||
|
--echo
|
||||||
|
|
||||||
|
EXECUTE stmt_a_1;
|
||||||
|
EXECUTE stmt_a_2;
|
||||||
|
|
||||||
|
# - Execute on mysqltest2.
|
||||||
|
|
||||||
|
--echo
|
||||||
|
|
||||||
|
use mysqltest2;
|
||||||
|
|
||||||
|
EXECUTE stmt_a_1;
|
||||||
|
EXECUTE stmt_a_2;
|
||||||
|
|
||||||
|
# - Check the results;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SELECT * FROM mysqltest1.t1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SELECT * FROM mysqltest2.t1;
|
||||||
|
|
||||||
|
# - Drop prepared statements.
|
||||||
|
|
||||||
|
--echo
|
||||||
|
DROP PREPARE stmt_a_1;
|
||||||
|
DROP PREPARE stmt_a_2;
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo #
|
||||||
|
--echo # The Query Cache test case.
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo
|
||||||
|
DELETE FROM mysqltest1.t1;
|
||||||
|
DELETE FROM mysqltest2.t1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
INSERT INTO mysqltest1.t1 VALUES('mysqltest1.t1');
|
||||||
|
INSERT INTO mysqltest2.t1 VALUES('mysqltest2.t1');
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use mysqltest1;
|
||||||
|
PREPARE stmt_b_1 FROM 'SELECT * FROM t1';
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use mysqltest2;
|
||||||
|
PREPARE stmt_b_2 FROM 'SELECT * FROM t1';
|
||||||
|
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_b_1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_b_2;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_b_1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_b_2;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
DROP PREPARE stmt_b_1;
|
||||||
|
DROP PREPARE stmt_b_2;
|
||||||
|
|
||||||
|
# Cleanup.
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use test;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
DROP DATABASE mysqltest2;
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo #
|
||||||
|
--echo # Check that prepared statements work properly when there is no current
|
||||||
|
--echo # database.
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo
|
||||||
|
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
|
||||||
|
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
PREPARE stmt_c_1 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use mysqltest2;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
PREPARE stmt_c_2 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
--echo
|
||||||
|
DROP DATABASE mysqltest2;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
|
||||||
|
# -- Here we have: current db: NULL; stmt db: mysqltest1;
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_c_1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
|
||||||
|
# -- Here we have: current db: NULL; stmt db: mysqltest2 (non-existent);
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_c_2;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
|
||||||
|
# -- Create prepared statement, which has no current database.
|
||||||
|
|
||||||
|
--echo
|
||||||
|
PREPARE stmt_c_3 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
# -- Here we have: current db: NULL; stmt db: NULL;
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_c_3;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
# -- Here we have: current db: mysqltest1; stmt db: mysqltest2 (non-existent);
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_c_2;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
|
||||||
|
# -- Here we have: current db: mysqltest1; stmt db: NULL;
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_c_3;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use test;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo ########################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
set @@global.query_cache_size=@initial_query_cache_size;
|
set @@global.query_cache_size=@initial_query_cache_size;
|
||||||
flush status; # reset Qcache status variables for next tests
|
flush status; # reset Qcache status variables for next tests
|
||||||
|
@ -371,5 +371,163 @@ Variable_name Value
|
|||||||
Qcache_hits 21
|
Qcache_hits 21
|
||||||
drop table t1;
|
drop table t1;
|
||||||
---- disconnect connection con1 ----
|
---- disconnect connection con1 ----
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# BUG#25843: Changing default database between PREPARE and EXECUTE of
|
||||||
|
# statement breaks binlog.
|
||||||
|
#
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that default database and its attributes are fixed at the
|
||||||
|
# creation time.
|
||||||
|
#
|
||||||
|
|
||||||
|
DROP DATABASE IF EXISTS mysqltest1;
|
||||||
|
DROP DATABASE IF EXISTS mysqltest2;
|
||||||
|
|
||||||
|
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
|
||||||
|
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
CREATE TABLE mysqltest1.t1(msg VARCHAR(255));
|
||||||
|
CREATE TABLE mysqltest2.t1(msg VARCHAR(255));
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
PREPARE stmt_a_1 FROM 'INSERT INTO t1 VALUES(DATABASE())';
|
||||||
|
PREPARE stmt_a_2 FROM 'INSERT INTO t1 VALUES(@@collation_database)';
|
||||||
|
|
||||||
|
EXECUTE stmt_a_1;
|
||||||
|
EXECUTE stmt_a_2;
|
||||||
|
|
||||||
|
use mysqltest2;
|
||||||
|
EXECUTE stmt_a_1;
|
||||||
|
EXECUTE stmt_a_2;
|
||||||
|
|
||||||
|
SELECT * FROM mysqltest1.t1;
|
||||||
|
msg
|
||||||
|
mysqltest1
|
||||||
|
utf8_unicode_ci
|
||||||
|
mysqltest1
|
||||||
|
utf8_unicode_ci
|
||||||
|
|
||||||
|
SELECT * FROM mysqltest2.t1;
|
||||||
|
msg
|
||||||
|
|
||||||
|
DROP PREPARE stmt_a_1;
|
||||||
|
DROP PREPARE stmt_a_2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# The Query Cache test case.
|
||||||
|
#
|
||||||
|
|
||||||
|
DELETE FROM mysqltest1.t1;
|
||||||
|
DELETE FROM mysqltest2.t1;
|
||||||
|
|
||||||
|
INSERT INTO mysqltest1.t1 VALUES('mysqltest1.t1');
|
||||||
|
INSERT INTO mysqltest2.t1 VALUES('mysqltest2.t1');
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
PREPARE stmt_b_1 FROM 'SELECT * FROM t1';
|
||||||
|
|
||||||
|
use mysqltest2;
|
||||||
|
PREPARE stmt_b_2 FROM 'SELECT * FROM t1';
|
||||||
|
|
||||||
|
EXECUTE stmt_b_1;
|
||||||
|
msg
|
||||||
|
mysqltest1.t1
|
||||||
|
|
||||||
|
EXECUTE stmt_b_2;
|
||||||
|
msg
|
||||||
|
mysqltest2.t1
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
EXECUTE stmt_b_1;
|
||||||
|
msg
|
||||||
|
mysqltest1.t1
|
||||||
|
|
||||||
|
EXECUTE stmt_b_2;
|
||||||
|
msg
|
||||||
|
mysqltest2.t1
|
||||||
|
|
||||||
|
DROP PREPARE stmt_b_1;
|
||||||
|
DROP PREPARE stmt_b_2;
|
||||||
|
|
||||||
|
use test;
|
||||||
|
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
DROP DATABASE mysqltest2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that prepared statements work properly when there is no current
|
||||||
|
# database.
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
|
||||||
|
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
PREPARE stmt_c_1 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
use mysqltest2;
|
||||||
|
|
||||||
|
PREPARE stmt_c_2 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
DROP DATABASE mysqltest2;
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
EXECUTE stmt_c_1;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
mysqltest1 utf8_unicode_ci
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
EXECUTE stmt_c_2;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
Warnings:
|
||||||
|
Note 1049 Unknown database 'mysqltest2'
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
PREPARE stmt_c_3 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
EXECUTE stmt_c_3;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
EXECUTE stmt_c_2;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
Warnings:
|
||||||
|
Note 1049 Unknown database 'mysqltest2'
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
mysqltest1 utf8_unicode_ci
|
||||||
|
|
||||||
|
EXECUTE stmt_c_3;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
mysqltest1 utf8_unicode_ci
|
||||||
|
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
|
||||||
|
use test;
|
||||||
|
|
||||||
|
########################################################################
|
||||||
set @@global.query_cache_size=@initial_query_cache_size;
|
set @@global.query_cache_size=@initial_query_cache_size;
|
||||||
flush status;
|
flush status;
|
||||||
|
@ -371,5 +371,163 @@ Variable_name Value
|
|||||||
Qcache_hits 19
|
Qcache_hits 19
|
||||||
drop table t1;
|
drop table t1;
|
||||||
---- disconnect connection con1 ----
|
---- disconnect connection con1 ----
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# BUG#25843: Changing default database between PREPARE and EXECUTE of
|
||||||
|
# statement breaks binlog.
|
||||||
|
#
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that default database and its attributes are fixed at the
|
||||||
|
# creation time.
|
||||||
|
#
|
||||||
|
|
||||||
|
DROP DATABASE IF EXISTS mysqltest1;
|
||||||
|
DROP DATABASE IF EXISTS mysqltest2;
|
||||||
|
|
||||||
|
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
|
||||||
|
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
CREATE TABLE mysqltest1.t1(msg VARCHAR(255));
|
||||||
|
CREATE TABLE mysqltest2.t1(msg VARCHAR(255));
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
PREPARE stmt_a_1 FROM 'INSERT INTO t1 VALUES(DATABASE())';
|
||||||
|
PREPARE stmt_a_2 FROM 'INSERT INTO t1 VALUES(@@collation_database)';
|
||||||
|
|
||||||
|
EXECUTE stmt_a_1;
|
||||||
|
EXECUTE stmt_a_2;
|
||||||
|
|
||||||
|
use mysqltest2;
|
||||||
|
EXECUTE stmt_a_1;
|
||||||
|
EXECUTE stmt_a_2;
|
||||||
|
|
||||||
|
SELECT * FROM mysqltest1.t1;
|
||||||
|
msg
|
||||||
|
mysqltest1
|
||||||
|
utf8_unicode_ci
|
||||||
|
mysqltest1
|
||||||
|
utf8_unicode_ci
|
||||||
|
|
||||||
|
SELECT * FROM mysqltest2.t1;
|
||||||
|
msg
|
||||||
|
|
||||||
|
DROP PREPARE stmt_a_1;
|
||||||
|
DROP PREPARE stmt_a_2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# The Query Cache test case.
|
||||||
|
#
|
||||||
|
|
||||||
|
DELETE FROM mysqltest1.t1;
|
||||||
|
DELETE FROM mysqltest2.t1;
|
||||||
|
|
||||||
|
INSERT INTO mysqltest1.t1 VALUES('mysqltest1.t1');
|
||||||
|
INSERT INTO mysqltest2.t1 VALUES('mysqltest2.t1');
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
PREPARE stmt_b_1 FROM 'SELECT * FROM t1';
|
||||||
|
|
||||||
|
use mysqltest2;
|
||||||
|
PREPARE stmt_b_2 FROM 'SELECT * FROM t1';
|
||||||
|
|
||||||
|
EXECUTE stmt_b_1;
|
||||||
|
msg
|
||||||
|
mysqltest1.t1
|
||||||
|
|
||||||
|
EXECUTE stmt_b_2;
|
||||||
|
msg
|
||||||
|
mysqltest2.t1
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
EXECUTE stmt_b_1;
|
||||||
|
msg
|
||||||
|
mysqltest1.t1
|
||||||
|
|
||||||
|
EXECUTE stmt_b_2;
|
||||||
|
msg
|
||||||
|
mysqltest2.t1
|
||||||
|
|
||||||
|
DROP PREPARE stmt_b_1;
|
||||||
|
DROP PREPARE stmt_b_2;
|
||||||
|
|
||||||
|
use test;
|
||||||
|
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
DROP DATABASE mysqltest2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that prepared statements work properly when there is no current
|
||||||
|
# database.
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE DATABASE mysqltest1 COLLATE utf8_unicode_ci;
|
||||||
|
CREATE DATABASE mysqltest2 COLLATE utf8_general_ci;
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
PREPARE stmt_c_1 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
use mysqltest2;
|
||||||
|
|
||||||
|
PREPARE stmt_c_2 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
DROP DATABASE mysqltest2;
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
EXECUTE stmt_c_1;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
mysqltest1 utf8_unicode_ci
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
EXECUTE stmt_c_2;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
Warnings:
|
||||||
|
Note 1049 Unknown database 'mysqltest2'
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
PREPARE stmt_c_3 FROM 'SELECT DATABASE(), @@collation_database';
|
||||||
|
|
||||||
|
EXECUTE stmt_c_3;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
EXECUTE stmt_c_2;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
Warnings:
|
||||||
|
Note 1049 Unknown database 'mysqltest2'
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
mysqltest1 utf8_unicode_ci
|
||||||
|
|
||||||
|
EXECUTE stmt_c_3;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
NULL latin1_swedish_ci
|
||||||
|
|
||||||
|
SELECT DATABASE(), @@collation_database;
|
||||||
|
DATABASE() @@collation_database
|
||||||
|
mysqltest1 utf8_unicode_ci
|
||||||
|
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
|
||||||
|
use test;
|
||||||
|
|
||||||
|
########################################################################
|
||||||
set @@global.query_cache_size=@initial_query_cache_size;
|
set @@global.query_cache_size=@initial_query_cache_size;
|
||||||
flush status;
|
flush status;
|
||||||
|
@ -26,5 +26,44 @@ from-master-2-'',
|
|||||||
from-var-from-master-3
|
from-var-from-master-3
|
||||||
drop table t1;
|
drop table t1;
|
||||||
stop slave;
|
stop slave;
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
#
|
||||||
|
# BUG#25843: Changing default database between PREPARE and EXECUTE of
|
||||||
|
# statement breaks binlog.
|
||||||
|
#
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
#
|
||||||
|
# Check that binlog is filled properly.
|
||||||
|
#
|
||||||
|
|
||||||
|
CREATE DATABASE mysqltest1;
|
||||||
|
CREATE TABLE t1(c INT);
|
||||||
|
|
||||||
|
RESET MASTER;
|
||||||
|
RESET SLAVE;
|
||||||
|
|
||||||
|
PREPARE stmt_d_1 FROM 'INSERT INTO t1 VALUES(1)';
|
||||||
|
|
||||||
|
EXECUTE stmt_d_1;
|
||||||
|
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
EXECUTE stmt_d_1;
|
||||||
|
|
||||||
|
FLUSH LOGS;
|
||||||
|
|
||||||
|
SHOW BINLOG EVENTS FROM 106;
|
||||||
|
Log_name Pos Event_type Server_id End_log_pos Info
|
||||||
|
slave-bin.000001 106 Query 2 193 use `test`; INSERT INTO t1 VALUES(1)
|
||||||
|
slave-bin.000001 193 Query 2 280 use `test`; INSERT INTO t1 VALUES(1)
|
||||||
|
slave-bin.000001 280 Rotate 2 323 slave-bin.000002;pos=4
|
||||||
|
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
|
||||||
|
use test;
|
||||||
|
|
||||||
|
########################################################################
|
||||||
reset master;
|
reset master;
|
||||||
reset slave;
|
reset slave;
|
||||||
|
@ -46,6 +46,74 @@ stop slave;
|
|||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug #25843 Changing default database between PREPARE and EXECUTE of statement
|
||||||
|
# breaks binlog.
|
||||||
|
#
|
||||||
|
# There were actually two problems discovered by this bug:
|
||||||
|
#
|
||||||
|
# 1. Default (current) database is not fixed at the creation time.
|
||||||
|
# That leads to wrong output of DATABASE() function.
|
||||||
|
#
|
||||||
|
# 2. Database attributes (@@collation_database) are not fixed at the creation
|
||||||
|
# time. That leads to wrong resultset.
|
||||||
|
#
|
||||||
|
# Binlog breakage and Query Cache wrong output happened because of the first
|
||||||
|
# problem.
|
||||||
|
#
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo ########################################################################
|
||||||
|
--echo #
|
||||||
|
--echo # BUG#25843: Changing default database between PREPARE and EXECUTE of
|
||||||
|
--echo # statement breaks binlog.
|
||||||
|
--echo #
|
||||||
|
--echo ########################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo #
|
||||||
|
--echo # Check that binlog is filled properly.
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo
|
||||||
|
CREATE DATABASE mysqltest1;
|
||||||
|
CREATE TABLE t1(c INT);
|
||||||
|
|
||||||
|
--echo
|
||||||
|
RESET MASTER;
|
||||||
|
RESET SLAVE;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
PREPARE stmt_d_1 FROM 'INSERT INTO t1 VALUES(1)';
|
||||||
|
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_d_1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use mysqltest1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
EXECUTE stmt_d_1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
FLUSH LOGS;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
SHOW BINLOG EVENTS FROM 106;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
use test;
|
||||||
|
|
||||||
|
--echo
|
||||||
|
--echo ########################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
|
||||||
reset master;
|
reset master;
|
||||||
reset slave;
|
reset slave;
|
||||||
disconnect master;
|
disconnect master;
|
||||||
|
@ -937,9 +937,16 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent);
|
|||||||
bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
|
bool do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db,
|
||||||
char *new_table_name, char *new_table_alias,
|
char *new_table_name, char *new_table_alias,
|
||||||
bool skip_error);
|
bool skip_error);
|
||||||
|
|
||||||
bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
|
bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
|
||||||
bool force_switch);
|
bool force_switch);
|
||||||
|
|
||||||
|
bool mysql_opt_change_db(THD *thd,
|
||||||
|
const LEX_STRING *new_db_name,
|
||||||
|
LEX_STRING *saved_db_name,
|
||||||
|
bool force_switch,
|
||||||
|
bool *cur_db_changed);
|
||||||
|
|
||||||
void mysql_parse(THD *thd, const char *inBuf, uint length,
|
void mysql_parse(THD *thd, const char *inBuf, uint length,
|
||||||
const char ** semicolon);
|
const char ** semicolon);
|
||||||
|
|
||||||
|
150
sql/sp.cc
150
sql/sp.cc
@ -520,9 +520,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
|
|||||||
{
|
{
|
||||||
LEX *old_lex= thd->lex, newlex;
|
LEX *old_lex= thd->lex, newlex;
|
||||||
String defstr;
|
String defstr;
|
||||||
char old_db_buf[NAME_LEN+1];
|
char saved_cur_db_name_buf[NAME_LEN+1];
|
||||||
LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
|
LEX_STRING saved_cur_db_name=
|
||||||
bool dbchanged;
|
{ saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
|
||||||
|
bool cur_db_changed;
|
||||||
ulong old_sql_mode= thd->variables.sql_mode;
|
ulong old_sql_mode= thd->variables.sql_mode;
|
||||||
ha_rows old_select_limit= thd->variables.select_limit;
|
ha_rows old_select_limit= thd->variables.select_limit;
|
||||||
sp_rcontext *old_spcont= thd->spcont;
|
sp_rcontext *old_spcont= thd->spcont;
|
||||||
@ -567,16 +568,16 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Change current database if needed.
|
Change the current database (if needed).
|
||||||
|
|
||||||
collation_database will be updated here. However, it can be wrong,
|
TODO: why do we force switch here?
|
||||||
because it will contain the current value of the database collation.
|
|
||||||
We need collation_database to be fixed at the creation time -- so
|
|
||||||
we'll update it later in switch_query_ctx().
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((ret= sp_use_new_db(thd, name->m_db, &old_db, TRUE, &dbchanged)))
|
if (mysql_opt_change_db(thd, &name->m_db, &saved_cur_db_name, TRUE,
|
||||||
|
&cur_db_changed))
|
||||||
|
{
|
||||||
goto end;
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
thd->spcont= NULL;
|
thd->spcont= NULL;
|
||||||
|
|
||||||
@ -585,34 +586,42 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
|
|||||||
|
|
||||||
lex_start(thd);
|
lex_start(thd);
|
||||||
|
|
||||||
if (parse_sql(thd, &lip, creation_ctx) || newlex.sphead == NULL)
|
ret= parse_sql(thd, &lip, creation_ctx) || newlex.sphead == NULL;
|
||||||
{
|
|
||||||
sp_head *sp= newlex.sphead;
|
|
||||||
|
|
||||||
if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
|
/*
|
||||||
goto end;
|
Force switching back to the saved current database (if changed),
|
||||||
delete sp;
|
because it may be NULL. In this case, mysql_change_db() would
|
||||||
ret= SP_PARSE_ERROR;
|
generate an error.
|
||||||
}
|
*/
|
||||||
else
|
|
||||||
|
if (cur_db_changed && mysql_change_db(thd, &saved_cur_db_name, TRUE))
|
||||||
{
|
{
|
||||||
if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
|
delete newlex.sphead;
|
||||||
goto end;
|
ret= -1;
|
||||||
*sphp= newlex.sphead;
|
goto end;
|
||||||
(*sphp)->set_definer(&definer_user_name, &definer_host_name);
|
|
||||||
(*sphp)->set_info(created, modified, &chistics, sql_mode);
|
|
||||||
(*sphp)->set_creation_ctx(creation_ctx);
|
|
||||||
(*sphp)->optimize();
|
|
||||||
/*
|
|
||||||
Not strictly necessary to invoke this method here, since we know
|
|
||||||
that we've parsed CREATE PROCEDURE/FUNCTION and not an
|
|
||||||
UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to
|
|
||||||
maintain the invariant that this method is called for each
|
|
||||||
distinct statement, in case its logic is extended with other
|
|
||||||
types of analyses in future.
|
|
||||||
*/
|
|
||||||
newlex.set_trg_event_type_for_tables();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
delete newlex.sphead;
|
||||||
|
ret= SP_PARSE_ERROR;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
*sphp= newlex.sphead;
|
||||||
|
(*sphp)->set_definer(&definer_user_name, &definer_host_name);
|
||||||
|
(*sphp)->set_info(created, modified, &chistics, sql_mode);
|
||||||
|
(*sphp)->set_creation_ctx(creation_ctx);
|
||||||
|
(*sphp)->optimize();
|
||||||
|
/*
|
||||||
|
Not strictly necessary to invoke this method here, since we know
|
||||||
|
that we've parsed CREATE PROCEDURE/FUNCTION and not an
|
||||||
|
UPDATE/DELETE/INSERT/REPLACE/LOAD/CREATE TABLE, but we try to
|
||||||
|
maintain the invariant that this method is called for each
|
||||||
|
distinct statement, in case its logic is extended with other
|
||||||
|
types of analyses in future.
|
||||||
|
*/
|
||||||
|
newlex.set_trg_event_type_for_tables();
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
@ -2025,76 +2034,3 @@ create_string(THD *thd, String *buf,
|
|||||||
buf->append(body, bodylen);
|
buf->append(body, bodylen);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Change the current database if needed.
|
|
||||||
|
|
||||||
@param[in] thd thread handle
|
|
||||||
@param[in] new_db new database name
|
|
||||||
@param[in, out] old_db IN: str points to a buffer where to store
|
|
||||||
the old database, length contains the
|
|
||||||
size of the buffer
|
|
||||||
OUT: if old db was not NULL, its name is
|
|
||||||
copied to the buffer pointed at by str
|
|
||||||
and length is updated accordingly.
|
|
||||||
Otherwise str[0] is set to '\0' and
|
|
||||||
length is set to 0. The out parameter
|
|
||||||
should be used only if the database name
|
|
||||||
has been changed (see dbchangedp).
|
|
||||||
@param[in] force_switch Flag to mysql_change_db(). For more information,
|
|
||||||
see mysql_change_db() comment.
|
|
||||||
@param[out] dbchangedp is set to TRUE if the current database is
|
|
||||||
changed, FALSE otherwise. The current
|
|
||||||
database is not changed if the old name
|
|
||||||
is equal to the new one, both names are
|
|
||||||
empty, or an error has occurred.
|
|
||||||
|
|
||||||
@return Operation status.
|
|
||||||
@retval 0 on success
|
|
||||||
@retval 1 access denied or out of memory
|
|
||||||
(the error message is set in THD)
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
sp_use_new_db(THD *thd,
|
|
||||||
LEX_STRING new_db,
|
|
||||||
LEX_STRING *old_db,
|
|
||||||
bool force_switch,
|
|
||||||
bool *dbchangedp)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
DBUG_ENTER("sp_use_new_db");
|
|
||||||
DBUG_PRINT("enter", ("newdb: %s", new_db.str));
|
|
||||||
|
|
||||||
/*
|
|
||||||
A stored routine always belongs to some database. The
|
|
||||||
old database (old_db) might be NULL, but to restore the
|
|
||||||
old database we will use mysql_change_db.
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(new_db.str && new_db.length);
|
|
||||||
|
|
||||||
if (thd->db)
|
|
||||||
{
|
|
||||||
old_db->length= (strmake(old_db->str, thd->db, old_db->length) -
|
|
||||||
old_db->str);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
old_db->str[0]= '\0';
|
|
||||||
old_db->length= 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Don't change the database if the new name is the same as the old one. */
|
|
||||||
if (my_strcasecmp(system_charset_info, old_db->str, new_db.str) == 0)
|
|
||||||
{
|
|
||||||
*dbchangedp= FALSE;
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret= mysql_change_db(thd, &new_db, force_switch);
|
|
||||||
|
|
||||||
*dbchangedp= ret == 0;
|
|
||||||
DBUG_RETURN(ret);
|
|
||||||
}
|
|
||||||
|
11
sql/sp.h
11
sql/sp.h
@ -85,15 +85,4 @@ extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen,
|
|||||||
*/
|
*/
|
||||||
TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup);
|
TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Do a "use new_db". The current db is stored at old_db. If new_db is the
|
|
||||||
same as the current one, nothing is changed. dbchangedp is set to true if
|
|
||||||
the db was actually changed.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db,
|
|
||||||
bool no_access_check, bool *dbchangedp);
|
|
||||||
|
|
||||||
#endif /* _SP_H_ */
|
#endif /* _SP_H_ */
|
||||||
|
@ -1016,9 +1016,10 @@ bool
|
|||||||
sp_head::execute(THD *thd)
|
sp_head::execute(THD *thd)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("sp_head::execute");
|
DBUG_ENTER("sp_head::execute");
|
||||||
char old_db_buf[NAME_LEN+1];
|
char saved_cur_db_name_buf[NAME_LEN+1];
|
||||||
LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) };
|
LEX_STRING saved_cur_db_name=
|
||||||
bool dbchanged;
|
{ saved_cur_db_name_buf, sizeof(saved_cur_db_name_buf) };
|
||||||
|
bool cur_db_changed= FALSE;
|
||||||
sp_rcontext *ctx;
|
sp_rcontext *ctx;
|
||||||
bool err_status= FALSE;
|
bool err_status= FALSE;
|
||||||
uint ip= 0;
|
uint ip= 0;
|
||||||
@ -1073,8 +1074,11 @@ sp_head::execute(THD *thd)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
if (m_db.length &&
|
if (m_db.length &&
|
||||||
(err_status= sp_use_new_db(thd, m_db, &old_db, 0, &dbchanged)))
|
(err_status= mysql_opt_change_db(thd, &m_db, &saved_cur_db_name, FALSE,
|
||||||
|
&cur_db_changed)))
|
||||||
|
{
|
||||||
goto done;
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if ((ctx= thd->spcont))
|
if ((ctx= thd->spcont))
|
||||||
ctx->clear_handler();
|
ctx->clear_handler();
|
||||||
@ -1255,14 +1259,14 @@ sp_head::execute(THD *thd)
|
|||||||
If the DB has changed, the pointer has changed too, but the
|
If the DB has changed, the pointer has changed too, but the
|
||||||
original thd->db will then have been freed
|
original thd->db will then have been freed
|
||||||
*/
|
*/
|
||||||
if (dbchanged)
|
if (cur_db_changed && !thd->killed)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
No access check when changing back to where we came from.
|
Force switching back to the saved current database, because it may be
|
||||||
(It would generate an error from mysql_change_db() when old_db=="")
|
NULL. In this case, mysql_change_db() would generate an error.
|
||||||
*/
|
*/
|
||||||
if (! thd->killed)
|
|
||||||
err_status|= mysql_change_db(thd, &old_db, TRUE);
|
err_status|= mysql_change_db(thd, &saved_cur_db_name, TRUE);
|
||||||
}
|
}
|
||||||
m_flags&= ~IS_INVOKED;
|
m_flags&= ~IS_INVOKED;
|
||||||
DBUG_PRINT("info",
|
DBUG_PRINT("info",
|
||||||
|
@ -387,7 +387,6 @@ THD::THD()
|
|||||||
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
|
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
|
||||||
stmt_arena= this;
|
stmt_arena= this;
|
||||||
thread_stack= 0;
|
thread_stack= 0;
|
||||||
db= 0;
|
|
||||||
catalog= (char*)"std"; // the only catalog we have for now
|
catalog= (char*)"std"; // the only catalog we have for now
|
||||||
main_security_ctx.init();
|
main_security_ctx.init();
|
||||||
security_ctx= &main_security_ctx;
|
security_ctx= &main_security_ctx;
|
||||||
@ -395,7 +394,7 @@ THD::THD()
|
|||||||
query_start_used= 0;
|
query_start_used= 0;
|
||||||
count_cuted_fields= CHECK_FIELD_IGNORE;
|
count_cuted_fields= CHECK_FIELD_IGNORE;
|
||||||
killed= NOT_KILLED;
|
killed= NOT_KILLED;
|
||||||
db_length= col_access=0;
|
col_access=0;
|
||||||
query_error= thread_specific_used= FALSE;
|
query_error= thread_specific_used= FALSE;
|
||||||
hash_clear(&handler_tables_hash);
|
hash_clear(&handler_tables_hash);
|
||||||
tmp_table=0;
|
tmp_table=0;
|
||||||
@ -2040,7 +2039,9 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
|
|||||||
lex(lex_arg),
|
lex(lex_arg),
|
||||||
query(0),
|
query(0),
|
||||||
query_length(0),
|
query_length(0),
|
||||||
cursor(0)
|
cursor(0),
|
||||||
|
db(NULL),
|
||||||
|
db_length(0)
|
||||||
{
|
{
|
||||||
name.str= NULL;
|
name.str= NULL;
|
||||||
}
|
}
|
||||||
|
@ -593,6 +593,22 @@ public:
|
|||||||
uint32 query_length; // current query length
|
uint32 query_length; // current query length
|
||||||
Server_side_cursor *cursor;
|
Server_side_cursor *cursor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Name of the current (default) database.
|
||||||
|
|
||||||
|
If there is the current (default) database, "db" contains its name. If
|
||||||
|
there is no current (default) database, "db" is NULL and "db_length" is
|
||||||
|
0. In other words, "db", "db_length" must either be NULL, or contain a
|
||||||
|
valid database name.
|
||||||
|
|
||||||
|
@note this attribute is set and alloced by the slave SQL thread (for
|
||||||
|
the THD of that thread); that thread is (and must remain, for now) the
|
||||||
|
only responsible for freeing this member.
|
||||||
|
*/
|
||||||
|
|
||||||
|
char *db;
|
||||||
|
uint db_length;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* This constructor is called for backup statements */
|
/* This constructor is called for backup statements */
|
||||||
@ -1024,18 +1040,21 @@ public:
|
|||||||
*/
|
*/
|
||||||
char *thread_stack;
|
char *thread_stack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Currently selected catalog.
|
||||||
|
*/
|
||||||
|
char *catalog;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
db - currently selected database
|
WARNING: some members of THD (currently 'Statement::db',
|
||||||
catalog - currently selected catalog
|
'catalog' and 'query') are set and alloced by the slave SQL thread
|
||||||
WARNING: some members of THD (currently 'db', 'catalog' and 'query') are
|
(for the THD of that thread); that thread is (and must remain, for now)
|
||||||
set and alloced by the slave SQL thread (for the THD of that thread); that
|
the only responsible for freeing these 3 members. If you add members
|
||||||
thread is (and must remain, for now) the only responsible for freeing these
|
here, and you add code to set them in replication, don't forget to
|
||||||
3 members. If you add members here, and you add code to set them in
|
free_them_and_set_them_to_0 in replication properly. For details see
|
||||||
replication, don't forget to free_them_and_set_them_to_0 in replication
|
the 'err:' label of the handle_slave_sql() in sql/slave.cc.
|
||||||
properly. For details see the 'err:' label of the handle_slave_sql()
|
*/
|
||||||
in sql/slave.cc.
|
|
||||||
*/
|
|
||||||
char *db, *catalog;
|
|
||||||
Security_context main_security_ctx;
|
Security_context main_security_ctx;
|
||||||
Security_context *security_ctx;
|
Security_context *security_ctx;
|
||||||
|
|
||||||
@ -1390,7 +1409,6 @@ public:
|
|||||||
uint tmp_table, global_read_lock;
|
uint tmp_table, global_read_lock;
|
||||||
uint server_status,open_options;
|
uint server_status,open_options;
|
||||||
enum enum_thread_type system_thread;
|
enum enum_thread_type system_thread;
|
||||||
uint db_length;
|
|
||||||
uint select_number; //number of select (used for EXPLAIN)
|
uint select_number; //number of select (used for EXPLAIN)
|
||||||
/* variables.transaction_isolation is reset to this after each commit */
|
/* variables.transaction_isolation is reset to this after each commit */
|
||||||
enum_tx_isolation session_tx_isolation;
|
enum_tx_isolation session_tx_isolation;
|
||||||
@ -1814,11 +1832,10 @@ public:
|
|||||||
no current database selected (in addition to the error message set by
|
no current database selected (in addition to the error message set by
|
||||||
malloc).
|
malloc).
|
||||||
|
|
||||||
@note This operation just sets {thd->db, thd->db_length}. Switching the
|
@note This operation just sets {db, db_length}. Switching the current
|
||||||
current database usually involves other actions, like switching other
|
database usually involves other actions, like switching other database
|
||||||
database attributes including security context. In the future, this
|
attributes including security context. In the future, this operation
|
||||||
operation will be made private and more convenient interface will be
|
will be made private and more convenient interface will be provided.
|
||||||
provided.
|
|
||||||
|
|
||||||
@return Operation status
|
@return Operation status
|
||||||
@retval FALSE Success
|
@retval FALSE Success
|
||||||
@ -1844,11 +1861,10 @@ public:
|
|||||||
@param new_db a pointer to the new database name.
|
@param new_db a pointer to the new database name.
|
||||||
@param new_db_len length of the new database name.
|
@param new_db_len length of the new database name.
|
||||||
|
|
||||||
@note This operation just sets {thd->db, thd->db_length}. Switching the
|
@note This operation just sets {db, db_length}. Switching the current
|
||||||
current database usually involves other actions, like switching other
|
database usually involves other actions, like switching other database
|
||||||
database attributes including security context. In the future, this
|
attributes including security context. In the future, this operation
|
||||||
operation will be made private and more convenient interface will be
|
will be made private and more convenient interface will be provided.
|
||||||
provided.
|
|
||||||
*/
|
*/
|
||||||
void reset_db(char *new_db, size_t new_db_len)
|
void reset_db(char *new_db, size_t new_db_len)
|
||||||
{
|
{
|
||||||
|
@ -1359,8 +1359,67 @@ static void mysql_change_db_impl(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@brief Change the current database and its attributes.
|
Backup the current database name before switch.
|
||||||
|
|
||||||
|
@param[in] thd thread handle
|
||||||
|
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
|
||||||
|
the old database name, "length" contains the
|
||||||
|
buffer size
|
||||||
|
OUT: if the current (default) database is
|
||||||
|
not NULL, its name is copied to the
|
||||||
|
buffer pointed at by "str"
|
||||||
|
and "length" is updated accordingly.
|
||||||
|
Otherwise "str" is set to NULL and
|
||||||
|
"length" is set to 0.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void backup_current_db_name(THD *thd,
|
||||||
|
LEX_STRING *saved_db_name)
|
||||||
|
{
|
||||||
|
if (!thd->db)
|
||||||
|
{
|
||||||
|
/* No current (default) database selected. */
|
||||||
|
|
||||||
|
saved_db_name->str= NULL;
|
||||||
|
saved_db_name->length= 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strmake(saved_db_name->str, thd->db, saved_db_name->length);
|
||||||
|
saved_db_name->length= thd->db_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Return TRUE if db1_name is equal to db2_name, FALSE otherwise.
|
||||||
|
|
||||||
|
The function allows to compare database names according to the MySQL
|
||||||
|
rules. The database names db1 and db2 are equal if:
|
||||||
|
- db1 is NULL and db2 is NULL;
|
||||||
|
or
|
||||||
|
- db1 is not-NULL, db2 is not-NULL, db1 is equal (ignoring case) to
|
||||||
|
db2 in system character set (UTF8).
|
||||||
|
*/
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
cmp_db_names(const char *db1_name,
|
||||||
|
const char *db2_name)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
/* db1 is NULL and db2 is NULL */
|
||||||
|
!db1_name && !db2_name ||
|
||||||
|
|
||||||
|
/* db1 is not-NULL, db2 is not-NULL, db1 == db2. */
|
||||||
|
db1_name && db2_name &&
|
||||||
|
my_strcasecmp(system_charset_info, db1_name, db2_name) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Change the current database and its attributes unconditionally.
|
||||||
|
|
||||||
@param thd thread handle
|
@param thd thread handle
|
||||||
@param new_db_name database name
|
@param new_db_name database name
|
||||||
@ -1577,6 +1636,43 @@ bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Change the current database and its attributes if needed.
|
||||||
|
|
||||||
|
@param thd thread handle
|
||||||
|
@param new_db_name database name
|
||||||
|
@param[in, out] saved_db_name IN: "str" points to a buffer where to store
|
||||||
|
the old database name, "length" contains the
|
||||||
|
buffer size
|
||||||
|
OUT: if the current (default) database is
|
||||||
|
not NULL, its name is copied to the
|
||||||
|
buffer pointed at by "str"
|
||||||
|
and "length" is updated accordingly.
|
||||||
|
Otherwise "str" is set to NULL and
|
||||||
|
"length" is set to 0.
|
||||||
|
@param force_switch @see mysql_change_db()
|
||||||
|
@param[out] cur_db_changed out-flag to indicate whether the current
|
||||||
|
database has been changed (valid only if
|
||||||
|
the function suceeded)
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool mysql_opt_change_db(THD *thd,
|
||||||
|
const LEX_STRING *new_db_name,
|
||||||
|
LEX_STRING *saved_db_name,
|
||||||
|
bool force_switch,
|
||||||
|
bool *cur_db_changed)
|
||||||
|
{
|
||||||
|
*cur_db_changed= !cmp_db_names(thd->db, new_db_name->str);
|
||||||
|
|
||||||
|
if (!*cur_db_changed)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
backup_current_db_name(thd, saved_db_name);
|
||||||
|
|
||||||
|
return mysql_change_db(thd, new_db_name, force_switch);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lock_databases(THD *thd, const char *db1, uint length1,
|
lock_databases(THD *thd, const char *db1, uint length1,
|
||||||
const char *db2, uint length2)
|
const char *db2, uint length2)
|
||||||
|
@ -2868,6 +2868,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
|
|||||||
init_param_array(this);
|
init_param_array(this);
|
||||||
lex->set_trg_event_type_for_tables();
|
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)
|
While doing context analysis of the query (in check_prepared_statement)
|
||||||
we allocate a lot of additional memory: for open tables, JOINs, derived
|
we allocate a lot of additional memory: for open tables, JOINs, derived
|
||||||
@ -2974,6 +2987,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||||||
Query_arena *old_stmt_arena;
|
Query_arena *old_stmt_arena;
|
||||||
bool error= TRUE;
|
bool error= TRUE;
|
||||||
|
|
||||||
|
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) };
|
||||||
|
bool cur_db_changed;
|
||||||
|
|
||||||
|
LEX_STRING stmt_db_name= { db, db_length };
|
||||||
|
|
||||||
status_var_increment(thd->status_var.com_stmt_execute);
|
status_var_increment(thd->status_var.com_stmt_execute);
|
||||||
|
|
||||||
/* Check if we got an error when sending long data */
|
/* Check if we got an error when sending long data */
|
||||||
@ -3022,6 +3042,21 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
thd->set_n_backup_statement(this, &stmt_backup);
|
thd->set_n_backup_statement(this, &stmt_backup);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Change the current database (if needed).
|
||||||
|
|
||||||
|
Force switching, because the database of the prepared statement may be
|
||||||
|
NULL (prepared statements can be created while no current database
|
||||||
|
selected).
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (mysql_opt_change_db(thd, &stmt_db_name, &saved_cur_db_name, TRUE,
|
||||||
|
&cur_db_changed))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* Allocate query. */
|
||||||
|
|
||||||
if (expanded_query->length() &&
|
if (expanded_query->length() &&
|
||||||
alloc_query(thd, (char*) expanded_query->ptr(),
|
alloc_query(thd, (char*) expanded_query->ptr(),
|
||||||
expanded_query->length()+1))
|
expanded_query->length()+1))
|
||||||
@ -3050,6 +3085,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||||||
|
|
||||||
thd->protocol= protocol; /* activate stmt protocol */
|
thd->protocol= protocol; /* activate stmt protocol */
|
||||||
|
|
||||||
|
/* Go! */
|
||||||
|
|
||||||
if (open_cursor)
|
if (open_cursor)
|
||||||
error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
|
error= mysql_open_cursor(thd, (uint) ALWAYS_MATERIALIZED_CURSOR,
|
||||||
&result, &cursor);
|
&result, &cursor);
|
||||||
@ -3068,6 +3105,17 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Restore the current database (if changed).
|
||||||
|
|
||||||
|
Force switching back to the saved current database (if changed),
|
||||||
|
because it may be NULL. In this case, mysql_change_db() would generate
|
||||||
|
an error.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (cur_db_changed)
|
||||||
|
mysql_change_db(thd, &saved_cur_db_name, TRUE);
|
||||||
|
|
||||||
thd->protocol= &thd->protocol_text; /* use normal protocol */
|
thd->protocol= &thd->protocol_text; /* use normal protocol */
|
||||||
|
|
||||||
/* Assert that if an error, no cursor is open */
|
/* Assert that if an error, no cursor is open */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user