Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
0261d2d9
Commit
0261d2d9
authored
Aug 31, 2007
by
anozdrin/alik@ibm.opbmk
Browse files
Options
Browse Files
Download
Plain Diff
Merge bk-internal.mysql.com:/home/bk/mysql-5.1-runtime
into ibm.opbmk:/home/alik/Documents/MySQL/devel/5.1-rt-bug25843
parents
a2ae4112
d6f94b06
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
890 additions
and
152 deletions
+890
-152
mysql-test/include/query_cache_sql_prepare.inc
mysql-test/include/query_cache_sql_prepare.inc
+218
-0
mysql-test/r/query_cache_ps_no_prot.result
mysql-test/r/query_cache_ps_no_prot.result
+158
-0
mysql-test/r/query_cache_ps_ps_prot.result
mysql-test/r/query_cache_ps_ps_prot.result
+158
-0
mysql-test/suite/rpl/r/rpl_ps.result
mysql-test/suite/rpl/r/rpl_ps.result
+39
-0
mysql-test/suite/rpl/t/rpl_ps.test
mysql-test/suite/rpl/t/rpl_ps.test
+68
-0
sql/mysql_priv.h
sql/mysql_priv.h
+7
-0
sql/sp.cc
sql/sp.cc
+42
-106
sql/sp.h
sql/sp.h
+0
-11
sql/sp_head.cc
sql/sp_head.cc
+13
-9
sql/sql_class.cc
sql/sql_class.cc
+4
-3
sql/sql_class.h
sql/sql_class.h
+38
-22
sql/sql_db.cc
sql/sql_db.cc
+97
-1
sql/sql_prepare.cc
sql/sql_prepare.cc
+48
-0
No files found.
mysql-test/include/query_cache_sql_prepare.inc
View file @
0261d2d9
...
...
@@ -275,5 +275,223 @@ drop table t1;
--
echo
----
disconnect
connection
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
;
flush
status
;
# reset Qcache status variables for next tests
mysql-test/r/query_cache_ps_no_prot.result
View file @
0261d2d9
...
...
@@ -371,5 +371,163 @@ Variable_name Value
Qcache_hits 21
drop table t1;
---- 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;
flush status;
mysql-test/r/query_cache_ps_ps_prot.result
View file @
0261d2d9
...
...
@@ -371,5 +371,163 @@ Variable_name Value
Qcache_hits 19
drop table t1;
---- 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;
flush status;
mysql-test/suite/rpl/r/rpl_ps.result
View file @
0261d2d9
...
...
@@ -26,5 +26,44 @@ from-master-2-'',
from-var-from-master-3
drop table t1;
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 slave;
mysql-test/suite/rpl/t/rpl_ps.test
View file @
0261d2d9
...
...
@@ -46,6 +46,74 @@ stop slave;
# 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
slave
;
disconnect
master
;
sql/mysql_priv.h
View file @
0261d2d9
...
...
@@ -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
,
char
*
new_table_name
,
char
*
new_table_alias
,
bool
skip_error
);
bool
mysql_change_db
(
THD
*
thd
,
const
LEX_STRING
*
new_db_name
,
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
,
const
char
**
semicolon
);
...
...
sql/sp.cc
View file @
0261d2d9
...
...
@@ -520,9 +520,10 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
{
LEX
*
old_lex
=
thd
->
lex
,
newlex
;
String
defstr
;
char
old_db_buf
[
NAME_LEN
+
1
];
LEX_STRING
old_db
=
{
old_db_buf
,
sizeof
(
old_db_buf
)
};
bool
dbchanged
;
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
;
ulong
old_sql_mode
=
thd
->
variables
.
sql_mode
;
ha_rows
old_select_limit
=
thd
->
variables
.
select_limit
;
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,
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().
TODO: why do we force switch here?
*/
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
;
}
thd
->
spcont
=
NULL
;
...
...
@@ -585,34 +586,42 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
lex_start
(
thd
);
if
(
parse_sql
(
thd
,
&
lip
,
creation_ctx
)
||
newlex
.
sphead
==
NULL
)
{
sp_head
*
sp
=
newlex
.
sphead
;
ret
=
parse_sql
(
thd
,
&
lip
,
creation_ctx
)
||
newlex
.
sphead
==
NULL
;
if
(
dbchanged
&&
(
ret
=
mysql_change_db
(
thd
,
&
old_db
,
TRUE
)))
goto
end
;
delete
sp
;
ret
=
SP_PARSE_ERROR
;
/*
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
))
{
delete
newlex
.
sphead
;
ret
=
-
1
;
goto
end
;
}
else
if
(
ret
)
{
if
(
dbchanged
&&
(
ret
=
mysql_change_db
(
thd
,
&
old_db
,
TRUE
)))
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
();
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:
...
...
@@ -2025,76 +2034,3 @@ create_string(THD *thd, String *buf,
buf
->
append
(
body
,
bodylen
);
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
);
}
sql/sp.h
View file @
0261d2d9
...
...
@@ -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
);
/*
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_ */
sql/sp_head.cc
View file @
0261d2d9
...
...
@@ -1016,9 +1016,10 @@ bool
sp_head
::
execute
(
THD
*
thd
)
{
DBUG_ENTER
(
"sp_head::execute"
);
char
old_db_buf
[
NAME_LEN
+
1
];
LEX_STRING
old_db
=
{
old_db_buf
,
sizeof
(
old_db_buf
)
};
bool
dbchanged
;
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
=
FALSE
;
sp_rcontext
*
ctx
;
bool
err_status
=
FALSE
;
uint
ip
=
0
;
...
...
@@ -1073,8 +1074,11 @@ sp_head::execute(THD *thd)
*/
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
;
}
if
((
ctx
=
thd
->
spcont
))
ctx
->
clear_handler
();
...
...
@@ -1255,14 +1259,14 @@ sp_head::execute(THD *thd)
If the DB has changed, the pointer has changed too, but the
original thd->db will then have been freed
*/
if
(
dbchang
ed
)
if
(
cur_db_changed
&&
!
thd
->
kill
ed
)
{
/*
No access check when changing back to where we came from.
(It would generate an error from mysql_change_db() when old_db=="")
Force switching back to the saved current database, because it may be
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
;
DBUG_PRINT
(
"info"
,
...
...
sql/sql_class.cc
View file @
0261d2d9
...
...
@@ -387,7 +387,6 @@ THD::THD()
init_sql_alloc
(
&
main_mem_root
,
ALLOC_ROOT_MIN_BLOCK_SIZE
,
0
);
stmt_arena
=
this
;
thread_stack
=
0
;
db
=
0
;
catalog
=
(
char
*
)
"std"
;
// the only catalog we have for now
main_security_ctx
.
init
();
security_ctx
=
&
main_security_ctx
;
...
...
@@ -395,7 +394,7 @@ THD::THD()
query_start_used
=
0
;
count_cuted_fields
=
CHECK_FIELD_IGNORE
;
killed
=
NOT_KILLED
;
db_length
=
col_access
=
0
;
col_access
=
0
;
query_error
=
thread_specific_used
=
FALSE
;
hash_clear
(
&
handler_tables_hash
);
tmp_table
=
0
;
...
...
@@ -2040,7 +2039,9 @@ Statement::Statement(LEX *lex_arg, MEM_ROOT *mem_root_arg,
lex
(
lex_arg
),
query
(
0
),
query_length
(
0
),
cursor
(
0
)
cursor
(
0
),
db
(
NULL
),
db_length
(
0
)
{
name
.
str
=
NULL
;
}
...
...
sql/sql_class.h
View file @
0261d2d9
...
...
@@ -593,6 +593,22 @@ public:
uint32
query_length
;
// current query length
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:
/* This constructor is called for backup statements */
...
...
@@ -1024,18 +1040,21 @@ public:
*/
char
*
thread_stack
;
/**
Currently selected catalog.
*/
char
*
catalog
;
/*
db - currently selected database
catalog - currently selected catalog
WARNING: some members of THD (currently 'db', 'catalog' and 'query') are
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 these
3 members. If you add members here, and you add code to set them in
replication, don't forget to free_them_and_set_them_to_0 in replication
properly. For details see the 'err:' label of the handle_slave_sql()
in sql/slave.cc.
*/
char
*
db
,
*
catalog
;
WARNING: some members of THD (currently 'Statement::db',
'catalog' and 'query') are 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 these 3 members. If you add members
here, and you add code to set them in replication, don't forget to
free_them_and_set_them_to_0 in replication properly. For details see
the 'err:' label of the handle_slave_sql() in sql/slave.cc.
*/
Security_context
main_security_ctx
;
Security_context
*
security_ctx
;
...
...
@@ -1390,7 +1409,6 @@ public:
uint
tmp_table
,
global_read_lock
;
uint
server_status
,
open_options
;
enum
enum_thread_type
system_thread
;
uint
db_length
;
uint
select_number
;
//number of select (used for EXPLAIN)
/* variables.transaction_isolation is reset to this after each commit */
enum_tx_isolation
session_tx_isolation
;
...
...
@@ -1814,11 +1832,10 @@ public:
no current database selected (in addition to the error message set by
malloc).
@note This operation just sets {thd->db, thd->db_length}. Switching the
current database usually involves other actions, like switching other
database attributes including security context. In the future, this
operation will be made private and more convenient interface will be
provided.
@note This operation just sets {db, db_length}. Switching the current
database usually involves other actions, like switching other database
attributes including security context. In the future, this operation
will be made private and more convenient interface will be provided.
@return Operation status
@retval FALSE Success
...
...
@@ -1844,11 +1861,10 @@ public:
@param new_db a pointer to 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
current database usually involves other actions, like switching other
database attributes including security context. In the future, this
operation will be made private and more convenient interface will be
provided.
@note This operation just sets {db, db_length}. Switching the current
database usually involves other actions, like switching other database
attributes including security context. In the future, this operation
will be made private and more convenient interface will be provided.
*/
void
reset_db
(
char
*
new_db
,
size_t
new_db_len
)
{
...
...
sql/sql_db.cc
View file @
0261d2d9
...
...
@@ -1359,8 +1359,67 @@ static void mysql_change_db_impl(THD *thd,
}
/**
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.
@brief Change the current database and its attributes
unconditionally
.
@param thd thread handle
@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
lock_databases
(
THD
*
thd
,
const
char
*
db1
,
uint
length1
,
const
char
*
db2
,
uint
length2
)
...
...
sql/sql_prepare.cc
View file @
0261d2d9
...
...
@@ -2868,6 +2868,19 @@ bool Prepared_statement::prepare(const char *packet, uint packet_len)
init_param_array
(
this
);
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
...
...
@@ -2974,6 +2987,13 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
Query_arena
*
old_stmt_arena
;
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
);
/* 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
);
/*
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
()
&&
alloc_query
(
thd
,
(
char
*
)
expanded_query
->
ptr
(),
expanded_query
->
length
()
+
1
))
...
...
@@ -3050,6 +3085,8 @@ bool Prepared_statement::execute(String *expanded_query, bool open_cursor)
thd
->
protocol
=
protocol
;
/* activate stmt protocol */
/* Go! */
if
(
open_cursor
)
error
=
mysql_open_cursor
(
thd
,
(
uint
)
ALWAYS_MATERIALIZED_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 */
/* Assert that if an error, no cursor is open */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment