summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/grant4.result21
-rw-r--r--mysql-test/r/information_schema_prepare.result4
-rw-r--r--mysql-test/r/multi_update.result21
-rw-r--r--mysql-test/r/multi_update_big.result (renamed from mysql-test/r/multi_update2.result)0
-rw-r--r--mysql-test/r/view_grant.result4
-rw-r--r--mysql-test/suite/innodb/r/innodb-truncate.result13
-rw-r--r--mysql-test/suite/innodb/t/innodb-truncate.test18
-rw-r--r--mysql-test/suite/rpl/r/kill_race_condition.result13
-rw-r--r--mysql-test/suite/rpl/t/kill_race_condition.test28
-rw-r--r--mysql-test/t/grant4.test31
-rw-r--r--mysql-test/t/information_schema_prepare.test7
-rw-r--r--mysql-test/t/multi_update.test31
-rw-r--r--mysql-test/t/multi_update_big.opt (renamed from mysql-test/t/multi_update2-master.opt)0
-rw-r--r--mysql-test/t/multi_update_big.test (renamed from mysql-test/t/multi_update2.test)0
-rw-r--r--mysql-test/t/view_grant.test5
-rw-r--r--sql/log_event.cc25
-rw-r--r--sql/log_event_old.cc19
-rw-r--r--sql/sql_acl.cc10
-rw-r--r--sql/sql_base.cc92
-rw-r--r--sql/sql_base.h17
-rw-r--r--sql/sql_lex.h4
-rw-r--r--sql/sql_parse.cc6
-rw-r--r--sql/sql_show.cc2
-rw-r--r--sql/sql_truncate.cc14
-rw-r--r--sql/sql_update.cc36
-rw-r--r--sql/sql_view.cc3
-rw-r--r--sql/sql_yacc.yy37
-rw-r--r--sql/table.cc3
-rw-r--r--sql/table.h1
29 files changed, 357 insertions, 108 deletions
diff --git a/mysql-test/r/grant4.result b/mysql-test/r/grant4.result
index 5a0032cd338..88fad6edf49 100644
--- a/mysql-test/r/grant4.result
+++ b/mysql-test/r/grant4.result
@@ -123,6 +123,26 @@ View Create View character_set_client collation_connection
v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select `t_select_priv`.`a` AS `a`,`t_select_priv`.`b` AS `b` from `t_select_priv` latin1 latin1_swedish_ci
drop database mysqltest_db1;
drop user mysqltest_u1@localhost;
+call mtr.add_suppression("Table 'mysql.user' doesn't exist");
+call mtr.add_suppression("'mysql.user' is not TABLE");
+rename table mysql.user to mysql.user1;
+create view mysql.user as select * from mysql.user1;
+flush privileges;
+ERROR HY000: 'mysql.user' is not TABLE
+drop view mysql.user;
+create temporary table mysql.user select * from mysql.user1 limit 0;
+flush privileges;
+ERROR 42S02: Table 'mysql.user' doesn't exist
+drop temporary table mysql.user;
+rename table mysql.user1 to mysql.user;
+call mtr.add_suppression('mysql.user table is damaged');
+rename table mysql.user to mysql.user1;
+create table mysql.user (Host char(100), User char(100));
+flush privileges;
+ERROR HY000: Unknown error
+drop table mysql.user;
+rename table mysql.user1 to mysql.user;
+End of 5.5 tests
#
# Additional coverage for refactoring which is made as part
# of fix for bug #27480 "Extend CREATE TEMPORARY TABLES privilege
@@ -215,3 +235,4 @@ ERROR HY000: Password hash should be a 16-digit hexadecimal number
create user foo4 identified via mysql_old_password using '11111111111111111111111111111111111111111';
ERROR HY000: Password hash should be a 16-digit hexadecimal number
set GLOBAL sql_mode=default;
+End of 10.1 tests
diff --git a/mysql-test/r/information_schema_prepare.result b/mysql-test/r/information_schema_prepare.result
new file mode 100644
index 00000000000..3b5ee16b14b
--- /dev/null
+++ b/mysql-test/r/information_schema_prepare.result
@@ -0,0 +1,4 @@
+PREPARE stmt2 FROM "CREATE VIEW v AS SELECT * FROM INFORMATION_SCHEMA.TABLES";
+FLUSH PRIVILEGES;
+EXECUTE stmt2;
+DROP VIEW v;
diff --git a/mysql-test/r/multi_update.result b/mysql-test/r/multi_update.result
index 5991a5fd25a..f614ea1e497 100644
--- a/mysql-test/r/multi_update.result
+++ b/mysql-test/r/multi_update.result
@@ -1018,6 +1018,27 @@ execute stmt1;
deallocate prepare stmt1;
drop view v3,v2,v1;
drop table t1,t2,t3;
+create table t1 (id int not null, v1 varchar(10) not null);
+insert into t1 values (1,1),(2,2);
+create table t2 (log varchar(10) not null);
+create trigger t1_after_update after update on t1
+for each row insert into t2 values ('triggered');
+create user foo;
+grant select, insert, update, delete, create, drop, reload, index, alter, show databases, create temporary tables, lock tables, execute, create view, show view, create routine, alter routine, trigger on *.* to 'foo'@'%';
+set global read_only=1;
+create temporary table temp_t1 (id int not null, update_me varchar(10));
+insert into temp_t1 values (1,1),(2,2),(3,3);
+update temp_t1 left join t1 on temp_t1.id = t1.id set temp_t1.update_me = 'hello';
+set global read_only = 0;
+create table t3 (id int not null);
+insert t3 values (2);
+update t1 left join t3 on t1.id = t3.id set t1.v1 = 'hello';
+select * from t2;
+log
+triggered
+triggered
+drop table t1,t2, t3;
+drop user foo;
end of 5.5 tests
# Bug mdev-5970
diff --git a/mysql-test/r/multi_update2.result b/mysql-test/r/multi_update_big.result
index 3712e638f40..3712e638f40 100644
--- a/mysql-test/r/multi_update2.result
+++ b/mysql-test/r/multi_update_big.result
diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result
index 525f9fbb5e1..a1eb6e8bdb6 100644
--- a/mysql-test/r/view_grant.result
+++ b/mysql-test/r/view_grant.result
@@ -177,12 +177,15 @@ create table mysqltest.t1 (a int, b int, primary key(a));
insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
create table mysqltest.t2 (x int);
insert into mysqltest.t2 values (3), (4), (5), (6);
+create table mysqltest.t3 (x int);
+insert into mysqltest.t3 values (3), (4), (5), (6);
create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1;
create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1;
create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1;
create user mysqltest_1@localhost;
grant update (a) on mysqltest.v2 to mysqltest_1@localhost;
grant update on mysqltest.v1 to mysqltest_1@localhost;
+grant update on mysqltest.t3 to mysqltest_1@localhost;
grant select on mysqltest.* to mysqltest_1@localhost;
use mysqltest;
update t2,v1 set v1.a=v1.a+v1.c where t2.x=v1.c;
@@ -217,6 +220,7 @@ a b
48 4
62 5
71 10
+update t3,v3 set t3.x=t3.x+v3.c where t3.x=v3.c;
update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c;
ERROR 42000: UPDATE command denied to user 'mysqltest_1'@'localhost' for column 'c' in table 'v2'
update v2 set c=a+c;
diff --git a/mysql-test/suite/innodb/r/innodb-truncate.result b/mysql-test/suite/innodb/r/innodb-truncate.result
index f63e9272850..37ed19fa3fc 100644
--- a/mysql-test/suite/innodb/r/innodb-truncate.result
+++ b/mysql-test/suite/innodb/r/innodb-truncate.result
@@ -66,3 +66,16 @@ a
1
2
DROP TABLE t1;
+call mtr.add_suppression('InnoDB: Error: in RENAME TABLE table `test`.`t3`');
+SET FOREIGN_KEY_CHECKS= OFF;
+CREATE TABLE t1 (f2 INT, f4 INT, KEY(f2), FOREIGN KEY (f4) REFERENCES t3 (f4)) ENGINE=InnoDB;
+SET FOREIGN_KEY_CHECKS= ON;
+CREATE TABLE t2 (f2 INT, FOREIGN KEY(f2) REFERENCES t1 (f2)) ENGINE=InnoDB;
+CREATE TABLE t3 (a INT) ENGINE=InnoDB;
+ERROR HY000: Can't create table `test`.`t3` (errno: 150 "Foreign key constraint is incorrectly formed")
+ALTER TABLE t1 RENAME TO t3;
+ERROR HY000: Error on rename of './test/t1' to './test/t3' (errno: 150 "Foreign key constraint is incorrectly formed")
+ALTER TABLE t1 FORCE;
+TRUNCATE TABLE t1;
+ERROR 42000: Cannot truncate a table referenced in a foreign key constraint (`test`.`t2`, CONSTRAINT `t2_ibfk_1` FOREIGN KEY (`f2`) REFERENCES `test`.`t3` (`f2`))
+DROP TABLE t2, t1;
diff --git a/mysql-test/suite/innodb/t/innodb-truncate.test b/mysql-test/suite/innodb/t/innodb-truncate.test
index ae25aabd323..a5b500a4ea5 100644
--- a/mysql-test/suite/innodb/t/innodb-truncate.test
+++ b/mysql-test/suite/innodb/t/innodb-truncate.test
@@ -1,4 +1,5 @@
--source include/have_innodb.inc
+let $datadir=`select @@datadir`;
--echo #
--echo # TRUNCATE TABLE
--echo #
@@ -62,3 +63,20 @@ INSERT INTO t1 VALUES (NULL), (NULL);
SELECT * FROM t1 ORDER BY a;
DROP TABLE t1;
+#
+# MDEV-18923 Assertion `!lex_string_cmp(system_charset_info, fk_info->referenced_table, &table->s->table_name)' failed in fk_truncate_illegal_if_parent
+#
+call mtr.add_suppression('InnoDB: Error: in RENAME TABLE table `test`.`t3`');
+SET FOREIGN_KEY_CHECKS= OFF;
+CREATE TABLE t1 (f2 INT, f4 INT, KEY(f2), FOREIGN KEY (f4) REFERENCES t3 (f4)) ENGINE=InnoDB;
+SET FOREIGN_KEY_CHECKS= ON;
+CREATE TABLE t2 (f2 INT, FOREIGN KEY(f2) REFERENCES t1 (f2)) ENGINE=InnoDB;
+--error ER_CANT_CREATE_TABLE
+CREATE TABLE t3 (a INT) ENGINE=InnoDB;
+--replace_result $datadir ./
+--error ER_ERROR_ON_RENAME
+ALTER TABLE t1 RENAME TO t3;
+ALTER TABLE t1 FORCE;
+--error ER_TRUNCATE_ILLEGAL_FK
+TRUNCATE TABLE t1;
+DROP TABLE t2, t1;
diff --git a/mysql-test/suite/rpl/r/kill_race_condition.result b/mysql-test/suite/rpl/r/kill_race_condition.result
new file mode 100644
index 00000000000..e4e347dc786
--- /dev/null
+++ b/mysql-test/suite/rpl/r/kill_race_condition.result
@@ -0,0 +1,13 @@
+include/master-slave.inc
+[connection master]
+set global debug_dbug='d,rows_log_event_before_open_table';
+set debug_sync='now WAIT_FOR before_open_table';
+create table t1 (a int);
+insert t1 values (1),(2),(3);
+kill slave_sql_thread;
+set debug_sync='now SIGNAL go_ahead_sql';
+set global debug_dbug='';
+set debug_sync='RESET';
+drop table t1;
+start slave;
+include/rpl_end.inc
diff --git a/mysql-test/suite/rpl/t/kill_race_condition.test b/mysql-test/suite/rpl/t/kill_race_condition.test
new file mode 100644
index 00000000000..4268c12cdbf
--- /dev/null
+++ b/mysql-test/suite/rpl/t/kill_race_condition.test
@@ -0,0 +1,28 @@
+source include/have_debug_sync.inc;
+source include/have_binlog_format_row.inc;
+source include/master-slave.inc;
+
+connection slave;
+set global debug_dbug='d,rows_log_event_before_open_table';
+send set debug_sync='now WAIT_FOR before_open_table';
+
+connection master;
+create table t1 (a int);
+insert t1 values (1),(2),(3);
+
+connection slave;
+reap;
+let $a=`select id from information_schema.processlist where state='debug sync point: now'`;
+replace_result $a slave_sql_thread;
+eval kill $a;
+set debug_sync='now SIGNAL go_ahead_sql';
+set global debug_dbug='';
+set debug_sync='RESET';
+
+connection master;
+drop table t1;
+
+connection slave;
+start slave;
+
+source include/rpl_end.inc;
diff --git a/mysql-test/t/grant4.test b/mysql-test/t/grant4.test
index a3578c9b85a..93e016ace75 100644
--- a/mysql-test/t/grant4.test
+++ b/mysql-test/t/grant4.test
@@ -145,6 +145,34 @@ disconnect con1;
drop database mysqltest_db1;
drop user mysqltest_u1@localhost;
+#
+# MDEV-18241 Downgrade from 10.4 to 10.3 crashes
+#
+call mtr.add_suppression("Table 'mysql.user' doesn't exist");
+call mtr.add_suppression("'mysql.user' is not TABLE");
+rename table mysql.user to mysql.user1;
+create view mysql.user as select * from mysql.user1;
+--error ER_WRONG_OBJECT
+flush privileges;
+drop view mysql.user;
+create temporary table mysql.user select * from mysql.user1 limit 0;
+--error ER_NO_SUCH_TABLE
+flush privileges;
+drop temporary table mysql.user;
+rename table mysql.user1 to mysql.user;
+
+#
+# Bug#28986737: RENAMING AND REPLACING MYSQL.USER TABLE CAN LEAD TO A SERVER CRASH
+#
+call mtr.add_suppression('mysql.user table is damaged');
+rename table mysql.user to mysql.user1;
+create table mysql.user (Host char(100), User char(100));
+--error ER_UNKNOWN_ERROR
+flush privileges;
+drop table mysql.user;
+rename table mysql.user1 to mysql.user;
+
+--echo End of 5.5 tests
--echo #
--echo # Additional coverage for refactoring which is made as part
@@ -235,5 +263,6 @@ create user foo3 identified via mysql_old_password using '00';
--error ER_PASSWD_LENGTH
create user foo4 identified via mysql_old_password using '11111111111111111111111111111111111111111';
-
set GLOBAL sql_mode=default;
+
+--echo End of 10.1 tests
diff --git a/mysql-test/t/information_schema_prepare.test b/mysql-test/t/information_schema_prepare.test
new file mode 100644
index 00000000000..c5f3f89ff29
--- /dev/null
+++ b/mysql-test/t/information_schema_prepare.test
@@ -0,0 +1,7 @@
+#
+# MDEV-15907 ASAN heap-use-after-free in strnmov / .. / fill_effective_table_privileges on concurrent GRANT and CREATE VIEW
+#
+PREPARE stmt2 FROM "CREATE VIEW v AS SELECT * FROM INFORMATION_SCHEMA.TABLES";
+FLUSH PRIVILEGES;
+EXECUTE stmt2;
+DROP VIEW v;
diff --git a/mysql-test/t/multi_update.test b/mysql-test/t/multi_update.test
index 0297280340d..8399c465562 100644
--- a/mysql-test/t/multi_update.test
+++ b/mysql-test/t/multi_update.test
@@ -1056,6 +1056,37 @@ deallocate prepare stmt1;
drop view v3,v2,v1;
drop table t1,t2,t3;
+
+#
+# MDEV-18507 can't update temporary table when joined with table with triggers on read-only
+#
+create table t1 (id int not null, v1 varchar(10) not null);
+insert into t1 values (1,1),(2,2);
+create table t2 (log varchar(10) not null);
+create trigger t1_after_update after update on t1
+ for each row insert into t2 values ('triggered');
+
+create user foo;
+grant select, insert, update, delete, create, drop, reload, index, alter, show databases, create temporary tables, lock tables, execute, create view, show view, create routine, alter routine, trigger on *.* to 'foo'@'%';
+
+set global read_only=1;
+connect a, localhost, foo;
+
+create temporary table temp_t1 (id int not null, update_me varchar(10));
+insert into temp_t1 values (1,1),(2,2),(3,3);
+update temp_t1 left join t1 on temp_t1.id = t1.id set temp_t1.update_me = 'hello';
+
+connection default;
+set global read_only = 0;
+
+create table t3 (id int not null);
+insert t3 values (2);
+update t1 left join t3 on t1.id = t3.id set t1.v1 = 'hello';
+select * from t2;
+
+drop table t1,t2, t3;
+drop user foo;
+
--echo end of 5.5 tests
diff --git a/mysql-test/t/multi_update2-master.opt b/mysql-test/t/multi_update_big.opt
index da78f987af3..da78f987af3 100644
--- a/mysql-test/t/multi_update2-master.opt
+++ b/mysql-test/t/multi_update_big.opt
diff --git a/mysql-test/t/multi_update2.test b/mysql-test/t/multi_update_big.test
index a0f17fabec4..a0f17fabec4 100644
--- a/mysql-test/t/multi_update2.test
+++ b/mysql-test/t/multi_update_big.test
diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test
index 6d0cd8e5c28..4f10d48ee77 100644
--- a/mysql-test/t/view_grant.test
+++ b/mysql-test/t/view_grant.test
@@ -244,6 +244,8 @@ create table mysqltest.t1 (a int, b int, primary key(a));
insert into mysqltest.t1 values (10,2), (20,3), (30,4), (40,5), (50,10);
create table mysqltest.t2 (x int);
insert into mysqltest.t2 values (3), (4), (5), (6);
+create table mysqltest.t3 (x int);
+insert into mysqltest.t3 values (3), (4), (5), (6);
create view mysqltest.v1 (a,c) as select a, b+1 from mysqltest.t1;
create view mysqltest.v2 (a,c) as select a, b from mysqltest.t1;
create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1;
@@ -251,6 +253,7 @@ create view mysqltest.v3 (a,c) as select a, b+1 from mysqltest.t1;
create user mysqltest_1@localhost;
grant update (a) on mysqltest.v2 to mysqltest_1@localhost;
grant update on mysqltest.v1 to mysqltest_1@localhost;
+grant update on mysqltest.t3 to mysqltest_1@localhost;
grant select on mysqltest.* to mysqltest_1@localhost;
connection user1;
@@ -265,6 +268,8 @@ update t2,v2 set v2.a=v2.a+v2.c where t2.x=v2.c;
select * from t1;
update v2 set a=a+c;
select * from t1;
+# update a table, select only on view
+update t3,v3 set t3.x=t3.x+v3.c where t3.x=v3.c;
# no rights on column
--error ER_COLUMNACCESS_DENIED_ERROR
update t2,v2 set v2.c=v2.a+v2.c where t2.x=v2.c;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index bb373a4ed84..a6091fcc28d 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,6 +1,6 @@
/*
- Copyright (c) 2000, 2018, Oracle and/or its affiliates.
- Copyright (c) 2009, 2018, MariaDB
+ Copyright (c) 2000, 2019, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -40,6 +40,7 @@
#include "transaction.h"
#include <my_dir.h>
#include "sql_show.h" // append_identifier
+#include "debug_sync.h" // debug_sync
#include <mysql/psi/mysql_statement.h>
#include <strfunc.h>
#include "compat56.h"
@@ -9910,6 +9911,12 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
/* A small test to verify that objects have consistent types */
DBUG_ASSERT(sizeof(thd->variables.option_bits) == sizeof(OPTION_RELAXED_UNIQUE_CHECKS));
+ DBUG_EXECUTE_IF("rows_log_event_before_open_table",
+ {
+ const char action[] = "now SIGNAL before_open_table WAIT_FOR go_ahead_sql";
+ DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(action)));
+ };);
+
if (slave_run_triggers_for_rbr)
{
LEX *lex= thd->lex;
@@ -9934,7 +9941,6 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
}
if (open_and_lock_tables(thd, rgi->tables_to_lock, FALSE, 0))
{
- uint actual_error= thd->get_stmt_da()->sql_errno();
#ifdef WITH_WSREP
if (WSREP(thd))
{
@@ -9947,23 +9953,22 @@ int Rows_log_event::do_apply_event(rpl_group_info *rgi)
(long long)wsrep_thd_trx_seqno(thd));
}
#endif
- if ((thd->is_slave_error || thd->is_fatal_error) &&
- !is_parallel_retry_error(rgi, actual_error))
+ if (thd->is_error() &&
+ !is_parallel_retry_error(rgi, error= thd->get_stmt_da()->sql_errno()))
{
/*
Error reporting borrowed from Query_log_event with many excessive
- simplifications.
+ simplifications.
We should not honour --slave-skip-errors at this point as we are
- having severe errors which should not be skiped.
+ having severe errors which should not be skipped.
*/
- rli->report(ERROR_LEVEL, actual_error, rgi->gtid_info(),
+ rli->report(ERROR_LEVEL, error, rgi->gtid_info(),
"Error executing row event: '%s'",
- (actual_error ? thd->get_stmt_da()->message() :
+ (error ? thd->get_stmt_da()->message() :
"unexpected success or fatal error"));
thd->is_slave_error= 1;
}
/* remove trigger's tables */
- error= actual_error;
goto err;
}
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index a6f2ed3f416..f0c1c61bb1d 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1,5 +1,5 @@
-/* Copyright (c) 2007, 2018, Oracle and/or its affiliates.
- Copyright (c) 2009, 2018, MariaDB
+/* Copyright (c) 2007, 2019, Oracle and/or its affiliates.
+ Copyright (c) 2009, 2019, MariaDB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -101,21 +101,20 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, rpl_group_info *rgi)
if (open_and_lock_tables(ev_thd, rgi->tables_to_lock, FALSE, 0))
{
- uint actual_error= ev_thd->get_stmt_da()->sql_errno();
- if (ev_thd->is_slave_error || ev_thd->is_fatal_error)
+ if (ev_thd->is_error())
{
/*
Error reporting borrowed from Query_log_event with many excessive
- simplifications (we don't honour --slave-skip-errors)
+ simplifications.
+ We should not honour --slave-skip-errors at this point as we are
+ having severe errors which should not be skipped.
*/
- rli->report(ERROR_LEVEL, actual_error, NULL,
+ rli->report(ERROR_LEVEL, ev_thd->get_stmt_da()->sql_errno(), NULL,
"Error '%s' on opening tables",
- (actual_error ? ev_thd->get_stmt_da()->message() :
- "unexpected success or fatal error"));
+ ev_thd->get_stmt_da()->message());
ev_thd->is_slave_error= 1;
}
- rgi->slave_close_thread_tables(thd);
- DBUG_RETURN(actual_error);
+ DBUG_RETURN(1);
}
/*
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index c2e5bfd8c11..83526532bdd 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1271,6 +1271,13 @@ static bool acl_load(THD *thd, TABLE_LIST *tables)
goto end;
table->use_all_columns();
+ if (table->s->fields < 13) // number of columns in 3.21
+ {
+ sql_print_error("Fatal error: mysql.user table is damaged or in "
+ "unsupported 3.20 format.");
+ goto end;
+ }
+
username_char_length= MY_MIN(table->field[1]->char_length(),
USERNAME_CHAR_LENGTH);
password_length= table->field[2]->field_length /
@@ -8550,8 +8557,7 @@ static int open_grant_tables(THD *thd, TABLE_LIST *tables,
acl_table_names[cur].length,
acl_table_names[cur].str, lock_type);
tables[cur].open_type= OT_BASE_ONLY;
- if (lock_type >= TL_WRITE_ALLOW_WRITE)
- tables[cur].updating= 1;
+ tables[cur].i_s_requested_object= OPEN_TABLE_ONLY;
if (cur >= FIRST_OPTIONAL_TABLE)
tables[cur].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
if (prev != -1)
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 733a3a1f3ed..3a7ffdb656a 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -3923,6 +3923,45 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
DBUG_RETURN(FALSE);
}
+/*
+ If we are not already in prelocked mode and extended table list is not
+ yet built we might have to build the prelocking set for this statement.
+
+ Since currently no prelocking strategy prescribes doing anything for
+ tables which are only read, we do below checks only if table is going
+ to be changed.
+*/
+bool extend_table_list(THD *thd, TABLE_LIST *tables,
+ Prelocking_strategy *prelocking_strategy,
+ bool has_prelocking_list)
+{
+ bool error= false;
+ LEX *lex= thd->lex;
+
+ if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
+ ! has_prelocking_list && tables->updating &&
+ tables->lock_type >= TL_WRITE_ALLOW_WRITE)
+ {
+ bool need_prelocking= FALSE;
+ TABLE_LIST **save_query_tables_last= lex->query_tables_last;
+ /*
+ Extend statement's table list and the prelocking set with
+ tables and routines according to the current prelocking
+ strategy.
+
+ For example, for DML statements we need to add tables and routines
+ used by triggers which are going to be invoked for this element of
+ table list and also add tables required for handling of foreign keys.
+ */
+ error= prelocking_strategy->handle_table(thd, lex, tables,
+ &need_prelocking);
+
+ if (need_prelocking && ! lex->requires_prelocking())
+ lex->mark_as_requiring_prelocking(save_query_tables_last);
+ }
+ return error;
+}
+
/**
Handle table list element by obtaining metadata lock, opening table or view
@@ -3949,14 +3988,13 @@ open_and_process_routine(THD *thd, Query_tables_list *prelocking_ctx,
*/
static bool
-open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
- uint *counter, uint flags,
+open_and_process_table(THD *thd, TABLE_LIST *tables, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy,
- bool has_prelocking_list,
- Open_table_context *ot_ctx)
+ bool has_prelocking_list, Open_table_context *ot_ctx)
{
bool error= FALSE;
bool safe_to_ignore_table= FALSE;
+ LEX *lex= thd->lex;
DBUG_ENTER("open_and_process_table");
DEBUG_SYNC(thd, "open_and_process_table");
@@ -4175,38 +4213,9 @@ open_and_process_table(THD *thd, LEX *lex, TABLE_LIST *tables,
if (tables->open_strategy && !tables->table)
goto end;
- /*
- If we are not already in prelocked mode and extended table list is not
- yet built we might have to build the prelocking set for this statement.
-
- Since currently no prelocking strategy prescribes doing anything for
- tables which are only read, we do below checks only if table is going
- to be changed.
- */
- if (thd->locked_tables_mode <= LTM_LOCK_TABLES &&
- ! has_prelocking_list &&
- tables->lock_type >= TL_WRITE_ALLOW_WRITE)
- {
- bool need_prelocking= FALSE;
- TABLE_LIST **save_query_tables_last= lex->query_tables_last;
- /*
- Extend statement's table list and the prelocking set with
- tables and routines according to the current prelocking
- strategy.
-
- For example, for DML statements we need to add tables and routines
- used by triggers which are going to be invoked for this element of
- table list and also add tables required for handling of foreign keys.
- */
- error= prelocking_strategy->handle_table(thd, lex, tables,
- &need_prelocking);
-
- if (need_prelocking && ! lex->requires_prelocking())
- lex->mark_as_requiring_prelocking(save_query_tables_last);
-
- if (error)
- goto end;
- }
+ error= extend_table_list(thd, tables, prelocking_strategy, has_prelocking_list);
+ if (error)
+ goto end;
/* Copy grant information from TABLE_LIST instance to TABLE one. */
tables->table->grant= tables->grant;
@@ -4521,7 +4530,8 @@ open_tables_check_upgradable_mdl(THD *thd, TABLE_LIST *tables_start,
*/
bool open_tables(THD *thd, const DDL_options_st &options,
- TABLE_LIST **start, uint *counter, uint flags,
+ TABLE_LIST **start, uint *counter,
+ Sroutine_hash_entry **sroutine_to_open_list, uint flags,
Prelocking_strategy *prelocking_strategy)
{
/*
@@ -4564,7 +4574,7 @@ restart:
has_prelocking_list= thd->lex->requires_prelocking();
table_to_open= start;
- sroutine_to_open= (Sroutine_hash_entry**) &thd->lex->sroutines_list.first;
+ sroutine_to_open= sroutine_to_open_list;
*counter= 0;
THD_STAGE_INFO(thd, stage_opening_tables);
@@ -4634,9 +4644,9 @@ restart:
for (tables= *table_to_open; tables;
table_to_open= &tables->next_global, tables= tables->next_global)
{
- error= open_and_process_table(thd, thd->lex, tables, counter,
- flags, prelocking_strategy,
- has_prelocking_list, &ot_ctx);
+ error= open_and_process_table(thd, tables, counter, flags,
+ prelocking_strategy, has_prelocking_list,
+ &ot_ctx);
if (error)
{
diff --git a/sql/sql_base.h b/sql/sql_base.h
index 94294e3aa43..53b5885460b 100644
--- a/sql/sql_base.h
+++ b/sql/sql_base.h
@@ -251,8 +251,19 @@ lock_table_names(THD *thd, TABLE_LIST *table_list,
table_list_end, lock_wait_timeout, flags);
}
bool open_tables(THD *thd, const DDL_options_st &options,
- TABLE_LIST **tables, uint *counter, uint flags,
+ TABLE_LIST **tables, uint *counter,
+ Sroutine_hash_entry **sroutine_to_open, uint flags,
Prelocking_strategy *prelocking_strategy);
+
+static inline bool
+open_tables(THD *thd, const DDL_options_st &options, TABLE_LIST **tables,
+ uint *counter, uint flags, Prelocking_strategy *prelocking_strategy)
+{
+ return open_tables(thd, options, tables, counter,
+ &thd->lex->sroutines_list.first, flags,
+ prelocking_strategy);
+}
+
static inline bool
open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags,
Prelocking_strategy *prelocking_strategy)
@@ -547,6 +558,10 @@ inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
bool restart_trans_for_tables(THD *thd, TABLE_LIST *table);
+bool extend_table_list(THD *thd, TABLE_LIST *tables,
+ Prelocking_strategy *prelocking_strategy,
+ bool has_prelocking_list);
+
/**
A context of open_tables() function, used to recover
from a failed open_table() or open_routine() attempt.
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 0142f812632..845e1242eb7 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -543,7 +543,7 @@ public:
List<Index_hint> *hints= 0,
List<String> *partition_names= 0,
LEX_STRING *option= 0);
- virtual void set_lock_for_tables(thr_lock_type lock_type) {}
+ virtual void set_lock_for_tables(thr_lock_type lock_type, bool for_update) {}
friend class st_select_lex_unit;
friend bool mysql_new_select(LEX *lex, bool move_down);
@@ -963,7 +963,7 @@ public:
TABLE_LIST *convert_right_join();
List<Item>* get_item_list();
ulong get_table_join_options();
- void set_lock_for_tables(thr_lock_type lock_type);
+ void set_lock_for_tables(thr_lock_type lock_type, bool for_update);
inline void init_order()
{
order_list.elements= 0;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 6649c60f827..3f9d9190d76 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2629,9 +2629,6 @@ mysql_execute_command(THD *thd)
my_message(ER_SLAVE_IGNORED_TABLE, ER_THD(thd, ER_SLAVE_IGNORED_TABLE),
MYF(0));
}
-
- for (table=all_tables; table; table=table->next_global)
- table->updating= TRUE;
}
/*
@@ -8002,9 +7999,8 @@ TABLE_LIST *st_select_lex::convert_right_join()
query
*/
-void st_select_lex::set_lock_for_tables(thr_lock_type lock_type)
+void st_select_lex::set_lock_for_tables(thr_lock_type lock_type, bool for_update)
{
- bool for_update= lock_type >= TL_READ_NO_INSERT;
DBUG_ENTER("set_lock_for_tables");
DBUG_PRINT("enter", ("lock_type: %d for_update: %d", lock_type,
for_update));
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 46914ea14c4..7f0c50a2e55 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -7949,8 +7949,6 @@ int mysql_schema_table(THD *thd, LEX *lex, TABLE_LIST *table_list)
table->alias_name_used= my_strcasecmp(table_alias_charset,
table_list->schema_table_name,
table_list->alias);
- table_list->table_name= table->s->table_name.str;
- table_list->table_name_length= table->s->table_name.length;
table_list->table= table;
table->next= thd->derived_tables;
thd->derived_tables= table;
diff --git a/sql/sql_truncate.cc b/sql/sql_truncate.cc
index 57cb6df55ca..6252caf98b0 100644
--- a/sql/sql_truncate.cc
+++ b/sql/sql_truncate.cc
@@ -150,15 +150,11 @@ fk_truncate_illegal_if_parent(THD *thd, TABLE *table)
/* Loop over the set of foreign keys for which this table is a parent. */
while ((fk_info= it++))
{
- DBUG_ASSERT(!my_strcasecmp(system_charset_info,
- fk_info->referenced_db->str,
- table->s->db.str));
-
- DBUG_ASSERT(!my_strcasecmp(system_charset_info,
- fk_info->referenced_table->str,
- table->s->table_name.str));
-
- if (my_strcasecmp(system_charset_info, fk_info->foreign_db->str,
+ if (my_strcasecmp(system_charset_info, fk_info->referenced_db->str,
+ table->s->db.str) ||
+ my_strcasecmp(system_charset_info, fk_info->referenced_table->str,
+ table->s->table_name.str) ||
+ my_strcasecmp(system_charset_info, fk_info->foreign_db->str,
table->s->db.str) ||
my_strcasecmp(system_charset_info, fk_info->foreign_table->str,
table->s->table_name.str))
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 78aa059f64f..721e1ed908c 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -1384,6 +1384,9 @@ int mysql_multi_update_prepare(THD *thd)
List<Item> *fields= &lex->select_lex.item_list;
table_map tables_for_update;
bool update_view= 0;
+ DML_prelocking_strategy prelocking_strategy;
+ bool has_prelocking_list= thd->lex->requires_prelocking();
+
/*
if this multi-update was converted from usual update, here is table
counter else junk will be assigned here, but then replaced with real
@@ -1404,10 +1407,10 @@ int mysql_multi_update_prepare(THD *thd)
keep prepare of multi-UPDATE compatible with concurrent LOCK TABLES WRITE
and global read lock.
*/
- if ((original_multiupdate &&
- open_tables(thd, &table_list, &table_count,
- (thd->stmt_arena->is_stmt_prepare() ?
- MYSQL_OPEN_FORCE_SHARED_MDL : 0))) ||
+ if ((original_multiupdate && open_tables(thd, &table_list, &table_count,
+ thd->stmt_arena->is_stmt_prepare()
+ ? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
+ &prelocking_strategy)) ||
mysql_handle_derived(lex, DT_INIT))
DBUG_RETURN(TRUE);
/*
@@ -1454,6 +1457,9 @@ int mysql_multi_update_prepare(THD *thd)
if (unsafe_key_update(lex->select_lex.leaf_tables, tables_for_update))
DBUG_RETURN(true);
+ TABLE_LIST **new_tables= lex->query_tables_last;
+ DBUG_ASSERT(*new_tables== NULL);
+
/*
Setup timestamp handling and locking mode
*/
@@ -1479,6 +1485,11 @@ int mysql_multi_update_prepare(THD *thd)
If table will be updated we should not downgrade lock for it and
leave it as is.
*/
+ tl->updating= 1;
+ if (tl->belong_to_view)
+ tl->belong_to_view->updating= 1;
+ if (extend_table_list(thd, tl, &prelocking_strategy, has_prelocking_list))
+ DBUG_RETURN(TRUE);
}
else
{
@@ -1501,7 +1512,6 @@ int mysql_multi_update_prepare(THD *thd)
tl->lock_type= lock_type;
else
tl->set_lock_type(thd, lock_type);
- tl->updating= 0;
}
}
@@ -1510,6 +1520,20 @@ int mysql_multi_update_prepare(THD *thd)
Note that unlike in the above loop we need to iterate here not only
through all leaf tables but also through all view hierarchy.
*/
+
+ uint addon_table_count= 0;
+ if (*new_tables)
+ {
+ Sroutine_hash_entry **new_routines= thd->lex->sroutines_list.next;
+ DBUG_ASSERT(*new_routines == NULL);
+ if (open_tables(thd, thd->lex->create_info, new_tables,
+ &addon_table_count, new_routines,
+ thd->stmt_arena->is_stmt_prepare()
+ ? MYSQL_OPEN_FORCE_SHARED_MDL : 0,
+ &prelocking_strategy))
+ DBUG_RETURN(TRUE);
+ }
+
for (tl= table_list; tl; tl= tl->next_local)
{
bool not_used= false;
@@ -1538,7 +1562,7 @@ int mysql_multi_update_prepare(THD *thd)
/* now lock and fill tables */
if (!thd->stmt_arena->is_stmt_prepare() &&
- lock_tables(thd, table_list, table_count, 0))
+ lock_tables(thd, table_list, table_count + addon_table_count, 0))
{
DBUG_RETURN(TRUE);
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 4d7c3de9337..cef20ba08f9 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -435,7 +435,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
*/
if (lex->current_select->lock_type != TL_READ_DEFAULT)
{
- lex->current_select->set_lock_for_tables(TL_READ_DEFAULT);
+ lex->current_select->set_lock_for_tables(TL_READ_DEFAULT, false);
view->mdl_request.set_type(MDL_EXCLUSIVE);
}
@@ -1528,6 +1528,7 @@ bool mysql_make_view(THD *thd, TABLE_SHARE *share, TABLE_LIST *table,
{
tbl->lock_type= table->lock_type;
tbl->mdl_request.set_type(table->mdl_request.type);
+ tbl->updating= table->updating;
}
/*
If the view is mergeable, we might want to
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 5111f0690ab..ca30bc202cf 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -8399,7 +8399,7 @@ opt_select_lock_type:
{
LEX *lex=Lex;
lex->current_select->lock_type= TL_WRITE;
- lex->current_select->set_lock_for_tables(TL_WRITE);
+ lex->current_select->set_lock_for_tables(TL_WRITE, false);
lex->safe_to_cache_query=0;
}
| LOCK_SYM IN_SYM SHARE_SYM MODE_SYM
@@ -8407,7 +8407,7 @@ opt_select_lock_type:
LEX *lex=Lex;
lex->current_select->lock_type= TL_READ_WITH_SHARED_LOCKS;
lex->current_select->
- set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS);
+ set_lock_for_tables(TL_READ_WITH_SHARED_LOCKS, false);
lex->safe_to_cache_query=0;
}
;
@@ -11781,7 +11781,7 @@ insert:
insert_lock_option
opt_ignore insert2
{
- Select->set_lock_for_tables($3);
+ Select->set_lock_for_tables($3, true);
Lex->current_select= &Lex->select_lex;
}
insert_field_spec opt_insert_update
@@ -11798,7 +11798,7 @@ replace:
}
replace_lock_option insert2
{
- Select->set_lock_for_tables($3);
+ Select->set_lock_for_tables($3, true);
Lex->current_select= &Lex->select_lex;
}
insert_field_spec
@@ -11975,14 +11975,14 @@ update:
opt_low_priority opt_ignore join_table_list
SET update_list
{
- LEX *lex= Lex;
- if (lex->select_lex.table_list.elements > 1)
- lex->sql_command= SQLCOM_UPDATE_MULTI;
- else if (lex->select_lex.get_table_list()->derived)
+ SELECT_LEX *slex= &Lex->select_lex;
+ if (slex->table_list.elements > 1)
+ Lex->sql_command= SQLCOM_UPDATE_MULTI;
+ else if (slex->get_table_list()->derived)
{
/* it is single table update and it is update of derived table */
my_error(ER_NON_UPDATABLE_TABLE, MYF(0),
- lex->select_lex.get_table_list()->alias, "UPDATE");
+ slex->get_table_list()->alias, "UPDATE");
MYSQL_YYABORT;
}
/*
@@ -11990,7 +11990,7 @@ update:
be too pessimistic. We will decrease lock level if possible in
mysql_multi_update().
*/
- Select->set_lock_for_tables($3);
+ slex->set_lock_for_tables($3, slex->table_list.elements == 1);
}
opt_where_clause opt_order_clause delete_limit_clause {}
;
@@ -14851,13 +14851,16 @@ table_lock:
table_ident opt_table_alias lock_option
{
thr_lock_type lock_type= (thr_lock_type) $3;
- bool lock_for_write= (lock_type >= TL_WRITE_ALLOW_WRITE);
- if (!Select->add_table_to_list(thd, $1, $2, 0, lock_type,
- (lock_for_write ?
- lock_type == TL_WRITE_CONCURRENT_INSERT ?
- MDL_SHARED_WRITE :
- MDL_SHARED_NO_READ_WRITE :
- MDL_SHARED_READ)))
+ bool lock_for_write= lock_type >= TL_WRITE_ALLOW_WRITE;
+ ulong table_options= lock_for_write ? TL_OPTION_UPDATING : 0;
+ enum_mdl_type mdl_type= !lock_for_write
+ ? MDL_SHARED_READ
+ : lock_type == TL_WRITE_CONCURRENT_INSERT
+ ? MDL_SHARED_WRITE
+ : MDL_SHARED_NO_READ_WRITE;
+
+ if (!Select->add_table_to_list(thd, $1, $2, table_options,
+ lock_type, mdl_type))
MYSQL_YYABORT;
}
;
diff --git a/sql/table.cc b/sql/table.cc
index 31f0d255847..8373f6735dc 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -5553,7 +5553,8 @@ const char *Field_iterator_table_ref::get_table_name()
return natural_join_it.column_ref()->table_name();
DBUG_ASSERT(!strcmp(table_ref->table_name,
- table_ref->table->s->table_name.str));
+ table_ref->table->s->table_name.str) ||
+ table_ref->schema_table);
return table_ref->table_name;
}
diff --git a/sql/table.h b/sql/table.h
index afe3220c943..e7d3c95713e 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1789,6 +1789,7 @@ struct TABLE_LIST
table_name_length= table_name_length_arg;
alias= (char*) (alias_arg ? alias_arg : table_name_arg);
lock_type= lock_type_arg;
+ updating= lock_type >= TL_WRITE_ALLOW_WRITE;
mdl_request.init(MDL_key::TABLE, db, table_name, mdl_type, MDL_TRANSACTION);
}