#At file:///home/kgeorge/mysql/bzr/merge-6.0-bugteam/
2808 Georgi Kodinov 2008-08-28 [merge]
merged 6.0-main -> 6.0-bugteam
added:
mysql-test/include/wait_for_slave_sql_error_and_skip.inc
mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result
mysql-test/suite/rpl/t/rpl_filter_tables_not_exist-slave.opt
mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test
modified:
configure.in
libmysql/CMakeLists.txt
mysql-test/extra/binlog_tests/database.test
mysql-test/include/have_falcon.inc
mysql-test/r/multi_update.result
mysql-test/suite/binlog/r/binlog_database.result
mysql-test/suite/falcon/r/falcon_bug_22165.result
mysql-test/suite/falcon/t/falcon_bug_22165.test
sql/log_event.cc
sql/log_event.h
sql/sql_class.cc
sql/sql_class.h
sql/sql_db.cc
sql/sql_parse.cc
sql/sql_update.cc
storage/falcon/BackLog.cpp
storage/falcon/CMakeLists.txt
storage/falcon/Configuration.cpp
storage/falcon/IO.cpp
storage/falcon/Index.cpp
storage/falcon/Index2RootPage.cpp
storage/falcon/IndexRootPage.cpp
storage/falcon/Interlock.h
storage/falcon/MemMgr.cpp
storage/falcon/RepositoryVolume.cpp
storage/falcon/Statement.cpp
storage/falcon/StorageDatabase.cpp
storage/falcon/StorageDatabase.h
storage/falcon/StorageTable.cpp
storage/falcon/StorageTable.h
storage/falcon/StorageTableShare.cpp
storage/falcon/StorageTableShare.h
storage/falcon/Table.cpp
storage/falcon/Table.h
storage/falcon/TableSpace.cpp
storage/falcon/Transaction.cpp
storage/falcon/Transaction.h
storage/falcon/TransactionManager.cpp
storage/falcon/ha_falcon.cpp
storage/falcon/ha_falcon.h
storage/falcon/plug.in
storage/maria/CMakeLists.txt
=== modified file 'configure.in'
--- a/configure.in 2008-08-26 19:16:28 +0000
+++ b/configure.in 2008-08-28 08:44:13 +0000
@@ -1797,6 +1797,9 @@ if test "x$mysql_cv_gcc_atomic_builtins"
[Define to 1 if compiler provides atomic builtins.])
fi
+# Check if we have the atomic_* functions on Solaris
+AC_CHECK_FUNC(atomic_cas_32, AC_DEFINE([HAVE_SOLARIS_ATOMIC], [1], [Define to 1 if Solaris support atomic functions.]))
+
# Force static compilation to avoid linking problems/get more speed
AC_ARG_WITH(mysqld-ldflags,
[ --with-mysqld-ldflags Extra linking arguments for mysqld],
=== modified file 'libmysql/CMakeLists.txt'
--- a/libmysql/CMakeLists.txt 2008-05-29 15:44:11 +0000
+++ b/libmysql/CMakeLists.txt 2008-08-26 18:57:58 +0000
@@ -98,7 +98,7 @@ SET(CLIENT_SOURCES ../mysys/array.c ..
../strings/strtoll.c ../strings/strtoull.c ../strings/strxmov.c ../strings/strxnmov.c
../mysys/thr_mutex.c ../mysys/typelib.c ../vio/vio.c ../vio/viosocket.c
../vio/viossl.c ../vio/viosslfactories.c ../strings/xml.c ../mysys/mf_qsort.c
- ../mysys/my_getsystime.c ../mysys/my_sync.c ${LIB_SOURCES})
+ ../mysys/my_getsystime.c ${LIB_SOURCES})
# Need to set USE_TLS for building the DLL, since __declspec(thread)
# approach to thread local storage does not work properly in DLLs.
=== modified file 'mysql-test/extra/binlog_tests/database.test'
--- a/mysql-test/extra/binlog_tests/database.test 2007-11-16 14:55:22 +0000
+++ b/mysql-test/extra/binlog_tests/database.test 2008-08-27 08:40:11 +0000
@@ -13,3 +13,18 @@ create trigger tr1 before insert on t1 f
create procedure sp1 (a int) insert into t1 values(a);
drop database testing_1;
source include/show_binlog_events.inc;
+
+# BUG#38773: DROP DATABASE cause switch to stmt-mode when there are
+# temporary tables open
+
+use test;
+reset master;
+create temporary table tt1 (a int);
+create table t1 (a int);
+insert into t1 values (1);
+disable_warnings;
+drop database if exists mysqltest1;
+enable_warnings;
+insert into t1 values (1);
+drop table tt1, t1;
+source include/show_binlog_events.inc;
=== modified file 'mysql-test/include/have_falcon.inc'
--- a/mysql-test/include/have_falcon.inc 2008-03-30 13:57:32 +0000
+++ b/mysql-test/include/have_falcon.inc 2008-08-15 11:06:08 +0000
@@ -1,5 +1,18 @@
+##
+## Checks for the presence of the Falcon storage engine (plugin)
+## by querying the INFORMATION_SCHEMA.ENGINES table.
+##
+## If Falcon is not available, the test using this include file
+## is skipped.
+##
+
+# Do not echo these statements to test results
--disable_query_log
-# Ignore errors when trying to install the Falcon plugin
---require r/true.require
-SELECT (support = 'YES' OR support = 'DEFAULT' OR support = 'ENABLED') AS `TRUE` FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'Falcon';
+
+# Check if Falcon is available
+let $have_falcon = `SELECT (support = 'YES' OR support = 'DEFAULT' OR support = 'ENABLED') AS 'HAVE_FALCON' FROM INFORMATION_SCHEMA.ENGINES WHERE ENGINE = 'Falcon'`;
+if (!$have_falcon)
+{
+ skip Test needs the Falcon storage engine;
+}
--enable_query_log
=== added file 'mysql-test/include/wait_for_slave_sql_error_and_skip.inc'
--- a/mysql-test/include/wait_for_slave_sql_error_and_skip.inc 1970-01-01 00:00:00 +0000
+++ b/mysql-test/include/wait_for_slave_sql_error_and_skip.inc 2008-08-26 12:29:33 +0000
@@ -0,0 +1,24 @@
+# ==== Purpose ====
+#
+# Wait for slave SQL error, skip the erroneous statement and restart
+# slave
+#
+# ==== Usage ====
+#
+# let show_sql_error=0|1;
+# source include/wait_for_slave_sql_error_and_skip.inc;
+
+echo --source include/wait_for_slave_sql_error_and_skip.inc;
+connection slave;
+source include/wait_for_slave_sql_error.inc;
+if ($show_sql_error)
+{
+ let $error= query_get_value("SHOW SLAVE STATUS", Last_SQL_Error, 1);
+ echo Last_SQL_Error = $error;
+}
+
+# skip the erroneous statement
+set global sql_slave_skip_counter=1;
+start slave;
+source include/wait_for_slave_to_start.inc;
+connection master;
=== modified file 'mysql-test/r/multi_update.result'
--- a/mysql-test/r/multi_update.result 2008-04-01 15:13:57 +0000
+++ b/mysql-test/r/multi_update.result 2008-08-26 12:29:33 +0000
@@ -627,7 +627,7 @@ a b
4 4
show master status /* there must be the UPDATE query event */;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 198
+master-bin.000001 207
delete from t1;
delete from t2;
insert into t1 values (1,2),(3,4),(4,4);
@@ -637,7 +637,7 @@ UPDATE t2,t1 SET t2.a=t2.b where t2.a=t
ERROR 23000: Duplicate entry '4' for key 'PRIMARY'
show master status /* there must be the UPDATE query event */;
File Position Binlog_Do_DB Binlog_Ignore_DB
-master-bin.000001 213
+master-bin.000001 222
drop table t1, t2;
set @@session.binlog_format= @sav_binlog_format;
drop table if exists t1, t2, t3;
=== modified file 'mysql-test/suite/binlog/r/binlog_database.result'
--- a/mysql-test/suite/binlog/r/binlog_database.result 2008-05-16 15:35:15 +0000
+++ b/mysql-test/suite/binlog/r/binlog_database.result 2008-08-27 08:40:11 +0000
@@ -17,6 +17,22 @@ master-bin.000001 # Query # # use `testi
master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `sp1`(a int)
insert into t1 values(a)
master-bin.000001 # Query # # drop database testing_1
+use test;
+reset master;
+create temporary table tt1 (a int);
+create table t1 (a int);
+insert into t1 values (1);
+drop database if exists mysqltest1;
+insert into t1 values (1);
+drop table tt1, t1;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; create temporary table tt1 (a int)
+master-bin.000001 # Query # # use `test`; create table t1 (a int)
+master-bin.000001 # Query # # use `test`; insert into t1 values (1)
+master-bin.000001 # Query # # drop database if exists mysqltest1
+master-bin.000001 # Query # # use `test`; insert into t1 values (1)
+master-bin.000001 # Query # # use `test`; drop table tt1, t1
set binlog_format=mixed;
reset master;
create database testing_1;
@@ -36,6 +52,22 @@ master-bin.000001 # Query # # use `testi
master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `sp1`(a int)
insert into t1 values(a)
master-bin.000001 # Query # # drop database testing_1
+use test;
+reset master;
+create temporary table tt1 (a int);
+create table t1 (a int);
+insert into t1 values (1);
+drop database if exists mysqltest1;
+insert into t1 values (1);
+drop table tt1, t1;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; create temporary table tt1 (a int)
+master-bin.000001 # Query # # use `test`; create table t1 (a int)
+master-bin.000001 # Query # # use `test`; insert into t1 values (1)
+master-bin.000001 # Query # # drop database if exists mysqltest1
+master-bin.000001 # Query # # use `test`; insert into t1 values (1)
+master-bin.000001 # Query # # use `test`; drop table tt1, t1
set binlog_format=row;
reset master;
create database testing_1;
@@ -55,6 +87,27 @@ master-bin.000001 # Query # # use `testi
master-bin.000001 # Query # # use `testing_1`; CREATE DEFINER=`root`@`localhost` PROCEDURE `sp1`(a int)
insert into t1 values(a)
master-bin.000001 # Query # # drop database testing_1
+use test;
+reset master;
+create temporary table tt1 (a int);
+create table t1 (a int);
+insert into t1 values (1);
+drop database if exists mysqltest1;
+insert into t1 values (1);
+drop table tt1, t1;
+show binlog events from <binlog_start>;
+Log_name Pos Event_type Server_id End_log_pos Info
+master-bin.000001 # Query # # use `test`; create table t1 (a int)
+master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # drop database if exists mysqltest1
+master-bin.000001 # Query # # use `test`; BEGIN
+master-bin.000001 # Table_map # # table_id: # (test.t1)
+master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
+master-bin.000001 # Query # # use `test`; COMMIT
+master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
show databases;
Database
information_schema
=== modified file 'mysql-test/suite/falcon/r/falcon_bug_22165.result'
--- a/mysql-test/suite/falcon/r/falcon_bug_22165.result 2008-08-04 15:53:52 +0000
+++ b/mysql-test/suite/falcon/r/falcon_bug_22165.result 2008-08-21 13:18:06 +0000
@@ -16,7 +16,10 @@ while v < 10 do
START TRANSACTION;
INSERT INTO t1 (a, b) VALUES (v, 'a');
UPDATE t1 SET c = current_timestamp WHERE a = v;
-COMMIT;
+IF (v < 5)
+THEN COMMIT;
+ELSE ROLLBACK;
+END IF;
SET v = v + 1;
end while;
end//
=== modified file 'mysql-test/suite/falcon/t/falcon_bug_22165.test'
--- a/mysql-test/suite/falcon/t/falcon_bug_22165.test 2008-08-04 15:53:52 +0000
+++ b/mysql-test/suite/falcon/t/falcon_bug_22165.test 2008-08-21 13:18:06 +0000
@@ -30,7 +30,10 @@ begin
START TRANSACTION;
INSERT INTO t1 (a, b) VALUES (v, 'a');
UPDATE t1 SET c = current_timestamp WHERE a = v;
- COMMIT;
+ IF (v < 5)
+ THEN COMMIT;
+ ELSE ROLLBACK;
+ END IF;
SET v = v + 1;
end while;
end//
@@ -57,7 +60,7 @@ while ($i)
--reap
connection conn2;
--reap
-
+
dec $i;
}
--enable_query_log
=== added file 'mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result'
--- a/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_filter_tables_not_exist.result 2008-08-26 12:29:33 +0000
@@ -0,0 +1,151 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1 (id int, a int);
+CREATE TABLE t2 (id int, b int);
+CREATE TABLE t3 (id int, c int);
+CREATE TABLE t4 (id int, d int);
+CREATE TABLE t5 (id int, e int);
+CREATE TABLE t6 (id int, f int);
+CREATE TABLE t7 (id int, g int);
+CREATE TABLE t8 (id int, h int);
+CREATE TABLE t9 (id int, i int);
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t5 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t6 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t7 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t8 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t9 VALUES (1, 1), (2, 2), (3, 3);
+[on slave]
+SHOW TABLES LIKE 't%';
+Tables_in_test (t%)
+t1
+t2
+t3
+[on master]
+UPDATE t7 LEFT JOIN t4 ON (t4.id=t7.id) SET d=0, g=0 where t7.id=1;
+UPDATE t7 LEFT JOIN (t4, t5, t6) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t6.id) SET d=0, e=0, f=0, g=0 where t7.id=1;
+UPDATE t4 LEFT JOIN (t7, t8, t9) ON (t4.id=t7.id and t4.id=t8.id and t4.id=t9.id) SET d=0, g=0, h=0, i=0 where t4.id=1;
+UPDATE t7 LEFT JOIN (t8, t9) ON (t7.id=t8.id and t7.id=t9.id) SET g=0, h=0, i=0 where t7.id=1;
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET d=0 where t1.id=1;
+UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET g=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET d=0, e=0, f=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t4, t5, t8) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t8.id) SET d=0, e=0, h=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t7, t8, t5) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t5.id) SET g=0, h=0, e=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t2, t3, t5) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t5.id) SET e=0 where t1.id=1;
+UPDATE t4 LEFT JOIN t1 ON (t1.id=t4.id) SET a=0, d=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t7) ON (t4.id=t1.id and t7.id=t4.id) SET a = 0, d=0, g=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t2, t3) ON (t1.id=t4.id and t2.id=t4.id and t3.id=t4.id) SET a=0, b=0, c=0, d=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t2, t5) ON (t1.id=t4.id and t2.id=t4.id and t5.id=t4.id) SET a=0, b=0, e=0, d=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t6, t7) ON (t4.id=t1.id and t4.id=t6.id and t4.id=t7.id) SET a=0, d=0, f=0, g=0 where t4.id=1;
+UPDATE t7 LEFT JOIN (t4, t1, t2) ON (t7.id=t4.id and t7.id=t1.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
+UPDATE t7 LEFT JOIN (t8, t4, t1) ON (t7.id=t8.id and t7.id=t4.id and t7.id=t1.id) SET a=0, d=0, g=0, h=0 where t7.id=1;
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t4' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
+--source include/wait_for_slave_sql_error_and_skip.inc
+Last_SQL_Error = Error 'Table 'test.t7' doesn't exist' on query. Default database: 'test'. Query: 'UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1'
+set global sql_slave_skip_counter=1;
+start slave;
+[on slave]
+show tables like 't%';
+Tables_in_test (t%)
+t1
+t2
+t3
+SELECT * FROM t1;
+id a
+1 1
+2 2
+3 3
+SELECT * FROM t2;
+id b
+1 1
+2 2
+3 3
+SELECT * FROM t3;
+id c
+1 1
+2 2
+3 3
+[on master]
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
=== added file 'mysql-test/suite/rpl/t/rpl_filter_tables_not_exist-slave.opt'
--- a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist-slave.opt 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist-slave.opt 2008-08-26 12:29:33 +0000
@@ -0,0 +1 @@
+--replicate-do-table=test.t1 --replicate-do-table=test.t2 --replicate-do-table=test.t3 --replicate-ignore-table=test.t4 --replicate-ignore-table=test.t5 --replicate-ignore-table=test.t6
=== added file 'mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test'
--- a/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_filter_tables_not_exist.test 2008-08-26 12:29:33 +0000
@@ -0,0 +1,205 @@
+# Test evaluation of replication table filter rules
+#
+# ==== Purpose ====
+#
+# Test if replication table filter rules are properly evaluated when
+# some of the tables referenced by the multiple-table update do not
+# exist on slave.
+#
+# ==== Method ====
+#
+# Master creates tables t1, t2, t3, t4, t5, t6, t7, t8, t9 and the
+# slave is started with the following replication table filter rules:
+#
+# --replicate-do-table=t1
+# --replicate-do-table=t2
+# --replicate-do-table=t3
+#
+# and
+#
+# --replicate-ignore-table=t4
+# --replicate-ignore-table=t5
+# --replicate-ignore-table=t6
+#
+# So the slave only replicate changes to tables t1, t2 and t3 and only
+# these tables exist on slave.
+#
+# From now on, tables t1, t2, and t3 are referenced as do tables,
+# tables t4, t5, t6 are referenced as ignore tables, and tables t7,
+# t8, t9 are referenced as other tables.
+#
+# All multi-table update tests reference tables that are not do
+# tables, which do not exist on slave. And the following situations
+# of multi-table update will be tested:
+#
+# 1. Do tables are not referenced at all
+# 2. Do tables are not referenced for update
+# 3. Ignore tables are referenced for update before do tables
+# 4. Only do tables are referenced for update
+# 5. Do tables and other tables are referenced for update
+# 6. Do tables are referenced for update before ignore tables
+#
+# For 1, 2 and 3, the statement should be ignored by slave, for 4, 5
+# and 6 the statement should be accepted by slave and cause an error
+# because of non-exist tables.
+#
+# ==== Related bugs ====
+#
+# BUG#37051 Replication rules not evaluated correctly
+
+
+source include/have_binlog_format_statement.inc;
+source include/master-slave.inc;
+
+# These tables are mentioned in do-table rules
+CREATE TABLE t1 (id int, a int);
+CREATE TABLE t2 (id int, b int);
+CREATE TABLE t3 (id int, c int);
+
+# These tables are mentioned in ignore-table rules
+CREATE TABLE t4 (id int, d int);
+CREATE TABLE t5 (id int, e int);
+CREATE TABLE t6 (id int, f int);
+
+# These tables are not mentioned in do-table or ignore-table rules
+CREATE TABLE t7 (id int, g int);
+CREATE TABLE t8 (id int, h int);
+CREATE TABLE t9 (id int, i int);
+
+INSERT INTO t1 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t2 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t3 VALUES (1, 1), (2, 2), (3, 3);
+
+INSERT INTO t4 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t5 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t6 VALUES (1, 1), (2, 2), (3, 3);
+
+INSERT INTO t7 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t8 VALUES (1, 1), (2, 2), (3, 3);
+INSERT INTO t9 VALUES (1, 1), (2, 2), (3, 3);
+
+# Only t1, t2, t3 should be replicated to slave
+sync_slave_with_master;
+echo [on slave];
+SHOW TABLES LIKE 't%';
+
+connection master;
+echo [on master];
+
+#
+# Do tables are not referenced, these statements should be ignored by
+# slave.
+#
+UPDATE t7 LEFT JOIN t4 ON (t4.id=t7.id) SET d=0, g=0 where t7.id=1;
+UPDATE t7 LEFT JOIN (t4, t5, t6) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t6.id) SET d=0, e=0, f=0, g=0 where t7.id=1;
+UPDATE t4 LEFT JOIN (t7, t8, t9) ON (t4.id=t7.id and t4.id=t8.id and t4.id=t9.id) SET d=0, g=0, h=0, i=0 where t4.id=1;
+UPDATE t7 LEFT JOIN (t8, t9) ON (t7.id=t8.id and t7.id=t9.id) SET g=0, h=0, i=0 where t7.id=1;
+
+#
+# Do tables are not referenced for update, these statements should be
+# ignored by slave.
+#
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET d=0 where t1.id=1;
+UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET g=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET d=0, e=0, f=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t4, t5, t8) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t8.id) SET d=0, e=0, h=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t7, t8, t5) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t5.id) SET g=0, h=0, e=0 where t1.id=1;
+UPDATE t1 LEFT JOIN (t2, t3, t5) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t5.id) SET e=0 where t1.id=1;
+
+#
+# Ignore tables are referenced for update before do tables, these
+# statements should be ignore by slave.
+#
+UPDATE t4 LEFT JOIN t1 ON (t1.id=t4.id) SET a=0, d=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t7) ON (t4.id=t1.id and t7.id=t4.id) SET a = 0, d=0, g=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t2, t3) ON (t1.id=t4.id and t2.id=t4.id and t3.id=t4.id) SET a=0, b=0, c=0, d=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t2, t5) ON (t1.id=t4.id and t2.id=t4.id and t5.id=t4.id) SET a=0, b=0, e=0, d=0 where t4.id=1;
+UPDATE t4 LEFT JOIN (t1, t6, t7) ON (t4.id=t1.id and t4.id=t6.id and t4.id=t7.id) SET a=0, d=0, f=0, g=0 where t4.id=1;
+UPDATE t7 LEFT JOIN (t4, t1, t2) ON (t7.id=t4.id and t7.id=t1.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
+UPDATE t7 LEFT JOIN (t8, t4, t1) ON (t7.id=t8.id and t7.id=t4.id and t7.id=t1.id) SET a=0, d=0, g=0, h=0 where t7.id=1;
+
+# Sync slave to make sure all above statements are correctly ignored,
+# if any of the above statement are not ignored, it would cause error
+# and stop slave sql thread.
+sync_slave_with_master;
+connection master;
+
+# Parameter for include/wait_for_slave_sql_error_and_skip.inc, ask it
+# to show SQL error message
+let show_sql_error=1;
+
+#
+# Only do tables are referenced for update, these statements should
+# cause error on slave
+#
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t1 LEFT JOIN (t4, t7) ON (t1.id=t4.id and t1.id=t7.id) SET a=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t1 LEFT JOIN (t2, t4, t7) ON (t1.id=t2.id and t1.id=t4.id and t1.id=t7.id) SET a=0, b=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t1 LEFT JOIN (t2, t3, t7) ON (t1.id=t2.id and t1.id=t3.id and t1.id=t7.id) SET a=0, b=0, c=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+#
+# Do tables and other tables are referenced for update, these
+# statements should cause error on slave
+#
+UPDATE t1 LEFT JOIN t7 ON (t1.id=t7.id) SET a=0, g=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t7 LEFT JOIN t1 ON (t1.id=t7.id) SET a=0, g=0 where t7.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t1 LEFT JOIN (t4, t5, t7) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t7.id) SET a=0, g=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t1 LEFT JOIN (t4, t7, t8) ON (t1.id=t4.id and t1.id=t7.id and t1.id=t8.id) SET a=0, g=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t1 LEFT JOIN (t7, t8, t9) ON (t1.id=t7.id and t1.id=t8.id and t1.id=t9.id) SET a=0, g=0, h=0, i=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t7 LEFT JOIN (t1, t2, t3) ON (t7.id=t1.id and t7.id=t2.id and t7.id=t3.id) SET g=0, a=0, b=0, c=0 where t7.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t7 LEFT JOIN (t4, t5, t3) ON (t7.id=t4.id and t7.id=t5.id and t7.id=t3.id) SET g=0, c=0 where t7.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t7 LEFT JOIN (t8, t9, t3) ON (t7.id=t8.id and t7.id=t9.id and t7.id=t3.id) SET g=0, h=0, i=0, c=0 where t7.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+#
+# Do tables are referenced for update before ignore tables
+#
+UPDATE t1 LEFT JOIN t4 ON (t1.id=t4.id) SET a=0, d=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t1 LEFT JOIN (t4, t5, t6) ON (t1.id=t4.id and t1.id=t5.id and t1.id=t6.id) SET a=0, d=0, e=0, f=0 where t1.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t4 LEFT JOIN (t1, t5, t6) ON (t4.id=t1.id and t4.id=t5.id and t4.id=t6.id) SET a=0, e=0, f=0 where t4.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+UPDATE t7 LEFT JOIN (t1, t4, t2) ON (t7.id=t1.id and t7.id=t4.id and t7.id=t2.id) SET a=0, b=0, d=0, g=0 where t7.id=1;
+source include/wait_for_slave_sql_error_and_skip.inc;
+
+sync_slave_with_master;
+echo [on slave];
+
+# We should only have tables t1, t2, t3 on slave
+show tables like 't%';
+
+# The rows in these tables should remain untouched
+SELECT * FROM t1;
+SELECT * FROM t2;
+SELECT * FROM t3;
+
+# Clean up
+connection master;
+echo [on master];
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+source include/master-slave-end.inc;
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2008-08-25 08:12:02 +0000
+++ b/sql/log_event.cc 2008-08-27 18:54:03 +0000
@@ -2050,6 +2050,11 @@ void Query_log_event::pack_info(Protocol
static void write_str_with_code_and_len(char **dst, const char *src,
int len, uint code)
{
+ /*
+ only 1 byte to store the length of catalog, so it should not
+ surpass 255
+ */
+ DBUG_ASSERT(len <= 255);
DBUG_ASSERT(src);
*((*dst)++)= code;
*((*dst)++)= (uchar) len;
@@ -2069,21 +2074,8 @@ static void write_str_with_code_and_len(
bool Query_log_event::write(IO_CACHE* file)
{
- /**
- @todo if catalog can be of length FN_REFLEN==512, then we are not
- replicating it correctly, since the length is stored in a byte
- /sven
- */
- uchar buf[QUERY_HEADER_LEN+
- 1+4+ // code of flags2 and flags2
- 1+8+ // code of sql_mode and sql_mode
- 1+1+FN_REFLEN+ // code of catalog and catalog length and catalog
- 1+4+ // code of autoinc and the 2 autoinc variables
- 1+6+ // code of charset and charset
- 1+1+MAX_TIME_ZONE_NAME_LENGTH+ // code of tz and tz length and tz name
- 1+2+ // code of lc_time_names and lc_time_names_number
- 1+2 // code of charset_database and charset_database_number
- ], *start, *start_of_status;
+ uchar buf[QUERY_HEADER_LEN + MAX_SIZE_LOG_EVENT_STATUS];
+ uchar *start, *start_of_status;
ulong event_length;
if (!query)
@@ -2189,10 +2181,8 @@ bool Query_log_event::write(IO_CACHE* fi
{
/* In the TZ sys table, column Name is of length 64 so this should be ok */
DBUG_ASSERT(time_zone_len <= MAX_TIME_ZONE_NAME_LENGTH);
- *start++= Q_TIME_ZONE_CODE;
- *start++= time_zone_len;
- memcpy(start, time_zone_str, time_zone_len);
- start+= time_zone_len;
+ write_str_with_code_and_len((char **)(&start),
+ time_zone_str, time_zone_len, Q_TIME_ZONE_CODE);
}
if (lc_time_names_number)
{
@@ -2208,7 +2198,17 @@ bool Query_log_event::write(IO_CACHE* fi
int2store(start, charset_database_number);
start+= 2;
}
+ if (table_map_for_update)
+ {
+ *start++= Q_TABLE_MAP_FOR_UPDATE_CODE;
+ int8store(start, table_map_for_update);
+ start+= 8;
+ }
/*
+ NOTE: When adding new status vars, please don't forget to update
+ the MAX_SIZE_LOG_EVENT_STATUS in log_event.h and update function
+ code_name in this file.
+
Here there could be code like
if (command-line-option-which-says-"log_this_variable" && inited)
{
@@ -2285,7 +2285,8 @@ Query_log_event::Query_log_event(THD* th
auto_increment_increment(thd_arg->variables.auto_increment_increment),
auto_increment_offset(thd_arg->variables.auto_increment_offset),
lc_time_names_number(thd_arg->variables.lc_time_names->number),
- charset_database_number(0)
+ charset_database_number(0),
+ table_map_for_update((ulonglong)thd_arg->table_map_for_update)
{
time_t end_time;
@@ -2414,6 +2415,7 @@ code_name(int code)
case Q_CATALOG_NZ_CODE: return "Q_CATALOG_NZ_CODE";
case Q_LC_TIME_NAMES_CODE: return "Q_LC_TIME_NAMES_CODE";
case Q_CHARSET_DATABASE_CODE: return "Q_CHARSET_DATABASE_CODE";
+ case Q_TABLE_MAP_FOR_UPDATE_CODE: return "Q_TABLE_MAP_FOR_UPDATE_CODE";
}
sprintf(buf, "CODE#%d", code);
return buf;
@@ -2450,7 +2452,8 @@ Query_log_event::Query_log_event(const c
db(NullS), catalog_len(0), status_vars_len(0),
flags2_inited(0), sql_mode_inited(0), charset_inited(0),
auto_increment_increment(1), auto_increment_offset(1),
- time_zone_len(0), lc_time_names_number(0), charset_database_number(0)
+ time_zone_len(0), lc_time_names_number(0), charset_database_number(0),
+ table_map_for_update(0)
{
ulong data_len;
uint32 tmp;
@@ -2592,6 +2595,11 @@ Query_log_event::Query_log_event(const c
charset_database_number= uint2korr(pos);
pos+= 2;
break;
+ case Q_TABLE_MAP_FOR_UPDATE_CODE:
+ CHECK_SPACE(pos, end, 8);
+ table_map_for_update= uint8korr(pos);
+ pos+= 8;
+ break;
default:
/* That's why you must write status vars in growing order of code */
DBUG_PRINT("info",("Query_log_event has unknown status vars (first has\
@@ -2999,6 +3007,8 @@ int Query_log_event::do_apply_event(Rela
else
thd->variables.collation_database= thd->db_charset;
+ thd->table_map_for_update= (table_map)table_map_for_update;
+
/* Execute the query (note that we bypass dispatch_command()) */
const char* found_semicolon= NULL;
mysql_parse(thd, thd->query, thd->query_length, &found_semicolon);
=== modified file 'sql/log_event.h'
--- a/sql/log_event.h 2008-08-22 06:48:55 +0000
+++ b/sql/log_event.h 2008-08-27 18:54:03 +0000
@@ -246,12 +246,15 @@ struct sql_ex_info
packet (i.e. a query) sent from client to master;
First, an auxiliary log_event status vars estimation:
*/
-#define MAX_SIZE_LOG_EVENT_STATUS (4 /* flags2 */ + \
- 8 /* sql mode */ + \
- 1 + 1 + 255 /* catalog */ + \
- 4 /* autoinc */ + \
- 6 /* charset */ + \
- MAX_TIME_ZONE_NAME_LENGTH)
+#define MAX_SIZE_LOG_EVENT_STATUS (1 + 4 /* type, flags2 */ + \
+ 1 + 8 /* type, sql_mode */ + \
+ 1 + 1 + 255 /* type, length, catalog */ + \
+ 1 + 4 /* type, auto_increment */ + \
+ 1 + 6 /* type, charset */ + \
+ 1 + 1 + 255 /* type, length, time_zone */ + \
+ 1 + 2 /* type, lc_time_names_number */ + \
+ 1 + 2 /* type, charset_database_number */ + \
+ 1 + 8 /* type, table_map_for_update */)
#define MAX_LOG_EVENT_HEADER ( /* in order of Query_log_event::write */ \
LOG_EVENT_HEADER_LEN + /* write_header */ \
QUERY_HEADER_LEN + /* write_data */ \
@@ -315,6 +318,8 @@ struct sql_ex_info
#define Q_LC_TIME_NAMES_CODE 7
#define Q_CHARSET_DATABASE_CODE 8
+
+#define Q_TABLE_MAP_FOR_UPDATE_CODE 9
/* Intvar event post-header */
#define I_TYPE_OFFSET 0
@@ -1490,6 +1495,22 @@ protected:
This field is written if it is not 0.
</td>
</tr>
+ <tr>
+ <td>table_map_for_update</td>
+ <td>Q_TABLE_MAP_FOR_UPDATE_CODE == 9</td>
+ <td>8 byte integer</td>
+
+ <td>The value of the table map that is to be updated by the
+ multi-table update query statement. Every bit of this variable
+ represents a table, and is set to 1 if the corresponding table is
+ to be updated by this statement.
+
+ The value of this variable is set when executing a multi-table update
+ statement and used by slave to apply filter rules without opening
+ all the tables on slave. This is required because some tables may
+ not exist on slave because of the filter rules.
+ </td>
+ </tr>
</table>
@subsection Query_log_event_notes_on_previous_versions Notes on Previous Versions
@@ -1506,6 +1527,9 @@ protected:
* See Q_CHARSET_DATABASE_CODE in the table above.
+ * When adding new status vars, please don't forget to update the
+ MAX_SIZE_LOG_EVENT_STATUS, and update function code_name
+
*/
class Query_log_event: public Log_event
{
@@ -1583,6 +1607,11 @@ public:
const char *time_zone_str;
uint lc_time_names_number; /* 0 means en_US */
uint charset_database_number;
+ /*
+ map for tables that will be updated for a multi-table update query
+ statement, for other query statements, this will be zero.
+ */
+ ulonglong table_map_for_update;
#ifndef MYSQL_CLIENT
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2008-08-26 19:16:28 +0000
+++ b/sql/sql_class.cc 2008-08-28 08:44:13 +0000
@@ -513,6 +513,7 @@ THD::THD()
lock_id(&main_lock_id),
user_time(0), in_sub_stmt(0),
binlog_table_maps(0), binlog_flags(0UL),
+ table_map_for_update(0),
arg_of_last_insert_id_function(FALSE),
first_successful_insert_id_in_prev_stmt(0),
first_successful_insert_id_in_prev_stmt_for_binlog(0),
@@ -1156,6 +1157,8 @@ void THD::cleanup_after_query()
free_items();
/* Reset where. */
where= THD::DEFAULT_WHERE;
+ /* reset table map for multi-table update */
+ table_map_for_update= 0;
}
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2008-08-25 12:25:07 +0000
+++ b/sql/sql_class.h 2008-08-27 18:54:03 +0000
@@ -442,7 +442,6 @@ struct system_variables
DATE_TIME_FORMAT *datetime_format;
DATE_TIME_FORMAT *time_format;
my_bool sysdate_is_now;
-
};
@@ -1587,6 +1586,13 @@ public:
Note: in the parser, stmt_arena == thd, even for PS/SP.
*/
Query_arena *stmt_arena;
+
+ /*
+ map for tables that will be updated for a multi-table update query
+ statement, for other query statements, this will be zero.
+ */
+ table_map table_map_for_update;
+
/* Tells if LAST_INSERT_ID(#) was called for the current statement */
bool arg_of_last_insert_id_function;
/*
=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc 2008-06-27 16:10:42 +0000
+++ b/sql/sql_db.cc 2008-08-27 08:47:03 +0000
@@ -883,13 +883,6 @@ bool mysql_rm_db(THD *thd,char *db,bool
pthread_mutex_lock(&LOCK_mysql_create_db);
- /*
- This statement will be replicated as a statement, even when using
- row-based replication. The flag will be reset at the end of the
- statement.
- */
- thd->clear_current_stmt_binlog_row_based();
-
length= build_table_filename(path, sizeof(path), db, "", "", 0);
strmov(path+length, MY_DB_OPT_FILE); // Append db option file name
del_dbopt(path); // Remove dboption hash entry
@@ -911,16 +904,36 @@ bool mysql_rm_db(THD *thd,char *db,bool
else
{
error= -1;
+ /*
+ We temporarily disable the binary log while dropping the objects
+ in the database. Since the DROP DATABASE statement is always
+ replicated as a statement, execution of it will drop all objects
+ in the database on the slave as well, so there is no need to
+ replicate the removal of the individual objects in the database
+ as well.
+
+ This is more of a safety precaution, since normally no objects
+ should be dropped while the database is being cleaned, but in
+ the event that a change in the code to remove other objects is
+ made, these drops should still not be logged.
+
+ Notice that the binary log have to be enabled over the call to
+ ha_drop_database(), since NDB otherwise detects the binary log
+ as disabled and will not log the drop database statement on any
+ other connected server.
+ */
if ((deleted= mysql_rm_known_files(thd, dirp, db, path, 0,
&dropped_tables)) >= 0)
{
ha_drop_database(path);
+ tmp_disable_binlog(thd);
query_cache_invalidate1(db);
(void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
#ifdef HAVE_EVENT_SCHEDULER
Events::drop_schema_events(thd, db);
#endif
error = 0;
+ reenable_binlog(thd);
}
}
if (!silent && deleted>=0)
=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc 2008-08-26 19:16:28 +0000
+++ b/sql/sql_parse.cc 2008-08-28 08:44:13 +0000
@@ -1920,6 +1920,10 @@ mysql_execute_command(THD *thd)
TABLE_LIST *all_tables;
/* most outer SELECT_LEX_UNIT of query */
SELECT_LEX_UNIT *unit= &lex->unit;
+#ifdef HAVE_REPLICATION
+ /* have table map for update for multi-update statement (BUG#37051) */
+ bool have_table_map_for_update= FALSE;
+#endif
/* Saved variable value */
DBUG_ENTER("mysql_execute_command");
#ifdef WITH_PARTITION_STORAGE_ENGINE
@@ -1985,6 +1989,48 @@ mysql_execute_command(THD *thd)
// force searching in slave.cc:tables_ok()
all_tables->updating= 1;
}
+
+ /*
+ For fix of BUG#37051, the master stores the table map for update
+ in the Query_log_event, and the value is assigned to
+ thd->variables.table_map_for_update before executing the update
+ query.
+
+ If thd->variables.table_map_for_update is set, then we are
+ replicating from a new master, we can use this value to apply
+ filter rules without opening all the tables. However If
+ thd->variables.table_map_for_update is not set, then we are
+ replicating from an old master, so we just skip this and
+ continue with the old method. And of course, the bug would still
+ exist for old masters.
+ */
+ if (lex->sql_command == SQLCOM_UPDATE_MULTI &&
+ thd->table_map_for_update)
+ {
+ have_table_map_for_update= TRUE;
+ table_map table_map_for_update= thd->table_map_for_update;
+ uint nr= 0;
+ TABLE_LIST *table;
+ for (table=all_tables; table; table=table->next_global, nr++)
+ {
+ if (table_map_for_update & ((table_map)1 << nr))
+ table->updating= TRUE;
+ else
+ table->updating= FALSE;
+ }
+
+ if (all_tables_not_ok(thd, all_tables))
+ {
+ /* we warn the slave SQL thread */
+ my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
+ if (thd->one_shot_set)
+ reset_one_shot_variables(thd);
+ DBUG_RETURN(0);
+ }
+
+ for (table=all_tables; table; table=table->next_global)
+ table->updating= TRUE;
+ }
/*
Check if statment should be skipped because of slave filtering
@@ -2960,7 +3006,7 @@ end_with_restore_list:
#ifdef HAVE_REPLICATION
/* Check slave filtering rules */
- if (unlikely(thd->slave_thread))
+ if (unlikely(thd->slave_thread && !have_table_map_for_update))
{
if (all_tables_not_ok(thd, all_tables))
{
=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc 2008-07-17 19:55:18 +0000
+++ b/sql/sql_update.cc 2008-08-26 12:29:33 +0000
@@ -1007,7 +1007,7 @@ reopen_tables:
DBUG_RETURN(TRUE);
}
- tables_for_update= get_table_map(fields);
+ thd->table_map_for_update= tables_for_update= get_table_map(fields);
/*
Setup timestamp handling and locking mode
=== modified file 'storage/falcon/BackLog.cpp'
--- a/storage/falcon/BackLog.cpp 2008-07-17 13:52:17 +0000
+++ b/storage/falcon/BackLog.cpp 2008-08-18 20:17:15 +0000
@@ -37,7 +37,9 @@ BackLog::BackLog(Database *db, const cha
{
database = db;
dbb = new Dbb(database->dbb, 0);
+#ifndef FALCONDB
dbb->createPath(fileName);
+#endif
dbb->create(fileName, dbb->pageSize, 0, HdrTableSpace, 0, NULL);
dbb->noLog = true;
dbb->tableSpaceId = -1;
=== modified file 'storage/falcon/CMakeLists.txt'
--- a/storage/falcon/CMakeLists.txt 2008-06-19 15:09:45 +0000
+++ b/storage/falcon/CMakeLists.txt 2008-08-27 09:49:44 +0000
@@ -23,13 +23,11 @@ INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/
. TransformLib
${CMAKE_SOURCE_DIR}/extra/yassl/include
${CMAKE_SOURCE_DIR}/zlib)
-IF(CMAKE_GENERATOR MATCHES "Visual Studio 7" OR
- CMAKE_GENERATOR MATCHES "Visual Studio 8")
+IF(MSVC)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc")
SET(CMAKE_CXX_FLAGS_INIT "${CMAKE_CXX_FLAGS_INIT} /EHsc")
SET(CMAKE_CXX_FLAGS_DEBUG_INIT "${CMAKE_CXX_FLAGS_DEBUG_INIT} /EHsc")
-ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio 7" OR
- CMAKE_GENERATOR MATCHES "Visual Studio 8")
+ENDIF(MSVC)
SET(FALCON_SOURCES
Agent.cpp
@@ -274,7 +272,6 @@ SET(FALCON_SOURCES
StreamSegment.cpp
SymbolManager.cpp
Sync.cpp
- SyncWait.cpp
Synchronize.cpp
SyncObject.cpp
SyncTest.cpp
=== modified file 'storage/falcon/Configuration.cpp'
--- a/storage/falcon/Configuration.cpp 2008-07-17 13:52:17 +0000
+++ b/storage/falcon/Configuration.cpp 2008-08-19 14:27:42 +0000
@@ -151,8 +151,14 @@ Configuration::Configuration(const char
if (!scanDir.isDirectory())
{
- //throw SQLEXCEPTION (RUNTIME_ERROR, "Invalid serial log directory path \"%s\"", falcon_serial_log_dir);
- serialLogDir = "";
+ fprintf(stderr,
+ "Falcon: The specified serial log directory, \"%s\", "
+ "does not exist.\n"
+ "Falcon: The serial log directory must be created by "
+ "the user before initializing Falcon.\n",
+ falcon_serial_log_dir
+ );
+ throw SQLEXCEPTION (FILE_ACCESS_ERROR, "Invalid serial log directory path \"%s\"", falcon_serial_log_dir);
}
}
#else
=== modified file 'storage/falcon/IO.cpp'
--- a/storage/falcon/IO.cpp 2008-08-14 16:34:43 +0000
+++ b/storage/falcon/IO.cpp 2008-08-18 20:17:15 +0000
@@ -411,13 +411,17 @@ void IO::declareFatalError()
fatalError = true;
}
+
+#ifndef ENOSYS
+#define ENOSYS EEXIST
+#endif
+
+// Make sure parent directories for file exist
void IO::createPath(const char *fileName)
{
- // First, better make sure directories exists
JString fname = getPath(fileName);
char directory [256], *q = directory;
-
for (const char *p = fname.getString(); *p;)
{
char c = *p++;
@@ -427,9 +431,14 @@ void IO::createPath(const char *fileName
*q = 0;
if (q > directory && q [-1] != ':')
- if (MKDIR (directory) && errno != EEXIST)
+ {
+ if (MKDIR (directory) && errno != EEXIST && errno != ENOSYS)
+ // ENOSYS is a Solaris speficic workaround, mkdir returns it
+ // on existing automounted NFS directories, instead
+ // of EEXIST.
throw SQLError (IO_ERROR,
"can't create directory \"%s\"\n", directory);
+ }
}
*q++ = c;
}
=== modified file 'storage/falcon/Index.cpp'
--- a/storage/falcon/Index.cpp 2008-07-25 18:07:24 +0000
+++ b/storage/falcon/Index.cpp 2008-08-19 03:33:01 +0000
@@ -107,7 +107,6 @@ void Index::init(Table *tbl, const char
DIHashTable = NULL;
DIHashTableCounts = 0;
DIHashTableSlotsUsed = 0;
-
syncDIHash.setName("Index::syncDIHash");
syncUnique.setName("Index::syncUnique");
deferredIndexes.syncObject.setName("Index::deferredIndexes.syncObject");
=== modified file 'storage/falcon/Index2RootPage.cpp'
--- a/storage/falcon/Index2RootPage.cpp 2008-03-27 06:09:29 +0000
+++ b/storage/falcon/Index2RootPage.cpp 2008-08-25 22:09:13 +0000
@@ -518,9 +518,9 @@ bool Index2RootPage::splitIndexPage(Dbb
leftPage->parentPage = bdb->pageNumber;
splitPage->parentPage = bdb->pageNumber;
- Index2Page::logIndexPage(bdb, transId);
Index2Page::logIndexPage(splitBdb, transId);
Index2Page::logIndexPage(leftBdb, transId);
+ Index2Page::logIndexPage(bdb, transId);
splitBdb->release(REL_HISTORY);
leftBdb->release(REL_HISTORY);
=== modified file 'storage/falcon/IndexRootPage.cpp'
--- a/storage/falcon/IndexRootPage.cpp 2008-05-14 18:39:57 +0000
+++ b/storage/falcon/IndexRootPage.cpp 2008-08-25 22:09:13 +0000
@@ -552,12 +552,16 @@ bool IndexRootPage::splitIndexPage(Dbb *
page->addNode(dbb, &dummy, END_LEVEL);
page->addNode(dbb, &leftKey, leftBdb->pageNumber);
page->addNode(dbb, &splitKey, splitBdb->pageNumber);
-
+
leftPage->parentPage = bdb->pageNumber;
splitPage->parentPage = bdb->pageNumber;
- IndexPage::logIndexPage(bdb, transId);
+
+ // the order of adding these to the serial log is important.
+ // Recovery must write them in this order incase recovery itself crashes.
+
IndexPage::logIndexPage(splitBdb, transId);
IndexPage::logIndexPage(leftBdb, transId);
+ IndexPage::logIndexPage(bdb, transId);
/***
IndexPage::printPage(bdb, false);
=== modified file 'storage/falcon/Interlock.h'
--- a/storage/falcon/Interlock.h 2008-07-10 09:27:51 +0000
+++ b/storage/falcon/Interlock.h 2008-08-21 11:23:44 +0000
@@ -396,7 +396,7 @@ inline INTERLOCK_TYPE interlockedAdd(vol
{
INTERLOCK_TYPE current= *addend;
INTERLOCK_TYPE ret= current + value;
- if (COMPARE_EXCHANGE_POINTER(addend, current, ret))
+ if (COMPARE_EXCHANGE(addend, current, ret))
return ret;
}
#endif
=== modified file 'storage/falcon/MemMgr.cpp'
--- a/storage/falcon/MemMgr.cpp 2008-08-12 22:21:35 +0000
+++ b/storage/falcon/MemMgr.cpp 2008-08-20 16:28:44 +0000
@@ -694,7 +694,7 @@ void MemMgr::corrupt(const char* text)
#endif
MemMgrLogDump();
- throw SQLError (BUG_CHECK, "memory is corrupt: %s", text);
+ FATAL("memory is corrupt: %s", text);
}
void* MemMgr::memoryIsExhausted(void)
=== modified file 'storage/falcon/RepositoryVolume.cpp'
--- a/storage/falcon/RepositoryVolume.cpp 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/RepositoryVolume.cpp 2008-08-18 20:17:15 +0000
@@ -232,7 +232,9 @@ void RepositoryVolume::makeWritable()
void RepositoryVolume::create()
{
+#ifndef FALCONDB
IO::createPath (fileName);
+#endif
dbb->create(fileName, dbb->pageSize, 0, HdrRepositoryFile, 0, NULL);
Sync syncDDL(&database->syncSysDDL, "RepositoryVolume::create");
Transaction *transaction = database->getSystemTransaction();
=== modified file 'storage/falcon/Statement.cpp'
--- a/storage/falcon/Statement.cpp 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/Statement.cpp 2008-08-18 05:45:29 +0000
@@ -144,7 +144,6 @@ Statement::Statement(Connection *pConnec
special = false;
active = false;
memset (&stats, 0, sizeof (stats));
- syncObject.setName("Statement::syncObject");
}
Statement::~Statement()
@@ -2303,16 +2302,10 @@ void Statement::dropIndex(Syntax *syntax
throw SQLEXCEPTION (DDL_ERROR, "table %s.%s not defined", (const char*) tableName, schema);
checkAlterPriv (table);
- Index *index = table->findIndex (name);
- if (index)
- {
Transaction *sysTransaction = database->getSystemTransaction();
- table->dropIndex(index);
- index->deleteIndex(sysTransaction); /* transaction */
- delete index;
+ table->dropIndex(name, sysTransaction);
database->commitSystemTransaction();
- }
Index::deleteIndex (database, schema, name);
database->commitSystemTransaction();
=== modified file 'storage/falcon/StorageDatabase.cpp'
--- a/storage/falcon/StorageDatabase.cpp 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/StorageDatabase.cpp 2008-08-18 20:17:15 +0000
@@ -156,7 +156,9 @@ Connection* StorageDatabase::createDatab
try
{
masterConnection = getConnection();
+#ifndef FALCONDB
IO::createPath(filename);
+#endif
masterConnection->createDatabase(name, filename, ACCOUNT, PASSWORD, threads);
Statement *statement = masterConnection->createStatement();
@@ -688,7 +690,7 @@ int StorageDatabase::updateRow(StorageCo
return 0;
}
-int StorageDatabase::createIndex(StorageConnection *storageConnection, Table* table, const char* indexName, const char* sql)
+int StorageDatabase::createIndex(StorageConnection *storageConnection, Table* table, const char* sql)
{
Connection *connection = storageConnection->connection;
Statement *statement = connection->createStatement();
@@ -713,7 +715,7 @@ int StorageDatabase::createIndex(Storage
return 0;
}
-int StorageDatabase::dropIndex(StorageConnection *storageConnection, Table* table, const char* indexName, const char* sql)
+int StorageDatabase::dropIndex(StorageConnection *storageConnection, Table* table, const char* sql)
{
Connection *connection = storageConnection->connection;
Statement *statement = connection->createStatement();
@@ -746,17 +748,6 @@ int StorageDatabase::renameTable(Storage
{
Database *database = connection->database;
Sequence *sequence = connection->findSequence(schemaName, table->name);
- int numberIndexes = 0;
- int firstIndex = 0;
- Index *index;
-
- for (index = table->indexes; index; index = index->next)
- {
- if (index->type == PrimaryKey)
- firstIndex = 1;
-
- ++numberIndexes;
- }
Sync syncDDL(&database->syncSysDDL, "StorageDatabase::renameTable(1)");
syncDDL.lock(Exclusive);
@@ -764,19 +755,6 @@ int StorageDatabase::renameTable(Storage
Sync syncTables(&database->syncTables, "StorageDatabase::renameTable(2)");
syncTables.lock(Exclusive);
- for (int n = firstIndex; n < numberIndexes; ++n)
- {
- char indexName[256];
- sprintf(indexName, "%s$%d", (const char*) table->name, n);
- Index *index = table->findIndex(indexName);
-
- if (index)
- {
- sprintf(indexName, "%s$%d", tableName, n);
- index->rename(indexName);
- }
- }
-
table->rename(schemaName, tableName);
if (sequence)
=== modified file 'storage/falcon/StorageDatabase.h'
--- a/storage/falcon/StorageDatabase.h 2008-07-24 08:45:03 +0000
+++ b/storage/falcon/StorageDatabase.h 2008-08-18 05:45:29 +0000
@@ -40,7 +40,7 @@ class IndexWalker;
CLASS(Field);
-struct StorageIndexDesc;
+class StorageIndexDesc;
struct StorageKey;
struct StorageBlob;
struct StorageSegment;
@@ -61,7 +61,6 @@ public:
int savepointRollback(Connection* connection, int savePoint);
int deleteTable(StorageConnection* storageConnection,StorageTableShare *tableShare);
int truncateTable(StorageConnection* storageConnection, StorageTableShare *tableShare);
- int createIndex(StorageConnection *storageConnection, Table* table, StorageIndexDesc* indexDesc);
int renameTable(StorageConnection* storageConnection, Table* table, const char* newName, const char *schemaName);
Bitmap* indexScan(Index* index, StorageKey *lower, StorageKey *upper, int searchFlags, StorageConnection* storageConnection, Bitmap *bitmap);
IndexWalker* indexPosition(Index* index, StorageKey* lower, StorageKey* upper, int searchFlags, StorageConnection* storageConnection);
@@ -74,8 +73,8 @@ public:
void freeBlob(StorageBlob *blob);
void close(void);
void validateCache(void);
- int createIndex(StorageConnection* storageConnection, Table* table, const char* indexName, const char* sql);
- int dropIndex(StorageConnection* storageConnection, Table* table, const char* indexName, const char* sql);
+ int createIndex(StorageConnection* storageConnection, Table* table, const char* sql);
+ int dropIndex(StorageConnection* storageConnection, Table* table, const char* sql);
int insert(Connection* connection, Table* table, Stream* stream);
int nextRow(StorageTable* storageTable, int recordNumber, bool lockForUpdate);
=== modified file 'storage/falcon/StorageTable.cpp'
--- a/storage/falcon/StorageTable.cpp 2008-08-11 13:22:53 +0000
+++ b/storage/falcon/StorageTable.cpp 2008-08-22 06:47:40 +0000
@@ -51,11 +51,13 @@ StorageTable::StorageTable(StorageConnec
upperBound = lowerBound = NULL;
record = NULL;
recordLocked = false;
- haveTruncateLock = false;
+ indexesLocked = false;
}
StorageTable::~StorageTable(void)
{
+ clearCurrentIndex();
+
if (bitmap)
((Bitmap*) bitmap)->release();
@@ -94,12 +96,12 @@ int StorageTable::deleteTable(void)
int StorageTable::truncateTable(void)
{
clearRecord();
+ clearCurrentIndex();
+
int ret = share->truncateTable(storageConnection);
return ret;
}
-
-
int StorageTable::insert(void)
{
try
@@ -139,6 +141,16 @@ int StorageTable::updateRow(int recordNu
return 0;
}
+int StorageTable::createIndex(StorageIndexDesc *indexDesc, const char *sql)
+{
+ return share->createIndex(storageConnection, indexDesc, sql);
+}
+
+int StorageTable::dropIndex(StorageIndexDesc *indexDesc, const char *sql)
+{
+ return share->dropIndex(storageConnection, indexDesc, sql);
+}
+
int StorageTable::next(int recordNumber, bool lockForUpdate)
{
recordLocked = false;
@@ -174,21 +186,51 @@ void StorageTable::transactionEnded(void
{
}
-int StorageTable::setIndex(int numberIndexes, int indexId, StorageIndexDesc* storageIndex)
+int StorageTable::setCurrentIndex(int indexId)
{
- if (!(currentIndex = share->getIndex(numberIndexes, indexId, storageIndex)))
+ if (!indexesLocked)
+ {
+ share->lockIndexes();
+ indexesLocked = true;
+ }
+
+ if (!(currentIndex = share->getIndex(indexId)))
+{
+ clearCurrentIndex();
return StorageErrorNoIndex;
-
+ }
+
upperBound = lowerBound = NULL;
searchFlags = 0;
+ return 0;
+}
+int StorageTable::clearCurrentIndex()
+{
+ if (indexesLocked)
+ {
+ share->unlockIndexes();
+ indexesLocked = false;
+ }
+
+ currentIndex = NULL;
+ upperBound = lowerBound = NULL;
+ searchFlags = 0;
return 0;
}
+int StorageTable::setIndex(StorageIndexDesc* indexDesc)
+{
+ return share->setIndex(indexDesc);
+}
+
int StorageTable::indexScan(int indexOrder)
{
if (!currentIndex)
+ {
+ clearCurrentIndex();
return StorageErrorNoIndex;
+ }
int numberSegments = (upperBound) ? upperBound->numberSegments : (lowerBound) ? lowerBound->numberSegments : 0;
@@ -203,26 +245,16 @@ int StorageTable::indexScan(int indexOrd
return 0;
}
-
void StorageTable::clearBitmap(void)
{
if (bitmap)
((Bitmap*) bitmap)->clear();
}
-int StorageTable::setIndex(int indexId)
-{
- if (!(currentIndex = share->getIndex(indexId)))
- return StorageErrorNoIndex;
-
- upperBound = lowerBound = NULL;
- searchFlags = 0;
-
- return 0;
-}
-
void StorageTable::indexEnd(void)
{
+ clearCurrentIndex();
+
if (bitmap)
clearBitmap();
@@ -236,7 +268,10 @@ void StorageTable::indexEnd(void)
int StorageTable::setIndexBound(const unsigned char* key, int keyLength, int which)
{
if (!currentIndex)
+ {
+ clearCurrentIndex();
return StorageErrorNoIndex;
+ }
if (which & LowerBound)
{
=== modified file 'storage/falcon/StorageTable.h'
--- a/storage/falcon/StorageTable.h 2008-08-11 13:22:53 +0000
+++ b/storage/falcon/StorageTable.h 2008-08-22 06:47:40 +0000
@@ -49,8 +49,7 @@ class Record;
class SyncObject;
class Format;
class IndexWalker;
-
-struct StorageIndexDesc;
+class StorageIndexDesc;
class StorageTable
{
@@ -65,8 +64,6 @@ public:
void clearAlter(void);
bool setAlter(void);
-
-
virtual void setConnection(StorageConnection* connection);
virtual void clearIndexBounds(void);
virtual void clearRecord(void);
@@ -78,9 +75,10 @@ public:
virtual int deleteTable(void);
virtual int deleteRow(int recordNumber);
virtual int truncateTable(void);
- virtual int setIndex(int numberIndexes, int indexId, StorageIndexDesc* storageIndex);
virtual int indexScan(int indexOrder);
- virtual int setIndex(int indexId);
+ virtual int setCurrentIndex(int indexId);
+ virtual int clearCurrentIndex();
+ virtual int setIndex(StorageIndexDesc* indexDesc);
virtual void indexEnd(void);
virtual int setIndexBound(const unsigned char* key, int keyLength, int which);
virtual int storeBlob(StorageBlob* blob);
@@ -96,6 +94,8 @@ public:
virtual int fetch(int recordNumber, bool lockForUpdate);
virtual int updateRow(int recordNumber);
+ virtual int createIndex(StorageIndexDesc *indexDesc, const char *sql);
+ virtual int dropIndex(StorageIndexDesc *indexDesc, const char *sql);
virtual const unsigned char* getEncoding(int fieldIndex);
virtual const char* getName(void);
virtual const char* getSchemaName(void);
@@ -128,7 +128,7 @@ public:
Stream insertStream;
int searchFlags;
bool recordLocked;
- bool haveTruncateLock;
+ bool indexesLocked;
};
#endif
=== modified file 'storage/falcon/StorageTableShare.cpp'
--- a/storage/falcon/StorageTableShare.cpp 2008-08-04 15:53:52 +0000
+++ b/storage/falcon/StorageTableShare.cpp 2008-08-22 06:47:40 +0000
@@ -33,14 +33,11 @@
#include "PreparedStatement.h"
#include "ResultSet.h"
#include "SQLException.h"
+#include "CmdGen.h"
static const char *FALCON_TEMPORARY = "/falcon_temporary";
static const char *DB_ROOT = ".fts";
-#ifndef ONLINE_ALTER
-//#define ONLINE_ALTER
-#endif
-
#if defined(_WIN32) && MYSQL_VERSION_ID < 0x50100
#define IS_SLASH(c) (c == '/' || c == '\\')
#else
@@ -52,6 +49,43 @@ static const char *DB_ROOT = ".fts";
static const char THIS_FILE[]=__FILE__;
#endif
+StorageIndexDesc::StorageIndexDesc()
+{
+ id = 0;
+ unique = 0;
+ primaryKey = 0;
+ numberSegments = 0;
+ index = NULL;
+ segmentRecordCounts = NULL;
+ next = NULL;
+ name[0] = '\0';
+ rawName[0] = '\0';
+};
+
+StorageIndexDesc::StorageIndexDesc(const StorageIndexDesc *indexInfo)
+{
+ if (indexInfo)
+ *this = *indexInfo;
+ else
+ {
+ id = 0;
+ unique = 0;
+ primaryKey = 0;
+ numberSegments = 0;
+ segmentRecordCounts = NULL;
+ name[0] = '\0';
+ rawName[0] = '\0';
+ }
+
+ index = NULL;
+ next = NULL;
+ prev = NULL;
+};
+
+StorageIndexDesc::~StorageIndexDesc(void)
+{
+}
+
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
@@ -63,13 +97,15 @@ StorageTableShare::StorageTableShare(Sto
impure = new UCHAR[lockSize];
initialized = false;
table = NULL;
- indexes = NULL;
format = NULL;
syncObject = new SyncObject;
syncObject->setName("StorageTableShare::syncObject");
+ syncIndexes = new SyncObject;
+ syncIndexes->setName("StorageTableShare::syncIndexes");
sequence = NULL;
tempTable = tempTbl;
setPath(path);
+ indexes = NULL;
if (tempTable)
tableSpace = TEMPORARY_TABLESPACE;
@@ -82,18 +118,16 @@ StorageTableShare::StorageTableShare(Sto
StorageTableShare::~StorageTableShare(void)
{
delete syncObject;
+ delete syncIndexes;
delete [] impure;
if (storageDatabase)
storageDatabase->release();
- if (indexes)
+ for (StorageIndexDesc *indexDesc; (indexDesc = indexes);)
{
- for (int n = 0; n < numberIndexes; ++n)
- delete indexes[n];
-
- delete [] indexes;
- indexes = NULL;
+ indexes = indexDesc->next;
+ delete indexDesc;
}
}
@@ -107,6 +141,16 @@ void StorageTableShare::unlock(void)
syncObject->unlock();
}
+void StorageTableShare::lockIndexes(bool exclusiveLock)
+{
+ syncIndexes->lock(NULL, (exclusiveLock) ? Exclusive : Shared);
+}
+
+void StorageTableShare::unlockIndexes(void)
+{
+ syncIndexes->unlock();
+}
+
int StorageTableShare::open(void)
{
if (!table)
@@ -189,7 +233,7 @@ int StorageTableShare::truncateTable(Sto
return res;
}
-void StorageTableShare::cleanupFieldName(const char* name, char* buffer, int bufferLength)
+const char* StorageTableShare::cleanupFieldName(const char* name, char* buffer, int bufferLength)
{
char *q = buffer;
char *end = buffer + bufferLength - 1;
@@ -211,6 +255,8 @@ void StorageTableShare::cleanupFieldName
}
*q = 0;
+
+ return buffer;
}
const char* StorageTableShare::cleanupTableName(const char* name, char* buffer, int bufferLength, char *schema, int schemaLength)
@@ -239,20 +285,96 @@ const char* StorageTableShare::cleanupTa
return buffer;
}
-int StorageTableShare::createIndex(StorageConnection *storageConnection, const char* name, const char* sql)
+char* StorageTableShare::createIndexName(const char *rawName, char *indexName)
+{
+ char nameBuffer[indexNameSize];
+ cleanupFieldName(rawName, nameBuffer, sizeof(nameBuffer));
+ sprintf(indexName, "%s$%s", name.getString(), nameBuffer);
+ return indexName;
+}
+
+int StorageTableShare::createIndex(StorageConnection *storageConnection, StorageIndexDesc *indexDesc, const char *sql)
{
if (!table)
open();
- return storageDatabase->createIndex(storageConnection, table, name, sql);
+ // Lock out other clients before locking the table
+
+ Sync syncIndex(syncIndexes, "StorageTableShare::createIndex(1)");
+ syncIndex.lock(Exclusive);
+
+ Sync syncObj(syncObject, "StorageTableShare::createIndex(2)");
+ syncObj.lock(Exclusive);
+
+ int ret = storageDatabase->createIndex(storageConnection, table, sql);
+
+ if (!ret)
+ ret = setIndex(indexDesc);
+
+ return ret;
+}
+
+void StorageTableShare::addIndex(StorageIndexDesc *indexDesc)
+{
+ if (!getIndex(indexDesc->id))
+ {
+ if (indexes)
+ {
+ indexDesc->next = indexes;
+ indexDesc->prev = NULL;
+ indexes->prev = indexDesc;
+ }
+
+ indexes = indexDesc;
+ }
+}
+
+void StorageTableShare::deleteIndex(int indexId)
+{
+ for (StorageIndexDesc *indexDesc = indexes; indexDesc; indexDesc = indexDesc->next)
+ if (indexDesc->id == indexId)
+ {
+ if (indexDesc->prev)
+ indexDesc->prev->next = indexDesc->next;
+ else
+ indexes = indexDesc->next;
+
+ if (indexDesc->next)
+ indexDesc->next->prev = indexDesc->prev;
+
+ delete indexDesc;
+ break;
+ }
}
-int StorageTableShare::dropIndex(StorageConnection *storageConnection, const char* name, const char* sql)
+int StorageTableShare::dropIndex(StorageConnection *storageConnection, StorageIndexDesc *indexDesc, const char *sql)
{
if (!table)
open();
- return storageDatabase->dropIndex(storageConnection, table, name, sql);
+ // Lock out other clients before locking the table
+
+ Sync syncIndex(syncIndexes, "StorageTableShare::dropIndex(1)");
+ syncIndex.lock(Exclusive);
+
+ Sync syncObj(syncObject, "StorageTableShare::dropIndex(2)");
+ syncObj.lock(Exclusive);
+
+ int ret = storageDatabase->dropIndex(storageConnection, table, sql);
+
+ if (!ret)
+ deleteIndex(indexDesc->id);
+
+ return ret;
+}
+
+void StorageTableShare::deleteIndexes()
+{
+ for (StorageIndexDesc *indexDesc; (indexDesc = indexes);)
+ {
+ indexes = indexDesc->next;
+ delete indexDesc;
+ }
}
int StorageTableShare::renameTable(StorageConnection *storageConnection, const char* newName)
@@ -274,72 +396,109 @@ int StorageTableShare::renameTable(Stora
return ret;
}
-StorageIndexDesc* StorageTableShare::getIndex(int indexCount, int indexId, StorageIndexDesc* indexDesc)
+int StorageTableShare::setIndex(const StorageIndexDesc *indexInfo)
{
- // Rebuild array if indexes have been added or dropped
-
-#ifdef ONLINE_ALTER
-
- // TODO: This does not work. It should be done at the time of index creation
+ int ret = 0;
- if (indexes && (numberIndexes != indexCount))
+ if (!getIndex(indexInfo->id))
{
- Sync sync(syncObject, "StorageTableShare::getIndex");
- sync.lock(Exclusive);
- StorageIndexDesc **oldIndexes = indexes;
- StorageIndexDesc **newIndexes = new StorageIndexDesc*[indexCount];
- memset(newIndexes, 0, indexCount * sizeof(StorageIndexDesc*));
-
- for (int n = 0; n < numberIndexes; ++n)
- newIndexes[n] = indexes[n];
-
- indexes = newIndexes;
- numberIndexes = indexCount;
- delete [] oldIndexes;
- }
-#endif
-
- if (!indexes)
- {
- indexes = new StorageIndexDesc*[indexCount];
- memset(indexes, 0, indexCount * sizeof(StorageIndexDesc*));
- numberIndexes = indexCount;
- }
-
- if (indexId >= numberIndexes)
- return NULL;
-
- StorageIndexDesc *index = indexes[indexId];
-
- if (index)
- return index;
+ StorageIndexDesc *indexDesc = new StorageIndexDesc(indexInfo);
+ addIndex(indexDesc);
- indexes[indexId] = index = new StorageIndexDesc;
- *index = *indexDesc;
+ // Find the corresponding Falcon index
if (indexDesc->primaryKey)
- index->index = table->primaryKey;
+ indexDesc->index = table->primaryKey;
else
{
- char indexName[150];
- sprintf(indexName, "%s$%d", (const char*) name, indexId);
- index->index = storageDatabase->findIndex(table, indexName);
+ char indexName[indexNameSize];
+ sprintf(indexName, "%s$%s", name.getString(), indexDesc->name);
+ indexDesc->index = table->findIndex(indexName);
}
- if (index->index)
- index->segmentRecordCounts = index->index->recordsPerSegment;
+ if (indexDesc->index)
+ indexDesc->segmentRecordCounts = indexDesc->index->recordsPerSegment;
else
- index = NULL;
+ ret = StorageErrorNoIndex;
+ }
+
+ return ret;
+}
+
+StorageIndexDesc* StorageTableShare::getIndex(int indexId)
+{
+ if (!indexes)
+ return NULL;
+
+ for (StorageIndexDesc *indexDesc = indexes; indexDesc; indexDesc = indexDesc->next)
+ if (indexDesc->id == indexId)
+ return indexDesc;
+
+ return NULL;
+}
+
+StorageIndexDesc* StorageTableShare::getIndex(int indexId, StorageIndexDesc *indexDesc)
+{
+ if (!indexes)
+ return NULL;
+ Sync sync(syncIndexes, "StorageTableShare::getIndex");
+ sync.lock(Shared);
+
+ StorageIndexDesc *index = getIndex(indexId);
+
+ if (index)
+ *indexDesc = *index;
+
return index;
}
-StorageIndexDesc* StorageTableShare::getIndex(int indexId)
+StorageIndexDesc* StorageTableShare::getIndex(const char *name)
{
- if (!indexes || indexId >= numberIndexes)
+ if (!indexes)
return NULL;
- return indexes[indexId];
+ Sync sync(syncIndexes, "StorageTableShare::getIndex(name)");
+ sync.lock(Shared);
+
+ for (StorageIndexDesc *indexDesc = indexes; indexDesc; indexDesc = indexDesc->next)
+ if (indexDesc->name == name)
+ return indexDesc;
+
+ return NULL;
+}
+
+int StorageTableShare::getIndexId(const char* schemaName, const char* indexName)
+{
+ if (!indexes)
+ return -1;
+
+ for (StorageIndexDesc *indexDesc = indexes; indexDesc; indexDesc = indexDesc->next)
+ {
+ Index *index = indexDesc->index;
+
+ if (index)
+ if (strcmp(index->getIndexName(), indexName) == 0 &&
+ strcmp(index->getSchemaName(), schemaName) == 0)
+ return indexDesc->id;
+ }
+
+ return -1;
+}
+
+int StorageTableShare::haveIndexes(int indexCount)
+{
+ if (!indexes)
+ return false;
+
+ int n = 0;
+ for (StorageIndexDesc *indexDesc = indexes; indexDesc; indexDesc = indexDesc->next, n++)
+ {
+ if (!indexDesc->index)
+ return false;
+ }
+
+ return (n == indexCount);
}
INT64 StorageTableShare::getSequenceValue(int delta)
@@ -365,38 +524,6 @@ int StorageTableShare::setSequenceValue(
return 0;
}
-int StorageTableShare::getIndexId(const char* schemaName, const char* indexName)
-{
- if (indexes)
- for (int n = 0; n < numberIndexes; ++n)
- {
- Index *index = indexes[n]->index;
-
- if (strcmp(index->getIndexName(), indexName) == 0 &&
- strcmp(index->getSchemaName(), schemaName) == 0)
- return n;
- }
-
- return -1;
-}
-
-int StorageTableShare::haveIndexes(int indexCount)
-{
- if (indexes == NULL)
- return false;
-
-#ifdef ONLINE_ALTER
- if (indexCount != numberIndexes)
- return false;
-#endif
-
- for (int n = 0; n < numberIndexes; ++n)
- if (indexes[n]== NULL)
- return false;
-
- return true;
-}
-
void StorageTableShare::setTablePath(const char* path, bool tmp)
{
if (pathName.IsEmpty())
=== modified file 'storage/falcon/StorageTableShare.h'
--- a/storage/falcon/StorageTableShare.h 2008-08-04 15:53:52 +0000
+++ b/storage/falcon/StorageTableShare.h 2008-08-22 06:47:40 +0000
@@ -26,6 +26,7 @@
typedef __int64 INT64;
static const int MaxIndexSegments = 16;
+static const int indexNameSize = 257;
class StorageDatabase;
class StorageConnection;
@@ -47,14 +48,25 @@ struct StorageSegment {
void *mysql_charset;
};
-struct StorageIndexDesc {
+// StorageIndexDesc maps a server-side index to a Falcon index
+class StorageIndexDesc
+{
+public:
+ StorageIndexDesc();
+ StorageIndexDesc(const StorageIndexDesc *indexInfo);
+ virtual ~StorageIndexDesc(void);
+
+ int id;
int unique;
int primaryKey;
int numberSegments;
- const char *name;
+ char name[indexNameSize]; // clean name
+ char rawName[indexNameSize]; // original name
Index *index;
uint64 *segmentRecordCounts;
StorageSegment segments[MaxIndexSegments];
+ StorageIndexDesc *next;
+ StorageIndexDesc *prev;
};
@@ -95,22 +107,29 @@ public:
StorageTableShare(StorageHandler *handler, const char * path, const char *tableSpaceName, int lockSize, bool tempTbl);
virtual ~StorageTableShare(void);
- virtual void lock(bool exclusiveLock);
+ virtual void lock(bool exclusiveLock=false);
virtual void unlock(void);
- virtual int createIndex(StorageConnection *storageConnection, const char* name, const char* sql);
- virtual int dropIndex(StorageConnection *storageConnection, const char* name, const char* sql);
+ virtual void lockIndexes(bool exclusiveLock=false);
+ virtual void unlockIndexes(void);
+ virtual int createIndex(StorageConnection *storageConnection, StorageIndexDesc *indexDesc, const char *sql);
+ virtual int dropIndex(StorageConnection *storageConnection, StorageIndexDesc *indexDesc, const char *sql);
+ virtual void deleteIndexes();
virtual int renameTable(StorageConnection *storageConnection, const char* newName);
virtual INT64 getSequenceValue(int delta);
virtual int setSequenceValue(INT64 value);
virtual int haveIndexes(int indexCount);
- virtual void cleanupFieldName(const char* name, char* buffer, int bufferLength);
+ virtual const char* cleanupFieldName(const char* name, char* buffer, int bufferLength);
virtual void setTablePath(const char* path, bool tempTable);
virtual void registerCollation(const char* collationName, void* arg);
int open(void);
- StorageIndexDesc* getIndex(int indexCount, int indexId, StorageIndexDesc* indexDesc);
+ void addIndex(StorageIndexDesc *indexDesc);
+ void deleteIndex(int indexId);
+ int setIndex(const StorageIndexDesc* indexInfo);
+ void clearIndex(StorageIndexDesc *indexDesc);
StorageIndexDesc* getIndex(int indexId);
-
+ StorageIndexDesc* getIndex(int indexId, StorageIndexDesc *indexDesc);
+ StorageIndexDesc* getIndex(const char *name);
int getIndexId(const char* schemaName, const char* indexName);
int create(StorageConnection *storageConnection, const char* sql, int64 autoIncrementValue);
int upgrade(StorageConnection *storageConnection, const char* sql, int64 autoIncrementValue);
@@ -129,6 +148,7 @@ public:
static const char* getDefaultRoot(void);
static const char* cleanupTableName(const char* name, char* buffer, int bufferLength, char *schema, int schemaLength);
+ char* createIndexName(const char *rawName, char *indexName);
JString name;
JString schemaName;
@@ -140,13 +160,13 @@ public:
unsigned char *impure;
int initialized;
SyncObject *syncObject;
+ SyncObject *syncIndexes;
StorageDatabase *storageDatabase;
StorageHandler *storageHandler;
Table *table;
- StorageIndexDesc **indexes;
+ StorageIndexDesc *indexes;
Sequence *sequence;
Format *format; // format for insertion
- int numberIndexes;
bool tempTable;
int getFieldId(const char* fieldName);
};
=== modified file 'storage/falcon/Table.cpp'
--- a/storage/falcon/Table.cpp 2008-08-13 10:18:40 +0000
+++ b/storage/falcon/Table.cpp 2008-08-18 05:45:29 +0000
@@ -209,6 +209,34 @@ Index* Table::addIndex(const char * name
return index;
}
+void Table::dropIndex(const char* indexName, Transaction* transaction)
+{
+ Sync sync(&syncObject, "Table::dropIndex");
+ sync.lock(Exclusive);
+
+ Index *index = findIndex(indexName);
+
+ if (index)
+ deleteIndex(index, transaction);
+}
+
+void Table::renameIndexes(const char *newTableName)
+{
+ for (Index *index = indexes; index; index = index->next)
+ {
+ if (index->type != PrimaryKey)
+ {
+
+ // Assume that index name is <table>$<index>
+
+ char newIndexName[256];
+ const char *p = strchr((const char*)index->name, '$');
+ sprintf(newIndexName, "%s%s", newTableName, (const char *)p);
+ index->rename(newIndexName);
+ }
+ }
+}
+
const char* Table::getName()
{
return name;
@@ -1706,6 +1734,19 @@ void Table::addIndex(Index * index)
*ptr = index;
}
+void Table::dropIndex(Index *index)
+{
+ Sync sync(&syncObject, "Table::dropIndex");
+ sync.lock(Exclusive);
+
+ for (Index **ptr = &indexes; *ptr; ptr = &(*ptr)->next)
+ if (*ptr == index)
+ {
+ *ptr = index->next;
+ break;
+ }
+}
+
void Table::addAttachment(TableAttachment * attachment)
{
attachments.appendUnique(attachment);
@@ -2226,15 +2267,6 @@ void Table::dropTrigger(Trigger *trigger
#endif
}
-void Table::dropIndex(Index *index)
-{
- for (Index **ptr = &indexes; *ptr; ptr = &(*ptr)->next)
- if (*ptr == index)
- {
- *ptr = index->next;
- break;
- }
-}
int Table::nextColumnId(int previous)
{
@@ -3196,6 +3228,8 @@ void Table::rename(const char *newSchema
Index *primaryKey = getPrimaryKey();
database->renameTable(this, newSchema, newName);
+ renameIndexes(newName);
+
if (primaryKey)
primaryKey->rename(getPrimaryKeyName());
}
@@ -3491,7 +3525,7 @@ Record* Table::fetchForUpdate(Transactio
ASSERT(IS_CONSISTENT_READ(transaction->isolationLevel));
record->release();
- Log::debug("Table::fetchForUpdate: Update Conflict: TransId=%d, RecordNumber=%d, Table %s.%s",
+ Log::debug("Table::fetchForUpdate: Update Conflict: TransId=%d, RecordNumber=%d, Table %s.%s\n",
transaction->transactionId, record->recordNumber, schemaName, name);
throw SQLError(UPDATE_CONFLICT, "update conflict in table %s.%s", schemaName, name);
=== modified file 'storage/falcon/Table.h'
--- a/storage/falcon/Table.h 2008-08-11 13:22:53 +0000
+++ b/storage/falcon/Table.h 2008-08-18 05:45:29 +0000
@@ -180,6 +180,8 @@ public:
void create (const char *tableType, Transaction *transaction);
const char* getName();
Index* addIndex (const char *name, int numberFields, int type);
+ void dropIndex(const char* name, Transaction* transaction);
+ void renameIndexes(const char *newTableName);
Field* addField (const char *name, Type type, int length, int precision, int scale, int flags);
Field* findField (const char *name);
int getFormatVersion();
=== modified file 'storage/falcon/TableSpace.cpp'
--- a/storage/falcon/TableSpace.cpp 2008-07-17 13:52:17 +0000
+++ b/storage/falcon/TableSpace.cpp 2008-08-18 20:17:15 +0000
@@ -123,7 +123,9 @@ void TableSpace::open()
void TableSpace::create()
{
+#ifndef FALCONDB
dbb->createPath(filename);
+#endif
dbb->create(filename, dbb->pageSize, 0, HdrTableSpace, 0, NULL);
active = true;
dbb->flush();
=== modified file 'storage/falcon/Transaction.cpp'
--- a/storage/falcon/Transaction.cpp 2008-08-20 15:01:21 +0000
+++ b/storage/falcon/Transaction.cpp 2008-08-26 15:36:02 +0000
@@ -86,6 +86,7 @@ Transaction::Transaction(Connection *cnc
syncObject.setName("Transaction::syncObject");
syncActive.setName("Transaction::syncActive");
syncIndexes.setName("Transaction::syncIndexes");
+ syncRecords.setName("Transaction::syncRecords");
syncSavepoints.setName("Transaction::syncSavepoints");
firstRecord = NULL;
lastRecord = NULL;
@@ -216,20 +217,19 @@ Transaction::~Transaction()
delete backloggedRecords;
chillPoint = &firstRecord;
+ // We modify record list without locking.
+ // It is a destructor and if somebody accesses the list
+ // at this point, he is already lost.
for (RecordVersion *record; (record = firstRecord);)
{
- removeRecord(record);
+ removeRecordNoLock(record);
}
+ firstRecord = NULL;
releaseSavepoints();
if (deferredIndexes)
- {
- Sync sync(&syncIndexes, "Transaction::~Transaction");
- sync.lock(Exclusive);
-
releaseDeferredIndexes();
- }
}
void Transaction::commit()
@@ -275,10 +275,11 @@ void Transaction::commit()
releaseRecordLocks();
database->serialLog->preCommit(this);
- syncActive.unlock();
+ Sync syncRec(&syncRecords,"Transaction::commit(1.5)");
+ syncRec.lock(Shared);
for (RecordVersion *record = firstRecord; record; record = record->nextInTrans)
{
Table * table = record->format->table;
@@ -295,15 +296,15 @@ void Transaction::commit()
if (record->state == recDeleted && table->cardinality > 0)
--table->cardinality;
}
-
+ syncRec.unlock();
+
releaseDependencies();
database->flushInversion(this);
// Transfer transaction from active list to committed list, set committed state
-
- Sync syncCommitted(&transactionManager->committedTransactions.syncObject, "Transaction::commit(2)");
Sync syncActiveTransactions(&transactionManager->activeTransactions.syncObject, "Transaction::commit(3)");
-
+ Sync syncCommitted(&transactionManager->committedTransactions.syncObject, "Transaction::commit(2)");
+
syncActiveTransactions.lock(Exclusive);
syncCommitted.lock(Exclusive);
@@ -313,6 +314,8 @@ void Transaction::commit()
syncCommitted.unlock();
syncActiveTransactions.unlock();
+
+ syncActive.unlock(); // signal waiting transactions
database->commit(this);
@@ -341,11 +344,7 @@ void Transaction::commitNoUpdates(void)
++transactionManager->committed;
if (deferredIndexes)
- {
- Sync sync(&syncIndexes, "Transaction::commitNoUpdates(1)");
- sync.lock(Exclusive);
releaseDeferredIndexes();
- }
if (hasLocks)
releaseRecordLocks();
@@ -387,11 +386,7 @@ void Transaction::rollback()
throw SQLEXCEPTION (RUNTIME_ERROR, "transaction is not active");
if (deferredIndexes)
- {
- Sync sync(&syncIndexes, "Transaction::rollback(1)");
- sync.lock(Exclusive);
releaseDeferredIndexes();
- }
releaseSavepoints();
TransactionManager *transactionManager = database->transactionManager;
@@ -403,6 +398,9 @@ void Transaction::rollback()
// Rollback pending record versions from newest to oldest in case
// there are multiple record versions on a prior record chain
+ Sync syncRec(&syncRecords, "Transaction::rollback(1.5)");
+ syncRec.lock(Exclusive);
+
while (firstRecord)
{
record = firstRecord;
@@ -428,6 +426,8 @@ void Transaction::rollback()
record->transaction = rollbackTransaction;
record->release();
}
+ firstRecord = NULL;
+ syncRec.unlock();
for (SavePoint *savePoint = savePoints; savePoint; savePoint = savePoint->next)
if (savePoint->backloggedRecords)
@@ -621,6 +621,8 @@ void Transaction::addRecord(RecordVersio
record->addRef();
+ Sync syncRec(&syncRecords,"Transaction::addRecord");
+ syncRec.lock(Exclusive);
if ( (record->prevInTrans = lastRecord) )
lastRecord->nextInTrans = record;
else
@@ -628,6 +630,7 @@ void Transaction::addRecord(RecordVersio
record->nextInTrans = NULL;
lastRecord = record;
+ syncRec.unlock();
if (database->lowMemory && deletedRecords > MAX_LOW_MEMORY_RECORDS)
backlogRecords();
@@ -635,6 +638,12 @@ void Transaction::addRecord(RecordVersio
void Transaction::removeRecord(RecordVersion *record)
{
+ Sync syncRec(&syncRecords,"Transaction::removeRecord");
+ syncRec.lock(Exclusive);
+ removeRecordNoLock(record);
+}
+void Transaction::removeRecordNoLock(RecordVersion *record)
+{
RecordVersion **ptr;
if (record->nextInTrans)
@@ -800,6 +809,8 @@ void Transaction::releaseDependencies()
void Transaction::commitRecords()
{
+ Sync syncRec(&syncRecords,"Transaction::commitRecords");
+ syncRec.lock(Exclusive);
for (RecordVersion *recordList; (recordList = firstRecord);)
{
if (recordList && COMPARE_EXCHANGE_POINTER(&firstRecord, recordList, NULL))
@@ -903,13 +914,10 @@ State Transaction::getRelativeState(Tran
void Transaction::dropTable(Table* table)
{
- Sync sync(&syncIndexes, "Transaction::dropTable");
- sync.lock(Exclusive);
-
releaseDeferredIndexes(table);
- // Keep exclusive lock to avoid race condition with writeComplete
-
+ Sync syncRec(&syncRecords,"Transaction::dropTable(2)");
+ syncRec.lock(Exclusive);
for (RecordVersion **ptr = &firstRecord, *rec; (rec = *ptr);)
if (rec->format->table == table)
removeRecord(rec);
@@ -919,13 +927,9 @@ void Transaction::dropTable(Table* table
void Transaction::truncateTable(Table* table)
{
- Sync sync(&syncIndexes, "Transaction::truncateTable");
- sync.lock(Exclusive);
-
releaseDeferredIndexes(table);
-
- // Keep exclusive lock to avoid race condition with writeComplete
-
+ Sync syncRec(&syncRecords,"Transaction::truncateTable(2)");
+ syncRec.lock(Exclusive);
for (RecordVersion **ptr = &firstRecord, *rec; (rec = *ptr);)
if (rec->format->table == table)
removeRecord(rec);
@@ -935,9 +939,8 @@ void Transaction::truncateTable(Table* t
bool Transaction::hasRecords(Table* table)
{
- // This lock is to avoid race with writeComplete
- Sync sync(&syncIndexes, "Transaction::hasRecords");
- sync.lock(Exclusive);
+ Sync syncRec(&syncRecords, "Transaction::hasRecords");
+ syncRec.lock(Shared);
for (RecordVersion *rec = firstRecord; rec; rec = rec->nextInTrans)
if (rec->format->table == table)
return true;
@@ -949,17 +952,12 @@ void Transaction::writeComplete(void)
{
ASSERT(writePending);
ASSERT(state == Committed);
- Sync sync(&syncIndexes, "Transaction::writeComplete");
- sync.lock(Exclusive);
releaseDeferredIndexes();
-
- // Keep the synIndexes lock to avoid a race condition with dropTable
if (dependencies == 0)
commitRecords();
writePending = false;
- sync.unlock();
}
bool Transaction::waitForTransaction(TransId transId)
@@ -1243,6 +1241,7 @@ void Transaction::rollbackSavepoint(int
savePoint = savePoints;
+
while (savePoint)
{
//validateRecords();
@@ -1251,6 +1250,8 @@ void Transaction::rollbackSavepoint(int
break;
// Purge out records from this savepoint
+ Sync syncRec(&syncRecords,"Transaction::rollbackSavepoint(2)");
+ syncRec.lock(Exclusive);
RecordVersion *record = *savePoint->records;
RecordVersion *stack = NULL;
@@ -1290,6 +1291,7 @@ void Transaction::rollbackSavepoint(int
rec->transaction = NULL;
rec->release();
}
+ syncRec.unlock();
// Handle any backlogged records
@@ -1335,6 +1337,8 @@ void Transaction::releaseRecordLocks(voi
RecordVersion **ptr;
RecordVersion *record;
+ Sync syncRec(&syncRecords,"Transaction::releaseRecordLocks");
+ syncRec.lock(Exclusive);
for (ptr = &firstRecord; (record = *ptr);)
if (record->state == recLock)
{
@@ -1343,6 +1347,7 @@ void Transaction::releaseRecordLocks(voi
}
else
ptr = &record->nextInTrans;
+ syncRec.unlock();
}
void Transaction::print(void)
@@ -1360,6 +1365,8 @@ void Transaction::printBlocking(int leve
int deletes = 0;
RecordVersion *record;
+ Sync syncRec(&syncRecords,"Transaction::printBlocking");
+ syncRec.lock(Shared);
for (record = firstRecord; record; record = record->nextInTrans)
if (record->state == recLock)
++locks;
@@ -1407,7 +1414,7 @@ void Transaction::printBlocking(int leve
record->recordNumber,
what);
}
-
+ syncRec.unlock();
database->transactionManager->printBlocking(this, level);
}
@@ -1445,14 +1452,7 @@ void Transaction::releaseDependency(void
INTERLOCKED_DECREMENT(dependencies);
if ((dependencies == 0) && !writePending && firstRecord)
- {
- // The Sync is to avoid a race with writeComplete(). It looks whacko, but does the trick
-
- Sync sync(&syncIndexes, "Transaction::releaseDependency");
- sync.lock(Exclusive);
commitRecords();
- }
-
releaseCommittedTransaction();
}
@@ -1497,6 +1497,8 @@ void Transaction::printBlockage(void)
void Transaction::releaseDeferredIndexes(void)
{
+ Sync sync(&syncIndexes, "Transaction::releaseDeferredIndexes");
+ sync.lock(Exclusive);
for (DeferredIndex *deferredIndex; (deferredIndex = deferredIndexes);)
{
ASSERT(deferredIndex->transaction == this);
@@ -1554,7 +1556,8 @@ void Transaction::backlogRecords(void)
void Transaction::validateRecords(void)
{
RecordVersion *record;
-
+ Sync syncRec(&syncRecords,"Transaction::validateRecords");
+ syncRec.lock(Shared);
for (record = firstRecord; record && record->nextInTrans; record = record->nextInTrans)
;
=== modified file 'storage/falcon/Transaction.h'
--- a/storage/falcon/Transaction.h 2008-08-11 13:22:53 +0000
+++ b/storage/falcon/Transaction.h 2008-08-25 18:24:59 +0000
@@ -87,7 +87,8 @@ public:
State getRelativeState(Record* record, uint32 flags);
State getRelativeState (Transaction *transaction, TransId transId, uint32 flags);
- void removeRecord (RecordVersion *record);
+ void removeRecordNoLock (RecordVersion *record);
+ void removeRecord(RecordVersion *record);
void removeRecord (RecordVersion *record, RecordVersion **ptr);
void expungeTransaction (Transaction *transaction);
void commitRecords();
@@ -171,6 +172,7 @@ public:
SyncObject syncObject;
SyncObject syncActive;
SyncObject syncIndexes;
+ SyncObject syncRecords;
SyncObject syncSavepoints;
uint64 totalRecordData; // total bytes of record data for this transaction (unchilled + thawed)
uint32 totalRecords; // total record count
=== modified file 'storage/falcon/TransactionManager.cpp'
--- a/storage/falcon/TransactionManager.cpp 2008-08-14 12:08:37 +0000
+++ b/storage/falcon/TransactionManager.cpp 2008-08-25 21:51:46 +0000
@@ -74,26 +74,25 @@ TransId TransactionManager::findOldestAc
{
Sync syncCommitted(&committedTransactions.syncObject, "TransactionManager::findOldestActive(1)");
syncCommitted.lock(Shared);
- TransId oldestActive = transactionSequence;
+ TransId oldestCommitted = transactionSequence;
for (Transaction *trans = committedTransactions.first; trans; trans = trans->next)
- oldestActive = MIN(trans->transactionId, oldestActive);
+ oldestCommitted = MIN(trans->transactionId, oldestCommitted);
syncCommitted.unlock();
- Sync sync(&activeTransactions.syncObject, "TransactionManager::findOldestActive(2)");
- sync.lock(Shared);
+
Transaction *oldest = findOldest();
if (oldest)
{
- //Log::debug("Oldest transaction %d, oldest ancestor %d, oldest committed %d\n", oldest->transactionId, oldest->oldestActive, oldestActive);
-
- return MIN(oldest->oldestActive, oldestActive);
+ //Log::debug("Oldest transaction %d, oldest ancestor %d, oldest committed %d\n", oldest->transactionId, oldest->oldestActive, oldestCommitted);
+
+ return MIN(oldest->oldestActive, oldestCommitted);
}
//Log::debug("No active, current %d, oldest committed %d\n", transactionSequence, oldestActive);
- return oldestActive;
+ return oldestCommitted;
}
Transaction* TransactionManager::findOldest(void)
@@ -247,16 +246,20 @@ void TransactionManager::rollbackByXid(i
void TransactionManager::print(void)
{
- Sync sync (&activeTransactions.syncObject, "TransactionManager::print(1)");
- sync.lock (Exclusive);
- Sync committedTrans (&committedTransactions.syncObject, "TransactionManager::print(2)");
- committedTrans.lock (Exclusive);
+ Sync syncActive (&activeTransactions.syncObject, "TransactionManager::print(1)");
+ syncActive.lock (Exclusive);
+
+ Sync syncCommitted (&committedTransactions.syncObject, "TransactionManager::print(2)");
+ syncCommitted.lock (Exclusive);
+
Transaction *transaction;
Log::debug("Active Transaction:\n");
for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
transaction->print();
-
+
+ syncActive.unlock();
+
Log::debug("Committed Transaction:\n");
for (transaction = committedTransactions.first; transaction; transaction = transaction->next)
@@ -266,15 +269,19 @@ void TransactionManager::print(void)
void TransactionManager::getTransactionInfo(InfoTable* infoTable)
{
- Sync sync (&activeTransactions.syncObject, "TransactionManager::getTransactionInfo(1)");
- sync.lock (Exclusive);
- Sync committedTrans (&committedTransactions.syncObject, "TransactionManager::getTransactionInfo(2)");
- committedTrans.lock (Exclusive);
+ Sync syncActive (&activeTransactions.syncObject, "TransactionManager::getTransactionInfo(2)");
+ syncActive.lock (Exclusive);
+
+ Sync syncCommitted (&committedTransactions.syncObject, "TransactionManager::getTransactionInfo(1)");
+ syncCommitted.lock (Exclusive);
+
Transaction *transaction;
for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
transaction->getInfo(infoTable);
-
+
+ syncActive.unlock();
+
for (transaction = committedTransactions.first; transaction; transaction = transaction->next)
transaction->getInfo(infoTable);
}
@@ -307,10 +314,12 @@ void TransactionManager::purgeTransactio
void TransactionManager::getSummaryInfo(InfoTable* infoTable)
{
- Sync sync (&activeTransactions.syncObject, "TransactionManager::getSummaryInfo(1)");
- sync.lock (Exclusive);
- Sync committedTrans (&committedTransactions.syncObject, "TransactionManager::getSummaryInfo(2)");
- committedTrans.lock (Exclusive);
+ Sync syncActive (&activeTransactions.syncObject, "TransactionManager::getSummaryInfo(2)");
+ syncActive.lock (Exclusive);
+
+ Sync syncCommitted (&committedTransactions.syncObject, "TransactionManager::getSummaryInfo(1)");
+ syncCommitted.lock (Exclusive);
+
int numberCommitted = committed;
int numberRolledBack = rolledBack;
int numberActive = 0;
@@ -327,14 +336,14 @@ void TransactionManager::getSummaryInfo(
if (transaction->state == Committed)
++numberPendingCommit;
}
+ syncActive.unlock();
for (transaction = committedTransactions.first; transaction; transaction = transaction->next)
if (transaction->writePending)
++numberPendingCompletion;
- committedTrans.unlock();
- sync.unlock();
-
+ syncCommitted.unlock();
+
int n = 0;
infoTable->putInt(n++, numberCommitted);
infoTable->putInt(n++, numberRolledBack);
@@ -402,15 +411,16 @@ void TransactionManager::expungeTransact
Transaction* TransactionManager::findTransaction(TransId transactionId)
{
- Sync syncActiveTrans(&activeTransactions.syncObject, "TransactionManager::findTransaction(1)");
- syncActiveTrans.lock(Shared);
+ Sync syncActive(&activeTransactions.syncObject, "TransactionManager::findTransaction(1)");
+ syncActive.lock(Shared);
Transaction *transaction;
for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
if (transaction->transactionId == transactionId)
return transaction;
- syncActiveTrans.unlock();
+ syncActive.unlock();
+
Sync syncCommitted(&committedTransactions.syncObject, "TransactionManager::findTransaction(2)");
syncCommitted.lock(Shared);
@@ -418,20 +428,21 @@ Transaction* TransactionManager::findTra
if (transaction->transactionId == transactionId)
return transaction;
- return NULL;
+ return NULL;
}
void TransactionManager::validateDependencies(void)
{
- Sync sync(&committedTransactions.syncObject, "TransactionManager::validateDepedendencies(1)");
- sync.lock(Shared);
+ Sync syncActive(&activeTransactions.syncObject, "TransactionManager::validateDepedendencies(1)");
+ syncActive.lock(Shared);
Transaction *transaction;
for (transaction = activeTransactions.first; transaction; transaction = transaction->next)
if (transaction->isActive())
transaction->validateDependencies(false);
- sync.unlock();
+ syncActive.unlock();
+
Sync syncCommitted(&committedTransactions.syncObject, "TransactionManager::validateDepedendencies(2)");
syncCommitted.lock(Shared);
=== modified file 'storage/falcon/ha_falcon.cpp'
--- a/storage/falcon/ha_falcon.cpp 2008-08-28 06:20:55 +0000
+++ b/storage/falcon/ha_falcon.cpp 2008-08-28 08:44:13 +0000
@@ -54,7 +54,7 @@
#endif
#ifndef ONLINE_ALTER
-//#define ONLINE_ALTER
+#define ONLINE_ALTER
#endif
#ifdef DEBUG_BACKLOG
@@ -216,13 +216,13 @@ int StorageInterface::falcon_init(void *
}
catch(SQLException &e)
{
- sql_print_error("Falcon : exception '%s'during initialization",
+ sql_print_error("Falcon: Exception '%s' during initialization",
e.getText());
error = true;
}
catch(...)
{
- sql_print_error(" Falcon : general exception in initialization");
+ sql_print_error(" Falcon: General exception in initialization");
error = true;
}
@@ -398,6 +398,7 @@ StorageInterface::StorageInterface(handl
ref_length = sizeof(lastRecord);
stats.records = 1000;
stats.data_file_length = 10000;
+ stats.index_file_length = 0;
tableLocked = false;
lockForUpdate = false;
storageTable = NULL;
@@ -424,6 +425,9 @@ StorageInterface::StorageInterface(handl
StorageInterface::~StorageInterface(void)
{
+ if (storageTable)
+ storageTable->clearCurrentIndex();
+
if (activeBlobs)
freeActiveBlobs();
@@ -482,6 +486,7 @@ int StorageInterface::open(const char *n
if (!storageShare->initialized)
{
+// storageShare->lockIndexes(true);
storageShare->lock(true);
if (!storageShare->initialized)
@@ -505,6 +510,7 @@ int StorageInterface::open(const char *n
}
storageShare->unlock();
+// storageShare->unlockIndexes();
}
}
@@ -535,6 +541,10 @@ StorageConnection* StorageInterface::get
int StorageInterface::close(void)
{
DBUG_ENTER("StorageInterface::close");
+
+ if (storageTable)
+ storageTable->clearCurrentIndex();
+
unmapFields();
// Temporarily comment out DTrace probes in Falcon, see bug #36403
@@ -672,23 +682,27 @@ void StorageInterface::getDemographics(v
stats.block_size = 4096;
+ storageShare->lockIndexes();
+
for (uint n = 0; n < table->s->keys; ++n)
{
KEY *key = table->s->key_info + n;
- StorageIndexDesc *desc = storageShare->getIndex(n);
+ StorageIndexDesc *indexDesc = storageShare->getIndex(n);
- if (desc)
+ if (indexDesc)
{
- ha_rows rows = 1 << desc->numberSegments;
+ ha_rows rows = 1 << indexDesc->numberSegments;
for (uint segment = 0; segment < key->key_parts; ++segment, rows >>= 1)
{
- ha_rows recordsPerSegment = (ha_rows) desc->segmentRecordCounts[segment];
+ ha_rows recordsPerSegment = (ha_rows)indexDesc->segmentRecordCounts[segment];
key->rec_per_key[segment] = (ulong) MAX(recordsPerSegment, rows);
}
}
}
+ storageShare->unlockIndexes();
+
DBUG_VOID_RETURN;
}
@@ -832,7 +846,7 @@ int StorageInterface::create(const char
for (n = 0; n < form->s->keys; ++n)
if (n != form->s->primary_key)
- if ((ret = createIndex(schemaName, tableName, form->key_info + n, n)))
+ if ((ret = createIndex(schemaName, tableName, form, n)))
{
storageTable->deleteTable();
@@ -847,32 +861,42 @@ int StorageInterface::create(const char
int StorageInterface::add_index(TABLE* table_arg, KEY* key_info, uint num_of_keys)
{
DBUG_ENTER("StorageInterface::add_index");
- int ret = createIndex(storageTable->getSchemaName(), storageTable->getName(), key_info, table_arg->s->keys);
+ int ret = createIndex(storageTable->getSchemaName(), storageTable->getName(), table_arg, table_arg->s->keys);
DBUG_RETURN(ret);
}
-int StorageInterface::createIndex(const char *schemaName, const char *tableName,
- KEY *key, int indexNumber)
+int StorageInterface::createIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId)
{
+ KEY *key = table->key_info + indexId;
+ StorageIndexDesc indexDesc;
+ getKeyDesc(table, indexId, &indexDesc);
+
+ char indexName[indexNameSize];
+ storageShare->createIndexName(indexDesc.name, indexName);
+
CmdGen gen;
const char *unique = (key->flags & HA_NOSAME) ? "unique " : "";
- gen.gen("create %sindex \"%s$%d\" on %s.\"%s\" ", unique, tableName,
- indexNumber, schemaName, tableName);
+ gen.gen("create %sindex \"%s\" on %s.\"%s\" ", unique, indexName, schemaName, tableName);
genKeyFields(key, &gen);
const char *sql = gen.getString();
- return storageTable->share->createIndex(storageConnection, key->name, sql);
+ return storageTable->createIndex(&indexDesc, sql);
}
-int StorageInterface::dropIndex(const char *schemaName, const char *tableName,
- KEY *key, int indexNumber)
+int StorageInterface::dropIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId)
{
+ StorageIndexDesc indexDesc;
+ getKeyDesc(table, indexId, &indexDesc);
+
+ char indexName[indexNameSize];
+ storageShare->createIndexName(indexDesc.name, indexName);
+
CmdGen gen;
- gen.gen("drop index %s.\"%s$%d\"", schemaName, tableName, indexNumber);
+ gen.gen("drop index %s.\"%s\"", schemaName, indexName);
const char *sql = gen.getString();
- return storageTable->share->dropIndex(storageConnection, key->name, sql);
+ return storageTable->dropIndex(&indexDesc, sql);
}
#if 0
@@ -916,6 +940,8 @@ THR_LOCK_DATA **StorageInterface::store_
&& !(thd_tablespace_op(thd))
&& (sql_command != SQLCOM_ALTER_TABLE)
&& (sql_command != SQLCOM_DROP_TABLE)
+ && (sql_command != SQLCOM_CREATE_INDEX)
+ && (sql_command != SQLCOM_DROP_INDEX)
&& (sql_command != SQLCOM_TRUNCATE)
&& (sql_command != SQLCOM_OPTIMIZE)
&& (sql_command != SQLCOM_CREATE_TABLE)
@@ -963,6 +989,10 @@ int StorageInterface::delete_table(const
if (storageShare)
{
+
+ // Lock out other clients before locking the table
+
+ storageShare->lockIndexes(true);
storageShare->lock(true);
if (storageShare->initialized)
@@ -973,6 +1003,7 @@ int StorageInterface::delete_table(const
}
storageShare->unlock();
+ storageShare->unlockIndexes();
}
int res = storageTable->deleteTable();
@@ -1358,7 +1389,6 @@ int StorageInterface::index_read(uchar *
}
}
-
int StorageInterface::index_init(uint idx, bool sorted)
{
DBUG_ENTER("StorageInterface::index_init");
@@ -1367,33 +1397,30 @@ int StorageInterface::index_init(uint id
haveStartKey = false;
haveEndKey = false;
- if (!storageTable->setIndex(idx))
- DBUG_RETURN(0);
-
- StorageIndexDesc indexDesc;
- getKeyDesc(table->key_info + idx, &indexDesc);
-
- if (idx == table->s->primary_key)
- indexDesc.primaryKey = true;
-
- int ret = storageTable->setIndex(table->s->keys, idx, &indexDesc);
+ int ret = storageTable->setCurrentIndex(idx);
if (ret)
+ {
+ setIndex(table, idx);
+ ret = storageTable->setCurrentIndex(idx);
+ }
+
+ if (ret)
DBUG_RETURN(error(ret));
- DBUG_RETURN(0);
+ DBUG_RETURN(ret);
}
-
int StorageInterface::index_end(void)
{
DBUG_ENTER("StorageInterface::index_end");
+
storageTable->indexEnd();
+
DBUG_RETURN(0);
}
-ha_rows StorageInterface::records_in_range(uint indexId, key_range *lower,
- key_range *upper)
+ha_rows StorageInterface::records_in_range(uint indexId, key_range *lower, key_range *upper)
{
DBUG_ENTER("StorageInterface::records_in_range");
@@ -1406,9 +1433,9 @@ ha_rows StorageInterface::records_in_ran
if (!lower)
DBUG_RETURN(MAX(cardinality, 2));
- StorageIndexDesc *index = storageShare->getIndex(indexId);
+ StorageIndexDesc indexDesc;
- if (!index)
+ if (!storageShare->getIndex(indexId, &indexDesc))
DBUG_RETURN(MAX(cardinality, 2));
int numberSegments = 0;
@@ -1416,10 +1443,10 @@ ha_rows StorageInterface::records_in_ran
for (int map = lower->keypart_map; map; map >>= 1)
++numberSegments;
- if (index->unique && numberSegments == index->numberSegments)
+ if (indexDesc.unique && numberSegments == indexDesc.numberSegments)
DBUG_RETURN(1);
- ha_rows segmentRecords = (ha_rows) index->segmentRecordCounts[numberSegments - 1];
+ ha_rows segmentRecords = (ha_rows)indexDesc.segmentRecordCounts[numberSegments - 1];
ha_rows guestimate = cardinality;
if (lower->flag == HA_READ_KEY_EXACT)
@@ -1436,22 +1463,34 @@ ha_rows StorageInterface::records_in_ran
DBUG_RETURN(MAX(guestimate, 2));
}
-
-void StorageInterface::getKeyDesc(KEY *keyInfo, StorageIndexDesc *indexInfo)
+void StorageInterface::getKeyDesc(TABLE *table, int indexId, StorageIndexDesc *indexDesc)
{
+ KEY *keyInfo = table->key_info + indexId;
int numberKeys = keyInfo->key_parts;
- indexInfo->numberSegments = numberKeys;
- indexInfo->name = keyInfo->name;
- indexInfo->unique = (keyInfo->flags & HA_NOSAME);
- indexInfo->primaryKey = false;
+ char nameBuffer[indexNameSize];
+
+ // Clean up the index name for internal use
+
+ strncpy(indexDesc->rawName, (const char*)keyInfo->name, MIN(indexNameSize, (int)strlen(keyInfo->name)+1));
+ storageShare->cleanupFieldName(indexDesc->rawName, nameBuffer, sizeof(nameBuffer));
+ indexDesc->rawName[indexNameSize-1] = '\0';
+
+ strncpy(indexDesc->name, (const char*)nameBuffer, MIN(indexNameSize, (int)strlen(nameBuffer)+1));
+ indexDesc->name[indexNameSize-1] = '\0';
+
+ indexDesc->id = indexId;
+ indexDesc->numberSegments = numberKeys;
+ indexDesc->unique = (keyInfo->flags & HA_NOSAME);
+ indexDesc->primaryKey = (table->s->primary_key == (uint)indexId);
for (int n = 0; n < numberKeys; ++n)
{
- StorageSegment *segment = indexInfo->segments + n;
+ StorageSegment *segment = indexDesc->segments + n;
KEY_PART_INFO *part = keyInfo->key_part + n;
- segment->offset = part->offset;
- segment->length = part->length;
- segment->type = part->field->key_type();
+
+ segment->offset = part->offset;
+ segment->length = part->length;
+ segment->type = part->field->key_type();
segment->nullBit = part->null_bit;
segment->isUnsigned = (part->field->flags & ENUM_FLAG) ?
true : ((Field_num*) part->field)->unsigned_flag;
@@ -1472,7 +1511,6 @@ void StorageInterface::getKeyDesc(KEY *k
}
}
-
int StorageInterface::rename_table(const char *from, const char *to)
{
DBUG_ENTER("StorageInterface::rename_table");
@@ -1489,17 +1527,14 @@ int StorageInterface::rename_table(const
DBUG_RETURN(error(ret));
DBUG_RETURN(ret);
-
}
-
double StorageInterface::read_time(uint index, uint ranges, ha_rows rows)
{
DBUG_ENTER("StorageInterface::read_time");
DBUG_RETURN(rows2double(rows / 3));
}
-
int StorageInterface::read_range_first(const key_range *start_key,
const key_range *end_key,
bool eq_range_arg, bool sorted)
@@ -1634,7 +1669,6 @@ int StorageInterface::index_next(uchar *
}
}
-
int StorageInterface::index_next_same(uchar *buf, const uchar *key, uint key_len)
{
DBUG_ENTER("StorageInterface::index_next_same");
@@ -1654,7 +1688,6 @@ int StorageInterface::index_next_same(uc
}
}
-
double StorageInterface::scan_time(void)
{
DBUG_ENTER("StorageInterface::scan_time");
@@ -1691,13 +1724,11 @@ bool StorageInterface::threadSwitch(THD*
return true;
}
-
int StorageInterface::threadSwitchError(void)
{
return 1;
}
-
int StorageInterface::error(int storageError)
{
DBUG_ENTER("StorageInterface::error");
@@ -1737,7 +1768,6 @@ int StorageInterface::error(int storageE
DBUG_RETURN(mySqlError);
}
-
int StorageInterface::getMySqlError(int storageError)
{
switch (storageError)
@@ -1856,8 +1886,6 @@ int StorageInterface::reset()
DBUG_RETURN(0);
}
-
-
int StorageInterface::external_lock(THD *thd, int lock_type)
{
DBUG_ENTER("StorageInterface::external_lock");
@@ -1873,7 +1901,10 @@ int StorageInterface::external_lock(THD
storageConnection->releaseVerb();
if (storageTable)
+ {
storageTable->clearStatement();
+ storageTable->clearCurrentIndex();
+ }
}
else
{
@@ -1894,6 +1925,9 @@ int StorageInterface::external_lock(THD
if (ret)
{
+ if (storageTable)
+ storageTable->clearCurrentIndex();
+
DBUG_RETURN(error(ret));
}
}
@@ -1910,9 +1944,7 @@ int StorageInterface::external_lock(THD
checkBinLog();
if (storageConnection->startTransaction(isolation))
- {
trans_register_ha(thd, true, falcon_hton);
- }
if (storageConnection->markVerb())
trans_register_ha(thd, false, falcon_hton);
@@ -1922,9 +1954,7 @@ int StorageInterface::external_lock(THD
checkBinLog();
if (storageConnection->startImplicitTransaction(isolation))
- {
trans_register_ha(thd, false, falcon_hton);
- }
}
switch (thd_tx_isolation(mySqlThread))
@@ -1937,13 +1967,11 @@ int StorageInterface::external_lock(THD
error(StorageWarningSerializable);
break;
}
-
}
DBUG_RETURN(0);
}
-
void StorageInterface::get_auto_increment(ulonglong offset, ulonglong increment,
ulonglong nb_desired_values,
ulonglong *first_value,
@@ -1956,7 +1984,6 @@ void StorageInterface::get_auto_incremen
DBUG_VOID_RETURN;
}
-
const char *StorageInterface::index_type(uint key_number)
{
DBUG_ENTER("StorageInterface::index_type");
@@ -1971,7 +1998,6 @@ void StorageInterface::dropDatabase(hand
DBUG_VOID_RETURN;
}
-
void StorageInterface::freeActiveBlobs(void)
{
for (StorageBlob *blob; (blob = activeBlobs); )
@@ -1983,14 +2009,12 @@ void StorageInterface::freeActiveBlobs(v
}
}
-
void StorageInterface::shutdown(handlerton *htons)
{
if(storageHandler)
storageHandler->shutdownHandler();
}
-
int StorageInterface::panic(handlerton* hton, ha_panic_function flag)
{
if(storageHandler)
@@ -1999,7 +2023,6 @@ int StorageInterface::panic(handlerton*
return 0;
}
-
int StorageInterface::closeConnection(handlerton *hton, THD *thd)
{
DBUG_ENTER("NfsStorageEngine::closeConnection");
@@ -2009,7 +2032,6 @@ int StorageInterface::closeConnection(ha
DBUG_RETURN(0);
}
-
int StorageInterface::alter_tablespace(handlerton* hton, THD* thd, st_alter_tablespace* ts_info)
{
DBUG_ENTER("NfsStorageEngine::alter_tablespace");
@@ -2228,10 +2250,15 @@ int StorageInterface::addColumn(THD* thd
int StorageInterface::addIndex(THD* thd, TABLE* alteredTable, HA_CREATE_INFO* createInfo, HA_ALTER_INFO* alterInfo, HA_ALTER_FLAGS* alterFlags)
{
- int ret;
+ int ret = 0;
const char *tableName = storageTable->getName();
const char *schemaName = storageTable->getSchemaName();
+ // Lock out other clients before locking the table
+
+ storageShare->lockIndexes(true);
+ storageShare->lock(true);
+
// Find indexes to be added by comparing table and alteredTable
for (unsigned int n = 0; n < alteredTable->s->keys; n++)
@@ -2247,19 +2274,33 @@ int StorageInterface::addIndex(THD* thd,
break;
if (tableKey >= tableEnd)
- if ((ret = createIndex(schemaName, tableName, key, n)))
- return (error(ret));
+ if ((ret = createIndex(schemaName, tableName, alteredTable, n)))
+ break;
}
}
- return 0;
+
+ // The server indexes may have been reordered, so remap to the Falcon indexes
+
+ if (!ret)
+ remapIndexes(alteredTable);
+
+ storageShare->unlock();
+ storageShare->unlockIndexes();
+
+ return error(ret);
}
int StorageInterface::dropIndex(THD* thd, TABLE* alteredTable, HA_CREATE_INFO* createInfo, HA_ALTER_INFO* alterInfo, HA_ALTER_FLAGS* alterFlags)
{
- int ret;
+ int ret = 0;
const char *tableName = storageTable->getName();
const char *schemaName = storageTable->getSchemaName();
+ // Lock out other clients before locking the table
+
+ storageShare->lockIndexes(true);
+ storageShare->lock(true);
+
// Find indexes to be dropped by comparing table and alteredTable
for (unsigned int n = 0; n < table->s->keys; n++)
@@ -2275,12 +2316,20 @@ int StorageInterface::dropIndex(THD* thd
break;
if (alterKey >= alterEnd)
- if ((ret = dropIndex(schemaName, tableName, key, n)))
- return (error(ret));
+ if ((ret = dropIndex(schemaName, tableName, table, n)))
+ break;
}
}
- return 0;
+ // The server indexes have been reordered, so remap to the Falcon indexes
+
+ if (!ret)
+ remapIndexes(alteredTable);
+
+ storageShare->unlock();
+ storageShare->unlockIndexes();
+
+ return error(ret);
}
uint StorageInterface::max_supported_key_length(void) const
@@ -2292,7 +2341,6 @@ uint StorageInterface::max_supported_key
return MAX_INDEX_KEY_LENGTH_4K; // Default value.
}
-
uint StorageInterface::max_supported_key_part_length(void) const
{
// Assume 4K page unless proven otherwise.
@@ -2302,7 +2350,6 @@ uint StorageInterface::max_supported_key
return MAX_INDEX_KEY_LENGTH_4K; // Default for future sizes.
}
-
void StorageInterface::logger(int mask, const char* text, void* arg)
{
if (mask & falcon_debug_mask)
@@ -2318,32 +2365,47 @@ void StorageInterface::logger(int mask,
}
}
+int StorageInterface::setIndex(TABLE *table, int indexId)
+{
+ StorageIndexDesc indexDesc;
+ getKeyDesc(table, indexId, &indexDesc);
+
+ return storageTable->setIndex(&indexDesc);
+}
+
int StorageInterface::setIndexes(void)
{
+ int ret = 0;
+
if (!table || storageShare->haveIndexes(table->s->keys))
- return 0;
+ return ret;
- storageShare->lock(true);
+ storageShare->lockIndexes(true);
if (!storageShare->haveIndexes(table->s->keys))
- {
- StorageIndexDesc indexDesc;
-
for (uint n = 0; n < table->s->keys; ++n)
- {
- getKeyDesc(table->key_info + n, &indexDesc);
+ if ((ret = setIndex(table, n)))
+ break;
- if (n == table->s->primary_key)
- indexDesc.primaryKey = true;
+ storageShare->unlockIndexes();
- int ret = storageTable->setIndex(table->s->keys, n, &indexDesc);
- if (ret)
- return ret;
- }
- }
+ return ret;
+}
- storageShare->unlock();
- return 0;
+int StorageInterface::remapIndexes(TABLE *table)
+{
+ int ret = 0;
+
+ if (!table)
+ return ret;
+
+ storageShare->deleteIndexes();
+
+ for (uint n = 0; n < table->s->keys; ++n)
+ if ((ret = setIndex(table, n)))
+ break;
+
+ return ret;
}
int StorageInterface::genTable(TABLE* table, CmdGen* gen)
@@ -2352,7 +2414,7 @@ int StorageInterface::genTable(TABLE* ta
const char *schemaName = storageTable->getSchemaName();
gen->gen("upgrade table \"%s\".\"%s\" (\n", schemaName, tableName);
const char *sep = "";
- char nameBuffer[129];
+ char nameBuffer[256];
for (uint n = 0; n < table->s->fields; ++n)
{
@@ -2499,18 +2561,16 @@ int StorageInterface::genType(Field* fie
return 0;
}
-
void StorageInterface::genKeyFields(KEY* key, CmdGen* gen)
{
const char *sep = "(";
- char nameBuffer[129];
+ char nameBuffer[256];
for (uint n = 0; n < key->key_parts; ++n)
{
KEY_PART_INFO *part = key->key_part + n;
Field *field = part->field;
- storageShare->cleanupFieldName(field->field_name, nameBuffer,
- sizeof(nameBuffer));
+ storageShare->cleanupFieldName(field->field_name, nameBuffer, sizeof(nameBuffer));
if (part->key_part_flag & HA_PART_KEY_SEG)
gen->gen("%s\"%s\"(%d)", sep, nameBuffer, part->length);
@@ -2523,7 +2583,6 @@ void StorageInterface::genKeyFields(KEY*
gen->gen(")");
}
-
void StorageInterface::encodeRecord(uchar *buf, bool updateFlag)
{
storageTable->preInsert();
@@ -3508,7 +3567,7 @@ void StorageInterface::mapFields(TABLE *
unmapFields();
fieldMap = new Field*[maxFields];
memset(fieldMap, 0, sizeof(fieldMap[0]) * maxFields);
- char nameBuffer[129];
+ char nameBuffer[256];
for (uint n = 0; n < table->s->fields; ++n)
{
=== modified file 'storage/falcon/ha_falcon.h'
--- a/storage/falcon/ha_falcon.h 2008-07-29 10:45:39 +0000
+++ b/storage/falcon/ha_falcon.h 2008-08-22 06:47:40 +0000
@@ -29,7 +29,7 @@ static const int TRANSACTION_CONSISTENT_
static const int TRANSACTION_SERIALIZABLE = 16; // Dirty reads, non-repeatable reads and phantom reads are prevented.
struct st_table_share;
-struct StorageIndexDesc;
+class StorageIndexDesc;
struct StorageBlob;
class StorageInterface : public handler
@@ -113,15 +113,18 @@ public:
int dropIndex(THD* thd, TABLE* alteredTable, HA_CREATE_INFO* createInfo, HA_ALTER_INFO* alterInfo, HA_ALTER_FLAGS* alterFlags);
void getDemographics(void);
- int createIndex(const char *schemaName, const char *tableName, KEY *key, int indexNumber);
- int dropIndex(const char *schemaName, const char *tableName, KEY *key, int indexNumber);
- void getKeyDesc(KEY *keyInfo, StorageIndexDesc *indexInfo);
+// int createIndex(const char *schemaName, const char *tableName, KEY *key, int indexId);
+ int createIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId);
+ int dropIndex(const char *schemaName, const char *tableName, TABLE *table, int indexId);
+ void getKeyDesc(TABLE *table, int indexId, StorageIndexDesc *indexInfo);
void startTransaction(void);
bool threadSwitch(THD *newThread);
int threadSwitchError(void);
int error(int storageError);
void freeActiveBlobs(void);
+ int setIndex(TABLE *table, int indexId);
int setIndexes(void);
+ int remapIndexes(TABLE *table);
int genTable(TABLE* table, CmdGen* gen);
int genType(Field *field, CmdGen *gen);
void genKeyFields(KEY *key, CmdGen *gen);
=== modified file 'storage/falcon/plug.in'
--- a/storage/falcon/plug.in 2008-08-12 21:50:50 +0000
+++ b/storage/falcon/plug.in 2008-08-20 13:27:29 +0000
@@ -19,6 +19,18 @@ volatile int target= 0;
int compare= 1;
int exchange= 2;
],[
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+ /* When compiling with Sun Studio compiler we need the Solaris atomic
+ functions. These were first introduced in Solaris 10. */
+#if defined(HAVE_SOLARIS_ATOMIC)
+ return 0;
+#else
+ /* Fail if the atomic functions are not available. Support for this
+ will be added when the fix for bug 37622 is completed. */
+#error Need Solaris atomic functions to use Sun Studio compiler
+#endif /* HAVE_SOLARIS_ATOMIC */
+#else
+ /* Use gcc style inline assembly when compiling with gcc */
char ret;
__asm__ __volatile__ (
"membar #LoadLoad | #LoadStore | #StoreLoad | #StoreStore\n\t"
@@ -32,6 +44,7 @@ int exchange= 2;
: "r" (&target), "0" (compare)
: "memory", "cc"
)
+#endif /* !__SUNPRO_C && !__SUNPRO_CC */
], falcon_supported_by_machine="yes",
falcon_supported_by_machine="no")
;;
=== modified file 'storage/maria/CMakeLists.txt'
--- a/storage/maria/CMakeLists.txt 2008-06-09 09:06:06 +0000
+++ b/storage/maria/CMakeLists.txt 2008-08-26 18:57:58 +0000
@@ -49,6 +49,7 @@ SET(MARIA_SOURCES ma_init.c ma_open.c ma
IF(NOT SOURCE_SUBLIBS)
ADD_LIBRARY(maria ${MARIA_SOURCES})
+ ADD_DEPENDENCIES(ha_falcon GenError)
ADD_EXECUTABLE(maria_ftdump maria_ftdump.c)
TARGET_LINK_LIBRARIES(maria_ftdump maria myisam mysys dbug strings zlib wsock32)
| Thread |
|---|
| • bzr commit into mysql-6.0 branch (kgeorge:2808) | Georgi Kodinov | 28 Aug |