diff options
-rw-r--r-- | include/my_pthread.h | 8 | ||||
-rw-r--r-- | mysql-test/r/handler.result | 37 | ||||
-rw-r--r-- | mysql-test/r/myisam.result | 10 | ||||
-rw-r--r-- | mysql-test/r/ndb_charset.result | 20 | ||||
-rw-r--r-- | mysql-test/r/rpl_sp.result | 25 | ||||
-rw-r--r-- | mysql-test/r/sp-error.result | 103 | ||||
-rw-r--r-- | mysql-test/t/disabled.def | 1 | ||||
-rw-r--r-- | mysql-test/t/func_group.test | 4 | ||||
-rw-r--r-- | mysql-test/t/handler.test | 75 | ||||
-rw-r--r-- | mysql-test/t/myisam.test | 12 | ||||
-rw-r--r-- | mysql-test/t/ndb_charset.test | 15 | ||||
-rw-r--r-- | mysql-test/t/rpl_sp.test | 36 | ||||
-rw-r--r-- | mysql-test/t/sp-error.test | 138 | ||||
-rw-r--r-- | ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp | 17 | ||||
-rw-r--r-- | ndb/src/kernel/vm/SimulatedBlock.cpp | 92 | ||||
-rw-r--r-- | ndb/src/kernel/vm/SimulatedBlock.hpp | 6 | ||||
-rw-r--r-- | sql/ha_archive.cc | 3 | ||||
-rw-r--r-- | sql/lock.cc | 18 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sp_head.cc | 39 | ||||
-rw-r--r-- | sql/sp_head.h | 13 | ||||
-rw-r--r-- | sql/sql_base.cc | 7 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_handler.cc | 51 | ||||
-rw-r--r-- | sql/sql_parse.cc | 12 | ||||
-rw-r--r-- | sql/sql_select.cc | 8 | ||||
-rw-r--r-- | sql/sql_table.cc | 24 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 57 |
28 files changed, 683 insertions, 153 deletions
diff --git a/include/my_pthread.h b/include/my_pthread.h index ee2c801ff6e..6f60a6df2c1 100644 --- a/include/my_pthread.h +++ b/include/my_pthread.h @@ -536,9 +536,15 @@ void safe_mutex_end(FILE *file); #define pthread_cond_timedwait(A,B,C) safe_cond_timedwait((A),(B),(C),__FILE__,__LINE__) #define pthread_mutex_trylock(A) pthread_mutex_lock(A) #define pthread_mutex_t safe_mutex_t -#define safe_mutex_assert_owner(mp) DBUG_ASSERT((mp)->count > 0 && pthread_equal(pthread_self(),(mp)->thread)) +#define safe_mutex_assert_owner(mp) \ + DBUG_ASSERT((mp)->count > 0 && \ + pthread_equal(pthread_self(), (mp)->thread)) +#define safe_mutex_assert_not_owner(mp) \ + DBUG_ASSERT(! (mp)->count || \ + ! pthread_equal(pthread_self(), (mp)->thread)) #else #define safe_mutex_assert_owner(mp) +#define safe_mutex_assert_not_owner(mp) #endif /* SAFE_MUTEX */ /* READ-WRITE thread locking */ diff --git a/mysql-test/r/handler.result b/mysql-test/r/handler.result index 072d4582cbc..133683fb273 100644 --- a/mysql-test/r/handler.result +++ b/mysql-test/r/handler.result @@ -445,3 +445,40 @@ drop table t2; drop table t3; drop table t4; drop table t5; +create table t1 (c1 int); +insert into t1 values (1); +handler t1 open; +handler t1 read first; +c1 +1 +send the below to another connection, do not wait for the result + optimize table t1; +proceed with the normal connection +handler t1 read next; +c1 +1 +handler t1 close; +read the result from the other connection +Table Op Msg_type Msg_text +test.t1 optimize status OK +proceed with the normal connection +drop table t1; +create table t1 (c1 int); +insert into t1 values (14397); +flush tables with read lock; +drop table t1; +ERROR HY000: Can't execute the query because you have a conflicting read lock +send the below to another connection, do not wait for the result + drop table t1; +proceed with the normal connection +select * from t1; +c1 +14397 +unlock tables; +read the result from the other connection +proceed with the normal connection +select * from t1; +ERROR 42S02: Table 'test.t1' doesn't exist +drop table if exists t1; +Warnings: +Note 1051 Unknown table 't1' diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index 7da55b66376..e000cfd9c11 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -505,6 +505,16 @@ id select_type table type possible_keys key key_len ref rows Extra 1 SIMPLE t1 system NULL NULL NULL NULL 1 Using temporary 1 SIMPLE t2 index NULL PRIMARY 4 NULL 2 Using index; Distinct drop table t1,t2; +create table t1 ( +c1 varchar(32), +key (c1) +) engine=myisam; +alter table t1 disable keys; +insert into t1 values ('a'), ('b'); +select c1 from t1 order by c1 limit 1; +c1 +a +drop table t1; CREATE TABLE t1 (`a` int(11) NOT NULL default '0', `b` int(11) NOT NULL default '0', UNIQUE KEY `a` USING RTREE (`a`,`b`)) ENGINE=MyISAM; Got one of the listed errors create table t1 (a int, b varchar(200), c text not null) checksum=1; diff --git a/mysql-test/r/ndb_charset.result b/mysql-test/r/ndb_charset.result index 500b0497890..3763e20e59a 100644 --- a/mysql-test/r/ndb_charset.result +++ b/mysql-test/r/ndb_charset.result @@ -306,11 +306,21 @@ count(*) drop table t1; create table t1 ( a char(10) primary key -) engine=ndb; -insert into t1 values ('jonas % '); -replace into t1 values ('jonas % '); -replace into t1 values ('jonas % '); +) engine=ndbcluster default charset=latin1; +insert into t1 values ('aaabb'); +select * from t1; +a +aaabb +replace into t1 set a = 'AAABB'; +select * from t1; +a +AAABB +replace into t1 set a = 'aAaBb'; +select * from t1; +a +aAaBb +replace into t1 set a = 'aaabb'; select * from t1; a -jonas % +aaabb drop table t1; diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index ba840caf6c2..41bcfc7d72c 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -375,3 +375,28 @@ drop procedure foo; drop function fn1; drop database mysqltest1; drop user "zedjzlcsjhd"@127.0.0.1; +use test; +use test; +drop function if exists f1; +create function f1() returns int reads sql data +begin +declare var integer; +declare c cursor for select a from v1; +open c; +fetch c into var; +close c; +return var; +end| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +a +1 +drop view v1; +drop function f1; +select * from t1; +a +1 +drop table t1; +reset master; diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index fabbf13a96b..2f4b420a2ae 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -872,6 +872,109 @@ names foo4 drop procedure bug13510_3| drop procedure bug13510_4| +drop function if exists bug_13627_f| +CREATE TABLE t1 (a int)| +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DROP TRIGGER test1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN DROP TRIGGER test1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN load table t1 from master; END | +ERROR 0A000: LOAD TABLE is not allowed in stored procedures +CREATE FUNCTION bug_13627_f() returns int BEGIN load table t1 from master; return 1; END | +ERROR 0A000: LOAD TABLE is not allowed in stored procedures +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create table t2 (a int); END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create table t2 (a int); return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create index t1_i on t1 (a); END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create index t1_i on t1 (a); return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter table t1 add column b int; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN alter table t1 add column b int; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename table t1 to t2; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN rename table t1 to t2; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN truncate table t1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN truncate table t1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop table t1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop table t1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop index t1_i on t1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop index t1_i on t1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN unlock tables; END | +ERROR 0A000: UNLOCK is not allowed in stored procedures +CREATE FUNCTION bug_13627_f() returns int BEGIN unlock tables; return 1; END | +ERROR 0A000: UNLOCK is not allowed in stored procedures +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN LOCK TABLE t1 READ; END | +ERROR 0A000: LOCK is not allowed in stored procedures +CREATE FUNCTION bug_13627_f() returns int BEGIN LOCK TABLE t1 READ; return 1; END | +ERROR 0A000: LOCK is not allowed in stored procedures +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create database mysqltest; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create database mysqltest; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop database mysqltest; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop database mysqltest; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create view v1 as select 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN create view v1 as select 1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter view v1 as select 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN alter view v1 as select 1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop view v1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE FUNCTION bug_13627_f() returns int BEGIN drop view v1; return 1; END | +ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger. +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create trigger tr2 before insert on t1 for each row do select 1; END | +ERROR 2F003: Can't create a TRIGGER from within another stored routine +CREATE FUNCTION bug_13627_f() returns int BEGIN create trigger tr2 before insert on t1 for each row do select 1; return 1; END | +ERROR 2F003: Can't create a TRIGGER from within another stored routine +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop function bug_13627_f; END | +ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine +CREATE FUNCTION bug_13627_f() returns int BEGIN drop function bug_13627_f; return 1; END | +ERROR HY000: Can't drop or alter a FUNCTION from within another stored routine +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create function f2 () returns int return 1; END | +ERROR 2F003: Can't create a FUNCTION from within another stored routine +CREATE FUNCTION bug_13627_f() returns int BEGIN create function f2 () returns int return 1; return 1; END | +ERROR 2F003: Can't create a FUNCTION from within another stored routine +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW +BEGIN +CREATE TEMPORARY TABLE t2 (a int); +DROP TEMPORARY TABLE t2; +END | +CREATE FUNCTION bug_13627_f() returns int +BEGIN +CREATE TEMPORARY TABLE t2 (a int); +DROP TEMPORARY TABLE t2; +return 1; +END | +drop table t1| +drop function bug_13627_f| create database mysqltest1; use mysqltest1; drop database mysqltest1; diff --git a/mysql-test/t/disabled.def b/mysql-test/t/disabled.def index eedf4b30e73..fe95a543fb5 100644 --- a/mysql-test/t/disabled.def +++ b/mysql-test/t/disabled.def @@ -15,4 +15,3 @@ rpl_relayrotate : Unstable test case, bug#12429 rpl_until : Unstable test case, bug#12429 rpl_deadlock : Unstable test case, bug#12429 kill : Unstable test case, bug#9712 -archive_gis : The test fails on 32bit Linux diff --git a/mysql-test/t/func_group.test b/mysql-test/t/func_group.test index 9237205eeb5..c667f90940c 100644 --- a/mysql-test/t/func_group.test +++ b/mysql-test/t/func_group.test @@ -2,8 +2,6 @@ # simple test of all group functions # ---source include/have_innodb.inc - --disable_warnings drop table if exists t1,t2; --enable_warnings @@ -545,10 +543,12 @@ DROP TABLE t1; # Bug #12882 min/max inconsistent on empty table # +--disable_warnings create table t1m (a int) engine=myisam; create table t1i (a int) engine=innodb; create table t2m (a int) engine=myisam; create table t2i (a int) engine=innodb; +--enable_warnings insert into t2m values (5); insert into t2i values (5); diff --git a/mysql-test/t/handler.test b/mysql-test/t/handler.test index 1bb9b1d3504..f3e14c3cd2b 100644 --- a/mysql-test/t/handler.test +++ b/mysql-test/t/handler.test @@ -347,4 +347,79 @@ drop table t3; drop table t4; drop table t5; +# +# Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash +# +create table t1 (c1 int); +insert into t1 values (1); +# client 1 +handler t1 open; +handler t1 read first; +# client 2 +connect (con2,localhost,root,,); +connection con2; +--exec echo send the below to another connection, do not wait for the result +send optimize table t1; +--sleep 1 +# client 1 +--exec echo proceed with the normal connection +connection default; +handler t1 read next; +handler t1 close; +# client 2 +--exec echo read the result from the other connection +connection con2; +reap; +# client 1 +--exec echo proceed with the normal connection +connection default; +drop table t1; + # End of 4.1 tests + +# +# Addendum to Bug#14397 - OPTIMIZE TABLE with an open HANDLER causes a crash +# Show that DROP TABLE can no longer deadlock against +# FLUSH TABLES WITH READ LOCK. This is a 5.0 issue. +# +create table t1 (c1 int); +insert into t1 values (14397); +flush tables with read lock; +# The thread with the global read lock cannot drop the table itself: +--error 1223 +drop table t1; +# +# client 2 +# We need a second connection to try the drop. +# The drop waits for the global read lock to go away. +# Without the addendum fix it locked LOCK_open before entering the wait loop. +connection con2; +--exec echo send the below to another connection, do not wait for the result +send drop table t1; +--sleep 1 +# +# client 1 +# Now we need something that wants LOCK_open. A simple table access which +# opens the table does the trick. +--exec echo proceed with the normal connection +connection default; +# This would hang on LOCK_open without the 5.0 addendum fix. +select * from t1; +# Release the read lock. This should make the DROP go through. +unlock tables; +# +# client 2 +# Read the result of the drop command. +connection con2; +--exec echo read the result from the other connection +reap; +# +# client 1 +# Now back to normal operation. The table should not exist any more. +--exec echo proceed with the normal connection +connection default; +--error 1146 +select * from t1; +# Just to be sure and not confuse the next test case writer. +drop table if exists t1; + diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index d510ef66677..fb90c16bb86 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -477,6 +477,18 @@ explain select distinct t1.a from t1,t2 order by t2.a; drop table t1,t2; # +# Bug#14616 - Freshly imported table returns error 124 when using LIMIT +# +create table t1 ( + c1 varchar(32), + key (c1) +) engine=myisam; +alter table t1 disable keys; +insert into t1 values ('a'), ('b'); +select c1 from t1 order by c1 limit 1; +drop table t1; + +# # Test RTREE index # --error 1235, 1289 diff --git a/mysql-test/t/ndb_charset.test b/mysql-test/t/ndb_charset.test index fb43e1831f3..5941e5750db 100644 --- a/mysql-test/t/ndb_charset.test +++ b/mysql-test/t/ndb_charset.test @@ -237,13 +237,18 @@ drop table t1; #select a,b,length(a),length(b) from t1 where a='c' and b='c'; #drop table t1; -# bug +# bug#14007 create table t1 ( a char(10) primary key -) engine=ndb; -insert into t1 values ('jonas % '); -replace into t1 values ('jonas % '); -replace into t1 values ('jonas % '); +) engine=ndbcluster default charset=latin1; + +insert into t1 values ('aaabb'); +select * from t1; +replace into t1 set a = 'AAABB'; +select * from t1; +replace into t1 set a = 'aAaBb'; +select * from t1; +replace into t1 set a = 'aaabb'; select * from t1; drop table t1; diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index e7a3afca9cb..386582f8f1b 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -360,4 +360,40 @@ connection master; drop function fn1; drop database mysqltest1; drop user "zedjzlcsjhd"@127.0.0.1; +use test; sync_slave_with_master; +use test; + +# +# Bug#14077 "Failure to replicate a stored function with a cursor": +# verify that stored routines with cursors work on slave. +# +connection master; +--disable_warnings +drop function if exists f1; +--enable_warnings +delimiter |; +create function f1() returns int reads sql data +begin + declare var integer; + declare c cursor for select a from v1; + open c; + fetch c into var; + close c; + return var; +end| +delimiter ;| +create view v1 as select 1 as a; +create table t1 (a int); +insert into t1 (a) values (f1()); +select * from t1; +drop view v1; +drop function f1; +sync_slave_with_master; +connection slave; +select * from t1; + +# cleanup +connection master; +drop table t1; +reset master; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 3c1efe73c18..f16562227f3 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -1263,6 +1263,144 @@ call bug13510_4()| drop procedure bug13510_3| drop procedure bug13510_4| + + +# +# Test that statements which implicitly commit transaction are prohibited +# in stored function and triggers. Attempt to create function or trigger +# containing such statement should produce error (includes test for +# bug #13627). +# +--disable_warnings +drop function if exists bug_13627_f| +--enable_warnings + +CREATE TABLE t1 (a int)| +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN DROP TRIGGER test1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN DROP TRIGGER test1; return 1; END | + +-- error ER_SP_BADSTATEMENT +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN load table t1 from master; END | +-- error ER_SP_BADSTATEMENT +CREATE FUNCTION bug_13627_f() returns int BEGIN load table t1 from master; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create table t2 (a int); END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create table t2 (a int); return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create index t1_i on t1 (a); END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create index t1_i on t1 (a); return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter table t1 add column b int; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN alter table t1 add column b int; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename table t1 to t2; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN rename table t1 to t2; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN truncate table t1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN truncate table t1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop table t1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop table t1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop index t1_i on t1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop index t1_i on t1; return 1; END | + +-- error ER_SP_BADSTATEMENT +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN unlock tables; END | +-- error ER_SP_BADSTATEMENT +CREATE FUNCTION bug_13627_f() returns int BEGIN unlock tables; return 1; END | + +-- error ER_SP_BADSTATEMENT +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN LOCK TABLE t1 READ; END | +-- error ER_SP_BADSTATEMENT +CREATE FUNCTION bug_13627_f() returns int BEGIN LOCK TABLE t1 READ; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create database mysqltest; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create database mysqltest; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop database mysqltest; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop database mysqltest; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create user 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create user 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop user 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop user 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN rename user 'mysqltest_2' to 'mysqltest_1'; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create view v1 as select 1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN create view v1 as select 1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN alter view v1 as select 1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN alter view v1 as select 1; return 1; END | + +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop view v1; END | +-- error ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG +CREATE FUNCTION bug_13627_f() returns int BEGIN drop view v1; return 1; END | + +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create trigger tr2 before insert on t1 for each row do select 1; END | +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE FUNCTION bug_13627_f() returns int BEGIN create trigger tr2 before insert on t1 for each row do select 1; return 1; END | + +-- error ER_SP_NO_DROP_SP +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN drop function bug_13627_f; END | +-- error ER_SP_NO_DROP_SP +CREATE FUNCTION bug_13627_f() returns int BEGIN drop function bug_13627_f; return 1; END | + +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN create function f2 () returns int return 1; END | +-- error ER_SP_NO_RECURSIVE_CREATE +CREATE FUNCTION bug_13627_f() returns int BEGIN create function f2 () returns int return 1; return 1; END | + +CREATE TRIGGER tr1 BEFORE INSERT ON t1 FOR EACH ROW + BEGIN + CREATE TEMPORARY TABLE t2 (a int); + DROP TEMPORARY TABLE t2; + END | +CREATE FUNCTION bug_13627_f() returns int + BEGIN + CREATE TEMPORARY TABLE t2 (a int); + DROP TEMPORARY TABLE t2; + return 1; + END | + +drop table t1| +drop function bug_13627_f| + delimiter ;| # diff --git a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp index acdad3f9f1a..8a55777ac05 100644 --- a/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp +++ b/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp @@ -684,6 +684,21 @@ Dbtup::checkUpdateOfPrimaryKey(Uint32* updateBuffer, Tablerec* const regTabPtr) Uint32 attrDescriptorIndex = regTabPtr->tabDescriptor + (attributeId << ZAD_LOG_SIZE); Uint32 attrDescriptor = tableDescriptor[attrDescriptorIndex].tabDescr; Uint32 attributeOffset = tableDescriptor[attrDescriptorIndex + 1].tabDescr; + + Uint32 xfrmBuffer[1 + MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY]; + Uint32 charsetFlag = AttributeOffset::getCharsetFlag(attributeOffset); + if (charsetFlag) { + Uint32 csIndex = AttributeOffset::getCharsetPos(attributeOffset); + CHARSET_INFO* cs = regTabPtr->charsetArray[csIndex]; + Uint32 srcPos = 0; + Uint32 dstPos = 0; + xfrm_attr(attrDescriptor, cs, &updateBuffer[1], srcPos, + &xfrmBuffer[1], dstPos, MAX_KEY_SIZE_IN_WORDS * MAX_XFRM_MULTIPLY); + ahIn.setDataSize(dstPos); + xfrmBuffer[0] = ahIn.m_value; + updateBuffer = xfrmBuffer; + } + ReadFunction f = regTabPtr->readFunctionArray[attributeId]; AttributeHeader::init(&attributeHeader, attributeId, 0); @@ -691,7 +706,7 @@ Dbtup::checkUpdateOfPrimaryKey(Uint32* updateBuffer, Tablerec* const regTabPtr) tMaxRead = MAX_KEY_SIZE_IN_WORDS; bool tmp = tXfrmFlag; - tXfrmFlag = false; + tXfrmFlag = true; ndbrequire((this->*f)(&keyReadBuffer[0], ahOut, attrDescriptor, attributeOffset)); tXfrmFlag = tmp; ndbrequire(tOutBufIndex == ahOut->getDataSize()); diff --git a/ndb/src/kernel/vm/SimulatedBlock.cpp b/ndb/src/kernel/vm/SimulatedBlock.cpp index d708052ca4e..4625cd43640 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.cpp +++ b/ndb/src/kernel/vm/SimulatedBlock.cpp @@ -1868,49 +1868,9 @@ SimulatedBlock::xfrm_key(Uint32 tab, const Uint32* src, while (i < noOfKeyAttr) { const KeyDescriptor::KeyAttr& keyAttr = desc->keyAttr[i]; - - Uint32 srcBytes = - AttributeDescriptor::getSizeInBytes(keyAttr.attributeDescriptor); - Uint32 srcWords = (srcBytes + 3) / 4; - Uint32 dstWords = ~0; - uchar* dstPtr = (uchar*)&dst[dstPos]; - const uchar* srcPtr = (const uchar*)&src[srcPos]; - CHARSET_INFO* cs = keyAttr.charsetInfo; - - if (cs == NULL) - { - jam(); - memcpy(dstPtr, srcPtr, srcWords << 2); - dstWords = srcWords; - } - else - { - jam(); - Uint32 typeId = - AttributeDescriptor::getType(keyAttr.attributeDescriptor); - Uint32 lb, len; - bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len); - ndbrequire(ok); - Uint32 xmul = cs->strxfrm_multiply; - if (xmul == 0) - xmul = 1; - /* - * Varchar is really Char. End spaces do not matter. To get - * same hash we blank-pad to maximum length via strnxfrm. - * TODO use MySQL charset-aware hash function instead - */ - Uint32 dstLen = xmul * (srcBytes - lb); - ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); - int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); - ndbrequire(n != -1); - while ((n & 3) != 0) - { - dstPtr[n++] = 0; - } - dstWords = (n >> 2); - } - dstPos += dstWords; - srcPos += srcWords; + Uint32 dstWords = + xfrm_attr(keyAttr.attributeDescriptor, keyAttr.charsetInfo, + src, srcPos, dst, dstPos, dstSize); keyPartLen[i++] = dstWords; } @@ -1918,6 +1878,52 @@ SimulatedBlock::xfrm_key(Uint32 tab, const Uint32* src, } Uint32 +SimulatedBlock::xfrm_attr(Uint32 attrDesc, CHARSET_INFO* cs, + const Uint32* src, Uint32 & srcPos, + Uint32* dst, Uint32 & dstPos, Uint32 dstSize) const +{ + Uint32 srcBytes = AttributeDescriptor::getSizeInBytes(attrDesc); + Uint32 srcWords = (srcBytes + 3) / 4; + Uint32 dstWords = ~0; + uchar* dstPtr = (uchar*)&dst[dstPos]; + const uchar* srcPtr = (const uchar*)&src[srcPos]; + + if (cs == NULL) + { + jam(); + memcpy(dstPtr, srcPtr, srcWords << 2); + dstWords = srcWords; + } + else + { + jam(); + Uint32 typeId = AttributeDescriptor::getType(attrDesc); + Uint32 lb, len; + bool ok = NdbSqlUtil::get_var_length(typeId, srcPtr, srcBytes, lb, len); + ndbrequire(ok); + Uint32 xmul = cs->strxfrm_multiply; + if (xmul == 0) + xmul = 1; + /* + * Varchar end-spaces are ignored in comparisons. To get same hash + * we blank-pad to maximum length via strnxfrm. + */ + Uint32 dstLen = xmul * (srcBytes - lb); + ndbrequire(dstLen <= ((dstSize - dstPos) << 2)); + int n = NdbSqlUtil::strnxfrm_bug7284(cs, dstPtr, dstLen, srcPtr + lb, len); + ndbrequire(n != -1); + while ((n & 3) != 0) + { + dstPtr[n++] = 0; + } + dstWords = (n >> 2); + } + dstPos += dstWords; + srcPos += srcWords; + return dstWords; +} + +Uint32 SimulatedBlock::create_distr_key(Uint32 tableId, Uint32 *data, const Uint32 diff --git a/ndb/src/kernel/vm/SimulatedBlock.hpp b/ndb/src/kernel/vm/SimulatedBlock.hpp index ce77fa916d8..b7bd8c57ee8 100644 --- a/ndb/src/kernel/vm/SimulatedBlock.hpp +++ b/ndb/src/kernel/vm/SimulatedBlock.hpp @@ -395,8 +395,12 @@ protected: * @return length */ Uint32 xfrm_key(Uint32 tab, const Uint32* src, - Uint32 *dst, Uint32 dstLen, + Uint32 *dst, Uint32 dstSize, Uint32 keyPartLen[MAX_ATTRIBUTES_IN_INDEX]) const; + + Uint32 xfrm_attr(Uint32 attrDesc, CHARSET_INFO* cs, + const Uint32* src, Uint32 & srcPos, + Uint32* dst, Uint32 & dstPos, Uint32 dstSize) const; /** * diff --git a/sql/ha_archive.cc b/sql/ha_archive.cc index c4801de5fb2..1e8fc582eb8 100644 --- a/sql/ha_archive.cc +++ b/sql/ha_archive.cc @@ -233,7 +233,8 @@ ha_archive::ha_archive(TABLE *table_arg) buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); /* The size of the offset value we will use for position() */ - ref_length = sizeof(z_off_t); + ref_length = 2 << ((zlibCompileFlags() >> 6) & 3); + DBUG_ASSERT(ref_length <= sizeof(z_off_t)); } /* diff --git a/sql/lock.cc b/sql/lock.cc index f4c4a781e45..fe8dcb3aa5e 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -815,10 +815,13 @@ static void print_lock_error(int error, const char *table) access to them is protected with a mutex LOCK_global_read_lock - (XXX: one should never take LOCK_open if LOCK_global_read_lock is taken, - otherwise a deadlock may occur - see mysql_rm_table. Other mutexes could - be a problem too - grep the code for global_read_lock if you want to use - any other mutex here) + (XXX: one should never take LOCK_open if LOCK_global_read_lock is + taken, otherwise a deadlock may occur. Other mutexes could be a + problem too - grep the code for global_read_lock if you want to use + any other mutex here) Also one must not hold LOCK_open when calling + wait_if_global_read_lock(). When the thread with the global read lock + tries to close its tables, it needs to take LOCK_open in + close_thread_table(). How blocking of threads by global read lock is achieved: that's advisory. Any piece of code which should be blocked by global read lock must @@ -937,6 +940,13 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, DBUG_ENTER("wait_if_global_read_lock"); LINT_INIT(old_message); + /* + Assert that we do not own LOCK_open. If we would own it, other + threads could not close their tables. This would make a pretty + deadlock. + */ + safe_mutex_assert_not_owner(&LOCK_open); + (void) pthread_mutex_lock(&LOCK_global_read_lock); if ((need_exit_cond= must_wait)) { diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 15424087a43..905c6550cba 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -891,7 +891,8 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen); bool mysql_ha_close(THD *thd, TABLE_LIST *tables); bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags); +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked); /* mysql_ha_flush mode_flags bits */ #define MYSQL_HA_CLOSE_FINAL 0x00 #define MYSQL_HA_REOPEN_ON_USAGE 0x01 diff --git a/sql/sp_head.cc b/sql/sp_head.cc index facd984cc50..e3cdc909048 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -120,6 +120,45 @@ sp_get_flags_for_command(LEX *lex) case SQLCOM_DEALLOCATE_PREPARE: flags= sp_head::CONTAINS_DYNAMIC_SQL; break; + case SQLCOM_CREATE_TABLE: + if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) + flags= 0; + else + flags= sp_head::HAS_COMMIT_OR_ROLLBACK; + break; + case SQLCOM_DROP_TABLE: + if (lex->drop_temporary) + flags= 0; + else + flags= sp_head::HAS_COMMIT_OR_ROLLBACK; + break; + case SQLCOM_CREATE_INDEX: + case SQLCOM_CREATE_DB: + case SQLCOM_CREATE_VIEW: + case SQLCOM_CREATE_TRIGGER: + case SQLCOM_CREATE_USER: + case SQLCOM_ALTER_TABLE: + case SQLCOM_BEGIN: + case SQLCOM_RENAME_TABLE: + case SQLCOM_RENAME_USER: + case SQLCOM_DROP_INDEX: + case SQLCOM_DROP_DB: + case SQLCOM_DROP_USER: + case SQLCOM_DROP_VIEW: + case SQLCOM_DROP_TRIGGER: + case SQLCOM_TRUNCATE: + case SQLCOM_COMMIT: + case SQLCOM_ROLLBACK: + case SQLCOM_LOAD_MASTER_DATA: + case SQLCOM_LOCK_TABLES: + case SQLCOM_CREATE_PROCEDURE: + case SQLCOM_CREATE_SPFUNCTION: + case SQLCOM_ALTER_PROCEDURE: + case SQLCOM_ALTER_FUNCTION: + case SQLCOM_DROP_PROCEDURE: + case SQLCOM_DROP_FUNCTION: + flags= sp_head::HAS_COMMIT_OR_ROLLBACK; + break; default: flags= 0; break; diff --git a/sql/sp_head.h b/sql/sp_head.h index d1a122fd410..8c2d58a696e 100644 --- a/sql/sp_head.h +++ b/sql/sp_head.h @@ -115,10 +115,13 @@ public: MULTI_RESULTS= 8, // Is set if a procedure with SELECT(s) CONTAINS_DYNAMIC_SQL= 16, // Is set if a procedure with PREPARE/EXECUTE IS_INVOKED= 32, // Is set if this sp_head is being used - HAS_SET_AUTOCOMMIT_STMT = 64 // Is set if a procedure with 'set autocommit' + HAS_SET_AUTOCOMMIT_STMT= 64,// Is set if a procedure with 'set autocommit' + /* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */ + HAS_COMMIT_OR_ROLLBACK= 128 }; - int m_type; // TYPE_ENUM_FUNCTION or TYPE_ENUM_PROCEDURE + /* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */ + int m_type; uint m_flags; // Boolean attributes of a stored routine enum enum_field_types m_returns; // For FUNCTIONs only Field::geometry_type m_geom_returns; @@ -292,6 +295,12 @@ public: my_error(ER_SP_NO_RETSET, MYF(0), where); else if (m_flags & HAS_SET_AUTOCOMMIT_STMT) my_error(ER_SP_CANT_SET_AUTOCOMMIT, MYF(0)); + else if (m_type != TYPE_ENUM_PROCEDURE && + (m_flags & sp_head::HAS_COMMIT_OR_ROLLBACK)) + { + my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); + return TRUE; + } return test(m_flags & (CONTAINS_DYNAMIC_SQL|MULTI_RESULTS|HAS_SET_AUTOCOMMIT_STMT)); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index e75b3ac3db5..5753c51fcf4 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -311,7 +311,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL); + mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL, + TRUE); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", @@ -1238,7 +1239,7 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root, /* close handler tables which are marked for flush */ if (thd->handler_tables) - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; @@ -1642,7 +1643,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 3c8702006f3..d5292be422b 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -376,7 +376,7 @@ void THD::cleanup(void) close_thread_tables(this); } mysql_ha_flush(this, (TABLE_LIST*) 0, - MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); + MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL, FALSE); hash_free(&handler_tables_hash); delete_dynamic(&user_var_events); hash_free(&user_vars); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index cc45a7001cd..da72d283259 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -336,6 +336,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ha_rows select_limit_cnt, ha_rows offset_limit_cnt) { TABLE_LIST *hash_tables; + TABLE **table_ptr; TABLE *table; MYSQL_LOCK *lock; List<Item> list; @@ -368,6 +369,28 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", hash_tables->db, hash_tables->table_name, hash_tables->alias, table)); + /* Table might have been flushed. */ + if (table && (table->s->version != refresh_version)) + { + /* + We must follow the thd->handler_tables chain, as we need the + address of the 'next' pointer referencing this table + for close_thread_table(). + */ + for (table_ptr= &(thd->handler_tables); + *table_ptr && (*table_ptr != table); + table_ptr= &(*table_ptr)->next) + {} + (*table_ptr)->file->ha_index_or_rnd_end(); + VOID(pthread_mutex_lock(&LOCK_open)); + if (close_thread_table(thd, table_ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } + VOID(pthread_mutex_unlock(&LOCK_open)); + table= hash_tables->table= NULL; + } if (!table) { /* @@ -594,6 +617,7 @@ err0: MYSQL_HA_REOPEN_ON_USAGE mark for reopen. MYSQL_HA_FLUSH_ALL flush all tables, not only those marked for flush. + is_locked If LOCK_open is locked. DESCRIPTION The list of HANDLER tables may be NULL, in which case all HANDLER @@ -601,7 +625,6 @@ err0: If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set, all HANDLER tables marked for flush are closed. Broadcasts a COND_refresh condition, for every table closed. - The caller must lock LOCK_open. NOTE Since mysql_ha_flush() is called when the base table has to be closed, @@ -611,10 +634,12 @@ err0: 0 ok */ -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked) { TABLE_LIST *tmp_tables; TABLE **table_ptr; + bool did_lock= FALSE; DBUG_ENTER("mysql_ha_flush"); DBUG_PRINT("enter", ("tables: %p mode_flags: 0x%02x", tables, mode_flags)); @@ -640,6 +665,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) (*table_ptr)->s->db, (*table_ptr)->s->table_name, (*table_ptr)->alias)); + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -658,6 +689,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) if ((mode_flags & MYSQL_HA_FLUSH_ALL) || ((*table_ptr)->s->version != refresh_version)) { + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -665,6 +702,10 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) } } + /* Release the lock if it was taken by this function. */ + if (did_lock) + VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_RETURN(0); } @@ -696,8 +737,8 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) table->alias, mode_flags)); if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, - (byte*) (*table_ptr)->alias, - strlen((*table_ptr)->alias) + 1))) + (byte*) table->alias, + strlen(table->alias) + 1))) { if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) { @@ -711,7 +752,9 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) } } + safe_mutex_assert_owner(&LOCK_open); (*table_ptr)->file->ha_index_or_rnd_end(); + safe_mutex_assert_owner(&LOCK_open); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index b90e45a133f..2659689a4bc 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2403,18 +2403,6 @@ mysql_execute_command(THD *thd) reset_one_shot_variables(thd); DBUG_RETURN(0); } -#ifndef TO_BE_DELETED - /* - This is a workaround to deal with the shortcoming in 3.23.44-3.23.46 - masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK() - as DO RELEASE_LOCK() - */ - if (lex->sql_command == SQLCOM_SELECT) - { - lex->sql_command = SQLCOM_DO; - lex->insert_list = &select_lex->item_list; - } -#endif } else #endif /* HAVE_REPLICATION */ diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0ae598eb094..a847c2a57a5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -11142,8 +11142,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, DBUG_ENTER("test_if_skip_sort_order"); LINT_INIT(ref_key_parts); - /* Check which keys can be used to resolve ORDER BY */ - usable_keys.set_all(); + /* + Check which keys can be used to resolve ORDER BY. + We must not try to use disabled keys. + */ + usable_keys= table->s->keys_in_use; + for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { Item *item= (*tmp_order->item)->real_item(); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index c0748abf333..815cdfe6cc5 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -103,23 +103,28 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists, /* mark for close and remove all cached entries */ - thd->mysys_var->current_mutex= &LOCK_open; - thd->mysys_var->current_cond= &COND_refresh; - VOID(pthread_mutex_lock(&LOCK_open)); - if (!drop_temporary) { if ((error= wait_if_global_read_lock(thd, 0, 1))) { my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0), tables->table_name); - goto err; + DBUG_RETURN(TRUE); } else need_start_waiters= TRUE; } + + /* + Acquire LOCK_open after wait_if_global_read_lock(). If we would hold + LOCK_open during wait_if_global_read_lock(), other threads could not + close their tables. This would make a pretty deadlock. + */ + thd->mysys_var->current_mutex= &LOCK_open; + thd->mysys_var->current_cond= &COND_refresh; + VOID(pthread_mutex_lock(&LOCK_open)); + error= mysql_rm_table_part2(thd, tables, if_exists, drop_temporary, 0, 0); -err: pthread_mutex_unlock(&LOCK_open); pthread_mutex_lock(&thd->mysys_var->mutex); @@ -232,7 +237,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, char *db=table->db; db_type table_type= DB_TYPE_UNKNOWN; - mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, TRUE); if (!close_temporary_table(thd, db, table->table_name)) { tmp_table_deleted=1; @@ -2171,7 +2176,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) DBUG_RETURN(TRUE); - mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, FALSE); for (table= tables; table; table= table->next_local) { char table_name[NAME_LEN*2+2]; @@ -3127,8 +3132,9 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, if (!new_db || !my_strcasecmp(table_alias_charset, new_db, db)) new_db= db; used_fields=create_info->used_fields; + + mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL, FALSE); - mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL); /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) DBUG_RETURN(mysql_discard_or_import_tablespace(thd,table_list, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c9ae6179ee9..85c07e6daba 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1159,11 +1159,6 @@ create: | CREATE opt_unique_or_fulltext INDEX_SYM ident key_alg ON table_ident { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_CREATE_INDEX; if (!lex->current_select->add_table_to_list(lex->thd, $7, NULL, TL_OPTION_UPDATING)) @@ -3299,11 +3294,6 @@ alter: { THD *thd= YYTHD; LEX *lex= thd->lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_ALTER_TABLE; lex->name= 0; lex->duplicates= DUP_ERROR; @@ -3614,11 +3604,6 @@ start: START_SYM TRANSACTION_SYM start_transaction_opts { LEX *lex= Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_BEGIN; lex->start_transaction_opt= $3; } @@ -3803,13 +3788,7 @@ opt_no_write_to_binlog: rename: RENAME table_or_tables { - LEX *lex= Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } - lex->sql_command=SQLCOM_RENAME_TABLE; + Lex->sql_command= SQLCOM_RENAME_TABLE; } table_to_table_list {} @@ -5946,21 +5925,10 @@ drop: lex->sql_command = SQLCOM_DROP_TABLE; lex->drop_temporary= $2; lex->drop_if_exists= $4; - if (!lex->drop_temporary && lex->sphead && - lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } } | DROP INDEX_SYM ident ON table_ident {} { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_DROP_INDEX; lex->alter_info.drop_list.empty(); lex->alter_info.drop_list.push_back(new Alter_drop(Alter_drop::KEY, @@ -6006,13 +5974,7 @@ drop: } | DROP VIEW_SYM if_exists table_list opt_restrict { - THD *thd= YYTHD; - LEX *lex= thd->lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } + LEX *lex= Lex; lex->sql_command= SQLCOM_DROP_VIEW; lex->drop_if_exists= $3; } @@ -8652,11 +8614,6 @@ begin: BEGIN_SYM { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command = SQLCOM_BEGIN; lex->start_transaction_opt= 0; } @@ -8689,11 +8646,6 @@ commit: COMMIT_SYM opt_work opt_chain opt_release { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_COMMIT; lex->tx_chain= $3; lex->tx_release= $4; @@ -8704,11 +8656,6 @@ rollback: ROLLBACK_SYM opt_work opt_chain opt_release { LEX *lex=Lex; - if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE) - { - my_error(ER_COMMIT_NOT_ALLOWED_IN_SF_OR_TRG, MYF(0)); - YYABORT; - } lex->sql_command= SQLCOM_ROLLBACK; lex->tx_chain= $3; lex->tx_release= $4; |