From 0541dcad3bd09dc616298d7cc18c5a8c9d1e7458 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Jan 2007 12:48:17 +0300 Subject: [PATCH 01/11] Bug#24404: strange bug with view+permission+prepared statement. The problem was that if a prepared statement accessed a view, the access to the tables listed in the query after that view was done in the security context of the view. The bug was in the assigning of the security context to the tables belonging to a view: we traversed the list of all query tables instead. It didn't show up in the normal (non-prepared) statements because of the different order of the steps of checking privileges and descending into a view for normal and prepared statements. The solution is to traverse the list and stop once the last table belonging to the view was processed. mysql-test/r/view_grant.result: Add result for bug#24404: strange bug with view+permission+prepared statement. mysql-test/t/view_grant.test: Add test case for bug#24404: strange bug with view+permission+prepared statement. sql/sql_view.cc: Remove dead line. When setting security context, we should traverse the list of tables belonging to a given view, not all query tables. We achieve that by stopping at the first table past view_tables_tail. --- mysql-test/r/view_grant.result | 43 ++++++++++++++++++++ mysql-test/t/view_grant.test | 72 +++++++++++++++++++++++++++++++++- sql/sql_view.cc | 10 +++-- 3 files changed, 121 insertions(+), 4 deletions(-) diff --git a/mysql-test/r/view_grant.result b/mysql-test/r/view_grant.result index 35e7afc0a7b..bdb362a5112 100644 --- a/mysql-test/r/view_grant.result +++ b/mysql-test/r/view_grant.result @@ -712,3 +712,46 @@ DROP FUNCTION f1; DROP VIEW v2; DROP VIEW v1; DROP USER mysqltest_u1@localhost; +DROP DATABASE IF EXISTS mysqltest_db1; +DROP DATABASE IF EXISTS mysqltest_db2; +DROP USER mysqltest_u1; +DROP USER mysqltest_u2; +CREATE USER mysqltest_u1@localhost; +CREATE USER mysqltest_u2@localhost; +CREATE DATABASE mysqltest_db1; +CREATE DATABASE mysqltest_db2; +GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost WITH GRANT OPTION; +GRANT ALL ON mysqltest_db2.* TO mysqltest_u2@localhost; +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1); +CREATE VIEW v1 AS SELECT i FROM t1 WHERE 1 IN (SELECT * FROM t1); +CREATE TABLE t2 (s CHAR(7)); +INSERT INTO t2 VALUES ('public'); +GRANT SELECT ON v1 TO mysqltest_u2@localhost; +GRANT SELECT ON t2 TO mysqltest_u2@localhost; +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +i s +1 public +PREPARE stmt1 FROM "SELECT * FROM mysqltest_db1.t2"; +EXECUTE stmt1; +s +public +PREPARE stmt2 FROM "SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2"; +EXECUTE stmt2; +i s +1 public +REVOKE SELECT ON t2 FROM mysqltest_u2@localhost; +UPDATE t2 SET s = 'private' WHERE s = 'public'; +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' +EXECUTE stmt1; +ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' +EXECUTE stmt2; +ERROR 42000: SELECT command denied to user 'mysqltest_u2'@'localhost' for table 't2' +REVOKE ALL ON mysqltest_db1.* FROM mysqltest_u1@localhost; +REVOKE ALL ON mysqltest_db2.* FROM mysqltest_u2@localhost; +DROP DATABASE mysqltest_db1; +DROP DATABASE mysqltest_db2; +DROP USER mysqltest_u1@localhost; +DROP USER mysqltest_u2@localhost; +End of 5.0 tests. diff --git a/mysql-test/t/view_grant.test b/mysql-test/t/view_grant.test index 4a3a29e3afe..ea6dbeb0a4b 100644 --- a/mysql-test/t/view_grant.test +++ b/mysql-test/t/view_grant.test @@ -927,4 +927,74 @@ DROP VIEW v2; DROP VIEW v1; DROP USER mysqltest_u1@localhost; -# End of 5.0 tests. + +# +# BUG#24404: strange bug with view+permission+prepared statement +# +--disable_warnings +DROP DATABASE IF EXISTS mysqltest_db1; +DROP DATABASE IF EXISTS mysqltest_db2; +--enable_warnings +--error 0,ER_CANNOT_USER +DROP USER mysqltest_u1; +--error 0,ER_CANNOT_USER +DROP USER mysqltest_u2; + +CREATE USER mysqltest_u1@localhost; +CREATE USER mysqltest_u2@localhost; + +CREATE DATABASE mysqltest_db1; +CREATE DATABASE mysqltest_db2; + +GRANT ALL ON mysqltest_db1.* TO mysqltest_u1@localhost WITH GRANT OPTION; +GRANT ALL ON mysqltest_db2.* TO mysqltest_u2@localhost; + +connect (conn1, localhost, mysqltest_u1, , mysqltest_db1); + +CREATE TABLE t1 (i INT); +INSERT INTO t1 VALUES (1); + +# Use view with subquery for better coverage. +CREATE VIEW v1 AS SELECT i FROM t1 WHERE 1 IN (SELECT * FROM t1); + +CREATE TABLE t2 (s CHAR(7)); +INSERT INTO t2 VALUES ('public'); + +GRANT SELECT ON v1 TO mysqltest_u2@localhost; +GRANT SELECT ON t2 TO mysqltest_u2@localhost; + +connect (conn2, localhost, mysqltest_u2, , mysqltest_db2); + +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +PREPARE stmt1 FROM "SELECT * FROM mysqltest_db1.t2"; +EXECUTE stmt1; +PREPARE stmt2 FROM "SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2"; +EXECUTE stmt2; + +connection conn1; +# Make table 't2' private. +REVOKE SELECT ON t2 FROM mysqltest_u2@localhost; +UPDATE t2 SET s = 'private' WHERE s = 'public'; + +connection conn2; +--error ER_TABLEACCESS_DENIED_ERROR +SELECT * FROM mysqltest_db1.v1, mysqltest_db1.t2; +--error ER_TABLEACCESS_DENIED_ERROR +EXECUTE stmt1; +# Original bug was here: the statement didn't fail. +--error ER_TABLEACCESS_DENIED_ERROR +EXECUTE stmt2; + +# Cleanup. +disconnect conn2; +disconnect conn1; +connection default; +REVOKE ALL ON mysqltest_db1.* FROM mysqltest_u1@localhost; +REVOKE ALL ON mysqltest_db2.* FROM mysqltest_u2@localhost; +DROP DATABASE mysqltest_db1; +DROP DATABASE mysqltest_db2; +DROP USER mysqltest_u1@localhost; +DROP USER mysqltest_u2@localhost; + + +--echo End of 5.0 tests. diff --git a/sql/sql_view.cc b/sql/sql_view.cc index c0cdaf59712..8cb7ea9cd81 100644 --- a/sql/sql_view.cc +++ b/sql/sql_view.cc @@ -1136,13 +1136,17 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table, /* Prepare a security context to check underlying objects of the view */ - Security_context *save_security_ctx= thd->security_ctx; if (!(table->view_sctx= (Security_context *) thd->stmt_arena->alloc(sizeof(Security_context)))) goto err; /* Assign the context to the tables referenced in the view */ - for (tbl= view_tables; tbl; tbl= tbl->next_global) - tbl->security_ctx= table->view_sctx; + if (view_tables) + { + DBUG_ASSERT(view_tables_tail); + for (tbl= view_tables; tbl != view_tables_tail->next_global; + tbl= tbl->next_global) + tbl->security_ctx= table->view_sctx; + } /* assign security context to SELECT name resolution contexts of view */ for(SELECT_LEX *sl= lex->all_selects_list; sl; From d4ee8cebf369b0003819f63854063ff7e6161236 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Jan 2007 16:53:49 -0700 Subject: [PATCH 02/11] Bug#24562 (ALTER TABLE ... ORDER BY ... with complex expression asserts) WL#3681 (ALTER TABLE ORDER BY) Before this fix, the ALTER TABLE statement implemented an ORDER BY option with the following characteristics : 1) The order by clause accepts a list of criteria, with optional ASC or DESC keywords 2) Each criteria can be a general expression, involving operators, native functions, stored functions, user defined functions, subselects ... With this fix : 1) has been left unchanged, since it's a de-facto existing feature, that was already present in the code base and partially covered in the test suite. Code coverage for ASC and DESC was missing and has been improved. 2) has been changed to limit the kind of criteria that are permissible: now only a column name is valid. mysql-test/r/alter_table.result: Prevent ALTER TABLE ORDER BY clauses to use general expressions. mysql-test/t/alter_table.test: Prevent ALTER TABLE ORDER BY clauses to use general expressions. sql/sql_yacc.yy: Prevent ALTER TABLE ORDER BY clauses to use general expressions. --- mysql-test/r/alter_table.result | 113 ++++++++++++++++++++++++++++++++ mysql-test/t/alter_table.test | 66 +++++++++++++++++++ sql/sql_yacc.yy | 25 ++++++- 3 files changed, 203 insertions(+), 1 deletion(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 60830cd9c45..da5cf688325 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -690,3 +690,116 @@ SHOW INDEX FROM bug24219_2; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment bug24219_2 1 a 1 a A NULL NULL NULL YES BTREE disabled DROP TABLE bug24219_2; +drop table if exists table_24562; +create table table_24562( +section int, +subsection int, +title varchar(50)); +insert into table_24562 values +(1, 0, "Introduction"), +(1, 1, "Authors"), +(1, 2, "Acknowledgements"), +(2, 0, "Basics"), +(2, 1, "Syntax"), +(2, 2, "Client"), +(2, 3, "Server"), +(3, 0, "Intermediate"), +(3, 1, "Complex queries"), +(3, 2, "Stored Procedures"), +(3, 3, "Stored Functions"), +(4, 0, "Advanced"), +(4, 1, "Replication"), +(4, 2, "Load balancing"), +(4, 3, "High availability"), +(5, 0, "Conclusion"); +select * from table_24562; +section subsection title +1 0 Introduction +1 1 Authors +1 2 Acknowledgements +2 0 Basics +2 1 Syntax +2 2 Client +2 3 Server +3 0 Intermediate +3 1 Complex queries +3 2 Stored Procedures +3 3 Stored Functions +4 0 Advanced +4 1 Replication +4 2 Load balancing +4 3 High availability +5 0 Conclusion +alter table table_24562 add column reviewer varchar(20), +order by title; +select * from table_24562; +section subsection title reviewer +1 2 Acknowledgements NULL +4 0 Advanced NULL +1 1 Authors NULL +2 0 Basics NULL +2 2 Client NULL +3 1 Complex queries NULL +5 0 Conclusion NULL +4 3 High availability NULL +3 0 Intermediate NULL +1 0 Introduction NULL +4 2 Load balancing NULL +4 1 Replication NULL +2 3 Server NULL +3 3 Stored Functions NULL +3 2 Stored Procedures NULL +2 1 Syntax NULL +update table_24562 set reviewer="Me" where section=2; +update table_24562 set reviewer="You" where section=3; +alter table table_24562 +order by section ASC, subsection DESC; +select * from table_24562; +section subsection title reviewer +1 2 Acknowledgements NULL +1 1 Authors NULL +1 0 Introduction NULL +2 3 Server Me +2 2 Client Me +2 1 Syntax Me +2 0 Basics Me +3 3 Stored Functions You +3 2 Stored Procedures You +3 1 Complex queries You +3 0 Intermediate You +4 3 High availability NULL +4 2 Load balancing NULL +4 1 Replication NULL +4 0 Advanced NULL +5 0 Conclusion NULL +alter table table_24562 +order by table_24562.subsection ASC, table_24562.section DESC; +select * from table_24562; +section subsection title reviewer +5 0 Conclusion NULL +4 0 Advanced NULL +3 0 Intermediate You +2 0 Basics Me +1 0 Introduction NULL +4 1 Replication NULL +3 1 Complex queries You +2 1 Syntax Me +1 1 Authors NULL +4 2 Load balancing NULL +3 2 Stored Procedures You +2 2 Client Me +1 2 Acknowledgements NULL +4 3 High availability NULL +3 3 Stored Functions You +2 3 Server Me +alter table table_24562 order by 12; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '12' at line 1 +alter table table_24562 order by (section + 12); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(section + 12)' at line 1 +alter table table_24562 order by length(title); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'length(title)' at line 1 +alter table table_24562 order by (select 12 from dual); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(select 12 from dual)' at line 1 +alter table table_24562 order by no_such_col; +ERROR 42S22: Unknown column 'no_such_col' in 'order clause' +drop table table_24562; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 3e1e7952af1..52a569dfb57 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -518,4 +518,70 @@ SHOW INDEX FROM bug24219_2; DROP TABLE bug24219_2; +# +# Bug#24562 (ALTER TABLE ... ORDER BY ... with complex expression asserts) +# + +--disable_warnings +drop table if exists table_24562; +--enable_warnings + +create table table_24562( + section int, + subsection int, + title varchar(50)); + +insert into table_24562 values +(1, 0, "Introduction"), +(1, 1, "Authors"), +(1, 2, "Acknowledgements"), +(2, 0, "Basics"), +(2, 1, "Syntax"), +(2, 2, "Client"), +(2, 3, "Server"), +(3, 0, "Intermediate"), +(3, 1, "Complex queries"), +(3, 2, "Stored Procedures"), +(3, 3, "Stored Functions"), +(4, 0, "Advanced"), +(4, 1, "Replication"), +(4, 2, "Load balancing"), +(4, 3, "High availability"), +(5, 0, "Conclusion"); + +select * from table_24562; + +alter table table_24562 add column reviewer varchar(20), +order by title; + +select * from table_24562; + +update table_24562 set reviewer="Me" where section=2; +update table_24562 set reviewer="You" where section=3; + +alter table table_24562 +order by section ASC, subsection DESC; + +select * from table_24562; + +alter table table_24562 +order by table_24562.subsection ASC, table_24562.section DESC; + +select * from table_24562; + +--error 1064 +alter table table_24562 order by 12; +--error 1064 +alter table table_24562 order by (section + 12); +--error 1064 +alter table table_24562 order by length(title); +--error 1064 +alter table table_24562 order by (select 12 from dual); + +--error 1054 +alter table table_24562 order by no_such_col; + +drop table table_24562; + # End of 4.1 tests + diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 30283a47b21..ee57a4d611c 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2021,7 +2021,7 @@ alter_list_item: lex->alter_info.is_simple= 0; lex->alter_info.flags|= ALTER_OPTIONS; } - | order_clause + | alter_order_clause { LEX *lex=Lex; lex->alter_info.is_simple= 0; @@ -3780,6 +3780,29 @@ olap_opt: } ; +/* + Order by statement in ALTER TABLE +*/ + +alter_order_clause: + ORDER_SYM BY alter_order_list + ; + +alter_order_list: + alter_order_list ',' alter_order_item + | alter_order_item + ; + +alter_order_item: + simple_ident order_dir + { + THD *thd= YYTHD; + bool ascending= ($2 == 1) ? true : false; + if (add_order_to_list(thd, $1, ascending)) + YYABORT; + } + ; + /* Order by statement in select */ From 6c6a2785e9538363bba4d0eec1b1ad1c86c02cd0 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Jan 2007 18:37:52 -0700 Subject: [PATCH 03/11] Manual merge --- mysql-test/r/alter_table.result | 113 ++++++++++++++++++++++++++++++++ mysql-test/t/alter_table.test | 10 +-- sql/sql_yacc.yy | 25 ++++++- 3 files changed, 142 insertions(+), 6 deletions(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 80ad50b886f..d8de2655c6c 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -703,6 +703,119 @@ SHOW INDEX FROM bug24219_2; Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment bug24219_2 1 a 1 a A NULL NULL NULL YES BTREE disabled DROP TABLE bug24219_2; +drop table if exists table_24562; +create table table_24562( +section int, +subsection int, +title varchar(50)); +insert into table_24562 values +(1, 0, "Introduction"), +(1, 1, "Authors"), +(1, 2, "Acknowledgements"), +(2, 0, "Basics"), +(2, 1, "Syntax"), +(2, 2, "Client"), +(2, 3, "Server"), +(3, 0, "Intermediate"), +(3, 1, "Complex queries"), +(3, 2, "Stored Procedures"), +(3, 3, "Stored Functions"), +(4, 0, "Advanced"), +(4, 1, "Replication"), +(4, 2, "Load balancing"), +(4, 3, "High availability"), +(5, 0, "Conclusion"); +select * from table_24562; +section subsection title +1 0 Introduction +1 1 Authors +1 2 Acknowledgements +2 0 Basics +2 1 Syntax +2 2 Client +2 3 Server +3 0 Intermediate +3 1 Complex queries +3 2 Stored Procedures +3 3 Stored Functions +4 0 Advanced +4 1 Replication +4 2 Load balancing +4 3 High availability +5 0 Conclusion +alter table table_24562 add column reviewer varchar(20), +order by title; +select * from table_24562; +section subsection title reviewer +1 2 Acknowledgements NULL +4 0 Advanced NULL +1 1 Authors NULL +2 0 Basics NULL +2 2 Client NULL +3 1 Complex queries NULL +5 0 Conclusion NULL +4 3 High availability NULL +3 0 Intermediate NULL +1 0 Introduction NULL +4 2 Load balancing NULL +4 1 Replication NULL +2 3 Server NULL +3 3 Stored Functions NULL +3 2 Stored Procedures NULL +2 1 Syntax NULL +update table_24562 set reviewer="Me" where section=2; +update table_24562 set reviewer="You" where section=3; +alter table table_24562 +order by section ASC, subsection DESC; +select * from table_24562; +section subsection title reviewer +1 2 Acknowledgements NULL +1 1 Authors NULL +1 0 Introduction NULL +2 3 Server Me +2 2 Client Me +2 1 Syntax Me +2 0 Basics Me +3 3 Stored Functions You +3 2 Stored Procedures You +3 1 Complex queries You +3 0 Intermediate You +4 3 High availability NULL +4 2 Load balancing NULL +4 1 Replication NULL +4 0 Advanced NULL +5 0 Conclusion NULL +alter table table_24562 +order by table_24562.subsection ASC, table_24562.section DESC; +select * from table_24562; +section subsection title reviewer +5 0 Conclusion NULL +4 0 Advanced NULL +3 0 Intermediate You +2 0 Basics Me +1 0 Introduction NULL +4 1 Replication NULL +3 1 Complex queries You +2 1 Syntax Me +1 1 Authors NULL +4 2 Load balancing NULL +3 2 Stored Procedures You +2 2 Client Me +1 2 Acknowledgements NULL +4 3 High availability NULL +3 3 Stored Functions You +2 3 Server Me +alter table table_24562 order by 12; +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '12' at line 1 +alter table table_24562 order by (section + 12); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(section + 12)' at line 1 +alter table table_24562 order by length(title); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'length(title)' at line 1 +alter table table_24562 order by (select 12 from dual); +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(select 12 from dual)' at line 1 +alter table table_24562 order by no_such_col; +ERROR 42S22: Unknown column 'no_such_col' in 'order clause' +drop table table_24562; create table t1 (mycol int(10) not null); alter table t1 alter column mycol set default 0; desc t1; diff --git a/mysql-test/t/alter_table.test b/mysql-test/t/alter_table.test index 68f984c65e1..01f55931ca4 100644 --- a/mysql-test/t/alter_table.test +++ b/mysql-test/t/alter_table.test @@ -579,16 +579,16 @@ order by table_24562.subsection ASC, table_24562.section DESC; select * from table_24562; ---error 1064 +--error ER_PARSE_ERROR alter table table_24562 order by 12; ---error 1064 +--error ER_PARSE_ERROR alter table table_24562 order by (section + 12); ---error 1064 +--error ER_PARSE_ERROR alter table table_24562 order by length(title); ---error 1064 +--error ER_PARSE_ERROR alter table table_24562 order by (select 12 from dual); ---error 1054 +--error ER_BAD_FIELD_ERROR alter table table_24562 order by no_such_col; drop table table_24562; diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 92640ea58d6..0f29c3e1028 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -3722,7 +3722,7 @@ alter_list_item: { Lex->alter_info.flags|= ALTER_FORCE; } - | order_clause + | alter_order_clause { LEX *lex=Lex; lex->alter_info.flags|= ALTER_ORDER; @@ -5942,6 +5942,29 @@ olap_opt: } ; +/* + Order by statement in ALTER TABLE +*/ + +alter_order_clause: + ORDER_SYM BY alter_order_list + ; + +alter_order_list: + alter_order_list ',' alter_order_item + | alter_order_item + ; + +alter_order_item: + simple_ident_nospvar order_dir + { + THD *thd= YYTHD; + bool ascending= ($2 == 1) ? true : false; + if (add_order_to_list(thd, $1, ascending)) + YYABORT; + } + ; + /* Order by statement in select */ From 898740b6551e06c0670d018ba19de13d5134e34f Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 18 Jan 2007 21:30:25 -0700 Subject: [PATCH 04/11] Manual merge --- mysql-test/r/alter_table.result | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/r/alter_table.result b/mysql-test/r/alter_table.result index 16a20df0ad5..571ac8498b3 100644 --- a/mysql-test/r/alter_table.result +++ b/mysql-test/r/alter_table.result @@ -810,7 +810,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp alter table table_24562 order by (section + 12); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(section + 12)' at line 1 alter table table_24562 order by length(title); -ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'length(title)' at line 1 +ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(title)' at line 1 alter table table_24562 order by (select 12 from dual); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(select 12 from dual)' at line 1 alter table table_24562 order by no_such_col; From 35fdeff81f3c44609bf43899703ae47c6459605d Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 19 Jan 2007 18:33:48 +0300 Subject: [PATCH 05/11] BUG#25211: events_bugs.test fails on sapsrv1 The problem was that the events_bugs test could randomly fail due to races in the test case. The solution is to replace fixed sleeps with reliable polling of a certain state to settle. For that, a new auxiliary script include/wait_condition.inc is used, that allows waiting for a given query to return true. mysql-test/include/wait_until_rows_count.inc: Script is rewritten using new include/wait_condition.inc. mysql-test/r/events_bugs.result: Update result: add missing quotation mark. mysql-test/t/events_bugs.test: Replace --sleep with the reliable waiting for a certain state. mysql-test/include/wait_condition.inc: New BitKeeper file ``mysql-test/include/wait_condition.inc'' --- mysql-test/include/wait_condition.inc | 39 ++++++++ mysql-test/include/wait_until_rows_count.inc | 50 ++-------- mysql-test/r/events_bugs.result | 87 ++++++++++++++--- mysql-test/t/events_bugs.test | 99 +++++++++++++++++--- 4 files changed, 205 insertions(+), 70 deletions(-) create mode 100644 mysql-test/include/wait_condition.inc diff --git a/mysql-test/include/wait_condition.inc b/mysql-test/include/wait_condition.inc new file mode 100644 index 00000000000..cd80b58d44e --- /dev/null +++ b/mysql-test/include/wait_condition.inc @@ -0,0 +1,39 @@ +# include/wait_condition.inc +# +# SUMMARY +# +# Waits until the passed statement returns true, or the operation +# times out. +# +# USAGE +# +# let $wait_condition= +# SELECT c = 3 FROM t; +# --source include/wait_condition.inc +# +# EXAMPLE +# events_bugs.test +# + +--disable_query_log + +let $wait_counter= 300; +while ($wait_counter) +{ + let $success= `$wait_condition`; + if ($success) + { + let $wait_counter= 0; + } + if (!$success) + { + real_sleep 0.1; + dec $wait_counter; + } +} +if (!$success) +{ + echo Timeout in wait_condition.inc for $wait_condition; +} + +--enable_query_log diff --git a/mysql-test/include/wait_until_rows_count.inc b/mysql-test/include/wait_until_rows_count.inc index cf2a21d335a..f1b79c54424 100644 --- a/mysql-test/include/wait_until_rows_count.inc +++ b/mysql-test/include/wait_until_rows_count.inc @@ -1,52 +1,20 @@ # include/wait_until_rows_count.inc -# inspired by wait_for_slave_status by Matthias Leich # # SUMMARY # -# Waits until SELECT count(*)-$count from $table returns zero +# Waits until SELECT count(*) = $count from $table returns true, or +# the operation times out. # # USAGE # -# Set vars like -# let $count=11; -# let $table=t1; -# # invoke the macro -# --include wait_until_rows_count.inc +# let $count= 5; +# let $table= t1; +# --source include/wait_until_rows_count.inc # # EXAMPLE -# extra/binlog/binlog_insert_delayed.test +# extra/binlog/binlog_insert_delayed.test # -# -# TODO: generalize up to wait_[until|while] with arbitrary select or even query and -# a condition to wait or get awakened -# It's impossible to implement such a "most" general macro without -# extending mysqltest. Just no way to pass a query as an argument and -# evaluate it here, like eval "$quuery". One is bound -# to specify it inside of the macro ---disable_query_log - -let $wait_counter= 300; # max wait in 0.1 seconds -while ($wait_counter) -{ - eval select count(*)-$count from $table into @rez; - let $rez=`select @rez`; - let $success=`SELECT @rez = 0`; - let $no_success=1; - if ($success) - { - let $wait_counter= 1; # droppping counter to leave loop - let $no_success=0; - } - if ($no_success) - { - --sleep 0.1 - } - dec $wait_counter; -} - ---enable_query_log -if ($no_success) -{ - --die Timeout in wait_until_rows_count.inc, required table never had a prescribed number of rows. -} +let $wait_condition= + select count(*) = $count from $table; +--source include/wait_condition.inc diff --git a/mysql-test/r/events_bugs.result b/mysql-test/r/events_bugs.result index 363033e487a..44b930e0705 100644 --- a/mysql-test/r/events_bugs.result +++ b/mysql-test/r/events_bugs.result @@ -49,7 +49,7 @@ begin select get_lock('test_bug16407', 60); drop table "hashed_num"; end| -"Now if everything is fine the event has compiled and is locked +"Now if everything is fine the event has compiled and is locked" select /*1*/ user, host, db, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info; user host db info root localhost events_test select get_lock('test_bug16407', 60) @@ -239,26 +239,83 @@ insert into t1 values (2); create table t2 (a char(20)); insert into t2 values ("e22830_1"); create function f22830 () returns int return 5; -create event e22830 on schedule every f22830() second do select 123; +select get_lock('ee_22830', 60); +get_lock('ee_22830', 60) +1 +set global event_scheduler=on; +create procedure p22830_wait() +begin +select get_lock('ee_22830', 60); +select release_lock('ee_22830'); +end| +create event e22830 on schedule every f22830() second do +begin +call p22830_wait(); +select 123; +end| ERROR 42000: This version of MySQL doesn't yet support 'Usage of subqueries or stored function calls as part of this statement' -create event e22830_1 on schedule every 1 hour do alter event e22830_1 on schedule every (select 8 from dual) hour; -create event e22830_2 on schedule every 1 hour do alter event e22830_2 on schedule every (select 8 from t1) hour; -create event e22830_3 on schedule every 1 hour do alter event e22830_3 on schedule every f22830() hour; -create event e22830_4 on schedule every 1 hour do alter event e22830_4 on schedule every (select f22830() from dual) hour; +create event e22830_1 on schedule every 1 hour do +begin +call p22830_wait(); +alter event e22830_1 on schedule every (select 8 from dual) hour; +end| +create event e22830_2 on schedule every 1 hour do +begin +call p22830_wait(); +alter event e22830_2 on schedule every (select 8 from t1) hour; +end| +create event e22830_3 on schedule every 1 hour do +begin +call p22830_wait(); +alter event e22830_3 on schedule every f22830() hour; +end| +create event e22830_4 on schedule every 1 hour do +begin +call p22830_wait(); +alter event e22830_4 on schedule every (select f22830() from dual) hour; +end| +"All events should be blocked in get_lock()" select event_name, event_definition, interval_value, interval_field from information_schema.events order by event_name; event_name event_definition interval_value interval_field -e22830_1 alter event e22830_1 on schedule every (select 8 from dual) hour 1 HOUR -e22830_2 alter event e22830_2 on schedule every (select 8 from t1) hour 1 HOUR -e22830_3 alter event e22830_3 on schedule every f22830() hour 1 HOUR -e22830_4 alter event e22830_4 on schedule every (select f22830() from dual) hour 1 HOUR -set global event_scheduler=on; +e22830_1 begin +call p22830_wait(); +alter event e22830_1 on schedule every (select 8 from dual) hour; +end 1 HOUR +e22830_2 begin +call p22830_wait(); +alter event e22830_2 on schedule every (select 8 from t1) hour; +end 1 HOUR +e22830_3 begin +call p22830_wait(); +alter event e22830_3 on schedule every f22830() hour; +end 1 HOUR +e22830_4 begin +call p22830_wait(); +alter event e22830_4 on schedule every (select f22830() from dual) hour; +end 1 HOUR +select release_lock('ee_22830'); +release_lock('ee_22830') +1 set global event_scheduler=off; select event_name, event_definition, interval_value, interval_field from information_schema.events order by event_name; event_name event_definition interval_value interval_field -e22830_1 alter event e22830_1 on schedule every (select 8 from dual) hour 8 HOUR -e22830_2 alter event e22830_2 on schedule every (select 8 from t1) hour 1 HOUR -e22830_3 alter event e22830_3 on schedule every f22830() hour 1 HOUR -e22830_4 alter event e22830_4 on schedule every (select f22830() from dual) hour 1 HOUR +e22830_1 begin +call p22830_wait(); +alter event e22830_1 on schedule every (select 8 from dual) hour; +end 8 HOUR +e22830_2 begin +call p22830_wait(); +alter event e22830_2 on schedule every (select 8 from t1) hour; +end 1 HOUR +e22830_3 begin +call p22830_wait(); +alter event e22830_3 on schedule every f22830() hour; +end 1 HOUR +e22830_4 begin +call p22830_wait(); +alter event e22830_4 on schedule every (select f22830() from dual) hour; +end 1 HOUR +drop procedure p22830_wait; drop function f22830; drop event (select a from t2); ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(select a from t2)' at line 1 diff --git a/mysql-test/t/events_bugs.test b/mysql-test/t/events_bugs.test index e9751608a46..26abf663ce1 100644 --- a/mysql-test/t/events_bugs.test +++ b/mysql-test/t/events_bugs.test @@ -78,8 +78,13 @@ begin drop table "hashed_num"; end| delimiter ;| ---sleep 0.8 ---echo "Now if everything is fine the event has compiled and is locked + +let $wait_condition= + select count(*) = 1 from information_schema.processlist + where info = 'select get_lock(\'test_bug16407\', 60)'; +--source include/wait_condition.inc + +--echo "Now if everything is fine the event has compiled and is locked" select /*1*/ user, host, db, info from information_schema.processlist where command!='Daemon' and (info is null or info not like '%processlist%') order by info; select release_lock('test_bug16407'); @@ -127,10 +132,22 @@ begin end| delimiter ;| select event_schema, event_name, sql_mode from information_schema.events order by event_schema, event_name; ---sleep 1 + +let $wait_condition= + select count(*) = 3 from information_schema.processlist + where info = 'select get_lock(\'ee_16407_2\', 60)'; +--source include/wait_condition.inc + select /*2*/ user, host, db, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; select release_lock('ee_16407_2'); ---sleep 1.2 + +let $wait_condition= + select count(*) = 1 and user = 'event_scheduler' and info is null + from information_schema.processlist + where (command!='Daemon' || user='event_scheduler') + and (info is null or info not like '%processlist%'); +--source include/wait_condition.inc + select /*3*/ user, host, db, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; set global event_scheduler= off; select * from events_smode_test order by ev_name, a; @@ -150,6 +167,7 @@ set global event_scheduler= on; set sql_mode='traditional'; delimiter |; +# ee_16407_5_pendant() should not insert anything because of invalid date. create procedure ee_16407_5_pendant() begin insert into events_test.events_smode_test values('ee_16407_5','2001-02-29'); end| create procedure ee_16407_6_pendant() begin insert into events_test.events_smode_test values('ee_16407_6','2004-02-29'); end| create event ee_16407_5 on schedule every 60 second do @@ -165,11 +183,23 @@ begin call events_test.ee_16407_6_pendant(); end| delimiter ;| ---sleep 1 + +let $wait_condition= + select count(*) = 2 from information_schema.processlist + where info = 'select get_lock(\'ee_16407_5\', 60)'; +--source include/wait_condition.inc + --echo "Should have 2 locked processes" select /*4*/ user, host, db, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; select release_lock('ee_16407_5'); ---sleep 1.3 + +let $wait_condition= + select count(*) = 1 and user = 'event_scheduler' and info is null + from information_schema.processlist + where (command!='Daemon' || user='event_scheduler') + and (info is null or info not like '%processlist%'); +--source include/wait_condition.inc + --echo "Should have 0 processes locked" select /*5*/ user, host, db, info from information_schema.processlist where (command!='Daemon' || user='event_scheduler') and (info is null or info not like '%processlist%') order by info; select * from events_smode_test order by ev_name, a; @@ -272,17 +302,58 @@ insert into t1 values (2); create table t2 (a char(20)); insert into t2 values ("e22830_1"); create function f22830 () returns int return 5; ---error ER_NOT_SUPPORTED_YET -create event e22830 on schedule every f22830() second do select 123; -create event e22830_1 on schedule every 1 hour do alter event e22830_1 on schedule every (select 8 from dual) hour; -create event e22830_2 on schedule every 1 hour do alter event e22830_2 on schedule every (select 8 from t1) hour; -create event e22830_3 on schedule every 1 hour do alter event e22830_3 on schedule every f22830() hour; -create event e22830_4 on schedule every 1 hour do alter event e22830_4 on schedule every (select f22830() from dual) hour; -select event_name, event_definition, interval_value, interval_field from information_schema.events order by event_name; + +select get_lock('ee_22830', 60); set global event_scheduler=on; ---sleep 4 + +delimiter |; +create procedure p22830_wait() +begin + select get_lock('ee_22830', 60); + select release_lock('ee_22830'); +end| + +--error ER_NOT_SUPPORTED_YET +create event e22830 on schedule every f22830() second do +begin + call p22830_wait(); + select 123; +end| +create event e22830_1 on schedule every 1 hour do +begin + call p22830_wait(); + alter event e22830_1 on schedule every (select 8 from dual) hour; +end| +create event e22830_2 on schedule every 1 hour do +begin + call p22830_wait(); + alter event e22830_2 on schedule every (select 8 from t1) hour; +end| +create event e22830_3 on schedule every 1 hour do +begin + call p22830_wait(); + alter event e22830_3 on schedule every f22830() hour; +end| +create event e22830_4 on schedule every 1 hour do +begin + call p22830_wait(); + alter event e22830_4 on schedule every (select f22830() from dual) hour; +end| +delimiter ;| + +--echo "All events should be blocked in get_lock()" +select event_name, event_definition, interval_value, interval_field from information_schema.events order by event_name; + +select release_lock('ee_22830'); + +let $wait_condition= + select group_concat(interval_value order by interval_value) = '1,1,1,8' + from information_schema.events; +--source include/wait_condition.inc + set global event_scheduler=off; select event_name, event_definition, interval_value, interval_field from information_schema.events order by event_name; +drop procedure p22830_wait; drop function f22830; --error ER_PARSE_ERROR drop event (select a from t2); From ac5e6f60a80e248227207d6c375ecf6b213e3046 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 19 Jan 2007 23:15:59 +0300 Subject: [PATCH 06/11] Fix for bug #25044 "ALTER TABLE ... ENABLE KEYS acquires global 'opening tables' lock." Execution of ALTER TABLE ... ENABLE KEYS on a table (which can take rather long time) prevented concurrent execution of all statements using tables. The problem was caused by the fact that we were holding LOCK_open mutex during whole duration of this statement and particularly during call to handler::enable_indexes(). This behavior was introduced as part of the fix for bug 14262 "SP: DROP PROCEDURE|VIEW (maybe more) write to binlog too late (race cond)" The patch simply restores old behavior. Note that we can safely do this as this operation takes exclusive lock (similar to name-lock) which blocks both DML and DDL on the table being altered. It also introduces mysql-test/include/wait_show_pattern.inc helper script which is used to make test-case for this bug robust enough. mysql-test/include/wait_slave_status.inc: Now wait_slave_status.inc reuses more generic wait_output_matches.inc script. sql/sql_table.cc: mysql_alter_table(): Changed ALTER TABLE ... ENABLE/DISABLE KEYS not to hold LOCK_open mutex during call to handler::enable_indexes() as the latter can take rather long time and therefore such ALTER would block execution of all other statements that use tables. We can safely do this as this operation takes exclusive lock (similar to name-lock) on the table which is altered. mysql-test/include/wait_show_pattern.inc: New BitKeeper file ``mysql-test/include/wait_show_pattern.inc'' mysql-test/r/alter_table-big.result: New BitKeeper file ``mysql-test/r/alter_table-big.result'' mysql-test/t/alter_table-big.test: New BitKeeper file ``mysql-test/t/alter_table-big.test'' --- mysql-test/include/wait_show_pattern.inc | 51 +++++++++++++++++++ mysql-test/include/wait_slave_status.inc | 45 +++-------------- mysql-test/r/alter_table-big.result | 18 +++++++ mysql-test/t/alter_table-big.test | 62 ++++++++++++++++++++++++ sql/sql_table.cc | 25 +++++++++- 5 files changed, 162 insertions(+), 39 deletions(-) create mode 100644 mysql-test/include/wait_show_pattern.inc create mode 100644 mysql-test/r/alter_table-big.result create mode 100644 mysql-test/t/alter_table-big.test diff --git a/mysql-test/include/wait_show_pattern.inc b/mysql-test/include/wait_show_pattern.inc new file mode 100644 index 00000000000..c9f84ce7f08 --- /dev/null +++ b/mysql-test/include/wait_show_pattern.inc @@ -0,0 +1,51 @@ +# include/wait_show_pattern.inc +# +# SUMMARY +# +# Waits until output produced by SHOW statement which particular type is +# specified as parameter matches certain pattern or maximum time reached. +# +# NOTES +# +# Only the first row produced by the parameter statement is checked. +# +# USAGE +# +# let $show_type= ; +# let $show_pattern= 'Pattern to be used for LIKE matching'; +# --source wait_show_pattern.inc +# +# EXAMPLES +# +# alter_table-big.test, wait_slave_status.inc +# +# SEE ALSO +# +# wait_slave_status.inc, wait_condition.inc (>=5.1) +# +############################################################################### + +--disable_query_log + +# We accept to wait maximum 30 seconds (0.2 sec/loop). +let $wait_counter= 150; +while ($wait_counter) +{ + let $result= `SHOW $show_type`; + let $success= `SELECT '$result' LIKE $show_pattern`; + if ($success) + { + let $wait_counter= 0; + } + if (!$success) + { + real_sleep 0.2; + dec $wait_counter; + } +} +if (!$success) +{ + echo Timeout in wait_show_pattern.inc \$show_type= $show_type \$show_pattern= $show_pattern (\$result= '$result'); +} + +--enable_query_log diff --git a/mysql-test/include/wait_slave_status.inc b/mysql-test/include/wait_slave_status.inc index 7d3636e673c..d8d048527cf 100644 --- a/mysql-test/include/wait_slave_status.inc +++ b/mysql-test/include/wait_slave_status.inc @@ -104,50 +104,21 @@ eval SELECT "let \$result_pattern= $result_pattern ;" AS ""; SELECT '--source include/wait_slave_status.inc' AS ""; -# We accept to wait maximum 30 seconds (0.2 sec/loop). -let $max_wait= 150; -while ($max_wait) -{ - let $my_val= `SHOW SLAVE STATUS`; - # Now we have the first record of the SHOW result set as one fat string - # within the variable $my_val. - - eval SET @my_val = '$my_val'; - # DEBUG eval SELECT @my_val AS "response to SHOW SLAVE STATUS"; - - eval SELECT @my_val LIKE $result_pattern INTO @success; - # @success is '1' if we have a match - # '0' if we have no match - # DEBUG SELECT @success; - - let $success= `SELECT @success`; - let $no_success= `SELECT @success = 0`; - if ($success) - { - # We reached the expected result and want to jump out of the loop - # without unneeded sleeps. - # Attention: Do not set $max_wait to 0, because "while" with negative value - # does not work. - let $max_wait= 1; - } - if ($no_success) - { - # We did not reach the expected result and will have to sleep again - # or jump out of the loop, when max_wait is exhausted. - real_sleep 0.2; - } - dec $max_wait; -} +let $show_type= SLAVE STATUS; +let $show_pattern= $result_pattern; --enable_query_log -if ($no_success) + +--source include/wait_show_pattern.inc + +if (!$success) { let $message= ! Attention: Timeout in wait_slave_status.inc. | Possible reasons with decreasing probability: - | - The LIKE pattern ($result_pattern) is wrong, because the + | - The LIKE pattern is wrong, because the | testcase was altered or the layout of the | SHOW SLAVE STATUS result set changed. | - There is a new bug within the replication. - | - We met an extreme testing environment and $max_wait is + | - We met an extreme testing environment and timeout is | too small.; --source include/show_msg80.inc --echo DEBUG INFO START (wait_slave_status.inc): diff --git a/mysql-test/r/alter_table-big.result b/mysql-test/r/alter_table-big.result new file mode 100644 index 00000000000..873978c60de --- /dev/null +++ b/mysql-test/r/alter_table-big.result @@ -0,0 +1,18 @@ +drop table if exists t1, t2; +create table t1 (n1 int, n2 int, n3 int, +key (n1, n2, n3), +key (n2, n3, n1), +key (n3, n1, n2)); +create table t2 (i int); +alter table t1 disable keys; +reset master; +alter table t1 enable keys;; +insert into t2 values (1); +insert into t1 values (1, 1, 1); +show binlog events in 'master-bin.000001' from 98; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 # Query 1 # use `test`; insert into t2 values (1) +master-bin.000001 # Query 1 # use `test`; alter table t1 enable keys +master-bin.000001 # Query 1 # use `test`; insert into t1 values (1, 1, 1) +drop tables t1, t2; +End of 5.0 tests diff --git a/mysql-test/t/alter_table-big.test b/mysql-test/t/alter_table-big.test new file mode 100644 index 00000000000..9a773f48a9c --- /dev/null +++ b/mysql-test/t/alter_table-big.test @@ -0,0 +1,62 @@ +# In order to be more or less robust test for bug#25044 has to take +# significant time (e.g. about 9 seconds on my (Dmitri's) computer) +# so we probably want execute it only in --big-test mode. +# Also in 5.1 this test will require statement-based binlog. +--source include/big_test.inc + + +# +# Test for bug #25044 "ALTER TABLE ... ENABLE KEYS acquires global +# 'opening tables' lock". +# +# ALTER TABLE ... ENABLE KEYS should not acquire LOCK_open mutex for +# the whole its duration as it prevents other queries from execution. +--disable_warnings +drop table if exists t1, t2; +--enable_warnings +connect (addconroot, localhost, root,,); +connection default; +create table t1 (n1 int, n2 int, n3 int, + key (n1, n2, n3), + key (n2, n3, n1), + key (n3, n1, n2)); +create table t2 (i int); + +# Populating 't1' table with keys disabled, so ALTER TABLE .. ENABLE KEYS +# will run for some time +alter table t1 disable keys; +--disable_query_log +insert into t1 values (RAND()*1000,RAND()*1000,RAND()*1000); +let $1=19; +while ($1) +{ + eval insert into t1 select RAND()*1000,RAND()*1000,RAND()*1000 from t1; + dec $1; +} +--enable_query_log + +# Later we use binlog to check the order in which statements are +# executed so let us reset it first. +reset master; +--send alter table t1 enable keys; +connection addconroot; +let $show_type= PROCESSLIST; +let $show_pattern= '%Repair by sorting%alter table t1 enable keys%'; +--source include/wait_show_pattern.inc +# This statement should not be blocked by in-flight ALTER and therefore +# should be executed and written to binlog before ALTER TABLE ... ENABLE KEYS +# finishes. +insert into t2 values (1); +# And this should wait until the end of ALTER TABLE ... ENABLE KEYS. +insert into t1 values (1, 1, 1); +connection default; +--reap +# Check that statements were executed/binlogged in correct order. +--replace_column 2 # 5 # +show binlog events in 'master-bin.000001' from 98; + +# Clean up +drop tables t1, t2; + + +--echo End of 5.0 tests diff --git a/sql/sql_table.cc b/sql/sql_table.cc index b3bd3182a59..88c9be9ff59 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3146,19 +3146,30 @@ view_err: if (!(alter_info->flags & ~(ALTER_RENAME | ALTER_KEYS_ONOFF)) && !table->s->tmp_table) // no need to touch frm { - VOID(pthread_mutex_lock(&LOCK_open)); - switch (alter_info->keys_onoff) { case LEAVE_AS_IS: error= 0; break; case ENABLE: + /* + wait_while_table_is_used() ensures that table being altered is + opened only by this thread and that TABLE::TABLE_SHARE::version + of TABLE object corresponding to this table is 0. + The latter guarantees that no DML statement will open this table + until ALTER TABLE finishes (i.e. until close_thread_tables()) + while the fact that the table is still open gives us protection + from concurrent DDL statements. + */ + VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + VOID(pthread_mutex_unlock(&LOCK_open)); error= table->file->enable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; case DISABLE: + VOID(pthread_mutex_lock(&LOCK_open)); wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN); + VOID(pthread_mutex_unlock(&LOCK_open)); error=table->file->disable_indexes(HA_KEY_SWITCH_NONUNIQ_SAVE); /* COND_refresh will be signaled in close_thread_tables() */ break; @@ -3171,6 +3182,16 @@ view_err: error= 0; } + VOID(pthread_mutex_lock(&LOCK_open)); + /* + Unlike to the above case close_cached_table() below will remove ALL + instances of TABLE from table cache (it will also remove table lock + held by this thread). So to make actual table renaming and writing + to binlog atomic we have to put them into the same critical section + protected by LOCK_open mutex. This also removes gap for races between + access() and mysql_rename_table() calls. + */ + if (!error && (new_name != table_name || new_db != db)) { thd->proc_info="rename"; From c1a54d976aa29181bb7d241a6f081ed973dda4c7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 20 Jan 2007 14:08:53 +0300 Subject: [PATCH 07/11] Fixed test case for bug #25044 "ALTER TABLE ... ENABLE KEYS acquires global 'opening tables' lock." after merging it into 5.1 tree. mysql-test/r/alter_table-big.result: Fixed "show binlog events" usage as 5.1 and 5.0 sizes of binlog events differ. mysql-test/t/alter_table-big.test: This test needs statement based binlogging. Also fixed "show binlog events" usage as 5.1 and 5.0 sizes of binlog events differ. --- mysql-test/r/alter_table-big.result | 2 +- mysql-test/t/alter_table-big.test | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mysql-test/r/alter_table-big.result b/mysql-test/r/alter_table-big.result index 873978c60de..a9d0515d6bb 100644 --- a/mysql-test/r/alter_table-big.result +++ b/mysql-test/r/alter_table-big.result @@ -9,7 +9,7 @@ reset master; alter table t1 enable keys;; insert into t2 values (1); insert into t1 values (1, 1, 1); -show binlog events in 'master-bin.000001' from 98; +show binlog events in 'master-bin.000001' from 102; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000001 # Query 1 # use `test`; insert into t2 values (1) master-bin.000001 # Query 1 # use `test`; alter table t1 enable keys diff --git a/mysql-test/t/alter_table-big.test b/mysql-test/t/alter_table-big.test index 9a773f48a9c..befe6e14977 100644 --- a/mysql-test/t/alter_table-big.test +++ b/mysql-test/t/alter_table-big.test @@ -1,8 +1,8 @@ # In order to be more or less robust test for bug#25044 has to take # significant time (e.g. about 9 seconds on my (Dmitri's) computer) # so we probably want execute it only in --big-test mode. -# Also in 5.1 this test will require statement-based binlog. --source include/big_test.inc +--source include/have_binlog_format_mixed_or_statement.inc # @@ -53,7 +53,7 @@ connection default; --reap # Check that statements were executed/binlogged in correct order. --replace_column 2 # 5 # -show binlog events in 'master-bin.000001' from 98; +show binlog events in 'master-bin.000001' from 102; # Clean up drop tables t1, t2; From 426c64fdb1e24a4f584d5091e4f9cba81f155a72 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Jan 2007 19:50:34 +0300 Subject: [PATCH 08/11] Enabling im_daemon_life_cycle.imtest in team tree in order to debug IM. Do not propagate this change into main trees! mysql-test/t/disabled.def: im_daemon_life_cycle enabled. --- mysql-test/t/disabled.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index ce7bb345aad..da79a52e8d4 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -11,7 +11,7 @@ ############################################################################## user_limits : Bug#23921 random failure of user_limits.test -im_daemon_life_cycle : Bug#24415 see note: [19 Dec 23:17] Trudy Pelzer +# im_daemon_life_cycle : Bug#24415 see note: [19 Dec 23:17] Trudy Pelzer im_options : Bug#20294 2006-07-24 stewart Instance manager test im_options fails randomly concurrent_innodb : BUG#21579 2006-08-11 mleich innodb_concurrent random failures with varying differences ndb_autodiscover : BUG#18952 2006-02-16 jmiller Needs to be fixed w.r.t binlog From 356893a66444bd5f48d67222840a824ea82c9fb3 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 22 Jan 2007 20:00:27 +0300 Subject: [PATCH 09/11] Enabling im_daemon_life_cycle.imtest in team tree. Do not propagate this change into main trees. mysql-test/t/disabled.def: Enbled im_daemon_life_cycle.imtest --- mysql-test/t/disabled.def | 1 - 1 file changed, 1 deletion(-) diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index 3213bd4eb5b..53b73363c22 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -10,7 +10,6 @@ # ############################################################################## -im_daemon_life_cycle : Bug#24415 see note: [19 Dec 23:17] Trudy Pelzer ndb_load : Bug#17233 user_limits : Bug#23921 random failure of user_limits.test flush2 : Bug#24805 Pushbuild can't handle test with --disable-log-bin From 1dead07d1416201aba6d04ddfc7dc331dbf5a883 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 23 Jan 2007 15:03:48 +0300 Subject: [PATCH 10/11] Proposed fix for bug#24491 "using alias from source table in insert ... on duplicate key". INSERT ... SELECT ... ON DUPLICATE KEY UPDATE which was used in stored routine or as prepared statement and which in its ON DUPLICATE KEY clause erroneously tried to assign value to a column mentioned only in its SELECT part was properly emitting error on the first execution but succeeded on the second and following executions. Code which is responsible for name resolution of fields mentioned in UPDATE clause (e.g. see select_insert::prepare()) modifies table list and Name_resolution_context used in this process. It uses Name_resolution_context_state::save_state/restore_state() to revert these modifications. Unfortunately those two methods failed to revert properly modifications to TABLE_LIST::next_name_resolution_table and this broke name resolution process for successive executions. This patch fixes Name_resolution_context_state::save_state/restore_state() in such way that it properly handles TABLE_LIST::next_name_resolution_table. mysql-test/r/ps.result: Added test case for bug#24491 "using alias from source table in insert ... on duplicate key" mysql-test/r/sp-error.result: Added test case for bug#24491 "using alias from source table in insert ... on duplicate key" mysql-test/t/ps.test: Added test case for bug#24491 "using alias from source table in insert ... on duplicate key" mysql-test/t/sp-error.test: Added test case for bug#24491 "using alias from source table in insert ... on duplicate key" sql/item.h: Name_resolution_context::save_state/restore_state(): At the moment these methods are used only by code implementing INSERT and INSERT ... SELECT statements. This code doesn't modify 'next_name_resolution_table' member of table list element corresponding to the first table of SELECT clause (pointed by 'first_name_resolution_table'). But it modifies table list element corresponding to the target table of INSERT (pointed by 'table_list') So these methods were changed to reflect this. --- mysql-test/r/ps.result | 16 ++++++++++++++++ mysql-test/r/sp-error.result | 19 +++++++++++++++++++ mysql-test/t/ps.test | 30 ++++++++++++++++++++++++++++++ mysql-test/t/sp-error.test | 32 ++++++++++++++++++++++++++++++++ sql/item.h | 9 ++------- 5 files changed, 99 insertions(+), 7 deletions(-) diff --git a/mysql-test/r/ps.result b/mysql-test/r/ps.result index eb07bb8e672..279e89150da 100644 --- a/mysql-test/r/ps.result +++ b/mysql-test/r/ps.result @@ -1496,4 +1496,20 @@ Variable_name Value Slow_queries 1 deallocate prepare no_index; deallocate prepare sq; +drop tables if exists t1; +create table t1 (id int primary key auto_increment, value varchar(10)); +insert into t1 (id, value) values (1, 'FIRST'), (2, 'SECOND'), (3, 'THIRD'); +prepare stmt from "insert into t1 (id, value) select * from (select 4 as i, 'FOURTH' as v) as y on duplicate key update v = 'DUP'"; +execute stmt; +ERROR 42S22: Unknown column 'v' in 'field list' +execute stmt; +ERROR 42S22: Unknown column 'v' in 'field list' +deallocate prepare stmt; +prepare stmt from "insert into t1 (id, value) select * from (select 4 as id, 'FOURTH' as value) as y on duplicate key update y.value = 'DUP'"; +execute stmt; +ERROR 42S22: Unknown column 'y.value' in 'field list' +execute stmt; +ERROR 42S22: Unknown column 'y.value' in 'field list' +deallocate prepare stmt; +drop tables t1; End of 5.0 tests. diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 63fd1bfff6d..e7e387f4348 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -1250,3 +1250,22 @@ ERROR HY000: View's SELECT contains a variable or parameter PREPARE stmt FROM "CREATE VIEW v AS SELECT ?"; ERROR HY000: View's SELECT contains a variable or parameter DROP TABLE t1; +drop tables if exists t1; +drop procedure if exists bug24491; +create table t1 (id int primary key auto_increment, value varchar(10)); +insert into t1 (id, value) values (1, 'FIRST'), (2, 'SECOND'), (3, 'THIRD'); +create procedure bug24491() +insert into t1 (id, value) select * from (select 4 as i, 'FOURTH' as v) as y on duplicate key update v = 'DUP'; +call bug24491(); +ERROR 42S22: Unknown column 'v' in 'field list' +call bug24491(); +ERROR 42S22: Unknown column 'v' in 'field list' +drop procedure bug24491; +create procedure bug24491() +insert into t1 (id, value) select * from (select 4 as id, 'FOURTH' as value) as y on duplicate key update y.value = 'DUP'; +call bug24491(); +ERROR 42S22: Unknown column 'y.value' in 'field list' +call bug24491(); +ERROR 42S22: Unknown column 'y.value' in 'field list' +drop procedure bug24491; +drop tables t1; diff --git a/mysql-test/t/ps.test b/mysql-test/t/ps.test index 1c8d7b419a3..2059f2fb080 100644 --- a/mysql-test/t/ps.test +++ b/mysql-test/t/ps.test @@ -1540,4 +1540,34 @@ execute sq; deallocate prepare no_index; deallocate prepare sq; + +# +# BUG#24491 "using alias from source table in insert ... on duplicate key" +# +--disable_warnings +drop tables if exists t1; +--enable_warnings +create table t1 (id int primary key auto_increment, value varchar(10)); +insert into t1 (id, value) values (1, 'FIRST'), (2, 'SECOND'), (3, 'THIRD'); +# Let us prepare INSERT ... SELECT ... ON DUPLICATE KEY UPDATE statement +# which in its ON DUPLICATE KEY clause erroneously tries to assign value +# to a column which is mentioned only in SELECT part. +prepare stmt from "insert into t1 (id, value) select * from (select 4 as i, 'FOURTH' as v) as y on duplicate key update v = 'DUP'"; +# Both first and second attempts to execute it should fail +--error ER_BAD_FIELD_ERROR +execute stmt; +--error ER_BAD_FIELD_ERROR +execute stmt; +deallocate prepare stmt; +# And now the same test for more complex case which is more close +# to the one that was reported originally. +prepare stmt from "insert into t1 (id, value) select * from (select 4 as id, 'FOURTH' as value) as y on duplicate key update y.value = 'DUP'"; +--error ER_BAD_FIELD_ERROR +execute stmt; +--error ER_BAD_FIELD_ERROR +execute stmt; +deallocate prepare stmt; +drop tables t1; + + --echo End of 5.0 tests. diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 77bd5259eb5..e77e3df8301 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1808,6 +1808,38 @@ PREPARE stmt FROM "CREATE VIEW v AS SELECT ?"; DROP TABLE t1; +# +# BUG#24491 "using alias from source table in insert ... on duplicate key" +# +--disable_warnings +drop tables if exists t1; +drop procedure if exists bug24491; +--enable_warnings +create table t1 (id int primary key auto_increment, value varchar(10)); +insert into t1 (id, value) values (1, 'FIRST'), (2, 'SECOND'), (3, 'THIRD'); +# Let us create routine with INSERT ... SELECT ... ON DUPLICATE KEY UPDATE +# statement which in its ON DUPLICATE KEY clause erroneously tries to assign +# value to a column which is mentioned only in SELECT part. +create procedure bug24491() + insert into t1 (id, value) select * from (select 4 as i, 'FOURTH' as v) as y on duplicate key update v = 'DUP'; +# Both first and second calls to it should fail +--error ER_BAD_FIELD_ERROR +call bug24491(); +--error ER_BAD_FIELD_ERROR +call bug24491(); +drop procedure bug24491; +# And now the same test for more complex case which is more close +# to the one that was reported originally. +create procedure bug24491() + insert into t1 (id, value) select * from (select 4 as id, 'FOURTH' as value) as y on duplicate key update y.value = 'DUP'; +--error ER_BAD_FIELD_ERROR +call bug24491(); +--error ER_BAD_FIELD_ERROR +call bug24491(); +drop procedure bug24491; +drop tables t1; + + # # BUG#NNNN: New bug synopsis # diff --git a/sql/item.h b/sql/item.h index 63d89113ec1..7c6aa39cadf 100644 --- a/sql/item.h +++ b/sql/item.h @@ -337,23 +337,18 @@ public: { save_table_list= context->table_list; save_first_name_resolution_table= context->first_name_resolution_table; - save_next_name_resolution_table= (context->first_name_resolution_table) ? - context->first_name_resolution_table-> - next_name_resolution_table : - NULL; save_resolve_in_select_list= context->resolve_in_select_list; save_next_local= table_list->next_local; + save_next_name_resolution_table= table_list->next_name_resolution_table; } /* Restore a name resolution context from saved state. */ void restore_state(Name_resolution_context *context, TABLE_LIST *table_list) { table_list->next_local= save_next_local; + table_list->next_name_resolution_table= save_next_name_resolution_table; context->table_list= save_table_list; context->first_name_resolution_table= save_first_name_resolution_table; - if (context->first_name_resolution_table) - context->first_name_resolution_table-> - next_name_resolution_table= save_next_name_resolution_table; context->resolve_in_select_list= save_resolve_in_select_list; } }; From 07b6b2f8764c18766c11065f5ac8eea367f60c2c Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 24 Jan 2007 10:46:25 +0300 Subject: [PATCH 11/11] Fixed test case after merging fix for bug#24491 "using alias from source table in insert ... on duplicate key" in 5.1 tree. mysql-test/t/sp-error.test: After merge fix. --- mysql-test/t/sp-error.test | 63 +++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index bff3627e194..3e334bb61e8 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1812,6 +1812,38 @@ PREPARE stmt FROM "CREATE VIEW v AS SELECT ?"; DROP TABLE t1; +# +# BUG#24491 "using alias from source table in insert ... on duplicate key" +# +--disable_warnings +drop tables if exists t1; +drop procedure if exists bug24491; +--enable_warnings +create table t1 (id int primary key auto_increment, value varchar(10)); +insert into t1 (id, value) values (1, 'FIRST'), (2, 'SECOND'), (3, 'THIRD'); +# Let us create routine with INSERT ... SELECT ... ON DUPLICATE KEY UPDATE +# statement which in its ON DUPLICATE KEY clause erroneously tries to assign +# value to a column which is mentioned only in SELECT part. +create procedure bug24491() + insert into t1 (id, value) select * from (select 4 as i, 'FOURTH' as v) as y on duplicate key update v = 'DUP'; +# Both first and second calls to it should fail +--error ER_BAD_FIELD_ERROR +call bug24491(); +--error ER_BAD_FIELD_ERROR +call bug24491(); +drop procedure bug24491; +# And now the same test for more complex case which is more close +# to the one that was reported originally. +create procedure bug24491() + insert into t1 (id, value) select * from (select 4 as id, 'FOURTH' as value) as y on duplicate key update y.value = 'DUP'; +--error ER_BAD_FIELD_ERROR +call bug24491(); +--error ER_BAD_FIELD_ERROR +call bug24491(); +drop procedure bug24491; +drop tables t1; + + # # End of 5.0 tests # @@ -1853,37 +1885,6 @@ drop function bug20701; --echo End of 5.1 tests -# -# BUG#24491 "using alias from source table in insert ... on duplicate key" -# ---disable_warnings -drop tables if exists t1; -drop procedure if exists bug24491; ---enable_warnings -create table t1 (id int primary key auto_increment, value varchar(10)); -insert into t1 (id, value) values (1, 'FIRST'), (2, 'SECOND'), (3, 'THIRD'); -# Let us create routine with INSERT ... SELECT ... ON DUPLICATE KEY UPDATE -# statement which in its ON DUPLICATE KEY clause erroneously tries to assign -# value to a column which is mentioned only in SELECT part. -create procedure bug24491() - insert into t1 (id, value) select * from (select 4 as i, 'FOURTH' as v) as y on duplicate key update v = 'DUP'; -# Both first and second calls to it should fail ---error ER_BAD_FIELD_ERROR -call bug24491(); ---error ER_BAD_FIELD_ERROR -call bug24491(); -drop procedure bug24491; -# And now the same test for more complex case which is more close -# to the one that was reported originally. -create procedure bug24491() - insert into t1 (id, value) select * from (select 4 as id, 'FOURTH' as value) as y on duplicate key update y.value = 'DUP'; ---error ER_BAD_FIELD_ERROR -call bug24491(); ---error ER_BAD_FIELD_ERROR -call bug24491(); -drop procedure bug24491; -drop tables t1; - # # BUG#NNNN: New bug synopsis