summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client/client_priv.h2
-rw-r--r--client/mysqlbinlog.cc24
-rw-r--r--client/mysqldump.c24
-rw-r--r--include/raid.h4
-rw-r--r--mysql-test/r/grant.result122
-rw-r--r--mysql-test/r/information_schema_db.result71
-rw-r--r--mysql-test/r/mysqlbinlog2.result36
-rw-r--r--mysql-test/r/sp-security.result35
-rw-r--r--mysql-test/r/sp.result40
-rw-r--r--mysql-test/r/sp_trans.result21
-rw-r--r--mysql-test/r/view_grant.result97
-rw-r--r--mysql-test/t/grant.test227
-rw-r--r--mysql-test/t/information_schema_db.test55
-rw-r--r--mysql-test/t/mysqlbinlog2.test8
-rw-r--r--mysql-test/t/sp-security.test77
-rw-r--r--mysql-test/t/sp.test64
-rw-r--r--mysql-test/t/sp_trans.test31
-rw-r--r--mysql-test/t/view_grant.test110
-rw-r--r--mysys/my_handler.c1
-rw-r--r--mysys/my_lib.c4
-rw-r--r--mysys/my_seek.c2
-rw-r--r--mysys/raid.cc22
-rw-r--r--mysys/thr_lock.c2
-rw-r--r--sql/ha_ndbcluster.cc15
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/item_cmpfunc.cc2
-rw-r--r--sql/item_func.h4
-rw-r--r--sql/log.cc4
-rw-r--r--sql/mysql_priv.h12
-rw-r--r--sql/net_serv.cc2
-rw-r--r--sql/set_var.cc5
-rw-r--r--sql/sp.cc6
-rw-r--r--sql/sp_head.cc8
-rw-r--r--sql/sql_acl.cc31
-rw-r--r--sql/sql_base.cc27
-rw-r--r--sql/sql_cache.cc6
-rw-r--r--sql/sql_class.cc8
-rw-r--r--sql/sql_class.h8
-rw-r--r--sql/sql_db.cc331
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_insert.cc18
-rw-r--r--sql/sql_load.cc16
-rw-r--r--sql/sql_parse.cc227
-rw-r--r--sql/sql_prepare.cc2
-rw-r--r--sql/sql_show.cc23
-rw-r--r--sql/sql_table.cc2
-rw-r--r--sql/sql_update.cc48
-rw-r--r--sql/sql_view.cc42
-rw-r--r--sql/table.cc5
49 files changed, 1542 insertions, 395 deletions
diff --git a/client/client_priv.h b/client/client_priv.h
index 7748dc612d6..418bf86f2c8 100644
--- a/client/client_priv.h
+++ b/client/client_priv.h
@@ -51,5 +51,5 @@ enum options_client
OPT_TRIGGERS,
OPT_IGNORE_TABLE,OPT_INSERT_IGNORE,OPT_SHOW_WARNINGS,OPT_DROP_DATABASE,
OPT_TZ_UTC, OPT_AUTO_CLOSE, OPT_SSL_VERIFY_SERVER_CERT,
- OPT_DEBUG_INFO
+ OPT_DEBUG_INFO, OPT_ERROR_LOG_FILE
};
diff --git a/client/mysqlbinlog.cc b/client/mysqlbinlog.cc
index 2a070d14f0d..a371981e24d 100644
--- a/client/mysqlbinlog.cc
+++ b/client/mysqlbinlog.cc
@@ -1105,7 +1105,7 @@ could be out of memory");
}
if (len < 8 && net->read_pos[0] == 254)
break; // end of data
- DBUG_PRINT("info",( "len: %lu, net->read_pos[5]: %d\n",
+ DBUG_PRINT("info",( "len: %lu net->read_pos[5]: %d\n",
len, net->read_pos[5]));
if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
len - 1, &error_msg,
@@ -1160,6 +1160,18 @@ could be out of memory");
len= 1; // fake Rotate, so don't increment old_off
}
}
+ else if (type == FORMAT_DESCRIPTION_EVENT)
+ {
+ /*
+ This could be an fake Format_description_log_event that server
+ (5.0+) automatically sends to a slave on connect, before sending
+ a first event at the requested position. If this is the case,
+ don't increment old_off. Real Format_description_log_event always
+ starts from BIN_LOG_HEADER_SIZE position.
+ */
+ if (old_off != BIN_LOG_HEADER_SIZE)
+ len= 1; // fake event, don't increment old_off
+ }
if ((error= process_event(print_event_info, ev, old_off)))
{
error= ((error < 0) ? 0 : 1);
@@ -1172,16 +1184,16 @@ could be out of memory");
const char *old_fname= le->fname;
uint old_len= le->fname_len;
File file;
-
+
if ((file= load_processor.prepare_new_file_for_old_format(le,fname)) < 0)
{
error= 1;
goto err;
}
-
+
if ((error= process_event(print_event_info, ev, old_off)))
{
- my_close(file,MYF(MY_WME));
+ my_close(file,MYF(MY_WME));
error= ((error < 0) ? 0 : 1);
goto err;
}
@@ -1194,8 +1206,8 @@ could be out of memory");
}
}
/*
- Let's adjust offset for remote log as for local log to produce
- similar text.
+ Let's adjust offset for remote log as for local log to produce
+ similar text and to have --stop-position to work identically.
*/
old_off+= len-1;
}
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 1db6a6b4e2b..63db2cc268e 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -105,7 +105,8 @@ static char *opt_password=0,*current_user=0,
*lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
*where=0, *order_by=0,
*opt_compatible_mode_str= 0,
- *err_ptr= 0;
+ *err_ptr= 0,
+ *log_error_file= NULL;
static char **defaults_argv= 0;
static char compatible_mode_normal_str[255];
static ulong opt_compatible_mode= 0;
@@ -116,7 +117,9 @@ static my_string opt_mysql_unix_port=0;
static int first_error=0;
static DYNAMIC_STRING extended_row;
#include <sslopt-vars.h>
-FILE *md_result_file= 0;
+FILE *md_result_file= 0;
+FILE *stderror_file=0;
+
#ifdef HAVE_SMEM
static char *shared_memory_base_name=0;
#endif
@@ -306,6 +309,9 @@ static struct my_option my_long_options[] =
0, 0, 0, 0, 0, 0},
{"lock-tables", 'l', "Lock all tables for read.", (gptr*) &lock_tables,
(gptr*) &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+ {"log-error", OPT_ERROR_LOG_FILE, "Append warnings and errors to given file.",
+ (gptr*) &log_error_file, (gptr*) &log_error_file, 0, GET_STR,
+ REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"master-data", OPT_MASTER_DATA,
"This causes the binary log position and filename to be appended to the "
"output. If equal to 1, will print it as a CHANGE MASTER command; if equal"
@@ -3789,6 +3795,16 @@ int main(int argc, char **argv)
free_resources(0);
exit(exit_code);
}
+
+ if (log_error_file)
+ {
+ if(!(stderror_file= freopen(log_error_file, "a+", stderr)))
+ {
+ free_resources(0);
+ exit(EX_MYSQLERR);
+ }
+ }
+
if (connect_to_db(current_host, current_user, opt_password))
{
free_resources(0);
@@ -3841,5 +3857,9 @@ err:
if (!path)
write_footer(md_result_file);
free_resources();
+
+ if (stderror_file)
+ fclose(stderror_file);
+
return(first_error);
} /* main */
diff --git a/include/raid.h b/include/raid.h
index 8f0dc47d465..9d098305d14 100644
--- a/include/raid.h
+++ b/include/raid.h
@@ -140,7 +140,7 @@ class RaidFd {
inline void Calculate()
{
DBUG_ENTER("RaidFd::_Calculate");
- DBUG_PRINT("info",("_position: %lu _raid_chunksize: %d, _size: %lu",
+ DBUG_PRINT("info",("_position: %lu _raid_chunksize: %lu _size: %lu",
(ulong) _position, _raid_chunksize, (ulong) _size));
_total_block = (ulong) (_position / _raid_chunksize);
@@ -148,7 +148,7 @@ class RaidFd {
_remaining_bytes = (uint) (_raid_chunksize -
(_position - _total_block * _raid_chunksize));
DBUG_PRINT("info",
- ("_total_block: %d this_block: %d _remaining_bytes:%d",
+ ("_total_block: %lu this_block: %d _remaining_bytes: %d",
_total_block, _this_block, _remaining_bytes));
DBUG_VOID_RETURN;
}
diff --git a/mysql-test/r/grant.result b/mysql-test/r/grant.result
index d63e4181026..ae550649951 100644
--- a/mysql-test/r/grant.result
+++ b/mysql-test/r/grant.result
@@ -972,4 +972,126 @@ REVOKE EXECUTE ON PROCEDURE t1 FROM some_user_name@1234567890abcdefghij123456789
ERROR HY000: String '1234567890abcdefghij1234567890abcdefghij1234567890abcdefghijQWERTY' is too long for host name (should be no longer than 60)
GRANT PROCESS ON * TO user@localhost;
ERROR 3D000: No database selected
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+DROP DATABASE IF EXISTS mysqltest3;
+DROP DATABASE IF EXISTS mysqltest4;
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+CREATE DATABASE mysqltest3;
+CREATE DATABASE mysqltest4;
+CREATE PROCEDURE mysqltest1.p_def() SQL SECURITY DEFINER
+SELECT 1;
+CREATE PROCEDURE mysqltest2.p_inv() SQL SECURITY INVOKER
+SELECT 1;
+CREATE FUNCTION mysqltest3.f_def() RETURNS INT SQL SECURITY DEFINER
+RETURN 1;
+CREATE FUNCTION mysqltest4.f_inv() RETURNS INT SQL SECURITY INVOKER
+RETURN 1;
+GRANT EXECUTE ON PROCEDURE mysqltest1.p_def TO mysqltest_1@localhost;
+GRANT EXECUTE ON PROCEDURE mysqltest2.p_inv TO mysqltest_1@localhost;
+GRANT EXECUTE ON FUNCTION mysqltest3.f_def TO mysqltest_1@localhost;
+GRANT EXECUTE ON FUNCTION mysqltest4.f_inv TO mysqltest_1@localhost;
+GRANT ALL PRIVILEGES ON test.* TO mysqltest_1@localhost;
+
+---> connection: bug9504_con1
+use mysqltest1;
+use mysqltest2;
+use mysqltest3;
+use mysqltest4;
+use test;
+CALL mysqltest1.p_def();
+1
+1
+CALL mysqltest2.p_inv();
+1
+1
+SELECT mysqltest3.f_def();
+mysqltest3.f_def()
+1
+SELECT mysqltest4.f_inv();
+mysqltest4.f_inv()
+1
+
+---> connection: default
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+DROP DATABASE mysqltest3;
+DROP DATABASE mysqltest4;
+DROP USER mysqltest_1@localhost;
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+GRANT ALL PRIVILEGES ON mysqltest1.* TO mysqltest_1@localhost;
+GRANT SELECT ON mysqltest2.* TO mysqltest_1@localhost;
+CREATE PROCEDURE mysqltest1.p1() SQL SECURITY INVOKER
+SELECT 1;
+
+---> connection: bug27337_con1
+CREATE TABLE t1(c INT);
+ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1'
+CALL mysqltest1.p1();
+1
+1
+CREATE TABLE t1(c INT);
+ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1'
+
+---> connection: bug27337_con2
+CREATE TABLE t1(c INT);
+ERROR 42000: CREATE command denied to user 'mysqltest_1'@'localhost' for table 't1'
+SHOW TABLES;
+Tables_in_mysqltest2
+
+---> connection: default
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+DROP USER mysqltest_1@localhost;
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+CREATE TABLE mysqltest1.t1(c INT);
+CREATE TABLE mysqltest2.t2(c INT);
+GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost;
+GRANT SELECT ON mysqltest2.t2 TO mysqltest_2@localhost;
+
+---> connection: bug27337_con1
+SHOW TABLES FROM mysqltest1;
+Tables_in_mysqltest1
+t1
+PREPARE stmt1 FROM 'SHOW TABLES FROM mysqltest1';
+EXECUTE stmt1;
+Tables_in_mysqltest1
+t1
+
+---> connection: bug27337_con2
+SHOW COLUMNS FROM mysqltest2.t2;
+Field Type Null Key Default Extra
+c int(11) YES NULL
+PREPARE stmt2 FROM 'SHOW COLUMNS FROM mysqltest2.t2';
+EXECUTE stmt2;
+Field Type Null Key Default Extra
+c int(11) YES NULL
+
+---> connection: default
+REVOKE SELECT ON mysqltest1.t1 FROM mysqltest_1@localhost;
+REVOKE SELECT ON mysqltest2.t2 FROM mysqltest_2@localhost;
+
+---> connection: bug27337_con1
+SHOW TABLES FROM mysqltest1;
+ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest1'
+EXECUTE stmt1;
+ERROR 42000: Access denied for user 'mysqltest_1'@'localhost' to database 'mysqltest1'
+
+---> connection: bug27337_con2
+SHOW COLUMNS FROM mysqltest2.t2;
+ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2'
+EXECUTE stmt2;
+ERROR 42000: SELECT command denied to user 'mysqltest_2'@'localhost' for table 't2'
+
+---> connection: default
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+DROP USER mysqltest_1@localhost;
End of 5.0 tests
diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result
index 47efe1d17ad..2d330dda333 100644
--- a/mysql-test/r/information_schema_db.result
+++ b/mysql-test/r/information_schema_db.result
@@ -106,16 +106,82 @@ use testdb_1;
create table t1 (f1 char(4));
create view v1 as select f1 from t1;
grant insert on v1 to testdb_2@localhost;
+create view v5 as select f1 from t1;
+grant show view on v5 to testdb_2@localhost;
+create definer=`no_such_user`@`no_such_host` view v6 as select f1 from t1;
+ERROR 42000: Access denied; you need the SUPER privilege for this operation
+use testdb_1;
+create view v6 as select f1 from t1;
+grant show view on v6 to testdb_2@localhost;
+create table t2 (f1 char(4));
+create definer=`no_such_user`@`no_such_host` view v7 as select * from t2;
+Warnings:
+Note 1449 There is no 'no_such_user'@'no_such_host' registered
+show fields from testdb_1.v6;
+Field Type Null Key Default Extra
+f1 char(4) YES NULL
+show create view testdb_1.v6;
+View Create View
+v6 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v6` AS select `t1`.`f1` AS `f1` from `t1`
+show create view testdb_1.v7;
+View Create View
+v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2`
+Warnings:
+Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
+show fields from testdb_1.v7;
+Field Type Null Key Default Extra
+f1 null YES NULL
+Warnings:
+Note 1449 There is no 'no_such_user'@'no_such_host' registered
create table t3 (f1 char(4), f2 char(4));
create view v3 as select f1,f2 from t3;
grant insert(f1), insert(f2) on v3 to testdb_2@localhost;
create view v2 as select f1 from testdb_1.v1;
create view v4 as select f1,f2 from testdb_1.v3;
+show fields from testdb_1.v5;
+Field Type Null Key Default Extra
+f1 char(4) YES NULL
+show create view testdb_1.v5;
+View Create View
+v5 CREATE ALGORITHM=UNDEFINED DEFINER=`testdb_1`@`localhost` SQL SECURITY DEFINER VIEW `testdb_1`.`v5` AS select `testdb_1`.`t1`.`f1` AS `f1` from `testdb_1`.`t1`
+show fields from testdb_1.v6;
+Field Type Null Key Default Extra
+f1 char(4) YES NULL
+show create view testdb_1.v6;
+View Create View
+v6 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `testdb_1`.`v6` AS select `testdb_1`.`t1`.`f1` AS `f1` from `testdb_1`.`t1`
+show fields from testdb_1.v7;
+Field Type Null Key Default Extra
+f1 null YES NULL
+Warnings:
+Note 1449 There is no 'no_such_user'@'no_such_host' registered
+show create view testdb_1.v7;
+View Create View
+v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2`
+Warnings:
+Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
revoke insert(f1) on v3 from testdb_2@localhost;
+revoke show view on v5 from testdb_2@localhost;
+use testdb_1;
+revoke show view on v6 from testdb_2@localhost;
+show fields from testdb_1.v5;
+ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v5'
+show create view testdb_1.v5;
+ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v5'
+show fields from testdb_1.v6;
+ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v6'
+show create view testdb_1.v6;
+ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v6'
+show fields from testdb_1.v7;
+ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v7'
+show create view testdb_1.v7;
+ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v7'
show create view v4;
ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
show fields from v4;
-ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
+Field Type Null Key Default Extra
+f1 null YES NULL
+f2 char(4) YES NULL
show fields from v2;
Field Type Null Key Default Extra
f1 char(4) YES NULL
@@ -140,7 +206,8 @@ where a.table_name = 'testdb_1.v1';
view_definition
select * from v2;
ERROR HY000: View 'test.v2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
-drop view testdb_1.v1,v2, testdb_1.v3, v4;
+use test;
+drop view testdb_1.v1, v2, testdb_1.v3, v4;
drop database testdb_1;
drop user testdb_1@localhost;
drop user testdb_2@localhost;
diff --git a/mysql-test/r/mysqlbinlog2.result b/mysql-test/r/mysqlbinlog2.result
index 51ca19654c7..03b0e16d32a 100644
--- a/mysql-test/r/mysqlbinlog2.result
+++ b/mysql-test/r/mysqlbinlog2.result
@@ -122,6 +122,24 @@ DELIMITER ;
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+--- start and stop positions ---
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+DELIMITER /*!*/;
+SET INSERT_ID=4/*!*/;
+use test/*!*/;
+SET TIMESTAMP=1579609946/*!*/;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/;
+SET @@session.sql_mode=0/*!*/;
+/*!\C latin1 *//*!*/;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
+insert into t1 values(null, "d")/*!*/;
+SET INSERT_ID=5/*!*/;
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+
--- start-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
@@ -481,6 +499,24 @@ DELIMITER ;
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+--- start and stop positions ---
+/*!40019 SET @@session.max_insert_delayed_threads=0*/;
+/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
+DELIMITER /*!*/;
+SET INSERT_ID=4/*!*/;
+use test/*!*/;
+SET TIMESTAMP=1579609946/*!*/;
+SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=1, @@session.unique_checks=1/*!*/;
+SET @@session.sql_mode=0/*!*/;
+/*!\C latin1 *//*!*/;
+SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
+insert into t1 values(null, "d")/*!*/;
+SET INSERT_ID=5/*!*/;
+DELIMITER ;
+# End of log file
+ROLLBACK /* added by mysqlbinlog */;
+/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
+
--- start-datetime --
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
diff --git a/mysql-test/r/sp-security.result b/mysql-test/r/sp-security.result
index 26b3f352a1f..8462bafe0e3 100644
--- a/mysql-test/r/sp-security.result
+++ b/mysql-test/r/sp-security.result
@@ -8,22 +8,29 @@ create procedure db1_secret.dummy() begin end;
drop procedure db1_secret.dummy;
use db1_secret;
create table t1 ( u varchar(64), i int );
+insert into t1 values('test', 0);
create procedure stamp(i int)
insert into db1_secret.t1 values (user(), i);
show procedure status like 'stamp';
Db Name Type Definer Modified Created Security_type Comment
db1_secret stamp PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
-create function db() returns varchar(64) return database();
+create function db() returns varchar(64)
+begin
+declare v varchar(64);
+select u into v from t1 limit 1;
+return v;
+end|
show function status like 'db';
Db Name Type Definer Modified Created Security_type Comment
db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER
call stamp(1);
select * from t1;
u i
+test 0
root@localhost 1
select db();
db()
-db1_secret
+test
grant execute on procedure db1_secret.stamp to user1@'%';
grant execute on function db1_secret.db to user1@'%';
grant execute on procedure db1_secret.stamp to ''@'%';
@@ -31,25 +38,34 @@ grant execute on function db1_secret.db to ''@'%';
call db1_secret.stamp(2);
select db1_secret.db();
db1_secret.db()
-db1_secret
+test
select * from db1_secret.t1;
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
create procedure db1_secret.dummy() begin end;
ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
drop procedure db1_secret.dummy;
ERROR 42000: PROCEDURE db1_secret.dummy does not exist
+drop procedure db1_secret.stamp;
+ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db1_secret.stamp'
+drop function db1_secret.db;
+ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db1_secret.db'
call db1_secret.stamp(3);
select db1_secret.db();
db1_secret.db()
-db1_secret
+test
select * from db1_secret.t1;
ERROR 42000: SELECT command denied to user ''@'localhost' for table 't1'
create procedure db1_secret.dummy() begin end;
ERROR 42000: Access denied for user ''@'%' to database 'db1_secret'
drop procedure db1_secret.dummy;
ERROR 42000: PROCEDURE db1_secret.dummy does not exist
+drop procedure db1_secret.stamp;
+ERROR 42000: alter routine command denied to user ''@'%' for routine 'db1_secret.stamp'
+drop function db1_secret.db;
+ERROR 42000: alter routine command denied to user ''@'%' for routine 'db1_secret.db'
select * from t1;
u i
+test 0
root@localhost 1
user1@localhost 2
anon@localhost 3
@@ -64,21 +80,22 @@ db1_secret db FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 IN
call stamp(4);
select * from t1;
u i
+test 0
root@localhost 1
user1@localhost 2
anon@localhost 3
root@localhost 4
select db();
db()
-db1_secret
+test
call db1_secret.stamp(5);
-ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
+ERROR 42000: INSERT command denied to user 'user1'@'localhost' for table 't1'
select db1_secret.db();
-ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret'
+ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
call db1_secret.stamp(6);
-ERROR 42000: Access denied for user ''@'%' to database 'db1_secret'
+ERROR 42000: INSERT command denied to user ''@'localhost' for table 't1'
select db1_secret.db();
-ERROR 42000: Access denied for user ''@'%' to database 'db1_secret'
+ERROR 42000: SELECT command denied to user ''@'localhost' for table 't1'
drop database if exists db2;
create database db2;
use db2;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index c75697b93a2..5386aa642a6 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -5969,6 +5969,21 @@ SUM(f2) bug25373(f1)
21.300000071526 NULL
DROP FUNCTION bug25373|
DROP TABLE t3|
+DROP DATABASE IF EXISTS mysqltest1|
+DROP DATABASE IF EXISTS mysqltest2|
+CREATE DATABASE mysqltest1|
+CREATE DATABASE mysqltest2|
+CREATE PROCEDURE mysqltest1.p1()
+DROP DATABASE mysqltest2|
+use mysqltest2|
+CALL mysqltest1.p1()|
+Warnings:
+Note 1049 Unknown database 'mysqltest2'
+SELECT DATABASE()|
+DATABASE()
+NULL
+DROP DATABASE mysqltest1|
+use test|
drop function if exists bug20777|
drop table if exists examplebug20777|
create function bug20777(f1 bigint unsigned) returns bigint unsigned
@@ -6055,3 +6070,28 @@ bug20777(18446744073709551613)+1
drop function bug20777;
End of 5.0 tests.
drop table t1,t2;
+CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM;
+CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb;
+set @a=0;
+CREATE function bug27354() RETURNS int deterministic
+begin
+insert into t1 values (null);
+set @a=@a+1;
+return @a;
+end|
+update t2 set b=1 where a=bug27354();
+select count(t_1.a),count(t_2.a) from t1 as t_1, t2 as t_2 /* must be 0,0 */;
+count(t_1.a) count(t_2.a)
+0 0
+insert into t2 values (1,1),(2,2),(3,3);
+update t2 set b=-b where a=bug27354();
+select * from t2 /* must return 1,-1 ... */;
+a b
+1 -1
+2 -2
+3 -3
+select count(*) from t1 /* must be 3 */;
+count(*)
+3
+drop table t1,t2;
+drop function bug27354;
diff --git a/mysql-test/r/sp_trans.result b/mysql-test/r/sp_trans.result
index 564e31c9e32..f09645703ba 100644
--- a/mysql-test/r/sp_trans.result
+++ b/mysql-test/r/sp_trans.result
@@ -530,3 +530,24 @@ count(*)
drop table t3, t4|
drop procedure bug14210|
set @@session.max_heap_table_size=default|
+drop function if exists bug23333|
+drop table if exists t1,t2|
+CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM|
+CREATE TABLE t2 (a int NOT NULL auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB|
+insert into t2 values (1,1)|
+create function bug23333()
+RETURNS int(11)
+DETERMINISTIC
+begin
+insert into t1 values (null);
+select count(*) from t1 into @a;
+return @a;
+end|
+reset master|
+insert into t2 values (bug23333(),1)|
+ERROR 23000: Duplicate entry '1' for key 1
+show binlog events from 98 /* with fixes for #23333 will show there is the query */|
+Log_name Pos Event_type Server_id End_log_pos Info
+select count(*),@a from t1 /* must be 1,1 */|
+count(*) @a
+1 1
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index 6fec52896c9..32dffa305e5 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -282,15 +282,6 @@ create view mysqltest.v3 as select b from mysqltest.t2;
grant create view, update on mysqltest.v3 to mysqltest_1@localhost;
drop view mysqltest.v3;
create view mysqltest.v3 as select b from mysqltest.t2;
-grant create view, update, insert on mysqltest.v3 to mysqltest_1@localhost;
-drop view mysqltest.v3;
-create view mysqltest.v3 as select b from mysqltest.t2;
-ERROR 42000: create view command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 'v3'
-create table mysqltest.v3 (b int);
-grant select(b) on mysqltest.v3 to mysqltest_1@localhost;
-drop table mysqltest.v3;
-create view mysqltest.v3 as select b from mysqltest.t2;
-ERROR 42000: create view command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 'v3'
create view v4 as select b+1 from mysqltest.t2;
ERROR 42000: SELECT command denied to user 'mysqltest_1'@'localhost' for column 'b' in table 't2'
grant create view,update,select on test.* to mysqltest_1@localhost;
@@ -794,4 +785,92 @@ View Create View
v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t1`.`f2` AS `f2` from `t1`
DROP USER u26813@localhost;
DROP DATABASE db26813;
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+CREATE TABLE mysqltest1.t1(c1 INT);
+CREATE TABLE mysqltest1.t2(c2 INT);
+CREATE TABLE mysqltest1.t3(c3 INT);
+CREATE TABLE mysqltest1.t4(c4 INT);
+INSERT INTO mysqltest1.t1 VALUES (11), (12), (13), (14);
+INSERT INTO mysqltest1.t2 VALUES (21), (22), (23), (24);
+INSERT INTO mysqltest1.t3 VALUES (31), (32), (33), (34);
+INSERT INTO mysqltest1.t4 VALUES (41), (42), (43), (44);
+GRANT SELECT ON mysqltest1.t1 TO mysqltest_u1@localhost;
+GRANT INSERT ON mysqltest1.t2 TO mysqltest_u1@localhost;
+GRANT SELECT, UPDATE ON mysqltest1.t3 TO mysqltest_u1@localhost;
+GRANT SELECT, DELETE ON mysqltest1.t4 TO mysqltest_u1@localhost;
+GRANT ALL PRIVILEGES ON mysqltest2.* TO mysqltest_u1@localhost;
+
+---> connection: bug24040_con
+SELECT * FROM mysqltest1.t1;
+c1
+11
+12
+13
+14
+INSERT INTO mysqltest1.t2 VALUES(25);
+UPDATE mysqltest1.t3 SET c3 = 331 WHERE c3 = 31;
+DELETE FROM mysqltest1.t4 WHERE c4 = 44;
+CREATE VIEW v1 AS SELECT * FROM mysqltest1.t1;
+CREATE VIEW v2 AS SELECT * FROM mysqltest1.t2;
+CREATE VIEW v3 AS SELECT * FROM mysqltest1.t3;
+CREATE VIEW v4 AS SELECT * FROM mysqltest1.t4;
+SELECT * FROM v1;
+c1
+11
+12
+13
+14
+INSERT INTO v2 VALUES(26);
+UPDATE v3 SET c3 = 332 WHERE c3 = 32;
+DELETE FROM v4 WHERE c4 = 43;
+CREATE VIEW v12 AS SELECT c1, c2 FROM mysqltest1.t1, mysqltest1.t2;
+ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v12'
+CREATE VIEW v13 AS SELECT c1, c3 FROM mysqltest1.t1, mysqltest1.t3;
+CREATE VIEW v14 AS SELECT c1, c4 FROM mysqltest1.t1, mysqltest1.t4;
+CREATE VIEW v21 AS SELECT c2, c1 FROM mysqltest1.t2, mysqltest1.t1;
+ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c1' in table 'v21'
+CREATE VIEW v23 AS SELECT c2, c3 FROM mysqltest1.t2, mysqltest1.t3;
+ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c3' in table 'v23'
+CREATE VIEW v24 AS SELECT c2, c4 FROM mysqltest1.t2, mysqltest1.t4;
+ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c4' in table 'v24'
+CREATE VIEW v31 AS SELECT c3, c1 FROM mysqltest1.t3, mysqltest1.t1;
+CREATE VIEW v32 AS SELECT c3, c2 FROM mysqltest1.t3, mysqltest1.t2;
+ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v32'
+CREATE VIEW v34 AS SELECT c3, c4 FROM mysqltest1.t3, mysqltest1.t4;
+CREATE VIEW v41 AS SELECT c4, c1 FROM mysqltest1.t4, mysqltest1.t1;
+CREATE VIEW v42 AS SELECT c4, c2 FROM mysqltest1.t4, mysqltest1.t2;
+ERROR 42000: create view command denied to user 'mysqltest_u1'@'localhost' for column 'c2' in table 'v42'
+CREATE VIEW v43 AS SELECT c4, c3 FROM mysqltest1.t4, mysqltest1.t3;
+
+---> connection: default
+SELECT * FROM mysqltest1.t1;
+c1
+11
+12
+13
+14
+SELECT * FROM mysqltest1.t2;
+c2
+21
+22
+23
+24
+25
+26
+SELECT * FROM mysqltest1.t3;
+c3
+331
+332
+33
+34
+SELECT * FROM mysqltest1.t4;
+c4
+41
+42
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+DROP USER mysqltest_u1@localhost;
End of 5.0 tests.
diff --git a/mysql-test/t/grant.test b/mysql-test/t/grant.test
index 82bf011d32f..623bd4363cb 100644
--- a/mysql-test/t/grant.test
+++ b/mysql-test/t/grant.test
@@ -875,4 +875,231 @@ GRANT PROCESS ON * TO user@localhost;
disconnect con1;
connection default;
+
+#
+# BUG#9504: Stored procedures: execute privilege doesn't make 'use database'
+# okay.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+DROP DATABASE IF EXISTS mysqltest3;
+DROP DATABASE IF EXISTS mysqltest4;
+--enable_warnings
+
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+CREATE DATABASE mysqltest3;
+CREATE DATABASE mysqltest4;
+
+CREATE PROCEDURE mysqltest1.p_def() SQL SECURITY DEFINER
+ SELECT 1;
+
+CREATE PROCEDURE mysqltest2.p_inv() SQL SECURITY INVOKER
+ SELECT 1;
+
+CREATE FUNCTION mysqltest3.f_def() RETURNS INT SQL SECURITY DEFINER
+ RETURN 1;
+
+CREATE FUNCTION mysqltest4.f_inv() RETURNS INT SQL SECURITY INVOKER
+ RETURN 1;
+
+GRANT EXECUTE ON PROCEDURE mysqltest1.p_def TO mysqltest_1@localhost;
+GRANT EXECUTE ON PROCEDURE mysqltest2.p_inv TO mysqltest_1@localhost;
+GRANT EXECUTE ON FUNCTION mysqltest3.f_def TO mysqltest_1@localhost;
+GRANT EXECUTE ON FUNCTION mysqltest4.f_inv TO mysqltest_1@localhost;
+
+GRANT ALL PRIVILEGES ON test.* TO mysqltest_1@localhost;
+
+# Test.
+
+--connect (bug9504_con1,localhost,mysqltest_1,,)
+--echo
+--echo ---> connection: bug9504_con1
+
+# - Check that we can switch to the db;
+
+use mysqltest1;
+
+use mysqltest2;
+
+use mysqltest3;
+
+use mysqltest4;
+
+# - Check that we can call stored routines;
+
+use test;
+
+CALL mysqltest1.p_def();
+
+CALL mysqltest2.p_inv();
+
+SELECT mysqltest3.f_def();
+
+SELECT mysqltest4.f_inv();
+
+# Cleanup.
+
+--connection default
+--echo
+--echo ---> connection: default
+
+--disconnect bug9504_con1
+
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+DROP DATABASE mysqltest3;
+DROP DATABASE mysqltest4;
+
+DROP USER mysqltest_1@localhost;
+
+
+#
+# BUG#27337: Privileges are not restored properly.
+#
+# Actually, the patch for this bugs fixes two problems. So, here are two test
+# cases.
+
+# Test case 1: privileges are not restored properly after calling a stored
+# routine defined with SQL SECURITY INVOKER clause.
+
+# Prepare.
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+--enable_warnings
+
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+
+GRANT ALL PRIVILEGES ON mysqltest1.* TO mysqltest_1@localhost;
+GRANT SELECT ON mysqltest2.* TO mysqltest_1@localhost;
+
+CREATE PROCEDURE mysqltest1.p1() SQL SECURITY INVOKER
+ SELECT 1;
+
+# Test.
+
+--connect (bug27337_con1,localhost,mysqltest_1,,mysqltest2)
+--echo
+--echo ---> connection: bug27337_con1
+
+--error ER_TABLEACCESS_DENIED_ERROR
+CREATE TABLE t1(c INT);
+
+CALL mysqltest1.p1();
+
+--error ER_TABLEACCESS_DENIED_ERROR
+CREATE TABLE t1(c INT);
+
+--disconnect bug27337_con1
+
+--connect (bug27337_con2,localhost,mysqltest_1,,mysqltest2)
+--echo
+--echo ---> connection: bug27337_con2
+
+--error ER_TABLEACCESS_DENIED_ERROR
+CREATE TABLE t1(c INT);
+
+SHOW TABLES;
+
+# Cleanup.
+
+--connection default
+--echo
+--echo ---> connection: default
+
+--disconnect bug27337_con2
+
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+
+DROP USER mysqltest_1@localhost;
+
+# Test case 2: priveleges are not checked properly for prepared statements.
+
+# Prepare.
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+--enable_warnings
+
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+
+CREATE TABLE mysqltest1.t1(c INT);
+CREATE TABLE mysqltest2.t2(c INT);
+
+GRANT SELECT ON mysqltest1.t1 TO mysqltest_1@localhost;
+GRANT SELECT ON mysqltest2.t2 TO mysqltest_2@localhost;
+
+# Test.
+
+--connect (bug27337_con1,localhost,mysqltest_1,,mysqltest1)
+--echo
+--echo ---> connection: bug27337_con1
+
+SHOW TABLES FROM mysqltest1;
+
+PREPARE stmt1 FROM 'SHOW TABLES FROM mysqltest1';
+
+EXECUTE stmt1;
+
+--connect (bug27337_con2,localhost,mysqltest_2,,mysqltest2)
+--echo
+--echo ---> connection: bug27337_con2
+
+SHOW COLUMNS FROM mysqltest2.t2;
+
+PREPARE stmt2 FROM 'SHOW COLUMNS FROM mysqltest2.t2';
+
+EXECUTE stmt2;
+
+--connection default
+--echo
+--echo ---> connection: default
+
+REVOKE SELECT ON mysqltest1.t1 FROM mysqltest_1@localhost;
+REVOKE SELECT ON mysqltest2.t2 FROM mysqltest_2@localhost;
+
+--connection bug27337_con1
+--echo
+--echo ---> connection: bug27337_con1
+
+--error ER_DBACCESS_DENIED_ERROR
+SHOW TABLES FROM mysqltest1;
+
+--error ER_DBACCESS_DENIED_ERROR
+EXECUTE stmt1;
+
+--connection bug27337_con2
+--echo
+--echo ---> connection: bug27337_con2
+
+--error ER_TABLEACCESS_DENIED_ERROR
+SHOW COLUMNS FROM mysqltest2.t2;
+
+--error ER_TABLEACCESS_DENIED_ERROR
+EXECUTE stmt2;
+
+# Cleanup.
+
+--connection default
+--echo
+--echo ---> connection: default
+
+--disconnect bug27337_con2
+
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+
+DROP USER mysqltest_1@localhost;
+
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/information_schema_db.test b/mysql-test/t/information_schema_db.test
index e15e50e8766..666f331c7b9 100644
--- a/mysql-test/t/information_schema_db.test
+++ b/mysql-test/t/information_schema_db.test
@@ -121,6 +121,28 @@ create table t1 (f1 char(4));
create view v1 as select f1 from t1;
grant insert on v1 to testdb_2@localhost;
+create view v5 as select f1 from t1;
+grant show view on v5 to testdb_2@localhost;
+
+--error 1227
+create definer=`no_such_user`@`no_such_host` view v6 as select f1 from t1;
+
+connection default;
+use testdb_1;
+create view v6 as select f1 from t1;
+grant show view on v6 to testdb_2@localhost;
+
+create table t2 (f1 char(4));
+create definer=`no_such_user`@`no_such_host` view v7 as select * from t2;
+
+show fields from testdb_1.v6;
+show create view testdb_1.v6;
+
+show create view testdb_1.v7;
+show fields from testdb_1.v7;
+
+connection testdb_1;
+
create table t3 (f1 char(4), f2 char(4));
create view v3 as select f1,f2 from t3;
grant insert(f1), insert(f2) on v3 to testdb_2@localhost;
@@ -129,13 +151,41 @@ connect (testdb_2,localhost,testdb_2,,test);
create view v2 as select f1 from testdb_1.v1;
create view v4 as select f1,f2 from testdb_1.v3;
+show fields from testdb_1.v5;
+show create view testdb_1.v5;
+
+show fields from testdb_1.v6;
+show create view testdb_1.v6;
+
connection testdb_1;
+show fields from testdb_1.v7;
+show create view testdb_1.v7;
+
revoke insert(f1) on v3 from testdb_2@localhost;
+revoke show view on v5 from testdb_2@localhost;
+connection default;
+use testdb_1;
+revoke show view on v6 from testdb_2@localhost;
connection testdb_2;
+--error 1142
+show fields from testdb_1.v5;
+--error 1142
+show create view testdb_1.v5;
+
+--error 1142
+show fields from testdb_1.v6;
+--error 1142
+show create view testdb_1.v6;
+
+--error 1142
+show fields from testdb_1.v7;
+--error 1142
+show create view testdb_1.v7;
+
--error 1345
show create view v4;
---error 1345
+#--error 1345
show fields from v4;
show fields from v2;
@@ -155,7 +205,8 @@ where a.table_name = 'testdb_1.v1';
select * from v2;
connection default;
-drop view testdb_1.v1,v2, testdb_1.v3, v4;
+use test;
+drop view testdb_1.v1, v2, testdb_1.v3, v4;
drop database testdb_1;
drop user testdb_1@localhost;
drop user testdb_2@localhost;
diff --git a/mysql-test/t/mysqlbinlog2.test b/mysql-test/t/mysqlbinlog2.test
index 6afae538f04..14b213cd9cc 100644
--- a/mysql-test/t/mysqlbinlog2.test
+++ b/mysql-test/t/mysqlbinlog2.test
@@ -55,6 +55,10 @@ select "--- stop-position --" as "";
--enable_query_log
--exec $MYSQL_BINLOG --short-form --stop-position=600 $MYSQLTEST_VARDIR/log/master-bin.000001
--disable_query_log
+select "--- start and stop positions ---" as "";
+--enable_query_log
+--exec $MYSQL_BINLOG --short-form --start-position=600 --stop-position 725 $MYSQLTEST_VARDIR/log/master-bin.000001
+--disable_query_log
select "--- start-datetime --" as "";
--enable_query_log
--exec $MYSQL_BINLOG --short-form "--start-datetime=2020-01-21 15:32:24" $MYSQLTEST_VARDIR/log/master-bin.000001
@@ -111,6 +115,10 @@ select "--- stop-position --" as "";
--enable_query_log
--exec $MYSQL_BINLOG --short-form --stop-position=600 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
--disable_query_log
+select "--- start and stop positions ---" as "";
+--enable_query_log
+--exec $MYSQL_BINLOG --short-form --start-position=600 --stop-position 725 --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
+--disable_query_log
select "--- start-datetime --" as "";
--enable_query_log
--exec $MYSQL_BINLOG --short-form "--start-datetime=2020-01-21 15:32:24" --read-from-remote-server --user=root --host=127.0.0.1 --port=$MASTER_MYPORT master-bin.000001
diff --git a/mysql-test/t/sp-security.test b/mysql-test/t/sp-security.test
index a5d509f29b7..38c72fd4fa6 100644
--- a/mysql-test/t/sp-security.test
+++ b/mysql-test/t/sp-security.test
@@ -28,6 +28,7 @@ drop procedure db1_secret.dummy;
use db1_secret;
create table t1 ( u varchar(64), i int );
+insert into t1 values('test', 0);
# A test procedure and function
create procedure stamp(i int)
@@ -35,7 +36,16 @@ create procedure stamp(i int)
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show procedure status like 'stamp';
-create function db() returns varchar(64) return database();
+delimiter |;
+create function db() returns varchar(64)
+begin
+ declare v varchar(64);
+
+ select u into v from t1 limit 1;
+
+ return v;
+end|
+delimiter ;|
--replace_column 5 '0000-00-00 00:00:00' 6 '0000-00-00 00:00:00'
show function status like 'db';
@@ -63,14 +73,18 @@ call db1_secret.stamp(2);
select db1_secret.db();
# ...but not this
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
select * from db1_secret.t1;
# ...and not this
---error 1044
+--error ER_DBACCESS_DENIED_ERROR
create procedure db1_secret.dummy() begin end;
---error 1305
+--error ER_SP_DOES_NOT_EXIST
drop procedure db1_secret.dummy;
+--error ER_PROCACCESS_DENIED_ERROR
+drop procedure db1_secret.stamp;
+--error ER_PROCACCESS_DENIED_ERROR
+drop function db1_secret.db;
#
@@ -83,14 +97,18 @@ call db1_secret.stamp(3);
select db1_secret.db();
# ...but not this
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
select * from db1_secret.t1;
# ...and not this
---error 1044
+--error ER_DBACCESS_DENIED_ERROR
create procedure db1_secret.dummy() begin end;
---error 1305
+--error ER_SP_DOES_NOT_EXIST
drop procedure db1_secret.dummy;
+--error ER_PROCACCESS_DENIED_ERROR
+drop procedure db1_secret.stamp;
+--error ER_PROCACCESS_DENIED_ERROR
+drop function db1_secret.db;
#
@@ -121,9 +139,9 @@ select db();
connection con2user1;
# This should not work
---error 1044
+--error ER_TABLEACCESS_DENIED_ERROR
call db1_secret.stamp(5);
---error 1044
+--error ER_TABLEACCESS_DENIED_ERROR
select db1_secret.db();
#
@@ -132,9 +150,9 @@ select db1_secret.db();
connection con3anon;
# This should not work
---error 1044
+--error ER_TABLEACCESS_DENIED_ERROR
call db1_secret.stamp(6);
---error 1044
+--error ER_TABLEACCESS_DENIED_ERROR
select db1_secret.db();
#
@@ -165,7 +183,7 @@ use db2;
create procedure p () insert into t2 values (1);
# Check that this doesn't work.
---error 1142
+--error ER_TABLEACCESS_DENIED_ERROR
call p();
connect (con4user2,localhost,user2,,);
@@ -174,7 +192,7 @@ connection con4user2;
use db2;
# This should not work, since p is executed with definer's (user1's) rights.
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
call p();
select * from t2;
@@ -207,9 +225,9 @@ alter procedure p modifies sql data;
drop procedure p;
# This should NOT work
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
alter procedure q modifies sql data;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
drop procedure q;
connection con1root;
@@ -260,30 +278,30 @@ connect (con4userc,localhost,userc,,);
connection con2usera;
call sptest.p1(1);
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
grant execute on procedure sptest.p1 to userb@localhost;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
drop procedure sptest.p1;
connection con3userb;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
call sptest.p1(2);
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
grant execute on procedure sptest.p1 to userb@localhost;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
drop procedure sptest.p1;
connection con4userc;
call sptest.p1(3);
grant execute on procedure sptest.p1 to userb@localhost;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
drop procedure sptest.p1;
connection con3userb;
call sptest.p1(4);
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
grant execute on procedure sptest.p1 to userb@localhost;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
drop procedure sptest.p1;
connection con1root;
@@ -332,7 +350,7 @@ delimiter ;//
connect (user1,localhost,user1,,test);
connection user1;
use mysqltest;
--- error 1370
+-- error ER_PROCACCESS_DENIED_ERROR
select bug_9503();
connection root;
@@ -401,13 +419,13 @@ grant usage on *.* to mysqltest_1@localhost;
connect (n1,localhost,mysqltest_1,,information_schema,$MASTER_MYPORT,$MASTER_MYSOCK);
connection n1;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
call mysqltest_1.p1();
disconnect n1;
# Test also without a current database
connect (n2,localhost,mysqltest_1,,*NO-ONE*,$MASTER_MYPORT,$MASTER_MYSOCK);
connection n2;
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
call mysqltest_1.p1();
disconnect n2;
@@ -433,9 +451,9 @@ end;
create user user_bug12812@localhost IDENTIFIED BY 'ABC'|
--replace_result $MASTER_MYPORT MYSQL_PORT $MASTER_MYSOCK MYSQL_SOCK
connect (test_user_12812,localhost,user_bug12812,ABC,test)|
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
SELECT test.bug12812()|
---error 1370
+--error ER_PROCACCESS_DENIED_ERROR
CREATE VIEW v1 AS SELECT test.bug12812()|
# Cleanup
connection default|
@@ -489,7 +507,8 @@ drop database db_bug14834;
#
-# BUG#14533: 'desc tbl' in stored procedure causes error 1142
+# BUG#14533: 'desc tbl' in stored procedure causes error
+# ER_TABLEACCESS_DENIED_ERROR
#
create database db_bug14533;
use db_bug14533;
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 8403c8589ef..2bc9e7c1946 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -6929,6 +6929,47 @@ INSERT INTO t3 VALUES (1, 3.4), (1, 2), (1, 0.9), (2, 8), (2, 7)|
SELECT SUM(f2), bug25373(f1) FROM t3 GROUP BY bug25373(f1) WITH ROLLUP|
DROP FUNCTION bug25373|
DROP TABLE t3|
+
+
+#
+# BUG#25082: Default database change on trigger execution breaks replication.
+#
+# As it turned out, this bug has actually two bugs. So, here we have two test
+# cases -- one in sp.test, the other in sp-security.test.
+#
+
+#
+# Test case 1: error on dropping the current database.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest1|
+DROP DATABASE IF EXISTS mysqltest2|
+--enable_warnings
+
+CREATE DATABASE mysqltest1|
+CREATE DATABASE mysqltest2|
+
+# Test.
+
+CREATE PROCEDURE mysqltest1.p1()
+ DROP DATABASE mysqltest2|
+
+use mysqltest2|
+
+CALL mysqltest1.p1()|
+
+SELECT DATABASE()|
+
+# Cleanup.
+
+DROP DATABASE mysqltest1|
+
+use test|
+
+
#
# Bug#20777: Function w BIGINT UNSIGNED shows diff. behaviour --ps-protocol
--disable_warnings
@@ -6996,3 +7037,26 @@ delimiter |;
delimiter ;|
drop table t1,t2;
+CREATE TABLE t1 (a int auto_increment primary key) engine=MyISAM;
+CREATE TABLE t2 (a int auto_increment primary key, b int) engine=innodb;
+set @a=0;
+
+delimiter |;
+CREATE function bug27354() RETURNS int deterministic
+begin
+insert into t1 values (null);
+set @a=@a+1;
+return @a;
+end|
+
+delimiter ;|
+update t2 set b=1 where a=bug27354();
+select count(t_1.a),count(t_2.a) from t1 as t_1, t2 as t_2 /* must be 0,0 */;
+insert into t2 values (1,1),(2,2),(3,3);
+update t2 set b=-b where a=bug27354();
+select * from t2 /* must return 1,-1 ... */;
+select count(*) from t1 /* must be 3 */;
+
+
+drop table t1,t2;
+drop function bug27354;
diff --git a/mysql-test/t/sp_trans.test b/mysql-test/t/sp_trans.test
index 1ea32316f1e..d9b34c303ae 100644
--- a/mysql-test/t/sp_trans.test
+++ b/mysql-test/t/sp_trans.test
@@ -554,6 +554,37 @@ set @@session.max_heap_table_size=default|
#
+# Bug #13270 INSERT,UPDATE,etc that calls func with side-effect does not binlog
+# Bug #23333 stored function + non-transac table + transac table =
+# breaks stmt-based binlog
+# Bug #27395 OPTION_STATUS_NO_TRANS_UPDATE is not preserved at the end of SF()
+#
+--disable_warnings
+drop function if exists bug23333|
+drop table if exists t1,t2|
+--enable_warnings
+ CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM|
+ CREATE TABLE t2 (a int NOT NULL auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB|
+
+insert into t2 values (1,1)|
+
+create function bug23333()
+RETURNS int(11)
+DETERMINISTIC
+begin
+ insert into t1 values (null);
+ select count(*) from t1 into @a;
+ return @a;
+end|
+
+reset master|
+--error ER_DUP_ENTRY
+insert into t2 values (bug23333(),1)|
+--replace_column 2 # 5 # 6 #
+show binlog events from 98 /* with fixes for #23333 will show there is the query */|
+select count(*),@a from t1 /* must be 1,1 */|
+
+#
# BUG#NNNN: New bug synopsis
#
#--disable_warnings
diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test
index b45afe4f312..a102f87c4e8 100644
--- a/mysql-test/t/view_grant.test
+++ b/mysql-test/t/view_grant.test
@@ -350,25 +350,6 @@ drop view mysqltest.v3;
connection user1;
create view mysqltest.v3 as select b from mysqltest.t2;
-# give UPDATE and INSERT privilege (to get more privileges then underlying
-# table)
-connection root;
-grant create view, update, insert on mysqltest.v3 to mysqltest_1@localhost;
-drop view mysqltest.v3;
-connection user1;
--- error 1143
-create view mysqltest.v3 as select b from mysqltest.t2;
-
-
-# If we would get more privileges on VIEW then we have on
-# underlying tables => creation prohibited
-connection root;
-create table mysqltest.v3 (b int);
-grant select(b) on mysqltest.v3 to mysqltest_1@localhost;
-drop table mysqltest.v3;
-connection user1;
--- error 1143
-create view mysqltest.v3 as select b from mysqltest.t2;
# Expression need select privileges
-- error 1143
@@ -1066,4 +1047,95 @@ DROP USER u26813@localhost;
DROP DATABASE db26813;
disconnect u1;
+#
+# BUG#24040: Create View don't succed with "all privileges" on a database.
+#
+
+# Prepare.
+
+--disable_warnings
+DROP DATABASE IF EXISTS mysqltest1;
+DROP DATABASE IF EXISTS mysqltest2;
+--enable_warnings
+
+CREATE DATABASE mysqltest1;
+CREATE DATABASE mysqltest2;
+
+# Test.
+
+CREATE TABLE mysqltest1.t1(c1 INT);
+CREATE TABLE mysqltest1.t2(c2 INT);
+CREATE TABLE mysqltest1.t3(c3 INT);
+CREATE TABLE mysqltest1.t4(c4 INT);
+
+INSERT INTO mysqltest1.t1 VALUES (11), (12), (13), (14);
+INSERT INTO mysqltest1.t2 VALUES (21), (22), (23), (24);
+INSERT INTO mysqltest1.t3 VALUES (31), (32), (33), (34);
+INSERT INTO mysqltest1.t4 VALUES (41), (42), (43), (44);
+
+GRANT SELECT ON mysqltest1.t1 TO mysqltest_u1@localhost;
+GRANT INSERT ON mysqltest1.t2 TO mysqltest_u1@localhost;
+GRANT SELECT, UPDATE ON mysqltest1.t3 TO mysqltest_u1@localhost;
+GRANT SELECT, DELETE ON mysqltest1.t4 TO mysqltest_u1@localhost;
+
+GRANT ALL PRIVILEGES ON mysqltest2.* TO mysqltest_u1@localhost;
+
+--connect (bug24040_con,localhost,mysqltest_u1,,mysqltest2)
+--echo
+--echo ---> connection: bug24040_con
+
+SELECT * FROM mysqltest1.t1;
+INSERT INTO mysqltest1.t2 VALUES(25);
+UPDATE mysqltest1.t3 SET c3 = 331 WHERE c3 = 31;
+DELETE FROM mysqltest1.t4 WHERE c4 = 44;
+
+CREATE VIEW v1 AS SELECT * FROM mysqltest1.t1;
+CREATE VIEW v2 AS SELECT * FROM mysqltest1.t2;
+CREATE VIEW v3 AS SELECT * FROM mysqltest1.t3;
+CREATE VIEW v4 AS SELECT * FROM mysqltest1.t4;
+
+SELECT * FROM v1;
+INSERT INTO v2 VALUES(26);
+UPDATE v3 SET c3 = 332 WHERE c3 = 32;
+DELETE FROM v4 WHERE c4 = 43;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+CREATE VIEW v12 AS SELECT c1, c2 FROM mysqltest1.t1, mysqltest1.t2;
+CREATE VIEW v13 AS SELECT c1, c3 FROM mysqltest1.t1, mysqltest1.t3;
+CREATE VIEW v14 AS SELECT c1, c4 FROM mysqltest1.t1, mysqltest1.t4;
+
+--error ER_COLUMNACCESS_DENIED_ERROR
+CREATE VIEW v21 AS SELECT c2, c1 FROM mysqltest1.t2, mysqltest1.t1;
+--error ER_COLUMNACCESS_DENIED_ERROR
+CREATE VIEW v23 AS SELECT c2, c3 FROM mysqltest1.t2, mysqltest1.t3;
+--error ER_COLUMNACCESS_DENIED_ERROR
+CREATE VIEW v24 AS SELECT c2, c4 FROM mysqltest1.t2, mysqltest1.t4;
+
+CREATE VIEW v31 AS SELECT c3, c1 FROM mysqltest1.t3, mysqltest1.t1;
+--error ER_COLUMNACCESS_DENIED_ERROR
+CREATE VIEW v32 AS SELECT c3, c2 FROM mysqltest1.t3, mysqltest1.t2;
+CREATE VIEW v34 AS SELECT c3, c4 FROM mysqltest1.t3, mysqltest1.t4;
+
+CREATE VIEW v41 AS SELECT c4, c1 FROM mysqltest1.t4, mysqltest1.t1;
+--error ER_COLUMNACCESS_DENIED_ERROR
+CREATE VIEW v42 AS SELECT c4, c2 FROM mysqltest1.t4, mysqltest1.t2;
+CREATE VIEW v43 AS SELECT c4, c3 FROM mysqltest1.t4, mysqltest1.t3;
+
+--connection default
+--echo
+--echo ---> connection: default
+
+SELECT * FROM mysqltest1.t1;
+SELECT * FROM mysqltest1.t2;
+SELECT * FROM mysqltest1.t3;
+SELECT * FROM mysqltest1.t4;
+
+# Cleanup.
+
+-- disconnect bug24040_con
+
+DROP DATABASE mysqltest1;
+DROP DATABASE mysqltest2;
+DROP USER mysqltest_u1@localhost;
+
--echo End of 5.0 tests.
diff --git a/mysys/my_handler.c b/mysys/my_handler.c
index afc44cc2838..1c3bb20426e 100644
--- a/mysys/my_handler.c
+++ b/mysys/my_handler.c
@@ -557,4 +557,3 @@ HA_KEYSEG *ha_find_null(HA_KEYSEG *keyseg, uchar *a)
}
return keyseg;
}
-
diff --git a/mysys/my_lib.c b/mysys/my_lib.c
index 75e31c4d555..61de4ff9065 100644
--- a/mysys/my_lib.c
+++ b/mysys/my_lib.c
@@ -627,7 +627,7 @@ int my_fstat(int Filedes, MY_STAT *stat_area,
myf MyFlags __attribute__((unused)))
{
DBUG_ENTER("my_fstat");
- DBUG_PRINT("my",("fd: %d MyFlags: %d",Filedes,MyFlags));
+ DBUG_PRINT("my",("fd: %d MyFlags: %d", Filedes, MyFlags));
DBUG_RETURN(fstat(Filedes, (struct stat *) stat_area));
}
@@ -636,7 +636,7 @@ MY_STAT *my_stat(const char *path, MY_STAT *stat_area, myf my_flags)
{
int m_used;
DBUG_ENTER("my_stat");
- DBUG_PRINT("my", ("path: '%s', stat_area: 0x%lx, MyFlags: %d", path,
+ DBUG_PRINT("my", ("path: '%s' stat_area: 0x%lx MyFlags: %d", path,
(long) stat_area, my_flags));
if ((m_used= (stat_area == NULL)))
diff --git a/mysys/my_seek.c b/mysys/my_seek.c
index fd2344e0d36..2be4812a2bd 100644
--- a/mysys/my_seek.c
+++ b/mysys/my_seek.c
@@ -60,7 +60,7 @@ my_off_t my_seek(File fd, my_off_t pos, int whence,
if (newpos == (os_off_t) -1)
{
my_errno=errno;
- DBUG_PRINT("error",("lseek: %lu, errno: %d", (ulong) newpos,errno));
+ DBUG_PRINT("error",("lseek: %lu errno: %d", (ulong) newpos,errno));
DBUG_RETURN(MY_FILEPOS_ERROR);
}
if ((my_off_t) newpos != pos)
diff --git a/mysys/raid.cc b/mysys/raid.cc
index c70c01fde4b..0fbe1810208 100644
--- a/mysys/raid.cc
+++ b/mysys/raid.cc
@@ -232,7 +232,7 @@ extern "C" {
{
DBUG_ENTER("my_raid_pwrite");
DBUG_PRINT("enter",
- ("Fd: %d Buffer: 0x %lx Count: %u offset: %u MyFlags: %d",
+ ("Fd: %d Buffer: 0x%lx Count: %u offset: %u MyFlags: %d",
Filedes, Buffer, Count, offset, MyFlags));
if (is_raid(Filedes))
{
@@ -251,8 +251,8 @@ extern "C" {
myf MyFlags)
{
DBUG_ENTER("my_raid_lock");
- DBUG_PRINT("enter",("Fd: %d start: %u length: %u MyFlags: %d",
- fd, start, length, MyFlags));
+ DBUG_PRINT("enter",("Fd: %d start: %lu length: %lu MyFlags: %d",
+ fd, (ulong) start, (ulong) length, MyFlags));
if (my_disable_locking)
DBUG_RETURN(0);
if (is_raid(fd))
@@ -285,8 +285,8 @@ extern "C" {
int my_raid_chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
{
DBUG_ENTER("my_raid_chsize");
- DBUG_PRINT("enter",("Fd: %d newlength: %u MyFlags: %d",
- fd, newlength, MyFlags));
+ DBUG_PRINT("enter",("Fd: %d newlength: %lu MyFlags: %d",
+ fd, (ulong) newlength, MyFlags));
if (is_raid(fd))
{
RaidFd *raid= (*dynamic_element(&RaidFd::_raid_map,fd,RaidFd**));
@@ -414,7 +414,7 @@ RaidFd(uint raid_type, uint raid_chunks, ulong raid_chunksize)
_fd_vector(0)
{
DBUG_ENTER("RaidFd::RaidFd");
- DBUG_PRINT("enter",("RaidFd_type: %u Disks: %u Chunksize: %d",
+ DBUG_PRINT("enter",("RaidFd_type: %u Disks: %u Chunksize: %lu",
raid_type, raid_chunks, raid_chunksize));
/* TODO: Here we should add checks if the malloc fails */
@@ -623,7 +623,7 @@ Lock(int locktype, my_off_t start, my_off_t length, myf MyFlags)
{
DBUG_ENTER("RaidFd::Lock");
DBUG_PRINT("enter",("locktype: %d start: %lu length: %lu MyFlags: %d",
- locktype, start, length, MyFlags));
+ locktype, (ulong) start, (ulong) length, MyFlags));
my_off_t bufptr = start;
// Loop until all data is locked
while(length)
@@ -733,8 +733,8 @@ my_off_t RaidFd::
Tell(myf MyFlags)
{
DBUG_ENTER("RaidFd::Tell");
- DBUG_PRINT("enter",("MyFlags: %d _position %d",
- MyFlags,_position));
+ DBUG_PRINT("enter",("MyFlags: %d _position: %lu",
+ MyFlags, (ulong) _position));
DBUG_RETURN(_position);
}
@@ -742,8 +742,8 @@ int RaidFd::
Chsize(File fd, my_off_t newlength, int filler, myf MyFlags)
{
DBUG_ENTER("RaidFd::Chsize");
- DBUG_PRINT("enter",("Fd: %d, newlength: %d, MyFlags: %d",
- fd, newlength,MyFlags));
+ DBUG_PRINT("enter",("Fd: %d newlength: %lu MyFlags: %d",
+ fd, (ulong) newlength, MyFlags));
_position = newlength;
Calculate();
uint _rounds = _total_block / _raid_chunks; // INT() assumed
diff --git a/mysys/thr_lock.c b/mysys/thr_lock.c
index 3d29379a9fc..93884921687 100644
--- a/mysys/thr_lock.c
+++ b/mysys/thr_lock.c
@@ -658,7 +658,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
goto end;
}
}
- DBUG_PRINT("lock",("write locked by thread: %ld, type: %d",
+ DBUG_PRINT("lock",("write locked by thread: %ld type: %d",
lock->read.data->owner->info->thread_id, data->type));
}
wait_queue= &lock->write_wait;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 93ca6b7f96d..33744b49cef 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -755,7 +755,7 @@ int ha_ndbcluster::set_ndb_value(NdbOperation *ndb_op, Field *field,
blob_ptr= (char*)"";
}
- DBUG_PRINT("value", ("set blob ptr=%p len=%u",
+ DBUG_PRINT("value", ("set blob ptr: %p len: %u",
blob_ptr, blob_len));
DBUG_DUMP("value", (char*)blob_ptr, min(blob_len, 26));
@@ -3678,8 +3678,7 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type)
{
m_transaction_on= FALSE;
/* Would be simpler if has_transactions() didn't always say "yes" */
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
- thd->no_trans_update= TRUE;
+ thd->no_trans_update.all= thd->no_trans_update.stmt= TRUE;
}
else if (!thd->transaction.on)
m_transaction_on= FALSE;
@@ -4430,7 +4429,7 @@ int ha_ndbcluster::create(const char *name,
for (i= 0; i < form->s->fields; i++)
{
Field *field= form->field[i];
- DBUG_PRINT("info", ("name: %s, type: %u, pack_length: %d",
+ DBUG_PRINT("info", ("name: %s type: %u pack_length: %d",
field->field_name, field->real_type(),
field->pack_length()));
if ((my_errno= create_ndb_column(col, field, create_info)))
@@ -6010,7 +6009,7 @@ static int packfrm(const void *data, uint len,
uint blob_len;
frm_blob_struct* blob;
DBUG_ENTER("packfrm");
- DBUG_PRINT("enter", ("data: 0x%lx, len: %d", (long) data, len));
+ DBUG_PRINT("enter", ("data: 0x%lx len: %d", (long) data, len));
error= 1;
org_len= len;
@@ -6037,7 +6036,8 @@ static int packfrm(const void *data, uint len,
*pack_len= blob_len;
error= 0;
- DBUG_PRINT("exit", ("pack_data: 0x%lx, pack_len: %d", (long) *pack_data, *pack_len));
+ DBUG_PRINT("exit", ("pack_data: 0x%lx pack_len: %d", (long) *pack_data,
+ *pack_len));
err:
DBUG_RETURN(error);
@@ -6076,7 +6076,8 @@ static int unpackfrm(const void **unpack_data, uint *unpack_len,
*unpack_data= data;
*unpack_len= complen;
- DBUG_PRINT("exit", ("frmdata: 0x%lx, len: %d", (long) *unpack_data, *unpack_len));
+ DBUG_PRINT("exit", ("frmdata: 0x%lx len: %d", (long) *unpack_data,
+ *unpack_len));
DBUG_RETURN(0);
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 6afa4f1900a..c6c31593a5f 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -830,7 +830,7 @@ int ha_rollback_trans(THD *thd, bool all)
the error log; but we don't want users to wonder why they have this
message in the error log, so we don't send it.
*/
- if (is_real_trans && (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ if (is_real_trans && thd->no_trans_update.all &&
!thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index ac1adc235c3..3bb537c2fd5 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2387,7 +2387,7 @@ byte *in_row::get_value(Item *item)
void in_row::set(uint pos, Item *item)
{
DBUG_ENTER("in_row::set");
- DBUG_PRINT("enter", ("pos %u item 0x%lx", pos, (ulong) item));
+ DBUG_PRINT("enter", ("pos: %u item: 0x%lx", pos, (ulong) item));
((cmp_item_row*) base)[pos].store_value_by_template(&tmp, item);
DBUG_VOID_RETURN;
}
diff --git a/sql/item_func.h b/sql/item_func.h
index 2273087495a..635a409e0a2 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -1414,7 +1414,7 @@ private:
bool execute();
bool execute_impl(THD *thd);
bool init_result_field(THD *thd);
-
+
public:
Item_func_sp(Name_resolution_context *context_arg, sp_name *name);
@@ -1425,6 +1425,8 @@ public:
virtual ~Item_func_sp()
{}
+ table_map used_tables() const { return RAND_TABLE_BIT; }
+
void cleanup();
const char *func_name() const;
diff --git a/sql/log.cc b/sql/log.cc
index c2b4eb1a441..7563d754556 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -162,7 +162,7 @@ static int binlog_rollback(THD *thd, bool all)
table. Such cases should be rare (updating a
non-transactional table inside a transaction...)
*/
- if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
+ if (unlikely(thd->no_trans_update.all))
{
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
@@ -217,7 +217,7 @@ static int binlog_savepoint_rollback(THD *thd, void *sv)
non-transactional table. Otherwise, truncate the binlog cache starting
from the SAVEPOINT command.
*/
- if (unlikely(thd->options & OPTION_STATUS_NO_TRANS_UPDATE))
+ if (unlikely(thd->no_trans_update.all))
{
Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
DBUG_RETURN(mysql_bin_log.write(&qinfo));
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 39f115f6fd5..a9c20e142c5 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -347,9 +347,6 @@ MY_LOCALE *my_locale_by_number(uint number);
in the user query has requested */
#define SELECT_ALL (ULL(1) << 24) // SELECT, user, parser
-/* Set if we are updating a non-transaction safe table */
-#define OPTION_STATUS_NO_TRANS_UPDATE (ULL(1) << 25) // THD, intern
-
/* The following can be set when importing tables in a 'wrong order'
to suppress foreign key checks */
#define OPTION_NO_FOREIGN_KEY_CHECKS (ULL(1) << 26) // THD, user, binlog
@@ -696,7 +693,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
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 char *name,bool no_access_check);
+bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name,
+ bool force_switch);
void mysql_parse(THD *thd,char *inBuf,uint length);
bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
bool is_update_query(enum enum_sql_command command);
@@ -942,7 +940,7 @@ void append_definer(THD *thd, String *buffer, const LEX_STRING *definer_user,
/* information schema */
-extern LEX_STRING information_schema_name;
+extern LEX_STRING INFORMATION_SCHEMA_NAME;
LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
const char* str, uint length,
bool allocate_lex_string);
@@ -959,8 +957,10 @@ int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond);
bool get_schema_tables_result(JOIN *join,
enum enum_schema_table_state executed_place);
+enum enum_schema_tables get_schema_table_idx(ST_SCHEMA_TABLE *schema_table);
+
#define is_schema_db(X) \
- !my_strcasecmp(system_charset_info, information_schema_name.str, (X))
+ !my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str, (X))
/* sql_prepare.cc */
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index ef929bc67f0..a635d058cd5 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -818,7 +818,7 @@ my_real_read(NET *net, ulong *complen)
{
my_bool interrupted = vio_should_retry(net->vio);
- DBUG_PRINT("info",("vio_read returned %ld, errno: %d",
+ DBUG_PRINT("info",("vio_read returned %ld errno: %d",
length, vio_errno(net->vio)));
#if (!defined(__WIN__) && !defined(__EMX__) && !defined(OS2)) || defined(MYSQL_SERVER)
/*
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 46c2a775d8a..ca5b6471bec 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2873,14 +2873,15 @@ static bool set_option_autocommit(THD *thd, set_var *var)
if ((org_options & OPTION_NOT_AUTOCOMMIT))
{
/* We changed to auto_commit mode */
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->no_trans_update.all= FALSE;
thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
if (ha_commit(thd))
return 1;
}
else
{
- thd->options&= ~(ulong) (OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->no_trans_update.all= FALSE;
thd->server_status&= ~SERVER_STATUS_AUTOCOMMIT;
}
}
diff --git a/sql/sp.cc b/sql/sp.cc
index c8701aa2c87..4fc9ea1f602 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -441,14 +441,14 @@ db_load_routine(THD *thd, int type, sp_name *name, sp_head **sphp,
{
sp_head *sp= newlex.sphead;
- if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1)))
+ if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
goto end;
delete sp;
ret= SP_PARSE_ERROR;
}
else
{
- if (dbchanged && (ret= mysql_change_db(thd, old_db.str, 1)))
+ if (dbchanged && (ret= mysql_change_db(thd, &old_db, TRUE)))
goto end;
*sphp= newlex.sphead;
(*sphp)->set_definer(&definer_user_name, &definer_host_name);
@@ -1896,7 +1896,7 @@ sp_use_new_db(THD *thd, LEX_STRING new_db, LEX_STRING *old_db,
DBUG_RETURN(0);
}
- ret= mysql_change_db(thd, new_db.str, no_access_check);
+ ret= mysql_change_db(thd, &new_db, no_access_check);
*dbchangedp= ret == 0;
DBUG_RETURN(ret);
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 21225d82188..338b2eb84bb 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -337,13 +337,13 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
enum_check_fields save_count_cuted_fields= thd->count_cuted_fields;
bool save_abort_on_warning= thd->abort_on_warning;
- bool save_no_trans_update= thd->no_trans_update;
+ bool save_no_trans_update_stmt= thd->no_trans_update.stmt;
thd->count_cuted_fields= CHECK_FIELD_ERROR_FOR_NULL;
thd->abort_on_warning=
thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
/* Save the value in the field. Convert the value if needed. */
@@ -351,7 +351,7 @@ sp_eval_expr(THD *thd, Field *result_field, Item **expr_item_ptr)
thd->count_cuted_fields= save_count_cuted_fields;
thd->abort_on_warning= save_abort_on_warning;
- thd->no_trans_update= save_no_trans_update;
+ thd->no_trans_update.stmt= save_no_trans_update_stmt;
if (thd->net.report_error)
{
@@ -1136,7 +1136,7 @@ sp_head::execute(THD *thd)
(It would generate an error from mysql_change_db() when old_db=="")
*/
if (! thd->killed)
- err_status|= mysql_change_db(thd, old_db.str, 1);
+ err_status|= mysql_change_db(thd, &old_db, TRUE);
}
m_flags&= ~IS_INVOKED;
DBUG_PRINT("info",
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index ee15f95f305..ebf9385d177 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3893,6 +3893,26 @@ err2:
}
+static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
+{
+ Security_context *sctx= thd->security_ctx;
+
+ for (uint idx= 0; idx < hash->records; ++idx)
+ {
+ GRANT_NAME *item= (GRANT_NAME*) hash_element(hash, idx);
+
+ if (strcmp(item->user, sctx->priv_user) == 0 &&
+ strcmp(item->db, db) == 0 &&
+ compare_hostname(&item->host, sctx->host, sctx->ip))
+ {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
/*
Check if a user has the right to access a database
Access is accepted if he has a grant for any table/routine in the database
@@ -3904,9 +3924,10 @@ bool check_grant_db(THD *thd,const char *db)
Security_context *sctx= thd->security_ctx;
char helping [NAME_LEN+USERNAME_LENGTH+2];
uint len;
- bool error= 1;
+ bool error= TRUE;
len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
+
rw_rdlock(&LOCK_grant);
for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
@@ -3917,11 +3938,17 @@ bool check_grant_db(THD *thd,const char *db)
!memcmp(grant_table->hash_key,helping,len) &&
compare_hostname(&grant_table->host, sctx->host, sctx->ip))
{
- error=0; // Found match
+ error= FALSE; /* Found match. */
break;
}
}
+
+ if (error)
+ error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
+ check_grant_db_routine(thd, db, &func_priv_hash);
+
rw_unlock(&LOCK_grant);
+
return error;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 1100a452b15..7ebdc90f8b3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3576,14 +3576,35 @@ find_field_in_tables(THD *thd, Item_ident *item,
{
Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length,
item->name, db, table_name, ref,
- check_privileges, allow_rowid,
+ check_privileges,
+ allow_rowid,
&(item->cached_field_index),
register_tree_change,
&actual_table);
if (cur_field)
{
if (cur_field == WRONG_GRANT)
- return (Field*) 0;
+ {
+ if (thd->lex->sql_command != SQLCOM_SHOW_FIELDS)
+ return (Field*) 0;
+
+ thd->clear_error();
+ cur_field= find_field_in_table_ref(thd, cur_table, name, length,
+ item->name, db, table_name, ref,
+ false,
+ allow_rowid,
+ &(item->cached_field_index),
+ register_tree_change,
+ &actual_table);
+ if (cur_field)
+ {
+ Field *nf=new Field_null(NULL,0,Field::NONE,
+ cur_field->field_name,
+ cur_field->table,
+ &my_charset_bin);
+ cur_field= nf;
+ }
+ }
/*
Store the original table of the field, which may be different from
@@ -3606,7 +3627,7 @@ find_field_in_tables(THD *thd, Item_ident *item,
report_error == IGNORE_EXCEPT_NON_UNIQUE)
my_error(ER_NON_UNIQ_ERROR, MYF(0),
table_name ? item->full_name() : name, thd->where);
- return (Field*) 0;
+ return (Field*) 0;
}
found= cur_field;
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index d06ac7824fd..795711b34d8 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -381,7 +381,7 @@ inline Query_cache_block * Query_cache_block_table::block()
void Query_cache_block::init(ulong block_length)
{
DBUG_ENTER("Query_cache_block::init");
- DBUG_PRINT("qcache", ("init block 0x%lx length: %lu", (ulong) this,
+ DBUG_PRINT("qcache", ("init block: 0x%lx length: %lu", (ulong) this,
block_length));
length = block_length;
used = 0;
@@ -3675,7 +3675,7 @@ void Query_cache::queries_dump()
Query_cache_query_flags flags;
memcpy(&flags, str+len, QUERY_CACHE_FLAGS_SIZE);
str[len]= 0; // make zero ending DB name
- DBUG_PRINT("qcache", ("F:%u C:%u L:%lu T:'%s' (%u) '%s' '%s'",
+ DBUG_PRINT("qcache", ("F: %u C: %u L: %lu T: '%s' (%u) '%s' '%s'",
flags.client_long_flag,
flags.character_set_client_num,
(ulong)flags.limit,
@@ -3998,7 +3998,7 @@ my_bool Query_cache::check_integrity(bool locked)
} while (block != bins[i].free_blocks);
if (count != bins[i].number)
{
- DBUG_PRINT("error", ("bins[%d].number = %d, but bin have %d blocks",
+ DBUG_PRINT("error", ("bins[%d].number= %d, but bin have %d blocks",
i, bins[i].number, count));
result = 1;
}
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index a94f903a47b..984df3e84f9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -333,6 +333,7 @@ void THD::init(void)
if (variables.sql_mode & MODE_NO_BACKSLASH_ESCAPES)
server_status|= SERVER_STATUS_NO_BACKSLASH_ESCAPES;
options= thd_startup_options;
+ no_trans_update.stmt= no_trans_update.all= FALSE;
open_options=ha_open_options;
update_lock_default= (variables.low_priority_updates ?
TL_WRITE_LOW_PRIORITY :
@@ -760,7 +761,8 @@ void THD::add_changed_table(const char *key, long key_length)
{
list_include(prev_changed, curr, changed_table_dup(key, key_length));
DBUG_PRINT("info",
- ("key_length %ld %u", key_length, (*prev_changed)->key_length));
+ ("key_length: %ld %u", key_length,
+ (*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
else if (cmp == 0)
@@ -770,7 +772,7 @@ void THD::add_changed_table(const char *key, long key_length)
{
list_include(prev_changed, curr, changed_table_dup(key, key_length));
DBUG_PRINT("info",
- ("key_length %ld %u", key_length,
+ ("key_length: %ld %u", key_length,
(*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
@@ -782,7 +784,7 @@ void THD::add_changed_table(const char *key, long key_length)
}
}
*prev_changed = changed_table_dup(key, key_length);
- DBUG_PRINT("info", ("key_length %ld %u", key_length,
+ DBUG_PRINT("info", ("key_length: %ld %u", key_length,
(*prev_changed)->key_length));
DBUG_VOID_RETURN;
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 99803802001..12d7cb2368f 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1440,7 +1440,11 @@ public:
bool charset_is_system_charset, charset_is_collation_connection;
bool charset_is_character_set_filesystem;
bool enable_slow_log; /* enable slow log for current statement */
- bool no_trans_update, abort_on_warning;
+ struct {
+ bool all:1;
+ bool stmt:1;
+ } no_trans_update;
+ bool abort_on_warning;
bool got_warning; /* Set on call to push_warning() */
bool no_warnings_for_error; /* no warnings on call to my_error() */
/* set during loop of derived table processing */
@@ -1664,7 +1668,7 @@ public:
inline bool really_abort_on_warning()
{
return (abort_on_warning &&
- (!no_trans_update ||
+ (!no_trans_update.stmt ||
(variables.sql_mode & MODE_STRICT_ALL_TABLES)));
}
void set_status_var_init();
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index f95ed8b6fc9..963457cc896 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -461,7 +461,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
DBUG_ENTER("mysql_create_db");
/* do not create 'information_schema' db */
- if (!my_strcasecmp(system_charset_info, db, information_schema_name.str))
+ if (!my_strcasecmp(system_charset_info, db, INFORMATION_SCHEMA_NAME.str))
{
my_error(ER_DB_CREATE_EXISTS, MYF(0), db);
DBUG_RETURN(-1);
@@ -1126,154 +1126,253 @@ err:
}
-/*
- Change the current database.
+/**
+ @brief Internal implementation: switch current database to a valid one.
- SYNOPSIS
- mysql_change_db()
- thd thread handle
- name database name
- no_access_check if TRUE, don't do access check. In this
- case name may be ""
+ @param thd Thread context.
+ @param new_db_name Name of the database to switch to. The function will
+ take ownership of the name (the caller must not free
+ the allocated memory). If the name is NULL, we're
+ going to switch to NULL db.
+ @param new_db_access Privileges of the new database.
+ @param new_db_charset Character set of the new database.
+*/
- DESCRIPTION
- Check that the database name corresponds to a valid and
- existent database, check access rights (unless called with
- no_access_check), and set the current database. This function
- is called to change the current database upon user request
- (COM_CHANGE_DB command) or temporarily, to execute a stored
- routine.
+static void mysql_change_db_impl(THD *thd,
+ LEX_STRING *new_db_name,
+ ulong new_db_access,
+ CHARSET_INFO *new_db_charset)
+{
+ /* 1. Change current database in THD. */
- NOTES
- This function is not the only way to switch the database that
- is currently employed. When the replication slave thread
- switches the database before executing a query, it calls
- thd->set_db directly. However, if the query, in turn, uses
- a stored routine, the stored routine will use this function,
- even if it's run on the slave.
-
- This function allocates the name of the database on the system
- heap: this is necessary to be able to uniformly change the
- database from any module of the server. Up to 5.0 different
- modules were using different memory to store the name of the
- database, and this led to memory corruption: a stack pointer
- set by Stored Procedures was used by replication after the
- stack address was long gone.
-
- This function does not send anything, including error
- messages, to the client. If that should be sent to the client,
- call net_send_error after this function.
+ if (new_db_name == NULL)
+ {
+ /*
+ THD::set_db() does all the job -- it frees previous database name and
+ sets the new one.
+ */
- RETURN VALUES
- 0 OK
- 1 error
+ thd->set_db(NULL, 0);
+ }
+ else if (new_db_name == &INFORMATION_SCHEMA_NAME)
+ {
+ /*
+ Here we must use THD::set_db(), because we want to copy
+ INFORMATION_SCHEMA_NAME constant.
+ */
+
+ thd->set_db(INFORMATION_SCHEMA_NAME.str, INFORMATION_SCHEMA_NAME.length);
+ }
+ else
+ {
+ /*
+ Here we already have a copy of database name to be used in THD. So,
+ we just call THD::reset_db(). Since THD::reset_db() does not releases
+ the previous database name, we should do it explicitly.
+ */
+
+ x_free(thd->db);
+
+ thd->reset_db(new_db_name->str, new_db_name->length);
+ }
+
+ /* 2. Update security context. */
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ thd->security_ctx->db_access= new_db_access;
+#endif
+
+ /* 3. Update db-charset environment variables. */
+
+ thd->db_charset= new_db_charset;
+ thd->variables.collation_database= new_db_charset;
+}
+
+
+/**
+ @brief Change the current database.
+
+ @param thd thread handle
+ @param name database name
+ @param force_switch if this flag is set (TRUE), mysql_change_db() will
+ switch to NULL db if the specified database is not
+ available anymore. Corresponding warning will be
+ thrown in this case. This flag is used to change
+ database in stored-routine-execution code.
+
+ @details Check that the database name corresponds to a valid and existent
+ database, check access rights (unless called with no_access_check), and
+ set the current database. This function is called to change the current
+ database upon user request (COM_CHANGE_DB command) or temporarily, to
+ execute a stored routine.
+
+ This function is not the only way to switch the database that is
+ currently employed. When the replication slave thread switches the
+ database before executing a query, it calls thd->set_db directly.
+ However, if the query, in turn, uses a stored routine, the stored routine
+ will use this function, even if it's run on the slave.
+
+ This function allocates the name of the database on the system heap: this
+ is necessary to be able to uniformly change the database from any module
+ of the server. Up to 5.0 different modules were using different memory to
+ store the name of the database, and this led to memory corruption:
+ a stack pointer set by Stored Procedures was used by replication after
+ the stack address was long gone.
+
+ @return Operation status
+ @retval FALSE Success
+ @retval TRUE Error
*/
-bool mysql_change_db(THD *thd, const char *name, bool no_access_check)
+bool mysql_change_db(THD *thd, const LEX_STRING *new_db_name, bool force_switch)
{
- int db_length;
- char *db_name;
- bool system_db= 0;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- ulong db_access;
+ LEX_STRING new_db_file_name;
+
Security_context *sctx= thd->security_ctx;
- LINT_INIT(db_access);
-#endif
+ ulong db_access= sctx->db_access;
+
DBUG_ENTER("mysql_change_db");
- DBUG_PRINT("enter",("name: '%s'",name));
+ DBUG_PRINT("enter",("name: '%s'", new_db_name->str));
- if (name == NULL || name[0] == '\0' && no_access_check == FALSE)
+ if (new_db_name == NULL ||
+ new_db_name->length == 0 ||
+ new_db_name->str == NULL)
{
- my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
- DBUG_RETURN(1); /* purecov: inspected */
+ if (force_switch)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR));
+
+ /* Change db to NULL. */
+
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+ DBUG_RETURN(FALSE);
+ }
+ else
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+
+ DBUG_RETURN(TRUE);
+ }
}
- else if (name[0] == '\0')
+
+ if (my_strcasecmp(system_charset_info, new_db_name->str,
+ INFORMATION_SCHEMA_NAME.str) == 0)
{
- /* Called from SP to restore the original database, which was NULL */
- DBUG_ASSERT(no_access_check);
- system_db= 1;
- db_name= NULL;
- db_length= 0;
- goto end;
+ /* Switch database to INFORMATION_SCHEMA. */
+
+ mysql_change_db_impl(thd, &INFORMATION_SCHEMA_NAME, SELECT_ACL,
+ system_charset_info);
+
+ DBUG_RETURN(FALSE);
}
+
/*
Now we need to make a copy because check_db_name requires a
- non-constant argument. TODO: fix check_db_name.
+ non-constant argument. Actually, it takes database file name.
+
+ TODO: fix check_db_name().
+ */
+
+ new_db_file_name.str= my_strdup(new_db_name->str, MYF(MY_WME));
+ new_db_file_name.length= new_db_name->length;
+
+ if (new_db_file_name.str == NULL)
+ DBUG_RETURN(TRUE); /* the error is set */
+
+ /*
+ NOTE: if check_db_name() fails, we should throw an error in any case,
+ even if we are called from sp_head::execute().
+
+ It's next to impossible however to get this error when we are called
+ from sp_head::execute(). But let's switch database to NULL in this case
+ to be sure.
*/
- if ((db_name= my_strdup(name, MYF(MY_WME))) == NULL)
- DBUG_RETURN(1); /* the error is set */
- db_length= strlen(db_name);
- if (check_db_name(db_name))
+
+ if (check_db_name(new_db_file_name.str))
{
- my_error(ER_WRONG_DB_NAME, MYF(0), db_name);
- my_free(db_name, MYF(0));
- DBUG_RETURN(1);
+ my_error(ER_WRONG_DB_NAME, MYF(0), new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+
+ if (force_switch)
+ {
+ /* Change db to NULL. */
+
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+ }
+
+ DBUG_RETURN(TRUE);
}
- DBUG_PRINT("info",("Use database: %s", db_name));
- if (!my_strcasecmp(system_charset_info, db_name, information_schema_name.str))
- {
- system_db= 1;
+
+ DBUG_PRINT("info",("Use database: %s", new_db_file_name.str));
+
#ifndef NO_EMBEDDED_ACCESS_CHECKS
- db_access= SELECT_ACL;
-#endif
- goto end;
+ db_access=
+ test_all_bits(sctx->master_access, DB_ACLS) ?
+ DB_ACLS :
+ acl_get(sctx->host,
+ sctx->ip,
+ sctx->priv_user,
+ new_db_file_name.str,
+ FALSE) | sctx->master_access;
+
+ if (!force_switch &&
+ !(db_access & DB_ACLS) &&
+ (!grant_option || check_grant_db(thd, new_db_file_name.str)))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ sctx->priv_user,
+ sctx->priv_host,
+ new_db_file_name.str);
+ mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
+ sctx->priv_user, sctx->priv_host, new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+ DBUG_RETURN(TRUE);
}
+#endif
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!no_access_check)
+ if (check_db_dir_existence(new_db_file_name.str))
{
- if (test_all_bits(sctx->master_access, DB_ACLS))
- db_access=DB_ACLS;
+ if (force_switch)
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_BAD_DB_ERROR, ER(ER_BAD_DB_ERROR),
+ new_db_file_name.str);
+
+ my_free(new_db_file_name.str, MYF(0));
+
+ /* Change db to NULL. */
+
+ mysql_change_db_impl(thd, NULL, 0, thd->variables.collation_server);
+
+ DBUG_RETURN(FALSE);
+ }
else
- db_access= (acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name, 0) |
- sctx->master_access);
- if (!(db_access & DB_ACLS) && (!grant_option ||
- check_grant_db(thd,db_name)))
{
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- sctx->priv_user,
- sctx->priv_host,
- db_name);
- mysql_log.write(thd, COM_INIT_DB, ER(ER_DBACCESS_DENIED_ERROR),
- sctx->priv_user, sctx->priv_host, db_name);
- my_free(db_name, MYF(0));
- DBUG_RETURN(1);
+ my_error(ER_BAD_DB_ERROR, MYF(0), new_db_file_name.str);
+ my_free(new_db_file_name.str, MYF(0));
+ DBUG_RETURN(TRUE);
}
}
-#endif
- if (check_db_dir_existence(db_name))
- {
- my_error(ER_BAD_DB_ERROR, MYF(0), db_name);
- my_free(db_name, MYF(0));
- DBUG_RETURN(1);
- }
+ /*
+ NOTE: in mysql_change_db_impl() new_db_file_name is assigned to THD
+ attributes and will be freed in THD::~THD().
+ */
-end:
- x_free(thd->db);
- DBUG_ASSERT(db_name == NULL || db_name[0] != '\0');
- thd->reset_db(db_name, db_length); // THD::~THD will free this
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- if (!no_access_check)
- sctx->db_access= db_access;
-#endif
- if (system_db)
{
- thd->db_charset= system_charset_info;
- thd->variables.collation_database= system_charset_info;
- }
- else
- {
- HA_CREATE_INFO create;
+ HA_CREATE_INFO db_options;
- load_db_opt_by_name(thd, db_name, &create);
+ load_db_opt_by_name(thd, new_db_name->str, &db_options);
- thd->db_charset= create.default_table_charset ?
- create.default_table_charset :
- thd->variables.collation_server;
- thd->variables.collation_database= thd->db_charset;
+ mysql_change_db_impl(thd, &new_db_file_name, db_access,
+ db_options.default_table_charset ?
+ db_options.default_table_charset :
+ thd->variables.collation_server);
}
- DBUG_RETURN(0);
+
+ DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 19f3135c594..bccd4d4cafe 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -328,7 +328,7 @@ cleanup:
error=1;
}
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
free_underlaid_joins(thd, select_lex);
if (transactional_table)
@@ -820,7 +820,7 @@ bool multi_delete::send_eof()
local_error=1; // Log write failed: roll back the SQL statement
}
if (!transactional_tables)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
/* Commit or rollback the current SQL statement */
if (transactional_tables)
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 955f83de25e..f1d86224adb 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -629,7 +629,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (lock_type != TL_WRITE_DELAYED && !thd->prelocked_mode)
table->file->start_bulk_insert(values_list.elements);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!ignore && (thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES)));
@@ -776,7 +776,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
error=1;
}
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
}
if (transactional_table)
@@ -1175,7 +1175,7 @@ static int last_uniq_key(TABLE *table,uint keynr)
then both on update triggers will work instead. Similarly both on
delete triggers will be invoked if we will delete conflicting records.
- Sets thd->no_trans_update if table which is updated didn't have
+ Sets thd->no_trans_update.stmt to TRUE if table which is updated didn't have
transactions.
RETURN VALUE
@@ -1341,7 +1341,7 @@ int write_record(THD *thd, TABLE *table,COPY_INFO *info)
goto err;
info->deleted++;
if (!table->file->has_transactions())
- thd->no_trans_update= 1;
+ thd->no_trans_update.stmt= TRUE;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_AFTER, TRUE))
@@ -1373,7 +1373,7 @@ ok_or_after_trg_err:
if (key)
my_safe_afree(key,table->s->max_unique_length,MAX_KEY_LENGTH);
if (!table->file->has_transactions())
- thd->no_trans_update= 1;
+ thd->no_trans_update.stmt= TRUE;
DBUG_RETURN(trg_error);
err:
@@ -2564,7 +2564,7 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table->file->extra(HA_EXTRA_WRITE_CAN_REPLACE);
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
}
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
@@ -2723,7 +2723,7 @@ void select_insert::send_error(uint errcode,const char *err)
mysql_bin_log.write(&qinfo);
}
if (!table->s->tmp_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
if (info.copied || info.deleted || info.updated)
{
@@ -2752,7 +2752,7 @@ bool select_insert::send_eof()
{
query_cache_invalidate3(thd, table, 1);
if (!(table->file->has_transactions() || table->s->tmp_table))
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
if (last_insert_id)
@@ -2978,7 +2978,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
if (!thd->prelocked_mode)
table->file->start_bulk_insert((ha_rows) 0);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!info.ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index a9847e39518..ee6d2d0a572 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -377,7 +377,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
table->file->start_bulk_insert((ha_rows) 0);
table->copy_blobs=1;
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= (!ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
@@ -467,7 +467,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
(ulong) (info.records - info.copied), (ulong) thd->cuted_fields);
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
#ifndef EMBEDDED_LIBRARY
if (mysql_bin_log.is_open())
{
@@ -532,7 +532,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
Item_field *sql_field;
TABLE *table= table_list->table;
ulonglong id;
- bool no_trans_update, err;
+ bool no_trans_update_stmt, err;
DBUG_ENTER("read_fixed_length");
id= 0;
@@ -560,7 +560,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
#ifdef HAVE_purify
read_info.row_end[0]=0;
#endif
- no_trans_update= !table->file->has_transactions();
+ no_trans_update_stmt= !table->file->has_transactions();
restore_record(table, s->default_values);
/*
@@ -628,7 +628,7 @@ read_fixed_length(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
table->auto_increment_field_not_null= FALSE;
if (err)
DBUG_RETURN(1);
- thd->no_trans_update= no_trans_update;
+ thd->no_trans_update.stmt= no_trans_update_stmt;
/*
If auto_increment values are used, save the first one for
@@ -671,12 +671,12 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
TABLE *table= table_list->table;
uint enclosed_length;
ulonglong id;
- bool no_trans_update, err;
+ bool no_trans_update_stmt, err;
DBUG_ENTER("read_sep_field");
enclosed_length=enclosed.length();
id= 0;
- no_trans_update= !table->file->has_transactions();
+ no_trans_update_stmt= !table->file->has_transactions();
for (;;it.rewind())
{
@@ -817,7 +817,7 @@ read_sep_field(THD *thd, COPY_INFO &info, TABLE_LIST *table_list,
We don't need to reset auto-increment field since we are restoring
its default value at the beginning of each loop iteration.
*/
- thd->no_trans_update= no_trans_update;
+ thd->no_trans_update.stmt= no_trans_update_stmt;
if (read_info.next_line()) // Skip to next line
break;
if (read_info.line_cuted)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 1b8bfd38fc4..ac75e6ea2fa 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -147,7 +147,8 @@ static bool end_active_trans(THD *thd)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_commit(thd))
error=1;
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->no_trans_update.all= FALSE;
}
DBUG_RETURN(error);
}
@@ -171,8 +172,8 @@ static bool begin_trans(THD *thd)
else
{
LEX *lex= thd->lex;
- thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
- OPTION_BEGIN);
+ thd->no_trans_update.all= FALSE;
+ thd->options|= (ulong) OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
error= ha_start_consistent_snapshot(thd);
@@ -289,7 +290,8 @@ int check_user(THD *thd, enum enum_server_command command,
bool check_count)
{
DBUG_ENTER("check_user");
-
+ LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
+
#ifdef NO_EMBEDDED_ACCESS_CHECKS
thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
/* Change database if necessary */
@@ -300,7 +302,7 @@ int check_user(THD *thd, enum enum_server_command command,
function returns 0
*/
thd->reset_db(NULL, 0);
- if (mysql_change_db(thd, db, FALSE))
+ if (mysql_change_db(thd, &db_str, FALSE))
{
/* Send the error to the client */
net_send_error(thd);
@@ -442,7 +444,7 @@ int check_user(THD *thd, enum enum_server_command command,
/* Change database if necessary */
if (db && db[0])
{
- if (mysql_change_db(thd, db, FALSE))
+ if (mysql_change_db(thd, &db_str, FALSE))
{
/* Send error to the client */
net_send_error(thd);
@@ -1463,7 +1465,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
*/
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
res= ha_commit(thd);
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->no_trans_update.all= FALSE;
break;
case COMMIT_RELEASE:
do_release= 1; /* fall through */
@@ -1480,7 +1483,8 @@ int end_trans(THD *thd, enum enum_mysql_completiontype completion)
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (ha_rollback(thd))
res= -1;
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->no_trans_update.all= FALSE;
if (!res && (completion == ROLLBACK_AND_CHAIN))
res= begin_trans(thd);
break;
@@ -1635,7 +1639,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
&LOCK_status);
thd->convert_string(&tmp, system_charset_info,
packet, strlen(packet), thd->charset());
- if (!mysql_change_db(thd, tmp.str, FALSE))
+ if (!mysql_change_db(thd, &tmp, FALSE))
{
mysql_log.write(thd,command,"%s",thd->db);
send_ok(thd);
@@ -1859,7 +1863,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
packet= pend+1;
if (!my_strcasecmp(system_charset_info, table_list.db,
- information_schema_name.str))
+ INFORMATION_SCHEMA_NAME.str))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, table_list.alias);
if (schema_table)
@@ -2233,7 +2237,8 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
enum enum_schema_tables schema_table_idx)
{
DBUG_ENTER("prepare_schema_table");
- SELECT_LEX *sel= 0;
+ SELECT_LEX *schema_select_lex= NULL;
+
switch (schema_table_idx) {
case SCH_SCHEMATA:
#if defined(DONT_ALLOW_SHOW_COMMANDS)
@@ -2241,11 +2246,9 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
DBUG_RETURN(1);
#else
- if ((specialflag & SPECIAL_SKIP_SHOW_DB) &&
- check_global_access(thd, SHOW_DB_ACL))
- DBUG_RETURN(1);
break;
#endif
+
case SCH_TABLE_NAMES:
case SCH_TABLES:
case SCH_VIEWS:
@@ -2255,32 +2258,25 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
DBUG_RETURN(1);
#else
+ if (lex->select_lex.db == NULL &&
+ thd->copy_db_to(&lex->select_lex.db, NULL))
{
- char *db;
- if (lex->select_lex.db == NULL &&
- thd->copy_db_to(&lex->select_lex.db, 0))
- {
- DBUG_RETURN(1);
- }
- db= lex->select_lex.db;
- remove_escape(db); // Fix escaped '_'
- if (check_db_name(db))
- {
- my_error(ER_WRONG_DB_NAME, MYF(0), db);
- DBUG_RETURN(1);
- }
- if (check_access(thd, SELECT_ACL, db, &thd->col_access, 0, 0,
- is_schema_db(db)))
- DBUG_RETURN(1); /* purecov: inspected */
- if (!thd->col_access && check_grant_db(thd,db))
- {
- my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
- thd->security_ctx->priv_user, thd->security_ctx->priv_host,
- db);
- DBUG_RETURN(1);
- }
- break;
+ DBUG_RETURN(1);
}
+
+ schema_select_lex= new SELECT_LEX();
+ schema_select_lex->db= lex->select_lex.db;
+ schema_select_lex->table_list.first= NULL;
+ remove_escape(schema_select_lex->db); // Fix escaped '_'
+
+ if (check_db_name(schema_select_lex->db))
+ {
+ my_error(ER_WRONG_DB_NAME, MYF(0), schema_select_lex->db);
+ DBUG_RETURN(1);
+ }
+
+
+ break;
#endif
case SCH_COLUMNS:
case SCH_STATISTICS:
@@ -2289,28 +2285,23 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */
DBUG_RETURN(1);
#else
- if (table_ident)
{
+ DBUG_ASSERT(table_ident);
+
TABLE_LIST **query_tables_last= lex->query_tables_last;
- sel= new SELECT_LEX();
+ schema_select_lex= new SELECT_LEX();
/* 'parent_lex' is used in init_query() so it must be before it. */
- sel->parent_lex= lex;
- sel->init_query();
- if (!sel->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
- (List<String> *) 0, (List<String> *) 0))
+ schema_select_lex->parent_lex= lex;
+ schema_select_lex->init_query();
+ if (!schema_select_lex->add_table_to_list(thd, table_ident, 0, 0, TL_READ,
+ (List<String> *) 0, (List<String> *) 0))
DBUG_RETURN(1);
lex->query_tables_last= query_tables_last;
- TABLE_LIST *table_list= (TABLE_LIST*) sel->table_list.first;
- char *db= table_list->db;
- remove_escape(db); // Fix escaped '_'
- remove_escape(table_list->table_name);
- if (check_access(thd,SELECT_ACL | EXTRA_ACL,db,
- &table_list->grant.privilege, 0, 0,
- test(table_list->schema_table)))
- DBUG_RETURN(1); /* purecov: inspected */
- if (grant_option && check_grant(thd, SELECT_ACL, table_list, 2,
- UINT_MAX, 0))
- DBUG_RETURN(1);
+
+ TABLE_LIST *dst_table= (TABLE_LIST*) schema_select_lex->table_list.first;
+ remove_escape(dst_table->db); // Fix escaped '_'
+ remove_escape(dst_table->table_name);
+
break;
}
#endif
@@ -2337,7 +2328,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident,
DBUG_RETURN(1);
}
TABLE_LIST *table_list= (TABLE_LIST*) select_lex->table_list.first;
- table_list->schema_select_lex= sel;
+ table_list->schema_select_lex= schema_select_lex;
table_list->schema_table_reformed= 1;
statistic_increment(thd->status_var.com_stat[lex->orig_sql_command],
&LOCK_status);
@@ -2933,7 +2924,7 @@ mysql_execute_command(THD *thd)
else
{
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
DBUG_ASSERT(first_table == all_tables && first_table != 0);
bool link_to_local;
@@ -3707,10 +3698,10 @@ end_with_restore_list:
we silently add IF EXISTS if TEMPORARY was used.
*/
if (thd->slave_thread)
- lex->drop_if_exists= 1;
+ lex->drop_if_exists= 1;
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
- thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
/* DDL and binlog write order protected by LOCK_open */
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
@@ -3750,9 +3741,14 @@ end_with_restore_list:
}
#endif
case SQLCOM_CHANGE_DB:
- if (!mysql_change_db(thd,select_lex->db,FALSE))
+ {
+ LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };
+
+ if (!mysql_change_db(thd, &db_str, FALSE))
send_ok(thd);
+
break;
+ }
case SQLCOM_LOAD:
{
@@ -4296,7 +4292,7 @@ end_with_restore_list:
res= TRUE; // cannot happen
else
{
- if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
+ if (thd->no_trans_update.all &&
!thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
@@ -4939,8 +4935,8 @@ create_sp_error:
thd->transaction.xid_state.xa_state=XA_ACTIVE;
thd->transaction.xid_state.xid.set(thd->lex->xid);
xid_cache_insert(&thd->transaction.xid_state);
- thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
- OPTION_BEGIN);
+ thd->no_trans_update.all= FALSE;
+ thd->options|= (ulong) OPTION_BEGIN;
thd->server_status|= SERVER_STATUS_IN_TRANS;
send_ok(thd);
break;
@@ -5033,7 +5029,8 @@ create_sp_error:
xa_state_names[thd->transaction.xid_state.xa_state]);
break;
}
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->no_trans_update.all= FALSE;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state=XA_NOTR;
@@ -5063,7 +5060,8 @@ create_sp_error:
my_error(ER_XAER_RMERR, MYF(0));
else
send_ok(thd);
- thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
+ thd->options&= ~(ulong) OPTION_BEGIN;
+ thd->no_trans_update.all= FALSE;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
xid_cache_delete(&thd->transaction.xid_state);
thd->transaction.xid_state.xa_state=XA_NOTR;
@@ -5159,7 +5157,10 @@ bool check_single_table_access(THD *thd, ulong privilege,
goto deny;
/* Show only 1 table for check_grant */
- if (grant_option && check_grant(thd, privilege, all_tables, 0, 1, 0))
+ if (grant_option &&
+ !(all_tables->belong_to_view &&
+ (thd->lex->sql_command == SQLCOM_SHOW_FIELDS)) &&
+ check_grant(thd, privilege, all_tables, 0, 1, 0))
goto deny;
thd->security_ctx= backup_ctx;
@@ -5376,6 +5377,83 @@ bool check_global_access(THD *thd, ulong want_access)
}
+static bool check_show_access(THD *thd, TABLE_LIST *table)
+{
+ switch (get_schema_table_idx(table->schema_table))
+ {
+ case SCH_SCHEMATA:
+ return (specialflag & SPECIAL_SKIP_SHOW_DB) &&
+ check_global_access(thd, SHOW_DB_ACL);
+
+ case SCH_TABLE_NAMES:
+ case SCH_TABLES:
+ case SCH_VIEWS:
+ case SCH_TRIGGERS:
+ {
+ const char *dst_db_name= table->schema_select_lex->db;
+
+ DBUG_ASSERT(dst_db_name);
+
+ if (check_access(thd, SELECT_ACL, dst_db_name,
+ &thd->col_access, FALSE, FALSE,
+ is_schema_db(dst_db_name)))
+ {
+ return TRUE;
+ }
+
+ if (!thd->col_access && check_grant_db(thd, dst_db_name))
+ {
+ my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
+ thd->security_ctx->priv_user,
+ thd->security_ctx->priv_host,
+ dst_db_name);
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ case SCH_COLUMNS:
+ case SCH_STATISTICS:
+ {
+ TABLE_LIST *dst_table=
+ (TABLE_LIST *) table->schema_select_lex->table_list.first;
+
+ DBUG_ASSERT(dst_table);
+
+ if (check_access(thd, SELECT_ACL | EXTRA_ACL,
+ dst_table->db,
+ &dst_table->grant.privilege,
+ FALSE, FALSE,
+ test(dst_table->schema_table)))
+ {
+ return FALSE;
+ }
+
+ return grant_option &&
+ check_grant(thd, SELECT_ACL, dst_table, 2, UINT_MAX, FALSE);
+ }
+
+ case SCH_OPEN_TABLES:
+ case SCH_VARIABLES:
+ case SCH_STATUS:
+ case SCH_PROCEDURES:
+ case SCH_CHARSETS:
+ case SCH_COLLATIONS:
+ case SCH_COLLATION_CHARACTER_SET_APPLICABILITY:
+ case SCH_USER_PRIVILEGES:
+ case SCH_SCHEMA_PRIVILEGES:
+ case SCH_TABLE_PRIVILEGES:
+ case SCH_COLUMN_PRIVILEGES:
+ case SCH_TABLE_CONSTRAINTS:
+ case SCH_KEY_COLUMN_USAGE:
+ break;
+ }
+
+ return FALSE;
+}
+
+
/*
Check the privilege for all used tables.
@@ -5428,7 +5506,7 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
if (!no_errors)
my_error(ER_DBACCESS_DENIED_ERROR, MYF(0),
sctx->priv_user, sctx->priv_host,
- information_schema_name.str);
+ INFORMATION_SCHEMA_NAME.str);
return TRUE;
}
/*
@@ -5436,7 +5514,16 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
Remove SHOW_VIEW_ACL, because it will be checked during making view
*/
tables->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
- if (tables->derived || tables->schema_table ||
+
+ if (tables->schema_table_reformed)
+ {
+ if (check_show_access(thd, tables))
+ goto deny;
+
+ continue;
+ }
+
+ if (tables->derived ||
(tables->table && (int)tables->table->s->tmp_table) ||
my_tz_check_n_skip_implicit_tables(&tables,
thd->lex->time_zone_tables_used))
@@ -6248,7 +6335,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
ptr->ignore_leaves= test(table_options & TL_OPTION_IGNORE_LEAVES);
ptr->derived= table->sel;
if (!ptr->derived && !my_strcasecmp(system_charset_info, ptr->db,
- information_schema_name.str))
+ INFORMATION_SCHEMA_NAME.str))
{
ST_SCHEMA_TABLE *schema_table= find_schema_table(thd, ptr->table_name);
if (!schema_table ||
@@ -6256,7 +6343,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
lex->orig_sql_command == SQLCOM_END)) // not a 'show' command
{
my_error(ER_UNKNOWN_TABLE, MYF(0),
- ptr->table_name, information_schema_name.str);
+ ptr->table_name, INFORMATION_SCHEMA_NAME.str);
DBUG_RETURN(0);
}
ptr->schema_table_name= ptr->table_name;
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 85092f14624..1ec65743b0f 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1668,7 +1668,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
enum enum_sql_command sql_command= lex->sql_command;
int res= 0;
DBUG_ENTER("check_prepared_statement");
- DBUG_PRINT("enter",("command: %d, param_count: %u",
+ DBUG_PRINT("enter",("command: %d param_count: %u",
sql_command, stmt->param_count));
lex->first_lists_tables_same();
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 0c9ea7b0bbf..8cf3dc022d9 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -496,9 +496,9 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
}
#endif
if (!my_strcasecmp(system_charset_info, dbname,
- information_schema_name.str))
+ INFORMATION_SCHEMA_NAME.str))
{
- dbname= information_schema_name.str;
+ dbname= INFORMATION_SCHEMA_NAME.str;
create.default_table_charset= system_charset_info;
}
else
@@ -1823,7 +1823,8 @@ LEX_STRING *make_lex_string(THD *thd, LEX_STRING *lex_str,
/* INFORMATION_SCHEMA name */
-LEX_STRING information_schema_name= {(char*)"information_schema", 18};
+LEX_STRING INFORMATION_SCHEMA_NAME=
+ { (char *) STRING_WITH_LEN("information_schema") };
/* This is only used internally, but we need it here as a forward reference */
extern ST_SCHEMA_TABLE schema_tables[];
@@ -2039,11 +2040,11 @@ int make_db_list(THD *thd, List<char> *files,
*/
if (!idx_field_vals->db_value ||
!wild_case_compare(system_charset_info,
- information_schema_name.str,
+ INFORMATION_SCHEMA_NAME.str,
idx_field_vals->db_value))
{
*with_i_schema= 1;
- if (files->push_back(thd->strdup(information_schema_name.str)))
+ if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str)))
return 1;
}
return (find_files(thd, files, NullS, mysql_data_home,
@@ -2058,11 +2059,11 @@ int make_db_list(THD *thd, List<char> *files,
*/
if (lex->orig_sql_command != SQLCOM_END)
{
- if (!my_strcasecmp(system_charset_info, information_schema_name.str,
+ if (!my_strcasecmp(system_charset_info, INFORMATION_SCHEMA_NAME.str,
idx_field_vals->db_value))
{
*with_i_schema= 1;
- return files->push_back(thd->strdup(information_schema_name.str));
+ return files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str));
}
return files->push_back(thd->strdup(idx_field_vals->db_value));
}
@@ -2071,7 +2072,7 @@ int make_db_list(THD *thd, List<char> *files,
Create list of existing databases. It is used in case
of select from information schema table
*/
- if (files->push_back(thd->strdup(information_schema_name.str)))
+ if (files->push_back(thd->strdup(INFORMATION_SCHEMA_NAME.str)))
return 1;
*with_i_schema= 1;
return (find_files(thd, files, NullS,
@@ -2147,7 +2148,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond)
*/
thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
- if (lsel)
+ if (lsel && lsel->table_list.first)
{
TABLE_LIST *show_table_list= (TABLE_LIST*) lsel->table_list.first;
bool res;
@@ -3936,8 +3937,8 @@ int make_schema_select(THD *thd, SELECT_LEX *sel,
We have to make non const db_name & table_name
because of lower_case_table_names
*/
- make_lex_string(thd, &db, information_schema_name.str,
- information_schema_name.length, 0);
+ make_lex_string(thd, &db, INFORMATION_SCHEMA_NAME.str,
+ INFORMATION_SCHEMA_NAME.length, 0);
make_lex_string(thd, &table, schema_table->table_name,
strlen(schema_table->table_name), 0);
if (schema_table->old_format(thd, schema_table) || /* Handle old syntax */
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 57da29e2646..6836811e7f3 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -3993,7 +3993,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
alter_table_manage_keys(to, from->file->indexes_are_disabled(), keys_onoff);
/* We can abort alter table for any table type */
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= !ignore && test(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES));
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e7e54d8ca1d..6f6c4538040 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -429,7 +429,7 @@ int mysql_update(THD *thd,
query_id=thd->query_id;
transactional_table= table->file->has_transactions();
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= test(!ignore &&
(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
@@ -464,7 +464,7 @@ int mysql_update(THD *thd,
if (fill_record_n_invoke_before_triggers(thd, fields, values, 0,
table->triggers,
TRG_EVENT_UPDATE))
- break; /* purecov: inspected */
+ break; /* purecov: inspected */
found++;
@@ -482,12 +482,12 @@ int mysql_update(THD *thd,
break;
}
}
- if (!(error=table->file->update_row((byte*) table->record[1],
- (byte*) table->record[0])))
- {
- updated++;
- thd->no_trans_update= !transactional_table;
-
+ if (!(error=table->file->update_row((byte*) table->record[1],
+ (byte*) table->record[0])))
+ {
+ updated++;
+ thd->no_trans_update.stmt= !transactional_table;
+
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE))
@@ -495,25 +495,25 @@ int mysql_update(THD *thd,
error= 1;
break;
}
- }
- else if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
- {
+ }
+ else if (!ignore || error != HA_ERR_FOUND_DUPP_KEY)
+ {
/*
If (ignore && error == HA_ERR_FOUND_DUPP_KEY) we don't have to
do anything; otherwise...
*/
if (error != HA_ERR_FOUND_DUPP_KEY)
thd->fatal_error(); /* Other handler errors are fatal */
- table->file->print_error(error,MYF(0));
- error= 1;
- break;
- }
+ table->file->print_error(error,MYF(0));
+ error= 1;
+ break;
+ }
}
-
+
if (!--limit && using_limit)
{
- error= -1; // Simulate end of file
- break;
+ error= -1; // Simulate end of file
+ break;
}
}
else
@@ -558,7 +558,7 @@ int mysql_update(THD *thd,
error=1; // Rollback update
}
if (!transactional_table)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
free_underlaid_joins(thd, select_lex);
if (transactional_table)
@@ -922,7 +922,7 @@ bool mysql_multi_update(THD *thd,
handle_duplicates, ignore)))
DBUG_RETURN(TRUE);
- thd->no_trans_update= 0;
+ thd->no_trans_update.stmt= FALSE;
thd->abort_on_warning= test(thd->variables.sql_mode &
(MODE_STRICT_TRANS_TABLES |
MODE_STRICT_ALL_TABLES));
@@ -1250,7 +1250,7 @@ multi_update::~multi_update()
delete [] copy_field;
thd->count_cuted_fields= CHECK_FIELD_IGNORE; // Restore this setting
if (!trans_safe)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
@@ -1337,7 +1337,7 @@ bool multi_update::send_data(List<Item> &not_used_values)
else
{
if (!table->file->has_transactions())
- thd->no_trans_update= 1;
+ thd->no_trans_update.stmt= TRUE;
if (table->triggers &&
table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
TRG_ACTION_AFTER, TRUE))
@@ -1567,10 +1567,10 @@ bool multi_update::send_eof()
Query_log_event qinfo(thd, thd->query, thd->query_length,
transactional_tables, FALSE);
if (mysql_bin_log.write(&qinfo) && trans_safe)
- local_error= 1; // Rollback update
+ local_error= 1; // Rollback update
}
if (!transactional_tables)
- thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
+ thd->no_trans_update.all= TRUE;
}
if (transactional_tables)
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 83beec3d1be..14d9aeb4df5 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -496,35 +496,46 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
/*
Compare/check grants on view with grants of underlying tables
*/
+
+ fill_effective_table_privileges(thd, &view->grant, view->db,
+ view->table_name);
+
+ {
+ Item *report_item= NULL;
+ uint final_priv= VIEW_ANY_ACL;
+
for (sl= select_lex; sl; sl= sl->next_select())
{
DBUG_ASSERT(view->db); /* Must be set in the parser */
List_iterator_fast<Item> it(sl->item_list);
Item *item;
- fill_effective_table_privileges(thd, &view->grant, view->db,
- view->table_name);
while ((item= it++))
{
- Item_field *fld;
+ Item_field *fld= item->filed_for_view_update();
uint priv= (get_column_grant(thd, &view->grant, view->db,
view->table_name, item->name) &
VIEW_ANY_ACL);
- if ((fld= item->filed_for_view_update()))
+
+ if (fld && !fld->field->table->s->tmp_table)
{
- /*
- Do we have more privileges on view field then underlying table field?
- */
- if (!fld->field->table->s->tmp_table && (~fld->have_privileges & priv))
+ final_priv&= fld->have_privileges;
+
+ if (~fld->have_privileges & priv)
+ report_item= item;
+ }
+ }
+ }
+
+ if (!final_priv)
{
- /* VIEW column has more privileges */
+ DBUG_ASSERT(report_item);
+
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
"create view", thd->security_ctx->priv_user,
- thd->security_ctx->priv_host, item->name,
+ thd->security_ctx->priv_host, report_item->name,
view->table_name);
res= TRUE;
goto err;
- }
- }
}
}
#endif
@@ -1007,6 +1018,11 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
CHARSET_INFO *save_cs= thd->variables.character_set_client;
thd->variables.character_set_client= system_charset_info;
res= MYSQLparse((void *)thd);
+
+ if ((old_lex->sql_command == SQLCOM_SHOW_FIELDS) ||
+ (old_lex->sql_command == SQLCOM_SHOW_CREATE))
+ lex->sql_command= old_lex->sql_command;
+
thd->variables.character_set_client= save_cs;
thd->variables.sql_mode= save_mode;
}
@@ -1032,7 +1048,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
}
}
else if (!table->prelocking_placeholder &&
- old_lex->sql_command == SQLCOM_SHOW_CREATE &&
+ (old_lex->sql_command == SQLCOM_SHOW_CREATE) &&
!table->belong_to_view)
{
if (check_table_access(thd, SHOW_VIEW_ACL, table, 0))
diff --git a/sql/table.cc b/sql/table.cc
index 960534bf7d4..6d13514e782 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -2085,7 +2085,7 @@ void st_table_list::hide_view_error(THD *thd)
thd->net.last_errno == ER_NO_SUCH_TABLE)
{
TABLE_LIST *top= top_table();
- thd->clear_error();
+ thd->clear_error();
my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
}
else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
@@ -2441,7 +2441,8 @@ bool st_table_list::prepare_view_securety_context(THD *thd)
definer.host.str,
thd->db))
{
- if (thd->lex->sql_command == SQLCOM_SHOW_CREATE)
+ if ((thd->lex->sql_command == SQLCOM_SHOW_CREATE) ||
+ (thd->lex->sql_command == SQLCOM_SHOW_FIELDS))
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_NO_SUCH_USER,