1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Implementation of MDEV-5491: CREATE OR REPLACE TABLE

Using CREATE OR REPLACE TABLE is be identical to

DROP TABLE IF EXISTS table_name;
CREATE TABLE ...;

Except that:

* CREATE OR REPLACE is be atomic (now one can create the same table between drop and create).
* Temporary tables will not shadow the table name for the DROP as the CREATE TABLE tells us already if we are using a temporary table or not.
* If the table was locked with LOCK TABLES, the new table will be locked with the same lock after it's created.

Implementation details:
- We don't anymore open the to-be-created table during CREATE TABLE, which the original code did.
  - There is no need to open a table we are planning to create. It's enough to check if the table exists or not.
- Removed some of duplicated code for CREATE IF NOT EXISTS.
- Give an error when using CREATE OR REPLACE with IF NOT EXISTS (conflicting options).
- As a side effect of the code changes, we don't anymore have to internally re-prepare prepared statements with CREATE TABLE if the table exists.
- Made one code path for all testing if log table are in use.
- Better error message if one tries to create/drop/alter a log table in use
- Added back disabled rpl_row_create_table test as it now seams to work and includes a lot of interesting tests.
- Added HA_LEX_CREATE_REPLACE to mark if we are using CREATE OR REPLACE
- Aligned CREATE OR REPLACE parsing code in sql_yacc.yy for TABLE and VIEW
- Changed interface for drop_temporary_table() to make it more reusable
- Changed Locked_tables_list::init_locked_tables() to work on the table object instead of the table list object. Before this it used a mix of both, which was not good.
- Locked_tables_list::unlock_locked_tables(THD *thd) now requires a valid thd argument. Old usage of calling this with 0 i changed to instead call Locked_tables_list::reset()
- Added functions Locked_tables_list:restore_lock() and Locked_tables_list::add_back_last_deleted_lock() to be able to easily add back a locked table to the lock list.
- Added restart_trans_for_tables() to be able to restart a transaction.
- DROP_ACL is required if one uses CREATE TABLE OR REPLACE.
- Added drop of normal and temporary tables in create_table_imp() if CREATE OR REPLACE was used.
- Added reacquiring of table locks in mysql_create_table() and mysql_create_like_table()




mysql-test/include/commit.inc:
  With new code we get fewer status increments
mysql-test/r/commit_1innodb.result:
  With new code we get fewer status increments
mysql-test/r/create.result:
  Added testing of create or replace with timeout
mysql-test/r/create_or_replace.result:
  Basic testing of CREATE OR REPLACE TABLE
mysql-test/r/partition_exchange.result:
  New error message
mysql-test/r/ps_ddl.result:
  Fewer reprepares with new code
mysql-test/suite/archive/discover.result:
  Don't rediscover archive tables if the .frm file exists
  (Sergei will look at this if there is a better way...)
mysql-test/suite/archive/discover.test:
  Don't rediscover archive tables if the .frm file exists
  (Sergei will look at this if there is a better way...)
mysql-test/suite/funcs_1/r/innodb_views.result:
  New error message
mysql-test/suite/funcs_1/r/memory_views.result:
  New error message
mysql-test/suite/rpl/disabled.def:
  rpl_row_create_table should now be safe to use
mysql-test/suite/rpl/r/rpl_row_create_table.result:
  Updated results after adding back disabled test
mysql-test/suite/rpl/t/rpl_create_if_not_exists.test:
  Added comment
mysql-test/suite/rpl/t/rpl_row_create_table.test:
  Added CREATE OR REPLACE TABLE test
mysql-test/t/create.test:
  Added CREATE OR REPLACE TABLE test
mysql-test/t/create_or_replace-master.opt:
  Create logs
mysql-test/t/create_or_replace.test:
  Basic testing of CREATE OR REPLACE TABLE
mysql-test/t/partition_exchange.test:
  Error number changed as we are now using same code for all log table change issues
mysql-test/t/ps_ddl.test:
  Fewer reprepares with new code
sql/handler.h:
  Moved things around a bit in a structure to get better alignment.
  Added HA_LEX_CREATE_REPLACE to mark if we are using CREATE OR REPLACE
  Added 3 elements to end of HA_CREATE_INFO to be able to store state to add backs locks in case of LOCK TABLES.
sql/log.cc:
  Reimplemented check_if_log_table():
  - Simpler and faster usage
  - Can give error messages
  
  This gives us one code path for allmost all error messages if log tables are in use
sql/log.h:
  New interface for check_if_log_table()
sql/slave.cc:
  More logging
sql/sql_alter.cc:
  New interface for check_if_log_table()
sql/sql_base.cc:
  More documentation
  Changed interface for drop_temporary_table() to make it more reusable
  Changed Locked_tables_list::init_locked_tables() to work on the table object instead of the table list object. Before this it used a mix of both, which was not good.
  Locked_tables_list::unlock_locked_tables(THD *thd) now requires a valid thd argument.  Old usage of calling this with 0 i changed to instead call Locked_tables_list::reset()
  Added functions Locked_tables_list:restore_lock() and Locked_tables_list::add_back_last_deleted_lock() to be able to easily add back a locked table to the lock list.
  Check for command number instead of open_strategy of CREATE TABLE was used.
  Added restart_trans_for_tables() to be able to restart a transaction.  This was needed in "create or replace ... select" between the drop table and the select.
sql/sql_base.h:
  Added and updated function prototypes
sql/sql_class.h:
  Added new prototypes to Locked_tables_list class
  Added extra argument to select_create to avoid double call to eof() or send_error()
  - I needed this in some edge case where the table was not created against expections.
sql/sql_db.cc:
  New interface for check_if_log_table()
sql/sql_insert.cc:
  Remember position to lock information so that we can reaquire table lock for LOCK TABLES + CREATE OR REPLACE TABLE SELECT. Later add back the lock by calling restore_lock().
  Removed one not needed indentation level in create_table_from_items()
  Ensure we don't call send_eof() or abort_result_set() twice.
sql/sql_lex.h:
  Removed variable that I temporarly added in an earlier changeset
sql/sql_parse.cc:
  Removed old test code (marked with QQ)
  Ensure that we have open_strategy set as TABLE_LIST::OPEN_STUB in CREATE TABLE
  Removed some IF NOT EXISTS code as this is now handled in create_table_table_impl().
  Set OPTION_KEEP_LOGS later. This code had to be moved as the test for IF EXISTS has changed place.
  DROP_ACL is required if one uses CREATE TABLE OR REPLACE.
sql/sql_partition_admin.cc:
  New interface for check_if_log_table()
sql/sql_rename.cc:
  New interface for check_if_log_table()
sql/sql_table.cc:
  New interface for check_if_log_table()
  Moved some code in mysql_rm_table() under a common test.
  - Safe as temporary tables doesn't have statistics.
  - !is_temporary_table(table) test was moved out from drop_temporary_table() and merged with upper level code.
  - Added drop of normal and temporary tables in create_table_imp() if CREATE OR REPLACE was used.
  - Added reacquiring of table locks in mysql_create_table() and mysql_create_like_table()
  - In mysql_create_like_table(), restore table->open_strategy() if it was changed.
  - Re-test if table was a view after opening it.
sql/sql_table.h:
  New prototype for mysql_create_table_no_lock()
sql/sql_yacc.yy:
  Added syntax for CREATE OR REPLACE TABLE
  Reuse new code for CREATE OR REPLACE VIEW
sql/table.h:
  Added name for enum type
sql/table_cache.cc:
  More DBUG
This commit is contained in:
Michael Widenius
2014-01-29 15:37:17 +02:00
parent 659304d410
commit 7ffc9da093
38 changed files with 1207 additions and 420 deletions

View File

@ -751,7 +751,7 @@ call p_verify_status_increment(4, 4, 4, 4);
--echo # Sic: no table is created. --echo # Sic: no table is created.
create table if not exists t2 (a int) select 6 union select 7; create table if not exists t2 (a int) select 6 union select 7;
--echo # Sic: first commits the statement, and then the transaction. --echo # Sic: first commits the statement, and then the transaction.
call p_verify_status_increment(2, 0, 2, 0); call p_verify_status_increment(0, 0, 0, 0);
create table t3 select a from t2; create table t3 select a from t2;
call p_verify_status_increment(2, 0, 4, 4); call p_verify_status_increment(2, 0, 4, 4);
alter table t3 add column (b int); alter table t3 add column (b int);

View File

@ -830,7 +830,7 @@ create table if not exists t2 (a int) select 6 union select 7;
Warnings: Warnings:
Note 1050 Table 't2' already exists Note 1050 Table 't2' already exists
# Sic: first commits the statement, and then the transaction. # Sic: first commits the statement, and then the transaction.
call p_verify_status_increment(2, 0, 2, 0); call p_verify_status_increment(0, 0, 0, 0);
SUCCESS SUCCESS
create table t3 select a from t2; create table t3 select a from t2;

View File

@ -2602,6 +2602,8 @@ create table t1 (a int, b int) select 2,2;
ERROR 42S01: Table 't1' already exists ERROR 42S01: Table 't1' already exists
create table t1 like t2; create table t1 like t2;
ERROR 42S01: Table 't1' already exists ERROR 42S01: Table 't1' already exists
create or replace table t1 (a int, b int) select 2,2;
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
select * from t1; select * from t1;
a b a b
1 1 1 1

View File

@ -0,0 +1,293 @@
drop table if exists t1,t2;
CREATE TABLE t2 (a int);
INSERT INTO t2 VALUES(1),(2),(3);
#
# Check first syntax and wrong usage
#
CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int);
ERROR HY000: Incorrect usage of OR REPLACE and IF NOT EXISTS
create or replace trigger trg before insert on t1 for each row set @a:=1;
ERROR HY000: Incorrect usage of OR REPLACE and TRIGGERS / SP / EVENT
create or replace table mysql.general_log (a int);
ERROR HY000: You cannot 'CREATE OR REPLACE' a log table if logging is enabled
create or replace table mysql.slow_log (a int);
ERROR HY000: You cannot 'CREATE OR REPLACE' a log table if logging is enabled
#
# Usage when table doesn't exist
#
CREATE OR REPLACE TABLE t1 (a int);
CREATE TABLE t1 (a int);
ERROR 42S01: Table 't1' already exists
DROP TABLE t1;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int);
CREATE TEMPORARY TABLE t1 (a int, b int, c int);
ERROR 42S01: Table 't1' already exists
DROP TEMPORARY TABLE t1;
#
# Testing with temporary tables
#
CREATE OR REPLACE TABLE t1 (a int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TEMPORARY TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TEMPORARY TABLE t1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
create temporary table t1 (i int) engine=InnoDB;
create or replace temporary table t1 (a int, b int) engine=InnoDB;
create or replace temporary table t1 (j int);
show create table t1;
Table Create Table
t1 CREATE TEMPORARY TABLE `t1` (
`j` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine= innodb;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int) engine= innodb;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine=myisam;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TEMPORARY TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TEMPORARY TABLE t1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
CREATE OR REPLACE TABLE t2 (a int);
ERROR HY000: Table 't2' was not locked with LOCK TABLES
DROP TABLE t1;
UNLOCK TABLES;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int) SELECT * from t2;
SELECT * FROM t1;
a
1
2
3
CREATE OR REPLACE TEMPORARY TABLE t1 (b int) SELECT * from t2;
SELECT * FROM t1;
b a
NULL 1
NULL 2
NULL 3
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TEMPORARY TABLE `t1` (
`b` int(11) DEFAULT NULL,
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TEMPORARY TABLE t1 AS SELECT a FROM t2;
CREATE TEMPORARY TABLE IF NOT EXISTS t1(a int, b int) SELECT 1,2 FROM t2;
Warnings:
Note 1050 Table 't1' already exists
create or replace table t1 as select 1;
show create table t1;
Table Create Table
t1 CREATE TEMPORARY TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
#
# Testing with normal tables
#
CREATE OR REPLACE TABLE t1 (a int);
CREATE OR REPLACE TABLE t1 (a int, b int);
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a int) SELECT * from t2;
SELECT * FROM t1;
a
1
2
3
TRUNCATE TABLE t1;
CREATE TABLE IF NOT EXISTS t1 (a int) SELECT * from t2;
Warnings:
Note 1050 Table 't1' already exists
SELECT * FROM t1;
a
DROP TABLE t1;
CREATE TABLE t1 (i int);
CREATE OR REPLACE TABLE t1 AS SELECT 1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`1` int(1) NOT NULL DEFAULT '0'
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write,t2 write;
CREATE OR REPLACE TABLE t1 (a int, b int);
SELECT * FROM t1;
a b
INSERT INTO t1 values(1,1);
CREATE OR REPLACE TABLE t1 (a int, b int, c int);
INSERT INTO t1 values(1,1,1);
CREATE OR REPLACE TABLE t3 (a int);
ERROR HY000: Table 't3' was not locked with LOCK TABLES
UNLOCK TABLES;
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write,t2 write;
CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2;
SELECT * FROM t2;
a
1
2
3
SELECT * FROM t1;
b a 1
NULL 1 1
NULL 2 1
NULL 3 1
SELECT * FROM t1;
b a 1
NULL 1 1
NULL 2 1
NULL 3 1
INSERT INTO t1 values(1,1,1);
CREATE OR REPLACE TABLE t1 (a int, b int, c int, d int);
INSERT INTO t1 values(1,1,1,1);
CREATE OR REPLACE TABLE t3 (a int);
ERROR HY000: Table 't3' was not locked with LOCK TABLES
UNLOCK TABLES;
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write,t2 write, t1 as t1_read read;
CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2;
SELECT * FROM t1;
b a 1
NULL 1 1
NULL 2 1
NULL 3 1
SELECT * FROM t2;
a
1
2
3
SELECT * FROM t1 as t1_read;
ERROR HY000: Table 't1_read' was not locked with LOCK TABLES
DROP TABLE t1;
UNLOCK TABLES;
#
# Test also with InnoDB (transactional engine)
#
create table t1 (i int) engine=innodb;
lock table t1 write;
create or replace table t1 (j int);
unlock tables;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`j` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (i int) engine=InnoDB;
lock table t1 write, t2 write;
create or replace table t1 (j int) engine=innodb;
unlock tables;
drop table t1;
create table t1 (i int) engine=InnoDB;
create table t3 (i int) engine=InnoDB;
insert into t3 values(1),(2),(3);
lock table t1 write, t2 write, t3 write;
create or replace table t1 (a int, i int) engine=innodb select t2.a,t3.i from t2,t3;
unlock tables;
select * from t1 order by a,i;
a i
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
drop table t1,t3;
#
# Testing CREATE .. LIKE
#
create or replace table t1 like t2;
create or replace table t1 like t2;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
create table t1 (b int);
lock tables t1 write, t2 read;
create or replace table t1 like t2;
SELECT * FROM t1;
a
INSERT INTO t1 values(1);
CREATE OR REPLACE TABLE t1 like t2;
INSERT INTO t1 values(2);
unlock tables;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1;
#
# Test with prepared statements
#
prepare stmt1 from 'create or replace table t1 select * from t2';
execute stmt1;
select * from t1;
a
1
2
3
execute stmt1;
select * from t1;
a
1
2
3
drop table t1;
execute stmt1;
select * from t1;
a
1
2
3
deallocate prepare stmt1;
drop table t1;
#
# Test with views
#
create view t1 as select 1;
create table if not exists t1 (a int);
Warnings:
Note 1050 Table 't1' already exists
create or replace table t1 (a int);
ERROR 42S02: Unknown table 'test.t1'
drop table t1;
ERROR 42S02: Unknown table 'test.t1'
drop view t1;
DROP TABLE t2;

View File

@ -1088,7 +1088,7 @@ ALTER TABLE t PARTITION BY RANGE (UNIX_TIMESTAMP(event_time) DIV 1)
(PARTITION p0 VALUES LESS THAN (123456789), (PARTITION p0 VALUES LESS THAN (123456789),
PARTITION pMAX VALUES LESS THAN MAXVALUE); PARTITION pMAX VALUES LESS THAN MAXVALUE);
ALTER TABLE t EXCHANGE PARTITION p0 WITH TABLE general_log; ALTER TABLE t EXCHANGE PARTITION p0 WITH TABLE general_log;
ERROR HY000: Incorrect usage of PARTITION and log table ERROR HY000: You cannot 'ALTER PARTITION' a log table if logging is enabled
ALTER TABLE general_log ENGINE = CSV; ALTER TABLE general_log ENGINE = CSV;
SET @@global.general_log = @old_general_log_state; SET @@global.general_log = @old_general_log_state;
DROP TABLE t; DROP TABLE t;

View File

@ -1930,7 +1930,7 @@ SUCCESS
execute stmt; execute stmt;
ERROR 42S01: Table 't2' already exists ERROR 42S01: Table 't2' already exists
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
SUCCESS SUCCESS
execute stmt; execute stmt;
@ -1946,7 +1946,7 @@ SUCCESS
execute stmt; execute stmt;
ERROR 42S01: Table 't2' already exists ERROR 42S01: Table 't2' already exists
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
SUCCESS SUCCESS
drop temporary table t2; drop temporary table t2;
@ -1964,7 +1964,7 @@ drop table t2;
create view t2 as select 1; create view t2 as select 1;
execute stmt; execute stmt;
Got one of the listed errors Got one of the listed errors
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
SUCCESS SUCCESS
execute stmt; execute stmt;

View File

@ -135,4 +135,7 @@ select * from t1;
a a
flush tables; flush tables;
create table t1 (a int) engine=archive; create table t1 (a int) engine=archive;
ERROR 42S01: Table 't1' already exists
flush tables;
create table t1 (a int) engine=archive;
drop table t1; drop table t1;

View File

@ -125,6 +125,10 @@ create table t1 (a int) engine=archive;
select * from t1; select * from t1;
flush tables; flush tables;
remove_file $mysqld_datadir/test/t1.ARZ; remove_file $mysqld_datadir/test/t1.ARZ;
--error ER_TABLE_EXISTS_ERROR
create table t1 (a int) engine=archive;
remove_file $mysqld_datadir/test/t1.frm;
flush tables;
create table t1 (a int) engine=archive; create table t1 (a int) engine=archive;
drop table t1; drop table t1;

View File

@ -7579,7 +7579,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
SELECT * FROM test.tb2 limit 2' at line 1 SELECT * FROM test.tb2 limit 2' at line 1
CREATE OR REPLACE TEMPORARY VIEW test.v1 AS CREATE OR REPLACE TEMPORARY VIEW test.v1 AS
SELECT * FROM test.tb2 limit 2 ; SELECT * FROM test.tb2 limit 2 ;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'TEMPORARY VIEW test.v1 AS ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'VIEW test.v1 AS
SELECT * FROM test.tb2 limit 2' at line 1 SELECT * FROM test.tb2 limit 2' at line 1
Drop view if exists test.v1 ; Drop view if exists test.v1 ;
Use test; Use test;

View File

@ -7580,7 +7580,7 @@ ERROR 42000: You have an error in your SQL syntax; check the manual that corresp
SELECT * FROM test.tb2 limit 2' at line 1 SELECT * FROM test.tb2 limit 2' at line 1
CREATE OR REPLACE TEMPORARY VIEW test.v1 AS CREATE OR REPLACE TEMPORARY VIEW test.v1 AS
SELECT * FROM test.tb2 limit 2 ; SELECT * FROM test.tb2 limit 2 ;
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'TEMPORARY VIEW test.v1 AS ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'VIEW test.v1 AS
SELECT * FROM test.tb2 limit 2' at line 1 SELECT * FROM test.tb2 limit 2' at line 1
Drop view if exists test.v1 ; Drop view if exists test.v1 ;
Use test; Use test;

View File

@ -10,7 +10,6 @@
# #
############################################################################## ##############################################################################
rpl_row_create_table : Bug#11759274 2010-02-27 andrei failed different way than earlier with bug#45576
rpl_spec_variables : BUG#11755836 2009-10-27 jasonh rpl_spec_variables fails on PB2 hpux rpl_spec_variables : BUG#11755836 2009-10-27 jasonh rpl_spec_variables fails on PB2 hpux
rpl_get_master_version_and_clock : Bug#11766137 Jan 05 2011 joro Valgrind warnings rpl_get_master_version_and_clock rpl_get_master_version_and_clock : Bug#11766137 Jan 05 2011 joro Valgrind warnings rpl_get_master_version_and_clock
rpl_partition_archive : MDEV-5077 2013-09-27 svoj Cannot exchange partition with archive table rpl_partition_archive : MDEV-5077 2013-09-27 svoj Cannot exchange partition with archive table

View File

@ -1,23 +1,24 @@
stop slave; include/master-slave.inc
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; [connection master]
reset master; include/wait_for_slave_to_stop.inc
reset slave; include/wait_for_slave_to_start.inc
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; include/rpl_reset.inc
start slave; CREATE TABLE t1 (a INT);
**** Resetting master and slave **** CREATE OR REPLACE TABLE t1 (a INT, b INT);
include/stop_slave.inc
RESET SLAVE;
RESET MASTER;
include/start_slave.inc
CREATE TABLE t1 (a INT, b INT);
CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; CREATE TABLE t2 (a INT, b INT) ENGINE=Merge;
CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8;
CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8;
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT, b INT) master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT)
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE OR REPLACE TABLE t1 (a INT, b INT)
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT, b INT) ENGINE=Merge master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT, b INT) ENGINE=Merge
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8 master-bin.000001 # Query # # use `test`; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8 master-bin.000001 # Query # # use `test`; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8
**** On Master **** **** On Master ****
SHOW CREATE TABLE t1; SHOW CREATE TABLE t1;
@ -111,15 +112,10 @@ NULL 3 6
NULL 4 2 NULL 4 2
NULL 5 10 NULL 5 10
NULL 6 12 NULL 6 12
**** Resetting master and slave **** include/rpl_reset.inc
include/stop_slave.inc
RESET SLAVE;
RESET MASTER;
include/start_slave.inc
CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3; CREATE TABLE t7 (UNIQUE(b)) SELECT a,b FROM tt3;
ERROR 23000: Duplicate entry '2' for key 'b' ERROR 23000: Duplicate entry '2' for key 'b'
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info
CREATE TABLE t7 (a INT, b INT UNIQUE); CREATE TABLE t7 (a INT, b INT UNIQUE);
INSERT INTO t7 SELECT a,b FROM tt3; INSERT INTO t7 SELECT a,b FROM tt3;
ERROR 23000: Duplicate entry '2' for key 'b' ERROR 23000: Duplicate entry '2' for key 'b'
@ -128,23 +124,20 @@ a b
1 2 1 2
2 4 2 4
3 6 3 6
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE) master-bin.000001 # Query # # use `test`; CREATE TABLE t7 (a INT, b INT UNIQUE)
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Table_map # # table_id: # (test.t7) master-bin.000001 # Table_map # # table_id: # (test.t7)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
SELECT * FROM t7 ORDER BY a,b; SELECT * FROM t7 ORDER BY a,b;
a b a b
1 2 1 2
2 4 2 4
3 6 3 6
**** Resetting master and slave **** include/rpl_reset.inc
include/stop_slave.inc
RESET SLAVE;
RESET MASTER;
include/start_slave.inc
CREATE TEMPORARY TABLE tt4 (a INT, b INT); CREATE TEMPORARY TABLE tt4 (a INT, b INT);
INSERT INTO tt4 VALUES (4,8), (5,10), (6,12); INSERT INTO tt4 VALUES (4,8), (5,10), (6,12);
BEGIN; BEGIN;
@ -152,11 +145,11 @@ INSERT INTO t7 SELECT a,b FROM tt4;
ROLLBACK; ROLLBACK;
Warnings: Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Table_map # # table_id: # (test.t7) master-bin.000001 # Table_map # # table_id: # (test.t7)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
SELECT * FROM t7 ORDER BY a,b; SELECT * FROM t7 ORDER BY a,b;
a b a b
@ -174,11 +167,7 @@ a b
4 8 4 8
5 10 5 10
6 12 6 12
**** Resetting master and slave **** include/rpl_reset.inc
include/stop_slave.inc
RESET SLAVE;
RESET MASTER;
include/start_slave.inc
CREATE TABLE t8 LIKE t4; CREATE TABLE t8 LIKE t4;
CREATE TABLE t9 LIKE tt4; CREATE TABLE t9 LIKE tt4;
CREATE TEMPORARY TABLE tt5 LIKE t4; CREATE TEMPORARY TABLE tt5 LIKE t4;
@ -197,9 +186,11 @@ Create Table CREATE TABLE `t9` (
`a` int(11) DEFAULT NULL, `a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL `b` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t8 LIKE t4 master-bin.000001 # Query # # use `test`; CREATE TABLE t8 LIKE t4
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE `t9` ( master-bin.000001 # Query # # use `test`; CREATE TABLE `t9` (
`a` int(11) DEFAULT NULL, `a` int(11) DEFAULT NULL,
`b` int(11) DEFAULT NULL `b` int(11) DEFAULT NULL
@ -219,15 +210,12 @@ Create Table CREATE TABLE `t9` (
) ENGINE=MEMORY DEFAULT CHARSET=latin1 ) ENGINE=MEMORY DEFAULT CHARSET=latin1
DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9; DROP TABLE IF EXISTS t1,t2,t3,t4,t5,t6,t7,t8,t9;
STOP SLAVE; STOP SLAVE;
include/wait_for_slave_to_stop.inc
SET GLOBAL storage_engine=@storage_engine; SET GLOBAL storage_engine=@storage_engine;
START SLAVE; START SLAVE;
include/wait_for_slave_to_start.inc
================ BUG#22864 ================ ================ BUG#22864 ================
stop slave; include/rpl_reset.inc
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;
SET AUTOCOMMIT=0; SET AUTOCOMMIT=0;
CREATE TABLE t1 (a INT); CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3); INSERT INTO t1 VALUES (1),(2),(3);
@ -270,37 +258,38 @@ a
1 1
2 2
3 3
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT)
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE `t2` ( master-bin.000001 # Query # # use `test`; CREATE TABLE `t2` (
`a` int(11) DEFAULT NULL `a` int(11) DEFAULT NULL
) ENGINE=InnoDB ) ENGINE=InnoDB
master-bin.000001 # Table_map # # table_id: # (test.t2) master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE `t3` ( master-bin.000001 # Query # # use `test`; CREATE TABLE `t3` (
`a` int(11) DEFAULT NULL `a` int(11) DEFAULT NULL
) ENGINE=InnoDB ) ENGINE=InnoDB
master-bin.000001 # Table_map # # table_id: # (test.t3) master-bin.000001 # Table_map # # table_id: # (test.t3)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE `t4` ( master-bin.000001 # Query # # use `test`; CREATE TABLE `t4` (
`a` int(11) DEFAULT NULL `a` int(11) DEFAULT NULL
) ENGINE=InnoDB ) ENGINE=InnoDB
master-bin.000001 # Table_map # # table_id: # (test.t4) master-bin.000001 # Table_map # # table_id: # (test.t4)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
SHOW TABLES; SHOW TABLES;
Tables_in_test Tables_in_test
@ -333,10 +322,7 @@ a
3 3
DROP TABLE IF EXISTS t1,t2,t3,t4; DROP TABLE IF EXISTS t1,t2,t3,t4;
SET AUTOCOMMIT=1; SET AUTOCOMMIT=1;
STOP SLAVE; include/rpl_reset.inc
RESET SLAVE;
RESET MASTER;
START SLAVE;
CREATE TABLE t1 (a INT); CREATE TABLE t1 (a INT);
INSERT INTO t1 VALUES (1),(2),(3); INSERT INTO t1 VALUES (1),(2),(3);
CREATE TABLE t2 (a INT) ENGINE=INNODB; CREATE TABLE t2 (a INT) ENGINE=INNODB;
@ -355,19 +341,21 @@ a
4 4
6 6
9 9
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT) master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT)
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Table_map # # table_id: # (test.t1) master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB master-bin.000001 # Query # # use `test`; CREATE TABLE t2 (a INT) ENGINE=INNODB
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Table_map # # table_id: # (test.t2) master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t2) master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */ master-bin.000001 # Xid # # COMMIT /* XID */
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
a a
@ -377,11 +365,7 @@ a
6 6
9 9
TRUNCATE TABLE t2; TRUNCATE TABLE t2;
**** Resetting master and slave **** include/rpl_reset.inc
include/stop_slave.inc
RESET SLAVE;
RESET MASTER;
include/start_slave.inc
BEGIN; BEGIN;
INSERT INTO t2 SELECT a*a FROM t1; INSERT INTO t2 SELECT a*a FROM t1;
CREATE TEMPORARY TABLE tt2 CREATE TEMPORARY TABLE tt2
@ -394,8 +378,14 @@ Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back Warning 1196 Some non-transactional changed tables couldn't be rolled back
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
a a
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t2)
master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # ROLLBACK
SELECT * FROM t2 ORDER BY a; SELECT * FROM t2 ORDER BY a;
a a
DROP TABLE t1,t2; DROP TABLE t1,t2;
@ -412,35 +402,28 @@ a
1 1
2 2
DROP TABLE t1; DROP TABLE t1;
stop slave; include/rpl_reset.inc
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;
DROP DATABASE IF EXISTS mysqltest1; DROP DATABASE IF EXISTS mysqltest1;
CREATE DATABASE mysqltest1; CREATE DATABASE mysqltest1;
CREATE TABLE mysqltest1.without_select (f1 BIGINT); CREATE TABLE mysqltest1.without_select (f1 BIGINT);
CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1; CREATE TABLE mysqltest1.with_select AS SELECT 1 AS f1;
show binlog events from <binlog_start>; include/show_binlog_events.inc
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # DROP DATABASE IF EXISTS mysqltest1 master-bin.000001 # Query # # DROP DATABASE IF EXISTS mysqltest1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # CREATE DATABASE mysqltest1 master-bin.000001 # Query # # CREATE DATABASE mysqltest1
master-bin.000001 # Gtid # # GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE mysqltest1.without_select (f1 BIGINT) master-bin.000001 # Query # # use `test`; CREATE TABLE mysqltest1.without_select (f1 BIGINT)
master-bin.000001 # Query # # BEGIN master-bin.000001 # Gtid # # BEGIN GTID #-#-#
master-bin.000001 # Query # # use `test`; CREATE TABLE `mysqltest1`.`with_select` ( master-bin.000001 # Query # # use `test`; CREATE TABLE `mysqltest1`.`with_select` (
`f1` int(1) NOT NULL DEFAULT '0' `f1` int(1) NOT NULL DEFAULT '0'
) )
master-bin.000001 # Table_map # # table_id: # (mysqltest1.with_select) master-bin.000001 # Table_map # # table_id: # (mysqltest1.with_select)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F master-bin.000001 # Write_rows_v1 # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT master-bin.000001 # Query # # COMMIT
DROP DATABASE mysqltest1; DROP DATABASE mysqltest1;
stop slave; include/rpl_reset.inc
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 TEMPORARY TABLE t7(c1 INT); CREATE TEMPORARY TABLE t7(c1 INT);
CREATE TABLE t5(c1 INT); CREATE TABLE t5(c1 INT);
CREATE TABLE t4(c1 INT); CREATE TABLE t4(c1 INT);
@ -461,4 +444,5 @@ DROP VIEW IF EXISTS bug48506_t1, bug48506_t2, bug48506_t3;
DROP TEMPORARY TABLES t7; DROP TEMPORARY TABLES t7;
DROP TABLES t4, t5; DROP TABLES t4, t5;
DROP TABLES IF EXISTS bug48506_t4; DROP TABLES IF EXISTS bug48506_t4;
include/rpl_end.inc
end of the tests end of the tests

View File

@ -52,6 +52,8 @@ CREATE DATABASE IF NOT EXISTS mysqltest;
USE mysqltest; USE mysqltest;
CREATE TABLE IF NOT EXISTS t(c1 int); CREATE TABLE IF NOT EXISTS t(c1 int);
CREATE TABLE IF NOT EXISTS t1 LIKE t; CREATE TABLE IF NOT EXISTS t1 LIKE t;
# The following will not be logged because t2 existed and we will not
# put the data of SELECT into the binary log
CREATE TABLE IF NOT EXISTS t2 SELECT * FROM t; CREATE TABLE IF NOT EXISTS t2 SELECT * FROM t;
CREATE EVENT IF NOT EXISTS e CREATE EVENT IF NOT EXISTS e
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
@ -104,7 +106,7 @@ SELECT * FROM t1;
SELECT * FROM t2; SELECT * FROM t2;
sync_slave_with_master; sync_slave_with_master;
# In these two statements, t1 and t2 are the base table. The recoreds of t2 # In these two statements, t1 and t2 are the base table. The records of t2
# are inserted into it when CREATE TABLE ... SELECT was executed. # are inserted into it when CREATE TABLE ... SELECT was executed.
SELECT * FROM t1; SELECT * FROM t1;
SELECT * FROM t2; SELECT * FROM t2;

View File

@ -28,7 +28,8 @@ START SLAVE;
--source include/rpl_reset.inc --source include/rpl_reset.inc
connection master; connection master;
CREATE TABLE t1 (a INT, b INT); CREATE TABLE t1 (a INT);
CREATE OR REPLACE TABLE t1 (a INT, b INT);
CREATE TABLE t2 (a INT, b INT) ENGINE=Merge; CREATE TABLE t2 (a INT, b INT) ENGINE=Merge;
CREATE TABLE t3 (a INT, b INT) CHARSET=utf8; CREATE TABLE t3 (a INT, b INT) CHARSET=utf8;
CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8; CREATE TABLE t4 (a INT, b INT) ENGINE=Merge CHARSET=utf8;

View File

@ -2014,6 +2014,8 @@ create table t1 (a int, b int);
create table t1 (a int, b int) select 2,2; create table t1 (a int, b int) select 2,2;
--error ER_TABLE_EXISTS_ERROR --error ER_TABLE_EXISTS_ERROR
create table t1 like t2; create table t1 like t2;
--error ER_LOCK_WAIT_TIMEOUT
create or replace table t1 (a int, b int) select 2,2;
disconnect user1; disconnect user1;
connection default; connection default;
select * from t1; select * from t1;

View File

@ -0,0 +1 @@
--log-output=TABLE,FILE --general-log=1 --slow-query-log=1

View File

@ -0,0 +1,234 @@
#
# Check CREATE OR REPLACE ALTER TABLE
#
--source include/have_innodb.inc
--disable_warnings
drop table if exists t1,t2;
--enable_warnings
#
# Create help table
#
CREATE TABLE t2 (a int);
INSERT INTO t2 VALUES(1),(2),(3);
--echo #
--echo # Check first syntax and wrong usage
--echo #
--error ER_WRONG_USAGE
CREATE OR REPLACE TABLE IF NOT EXISTS t1 (a int);
--error ER_WRONG_USAGE
create or replace trigger trg before insert on t1 for each row set @a:=1;
# check that we don't try to create a log table in use
--error ER_BAD_LOG_STATEMENT
create or replace table mysql.general_log (a int);
--error ER_BAD_LOG_STATEMENT
create or replace table mysql.slow_log (a int);
--echo #
--echo # Usage when table doesn't exist
--echo #
CREATE OR REPLACE TABLE t1 (a int);
--error ER_TABLE_EXISTS_ERROR
CREATE TABLE t1 (a int);
DROP TABLE t1;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int);
--error ER_TABLE_EXISTS_ERROR
CREATE TEMPORARY TABLE t1 (a int, b int, c int);
DROP TEMPORARY TABLE t1;
--echo #
--echo # Testing with temporary tables
--echo #
CREATE OR REPLACE TABLE t1 (a int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int);
SHOW CREATE TABLE t1;
DROP TEMPORARY TABLE t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
# Test also with InnoDB
create temporary table t1 (i int) engine=InnoDB;
create or replace temporary table t1 (a int, b int) engine=InnoDB;
create or replace temporary table t1 (j int);
show create table t1;
drop table t1;
# Using lock tables on normal tables with create or replace on temp tables
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int);
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine= innodb;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int) engine= innodb;
CREATE OR REPLACE TEMPORARY TABLE t1 (a int, b int) engine=myisam;
SHOW CREATE TABLE t1;
DROP TEMPORARY TABLE t1;
SHOW CREATE TABLE t1;
# Verify that table is still locked
--error ER_TABLE_NOT_LOCKED
CREATE OR REPLACE TABLE t2 (a int);
DROP TABLE t1;
UNLOCK TABLES;
#
# Using CREATE SELECT
#
CREATE OR REPLACE TEMPORARY TABLE t1 (a int) SELECT * from t2;
SELECT * FROM t1;
CREATE OR REPLACE TEMPORARY TABLE t1 (b int) SELECT * from t2;
SELECT * FROM t1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TEMPORARY TABLE t1 AS SELECT a FROM t2;
CREATE TEMPORARY TABLE IF NOT EXISTS t1(a int, b int) SELECT 1,2 FROM t2;
create or replace table t1 as select 1;
show create table t1;
DROP TABLE t1;
--echo #
--echo # Testing with normal tables
--echo #
CREATE OR REPLACE TABLE t1 (a int);
CREATE OR REPLACE TABLE t1 (a int, b int);
SHOW CREATE TABLE t1;
DROP TABLE t1;
CREATE TABLE t1 (a int) SELECT * from t2;
SELECT * FROM t1;
TRUNCATE TABLE t1;
CREATE TABLE IF NOT EXISTS t1 (a int) SELECT * from t2;
SELECT * FROM t1;
DROP TABLE t1;
CREATE TABLE t1 (i int);
CREATE OR REPLACE TABLE t1 AS SELECT 1;
SHOW CREATE TABLE t1;
DROP TABLE t1;
# Using lock tables with CREATE OR REPLACE
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write,t2 write;
CREATE OR REPLACE TABLE t1 (a int, b int);
# Verify if table is still locked
SELECT * FROM t1;
INSERT INTO t1 values(1,1);
CREATE OR REPLACE TABLE t1 (a int, b int, c int);
INSERT INTO t1 values(1,1,1);
--error ER_TABLE_NOT_LOCKED
CREATE OR REPLACE TABLE t3 (a int);
UNLOCK TABLES;
DROP TABLE t1;
# Using lock tables with CREATE OR REPLACE ... SELECT
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write,t2 write;
CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2;
# Verify if table is still locked
SELECT * FROM t2;
SELECT * FROM t1;
SELECT * FROM t1;
INSERT INTO t1 values(1,1,1);
CREATE OR REPLACE TABLE t1 (a int, b int, c int, d int);
INSERT INTO t1 values(1,1,1,1);
--error ER_TABLE_NOT_LOCKED
CREATE OR REPLACE TABLE t3 (a int);
UNLOCK TABLES;
DROP TABLE t1;
CREATE OR REPLACE TABLE t1 (a int);
LOCK TABLES t1 write,t2 write, t1 as t1_read read;
CREATE OR REPLACE TABLE t1 (a int, b int) select a,1 from t2;
SELECT * FROM t1;
SELECT * FROM t2;
--error ER_TABLE_NOT_LOCKED
SELECT * FROM t1 as t1_read;
DROP TABLE t1;
UNLOCK TABLES;
--echo #
--echo # Test also with InnoDB (transactional engine)
--echo #
create table t1 (i int) engine=innodb;
lock table t1 write;
create or replace table t1 (j int);
unlock tables;
show create table t1;
drop table t1;
create table t1 (i int) engine=InnoDB;
lock table t1 write, t2 write;
create or replace table t1 (j int) engine=innodb;
unlock tables;
drop table t1;
create table t1 (i int) engine=InnoDB;
create table t3 (i int) engine=InnoDB;
insert into t3 values(1),(2),(3);
lock table t1 write, t2 write, t3 write;
create or replace table t1 (a int, i int) engine=innodb select t2.a,t3.i from t2,t3;
unlock tables;
select * from t1 order by a,i;
drop table t1,t3;
--echo #
--echo # Testing CREATE .. LIKE
--echo #
create or replace table t1 like t2;
create or replace table t1 like t2;
show create table t1;
drop table t1;
create table t1 (b int);
lock tables t1 write, t2 read;
create or replace table t1 like t2;
SELECT * FROM t1;
INSERT INTO t1 values(1);
CREATE OR REPLACE TABLE t1 like t2;
INSERT INTO t1 values(2);
unlock tables;
show create table t1;
drop table t1;
--echo #
--echo # Test with prepared statements
--echo #
prepare stmt1 from 'create or replace table t1 select * from t2';
execute stmt1;
select * from t1;
execute stmt1;
select * from t1;
drop table t1;
execute stmt1;
select * from t1;
deallocate prepare stmt1;
drop table t1;
--echo #
--echo # Test with views
--echo #
create view t1 as select 1;
create table if not exists t1 (a int);
--error ER_BAD_TABLE_ERROR
create or replace table t1 (a int);
--error ER_BAD_TABLE_ERROR
drop table t1;
drop view t1;
#
# Cleanup
#
DROP TABLE t2;

View File

@ -439,7 +439,7 @@ CREATE TABLE t LIKE general_log;
ALTER TABLE t PARTITION BY RANGE (UNIX_TIMESTAMP(event_time) DIV 1) ALTER TABLE t PARTITION BY RANGE (UNIX_TIMESTAMP(event_time) DIV 1)
(PARTITION p0 VALUES LESS THAN (123456789), (PARTITION p0 VALUES LESS THAN (123456789),
PARTITION pMAX VALUES LESS THAN MAXVALUE); PARTITION pMAX VALUES LESS THAN MAXVALUE);
--error ER_WRONG_USAGE --error ER_BAD_LOG_STATEMENT
ALTER TABLE t EXCHANGE PARTITION p0 WITH TABLE general_log; ALTER TABLE t EXCHANGE PARTITION p0 WITH TABLE general_log;
ALTER TABLE general_log ENGINE = CSV; ALTER TABLE general_log ENGINE = CSV;
SET @@global.general_log = @old_general_log_state; SET @@global.general_log = @old_general_log_state;

View File

@ -1610,7 +1610,7 @@ call p_verify_reprepare_count(0);
# Base table with name of table to be created exists # Base table with name of table to be created exists
--error ER_TABLE_EXISTS_ERROR --error ER_TABLE_EXISTS_ERROR
execute stmt; execute stmt;
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
--error ER_TABLE_EXISTS_ERROR --error ER_TABLE_EXISTS_ERROR
execute stmt; execute stmt;
call p_verify_reprepare_count(0); call p_verify_reprepare_count(0);
@ -1622,7 +1622,7 @@ execute stmt;
call p_verify_reprepare_count(0); call p_verify_reprepare_count(0);
--error ER_TABLE_EXISTS_ERROR --error ER_TABLE_EXISTS_ERROR
execute stmt; execute stmt;
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
drop temporary table t2; drop temporary table t2;
--error ER_TABLE_EXISTS_ERROR --error ER_TABLE_EXISTS_ERROR
execute stmt; execute stmt;
@ -1641,7 +1641,7 @@ drop table t2;
create view t2 as select 1; create view t2 as select 1;
--error ER_TABLE_EXISTS_ERROR,9999 --error ER_TABLE_EXISTS_ERROR,9999
execute stmt; execute stmt;
call p_verify_reprepare_count(1); call p_verify_reprepare_count(0);
--error ER_TABLE_EXISTS_ERROR,9999 --error ER_TABLE_EXISTS_ERROR,9999
execute stmt; execute stmt;
call p_verify_reprepare_count(0); call p_verify_reprepare_count(0);

View File

@ -32,6 +32,7 @@
#include "sql_cache.h" #include "sql_cache.h"
#include "structs.h" /* SHOW_COMP_OPTION */ #include "structs.h" /* SHOW_COMP_OPTION */
#include "sql_array.h" /* Dynamic_array<> */ #include "sql_array.h" /* Dynamic_array<> */
#include "mdl.h"
#include <my_compare.h> #include <my_compare.h>
#include <ft_global.h> #include <ft_global.h>
@ -378,6 +379,7 @@ enum enum_alter_inplace_result {
#define HA_LEX_CREATE_IF_NOT_EXISTS 2 #define HA_LEX_CREATE_IF_NOT_EXISTS 2
#define HA_LEX_CREATE_TABLE_LIKE 4 #define HA_LEX_CREATE_TABLE_LIKE 4
#define HA_CREATE_TMP_ALTER 8 #define HA_CREATE_TMP_ALTER 8
#define HA_LEX_CREATE_REPLACE 16
#define HA_MAX_REC_LENGTH 65535 #define HA_MAX_REC_LENGTH 65535
/* Table caching type */ /* Table caching type */
@ -1573,9 +1575,15 @@ struct HA_CREATE_INFO
ulong avg_row_length; ulong avg_row_length;
ulong used_fields; ulong used_fields;
ulong key_block_size; ulong key_block_size;
uint stats_sample_pages; /* number of pages to sample during /*
stats estimation, if used, otherwise 0. */ number of pages to sample during
enum_stats_auto_recalc stats_auto_recalc; stats estimation, if used, otherwise 0.
*/
uint stats_sample_pages;
uint null_bits; /* NULL bits at start of record */
uint options; /* OR of HA_CREATE_ options */
uint merge_insert_method;
uint extra_size; /* length of extra data segment */
SQL_I_List<TABLE_LIST> merge_list; SQL_I_List<TABLE_LIST> merge_list;
handlerton *db_type; handlerton *db_type;
/** /**
@ -1588,21 +1596,23 @@ struct HA_CREATE_INFO
If nothing speficied inherits the value of the original table (if present). If nothing speficied inherits the value of the original table (if present).
*/ */
enum row_type row_type; enum row_type row_type;
uint null_bits; /* NULL bits at start of record */
uint options; /* OR of HA_CREATE_ options */
uint merge_insert_method;
uint extra_size; /* length of extra data segment */
enum ha_choice transactional; enum ha_choice transactional;
bool varchar; ///< 1 if table has a VARCHAR
enum ha_storage_media storage_media; ///< DEFAULT, DISK or MEMORY enum ha_storage_media storage_media; ///< DEFAULT, DISK or MEMORY
enum ha_choice page_checksum; ///< If we have page_checksums enum ha_choice page_checksum; ///< If we have page_checksums
engine_option_value *option_list; ///< list of table create options engine_option_value *option_list; ///< list of table create options
enum_stats_auto_recalc stats_auto_recalc;
bool varchar; ///< 1 if table has a VARCHAR
/* the following three are only for ALTER TABLE, check_if_incompatible_data() */ /* the following three are only for ALTER TABLE, check_if_incompatible_data() */
ha_table_option_struct *option_struct; ///< structure with parsed table options ha_table_option_struct *option_struct; ///< structure with parsed table options
ha_field_option_struct **fields_option_struct; ///< array of field option structures ha_field_option_struct **fields_option_struct; ///< array of field option structures
ha_index_option_struct **indexes_option_struct; ///< array of index option structures ha_index_option_struct **indexes_option_struct; ///< array of index option structures
/* The following is used to remember the old state for CREATE OR REPLACE */
TABLE *table;
TABLE_LIST *pos_in_locked_tables;
MDL_ticket *mdl_ticket;
bool tmp_table() { return options & HA_LEX_CREATE_TMP_TABLE; } bool tmp_table() { return options & HA_LEX_CREATE_TMP_TABLE; }
}; };

View File

@ -525,35 +525,57 @@ bool LOGGER::is_log_table_enabled(uint log_table_type)
} }
/* Check if a given table is opened log table */ /**
int check_if_log_table(size_t db_len, const char *db, size_t table_name_len, Check if a given table is opened log table
const char *table_name, bool check_if_opened)
@param table Table to check
@param check_if_opened Only fail if it's a log table in use
@param error_msg String to put in error message if not ok.
No error message if 0
@return 0 ok
@return # Type of log file
*/
int check_if_log_table(const TABLE_LIST *table,
bool check_if_opened,
const char *error_msg)
{ {
if (db_len == 5 && int result= 0;
if (table->db_length == 5 &&
!(lower_case_table_names ? !(lower_case_table_names ?
my_strcasecmp(system_charset_info, db, "mysql") : my_strcasecmp(system_charset_info, table->db, "mysql") :
strcmp(db, "mysql"))) strcmp(table->db, "mysql")))
{ {
if (table_name_len == 11 && !(lower_case_table_names ? const char *table_name= table->table_name;
my_strcasecmp(system_charset_info,
table_name, "general_log") : if (table->table_name_length == 11 &&
strcmp(table_name, "general_log"))) !(lower_case_table_names ?
my_strcasecmp(system_charset_info,
table_name, "general_log") :
strcmp(table_name, "general_log")))
{ {
if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_GENERAL)) result= QUERY_LOG_GENERAL;
return QUERY_LOG_GENERAL; goto end;
return 0;
} }
if (table_name_len == 8 && !(lower_case_table_names ? if (table->table_name_length == 8 && !(lower_case_table_names ?
my_strcasecmp(system_charset_info, table_name, "slow_log") : my_strcasecmp(system_charset_info, table_name, "slow_log") :
strcmp(table_name, "slow_log"))) strcmp(table_name, "slow_log")))
{ {
if (!check_if_opened || logger.is_log_table_enabled(QUERY_LOG_SLOW)) result= QUERY_LOG_SLOW;
return QUERY_LOG_SLOW; goto end;
return 0;
} }
} }
return 0; return 0;
end:
if (!check_if_opened || logger.is_log_table_enabled(result))
{
if (error_msg)
my_error(ER_BAD_LOG_STATEMENT, MYF(0), error_msg);
return result;
}
return 0;
} }

View File

@ -833,8 +833,8 @@ public:
}; };
int check_if_log_table(size_t db_len, const char *db, size_t table_name_len, int check_if_log_table(const TABLE_LIST *table, bool check_if_opened,
const char *table_name, bool check_if_opened); const char *errmsg);
class Log_to_csv_event_handler: public Log_event_handler class Log_to_csv_event_handler: public Log_event_handler
{ {

View File

@ -1047,9 +1047,10 @@ static bool sql_slave_killed(rpl_group_info *rgi)
"documentation for details)."; "documentation for details).";
DBUG_PRINT("info", ("modified_non_trans_table: %d OPTION_BEGIN: %d " DBUG_PRINT("info", ("modified_non_trans_table: %d OPTION_BEGIN: %d "
"is_in_group: %d", "OPTION_KEEP_LOG: %d is_in_group: %d",
thd->transaction.all.modified_non_trans_table, thd->transaction.all.modified_non_trans_table,
test(thd->variables.option_bits & OPTION_BEGIN), test(thd->variables.option_bits & OPTION_BEGIN),
test(thd->variables.option_bits & OPTION_KEEP_LOG),
rli->is_in_group())); rli->is_in_group()));
if (rli->abort_slave) if (rli->abort_slave)

View File

@ -338,19 +338,8 @@ bool Sql_cmd_discard_import_tablespace::execute(THD *thd)
it is the case. it is the case.
TODO: this design is obsolete and will be removed. TODO: this design is obsolete and will be removed.
*/ */
int table_kind= check_if_log_table(table_list->db_length, table_list->db, if (check_if_log_table(table_list, TRUE, "ALTER"))
table_list->table_name_length, return true;
table_list->table_name, false);
if (table_kind)
{
/* Disable alter of enabled log tables */
if (logger.is_log_table_enabled(table_kind))
{
my_error(ER_BAD_LOG_STATEMENT, MYF(0), "ALTER");
return true;
}
}
return return
mysql_discard_or_import_tablespace(thd, table_list, mysql_discard_or_import_tablespace(thd, table_list,

View File

@ -784,12 +784,18 @@ static void close_open_tables(THD *thd)
access the table cache key access the table cache key
@param[in] extra @param[in] extra
HA_EXTRA_PREPRE_FOR_DROP if the table is being dropped HA_EXTRA_PREPARE_FOR_DROP
HA_EXTRA_PREPARE_FOR_REANME if the table is being renamed - The table is dropped
HA_EXTRA_NOT_USED no drop/rename HA_EXTRA_PREPARE_FOR_RENAME
In case of drop/reanme the documented behaviour is to - The table is renamed
HA_EXTRA_NOT_USED
- The table is marked as closed in the
locked_table_list but kept there so one can call
locked_table_list->reopen_tables() to put it back.
In case of drop/rename the documented behavior is to
implicitly remove the table from LOCK TABLES implicitly remove the table from LOCK TABLES
list. list.
@pre Must be called with an X MDL lock on the table. @pre Must be called with an X MDL lock on the table.
*/ */
@ -1588,26 +1594,21 @@ TABLE *find_temporary_table(THD *thd,
thd->temporary_tables list, it's impossible to tell here whether thd->temporary_tables list, it's impossible to tell here whether
we're dealing with an internal or a user temporary table. we're dealing with an internal or a user temporary table.
If is_trans is not null, we return the type of the table: @param thd Thread handler
either transactional (e.g. innodb) as TRUE or non-transactional @param table Temporary table to be deleted
(e.g. myisam) as FALSE. @param is_trans Is set to the type of the table:
transactional (e.g. innodb) as TRUE or non-transactional
(e.g. myisam) as FALSE.
@retval 0 the table was found and dropped successfully. @retval 0 the table was found and dropped successfully.
@retval 1 the table was not found in the list of temporary tables
of this thread
@retval -1 the table is in use by a outer query @retval -1 the table is in use by a outer query
*/ */
int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans) int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans)
{ {
DBUG_ENTER("drop_temporary_table"); DBUG_ENTER("drop_temporary_table");
DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'", DBUG_PRINT("tmptable", ("closing table: '%s'.'%s'",
table_list->db, table_list->table_name)); table->s->db.str, table->s->table_name.str));
if (!is_temporary_table(table_list))
DBUG_RETURN(1);
TABLE *table= table_list->table;
/* Table might be in use by some outer statement. */ /* Table might be in use by some outer statement. */
if (table->query_id && table->query_id != thd->query_id) if (table->query_id && table->query_id != thd->query_id)
@ -1627,10 +1628,10 @@ int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans)
*/ */
mysql_lock_remove(thd, thd->lock, table); mysql_lock_remove(thd, thd->lock, table);
close_temporary_table(thd, table, 1, 1); close_temporary_table(thd, table, 1, 1);
table_list->table= NULL;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/* /*
unlink from thd->temporary tables and close temporary table unlink from thd->temporary tables and close temporary table
*/ */
@ -2611,9 +2612,9 @@ Locked_tables_list::init_locked_tables(THD *thd)
{ {
TABLE_LIST *src_table_list= table->pos_in_table_list; TABLE_LIST *src_table_list= table->pos_in_table_list;
char *db, *table_name, *alias; char *db, *table_name, *alias;
size_t db_len= src_table_list->db_length; size_t db_len= table->s->db.length;
size_t table_name_len= src_table_list->table_name_length; size_t table_name_len= table->s->table_name.length;
size_t alias_len= strlen(src_table_list->alias); size_t alias_len= table->alias.length();
TABLE_LIST *dst_table_list; TABLE_LIST *dst_table_list;
if (! multi_alloc_root(&m_locked_tables_root, if (! multi_alloc_root(&m_locked_tables_root,
@ -2623,23 +2624,15 @@ Locked_tables_list::init_locked_tables(THD *thd)
&alias, alias_len + 1, &alias, alias_len + 1,
NullS)) NullS))
{ {
unlock_locked_tables(0); reset();
return TRUE; return TRUE;
} }
memcpy(db, src_table_list->db, db_len + 1); memcpy(db, table->s->db.str, db_len + 1);
memcpy(table_name, src_table_list->table_name, table_name_len + 1); memcpy(table_name, table->s->table_name.str, table_name_len + 1);
memcpy(alias, src_table_list->alias, alias_len + 1); strmake(alias, table->alias.ptr(), alias_len);
/**
Sic: remember the *actual* table level lock type taken, to
acquire the exact same type in reopen_tables().
E.g. if the table was locked for write, src_table_list->lock_type is
TL_WRITE_DEFAULT, whereas reginfo.lock_type has been updated from
thd->update_lock_default.
*/
dst_table_list->init_one_table(db, db_len, table_name, table_name_len, dst_table_list->init_one_table(db, db_len, table_name, table_name_len,
alias, alias, table->reginfo.lock_type);
src_table_list->table->reginfo.lock_type);
dst_table_list->table= table; dst_table_list->table= table;
dst_table_list->mdl_request.ticket= src_table_list->mdl_request.ticket; dst_table_list->mdl_request.ticket= src_table_list->mdl_request.ticket;
@ -2660,7 +2653,7 @@ Locked_tables_list::init_locked_tables(THD *thd)
(m_locked_tables_count+1)); (m_locked_tables_count+1));
if (m_reopen_array == NULL) if (m_reopen_array == NULL)
{ {
unlock_locked_tables(0); reset();
return TRUE; return TRUE;
} }
} }
@ -2681,42 +2674,50 @@ Locked_tables_list::init_locked_tables(THD *thd)
void void
Locked_tables_list::unlock_locked_tables(THD *thd) Locked_tables_list::unlock_locked_tables(THD *thd)
{ {
if (thd) DBUG_ASSERT(!thd->in_sub_stmt &&
!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
/*
Sic: we must be careful to not close open tables if
we're not in LOCK TABLES mode: unlock_locked_tables() is
sometimes called implicitly, expecting no effect on
open tables, e.g. from begin_trans().
*/
if (thd->locked_tables_mode != LTM_LOCK_TABLES)
return;
for (TABLE_LIST *table_list= m_locked_tables;
table_list; table_list= table_list->next_global)
{ {
DBUG_ASSERT(!thd->in_sub_stmt &&
!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL));
/* /*
Sic: we must be careful to not close open tables if Clear the position in the list, the TABLE object will be
we're not in LOCK TABLES mode: unlock_locked_tables() is returned to the table cache.
sometimes called implicitly, expecting no effect on
open tables, e.g. from begin_trans().
*/
if (thd->locked_tables_mode != LTM_LOCK_TABLES)
return;
for (TABLE_LIST *table_list= m_locked_tables;
table_list; table_list= table_list->next_global)
{
/*
Clear the position in the list, the TABLE object will be
returned to the table cache.
*/
if (table_list->table) // If not closed
table_list->table->pos_in_locked_tables= NULL;
}
thd->leave_locked_tables_mode();
DBUG_ASSERT(thd->transaction.stmt.is_empty());
close_thread_tables(thd);
/*
We rely on the caller to implicitly commit the
transaction and release transactional locks.
*/ */
if (table_list->table) // If not closed
table_list->table->pos_in_locked_tables= NULL;
} }
thd->leave_locked_tables_mode();
DBUG_ASSERT(thd->transaction.stmt.is_empty());
close_thread_tables(thd);
/*
We rely on the caller to implicitly commit the
transaction and release transactional locks.
*/
/* /*
After closing tables we can free memory used for storing lock After closing tables we can free memory used for storing lock
request for metadata locks and TABLE_LIST elements. request for metadata locks and TABLE_LIST elements.
*/ */
reset();
}
/*
Free memory allocated for storing locks
*/
void Locked_tables_list::reset()
{
free_root(&m_locked_tables_root, MYF(0)); free_root(&m_locked_tables_root, MYF(0));
m_locked_tables= NULL; m_locked_tables= NULL;
m_locked_tables_last= &m_locked_tables; m_locked_tables_last= &m_locked_tables;
@ -2781,6 +2782,7 @@ void Locked_tables_list::unlink_from_list(THD *thd,
m_locked_tables_last= table_list->prev_global; m_locked_tables_last= table_list->prev_global;
else else
table_list->next_global->prev_global= table_list->prev_global; table_list->next_global->prev_global= table_list->prev_global;
m_locked_tables_count--;
} }
} }
@ -2834,6 +2836,7 @@ unlink_all_closed_tables(THD *thd, MYSQL_LOCK *lock, size_t reopen_count)
m_locked_tables_last= table_list->prev_global; m_locked_tables_last= table_list->prev_global;
else else
table_list->next_global->prev_global= table_list->prev_global; table_list->next_global->prev_global= table_list->prev_global;
m_locked_tables_count--;
} }
} }
} }
@ -2908,6 +2911,57 @@ Locked_tables_list::reopen_tables(THD *thd)
return FALSE; return FALSE;
} }
/**
Add back a locked table to the locked list that we just removed from it.
This is needed in CREATE OR REPLACE TABLE where we are dropping, creating
and re-opening a locked table.
@return 0 0k
@return 1 error
*/
bool Locked_tables_list::restore_lock(THD *thd, TABLE_LIST *dst_table_list,
TABLE *table, MYSQL_LOCK *lock)
{
MYSQL_LOCK *merged_lock;
DBUG_ENTER("restore_lock");
DBUG_ASSERT(!strcmp(dst_table_list->table_name, table->s->table_name.str));
/* Ensure we have the memory to add the table back */
if (!(merged_lock= mysql_lock_merge(thd->lock, lock)))
DBUG_RETURN(1);
thd->lock= merged_lock;
/* Link to the new table */
dst_table_list->table= table;
/*
The lock type may have changed (normally it should not as create
table will lock the table in write mode
*/
dst_table_list->lock_type= table->reginfo.lock_type;
table->pos_in_locked_tables= dst_table_list;
add_back_last_deleted_lock(dst_table_list);
DBUG_RETURN(0);
}
/*
Add back the last deleted lock structure.
This should be followed by a call to reopen_tables() to
open the table.
*/
void Locked_tables_list::add_back_last_deleted_lock(TABLE_LIST *dst_table_list)
{
/* Link the lock back in the locked tables list */
dst_table_list->prev_global= m_locked_tables_last;
*m_locked_tables_last= dst_table_list;
m_locked_tables_last= &dst_table_list->next_global;
dst_table_list->next_global= 0;
m_locked_tables_count++;
}
#ifndef DBUG_OFF #ifndef DBUG_OFF
/* Cause a spurious statement reprepare for debug purposes. */ /* Cause a spurious statement reprepare for debug purposes. */
@ -4045,9 +4099,9 @@ lock_table_names(THD *thd,
if (mdl_requests.is_empty()) if (mdl_requests.is_empty())
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
/* Check if CREATE TABLE was used */ /* Check if CREATE TABLE without REPLACE was used */
create_table= (tables_start && tables_start->open_strategy == create_table= (thd->lex->sql_command == SQLCOM_CREATE_TABLE &&
TABLE_LIST::OPEN_IF_EXISTS); !(thd->lex->create_info.options & HA_LEX_CREATE_REPLACE));
if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK)) if (!(flags & MYSQL_OPEN_SKIP_SCOPED_MDL_LOCK))
{ {
@ -5293,6 +5347,39 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
} }
/*
Restart transaction for tables
This is used when we had to do an implicit commit after tables are opened
and want to restart transactions on tables.
This is used in case of:
LOCK TABLES xx
CREATE OR REPLACE TABLE xx;
*/
bool restart_trans_for_tables(THD *thd, TABLE_LIST *table)
{
DBUG_ENTER("restart_trans_for_tables");
if (!thd->locked_tables_mode)
DBUG_RETURN(FALSE);
for (; table; table= table->next_global)
{
if (table->placeholder())
continue;
if (check_lock_and_start_stmt(thd, thd->lex, table))
{
DBUG_ASSERT(0); // Should never happen
DBUG_RETURN(TRUE);
}
}
DBUG_RETURN(FALSE);
}
/** /**
Prepare statement for reopening of tables and recalculation of set of Prepare statement for reopening of tables and recalculation of set of
prelocked tables. prelocked tables.

View File

@ -248,7 +248,7 @@ void close_thread_table(THD *thd, TABLE **table_ptr);
bool close_temporary_tables(THD *thd); bool close_temporary_tables(THD *thd);
TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list, TABLE_LIST *unique_table(THD *thd, TABLE_LIST *table, TABLE_LIST *table_list,
bool check_alias); bool check_alias);
int drop_temporary_table(THD *thd, TABLE_LIST *table_list, bool *is_trans); int drop_temporary_table(THD *thd, TABLE *table, bool *is_trans);
void close_temporary_table(THD *thd, TABLE *table, bool free_share, void close_temporary_table(THD *thd, TABLE *table, bool free_share,
bool delete_table); bool delete_table);
void close_temporary(TABLE *table, bool free_share, bool delete_table); void close_temporary(TABLE *table, bool free_share, bool delete_table);
@ -486,6 +486,8 @@ inline bool open_and_lock_tables(THD *thd, TABLE_LIST *tables,
} }
bool restart_trans_for_tables(THD *thd, TABLE_LIST *table);
/** /**
A context of open_tables() function, used to recover A context of open_tables() function, used to recover
from a failed open_table() or open_routine() attempt. from a failed open_table() or open_routine() attempt.

View File

@ -1513,8 +1513,9 @@ public:
void unlock_locked_tables(THD *thd); void unlock_locked_tables(THD *thd);
~Locked_tables_list() ~Locked_tables_list()
{ {
unlock_locked_tables(0); reset();
} }
void reset();
bool init_locked_tables(THD *thd); bool init_locked_tables(THD *thd);
TABLE_LIST *locked_tables() { return m_locked_tables; } TABLE_LIST *locked_tables() { return m_locked_tables; }
void unlink_from_list(THD *thd, TABLE_LIST *table_list, void unlink_from_list(THD *thd, TABLE_LIST *table_list,
@ -1523,6 +1524,9 @@ public:
MYSQL_LOCK *lock, MYSQL_LOCK *lock,
size_t reopen_count); size_t reopen_count);
bool reopen_tables(THD *thd); bool reopen_tables(THD *thd);
bool restore_lock(THD *thd, TABLE_LIST *dst_table_list, TABLE *table,
MYSQL_LOCK *lock);
void add_back_last_deleted_lock(TABLE_LIST *dst_table_list);
}; };
@ -3995,6 +3999,8 @@ class select_create: public select_insert {
MYSQL_LOCK *m_lock; MYSQL_LOCK *m_lock;
/* m_lock or thd->extra_lock */ /* m_lock or thd->extra_lock */
MYSQL_LOCK **m_plock; MYSQL_LOCK **m_plock;
bool exit_done;
public: public:
select_create (TABLE_LIST *table_arg, select_create (TABLE_LIST *table_arg,
HA_CREATE_INFO *create_info_par, HA_CREATE_INFO *create_info_par,
@ -4006,7 +4012,7 @@ public:
create_info(create_info_par), create_info(create_info_par),
select_tables(select_tables_arg), select_tables(select_tables_arg),
alter_info(alter_info_arg), alter_info(alter_info_arg),
m_plock(NULL) m_plock(NULL), exit_done(0)
{} {}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u); int prepare(List<Item> &list, SELECT_LEX_UNIT *u);

View File

@ -798,14 +798,8 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0)) if ((my_strcasecmp(system_charset_info, MYSQL_SCHEMA_NAME.str, db) == 0))
{ {
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
{ if (check_if_log_table(table, TRUE, "DROP"))
if (check_if_log_table(table->db_length, table->db,
table->table_name_length, table->table_name, true))
{
my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
goto exit; goto exit;
}
}
} }
/* Lock all tables and stored routines about to be dropped. */ /* Lock all tables and stored routines about to be dropped. */

View File

@ -3916,6 +3916,16 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
DEBUG_SYNC(thd,"create_table_select_before_create"); DEBUG_SYNC(thd,"create_table_select_before_create");
/* Check if LOCK TABLES + CREATE OR REPLACE of existing normal table*/
if (thd->locked_tables_mode && create_table->table &&
!create_info->tmp_table())
{
/* Remember information about the locked table */
create_info->pos_in_locked_tables=
create_table->table->pos_in_locked_tables;
create_info->mdl_ticket= create_table->table->mdl_ticket;
}
/* /*
Create and lock table. Create and lock table.
@ -3932,51 +3942,62 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
TABLE, which is a wrong order. So we keep binary logging disabled when we TABLE, which is a wrong order. So we keep binary logging disabled when we
open_table(). open_table().
*/ */
{
if (!mysql_create_table_no_lock(thd, create_table->db,
create_table->table_name,
create_info, alter_info, NULL,
select_field_count))
{
DEBUG_SYNC(thd,"create_table_select_before_open");
if (!create_info->tmp_table()) if (!mysql_create_table_no_lock(thd, create_table->db,
{ create_table->table_name,
Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN); create_info, alter_info, NULL,
/* select_field_count))
Here we open the destination table, on which we already have {
an exclusive metadata lock. DEBUG_SYNC(thd,"create_table_select_before_open");
*/
if (open_table(thd, create_table, thd->mem_root, &ot_ctx)) /*
{ If we had a temporary table or a table used with LOCK TABLES,
quick_rm_table(thd, create_info->db_type, create_table->db, it was closed by mysql_create()
table_case_name(create_info, create_table->table_name), */
0); create_table->table= 0;
}
else if (!create_info->tmp_table())
table= create_table->table;
}
else
{
if (open_temporary_table(thd, create_table))
{
/*
This shouldn't happen as creation of temporary table should make
it preparable for open. Anyway we can't drop temporary table if
we are unable to find it.
*/
DBUG_ASSERT(0);
}
else
table= create_table->table;
}
}
if (!table) // open failed
{ {
if (!thd->is_error()) // CREATE ... IF NOT EXISTS Open_table_context ot_ctx(thd, MYSQL_OPEN_REOPEN);
my_ok(thd); // succeed, but did nothing TABLE_LIST::enum_open_strategy save_open_strategy;
DBUG_RETURN(0);
/* Force the newly created table to be opened */
save_open_strategy= create_table->open_strategy;
create_table->open_strategy= TABLE_LIST::OPEN_NORMAL;
/*
Here we open the destination table, on which we already have
an exclusive metadata lock.
*/
if (open_table(thd, create_table, thd->mem_root, &ot_ctx))
{
quick_rm_table(thd, create_info->db_type, create_table->db,
table_case_name(create_info, create_table->table_name),
0);
}
/* Restore */
create_table->open_strategy= save_open_strategy;
} }
else
{
if (open_temporary_table(thd, create_table))
{
/*
This shouldn't happen as creation of temporary table should make
it preparable for open. Anyway we can't drop temporary table if
we are unable to find it.
*/
DBUG_ASSERT(0);
}
}
}
else
create_table->table= 0; // Create failed
if (!(table= create_table->table))
{
if (!thd->is_error()) // CREATE ... IF NOT EXISTS
my_ok(thd); // succeed, but did nothing
DBUG_RETURN(0);
} }
DEBUG_SYNC(thd,"create_table_select_before_lock"); DEBUG_SYNC(thd,"create_table_select_before_lock");
@ -3994,7 +4015,7 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
/* purecov: begin tested */ /* purecov: begin tested */
/* /*
This can happen in innodb when you get a deadlock when using same table This can happen in innodb when you get a deadlock when using same table
in insert and select in insert and select or when you run out of memory.
*/ */
my_error(ER_CANT_LOCK, MYF(0), my_errno); my_error(ER_CANT_LOCK, MYF(0), my_errno);
if (*lock) if (*lock)
@ -4092,8 +4113,6 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
thd->binlog_start_trans_and_stmt(); thd->binlog_start_trans_and_stmt();
} }
DBUG_ASSERT(create_table->table == NULL);
DEBUG_SYNC(thd,"create_table_select_before_check_if_exists"); DEBUG_SYNC(thd,"create_table_select_before_check_if_exists");
if (!(table= create_table_from_items(thd, create_info, create_table, if (!(table= create_table_from_items(thd, create_info, create_table,
@ -4236,32 +4255,53 @@ void select_create::send_error(uint errcode,const char *err)
bool select_create::send_eof() bool select_create::send_eof()
{ {
bool tmp=select_insert::send_eof(); if (select_insert::send_eof())
if (tmp)
abort_result_set();
else
{ {
/* abort_result_set();
Do an implicit commit at end of statement for non-temporary return 1;
tables. This can fail, but we should unlock the table
nevertheless.
*/
if (!table->s->tmp_table)
{
trans_commit_stmt(thd);
trans_commit_implicit(thd);
}
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
if (m_plock)
{
mysql_unlock_tables(thd, *m_plock);
*m_plock= NULL;
m_plock= NULL;
}
} }
return tmp;
exit_done= 1; // Avoid double calls
/*
Do an implicit commit at end of statement for non-temporary
tables. This can fail, but we should unlock the table
nevertheless.
*/
if (!table->s->tmp_table)
{
trans_commit_stmt(thd);
trans_commit_implicit(thd);
}
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
if (m_plock)
{
MYSQL_LOCK *lock= *m_plock;
*m_plock= NULL;
m_plock= NULL;
if (create_info->pos_in_locked_tables)
{
/*
If we are under lock tables, we have created a table that was
originally locked. We should add back the lock to ensure that
all tables in the thd->open_list are locked!
*/
table->mdl_ticket= create_info->mdl_ticket;
/* The following should never fail, except if out of memory */
if (!thd->locked_tables_list.restore_lock(thd,
create_info->
pos_in_locked_tables,
table, lock))
return 0; // ok
/* Fail. Continue without locking the table */
}
mysql_unlock_tables(thd, lock);
}
return 0;
} }
@ -4269,6 +4309,11 @@ void select_create::abort_result_set()
{ {
DBUG_ENTER("select_create::abort_result_set"); DBUG_ENTER("select_create::abort_result_set");
/* Avoid double calls, could happen in case of out of memory on cleanup */
if (exit_done)
DBUG_VOID_RETURN;
exit_done= 1;
/* /*
In select_insert::abort_result_set() we roll back the statement, including In select_insert::abort_result_set() we roll back the statement, including
truncating the transaction cache of the binary log. To do this, we truncating the transaction cache of the binary log. To do this, we

View File

@ -2470,7 +2470,6 @@ struct LEX: public Query_tables_list
uint8 context_analysis_only; uint8 context_analysis_only;
bool drop_temporary, local_file, one_shot_set; bool drop_temporary, local_file, one_shot_set;
bool check_exists; bool check_exists;
bool replace;
bool autocommit; bool autocommit;
bool verbose, no_write_to_binlog; bool verbose, no_write_to_binlog;

View File

@ -2832,12 +2832,8 @@ case SQLCOM_PREPARE:
if ((res= create_table_precheck(thd, select_tables, create_table))) if ((res= create_table_precheck(thd, select_tables, create_table)))
goto end_with_restore_list; goto end_with_restore_list;
#ifndef QQ
/* Might have been updated in create_table_precheck */ /* Might have been updated in create_table_precheck */
create_info.alias= create_table->alias; create_info.alias= create_table->alias;
#else
create_table->alias= (char*) create_info.alias;
#endif
#ifdef HAVE_READLINK #ifdef HAVE_READLINK
/* Fix names if symlinked tables */ /* Fix names if symlinked tables */
@ -2867,6 +2863,12 @@ case SQLCOM_PREPARE:
create_info.table_charset= 0; create_info.table_charset= 0;
} }
/*
For CREATE TABLE we should not open the table even if it exists.
If the table exists, we should either not create it or replace it
*/
lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
#ifdef WITH_PARTITION_STORAGE_ENGINE #ifdef WITH_PARTITION_STORAGE_ENGINE
{ {
partition_info *part_info= thd->lex->part_info; partition_info *part_info= thd->lex->part_info;
@ -2958,25 +2960,6 @@ case SQLCOM_PREPARE:
} }
else else
{ {
/* The table already exists */
if (create_table->table)
{
if (create_info.options & HA_LEX_CREATE_IF_NOT_EXISTS)
{
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR,
ER(ER_TABLE_EXISTS_ERROR),
create_info.alias);
my_ok(thd);
}
else
{
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_info.alias);
res= 1;
}
goto end_with_restore_list;
}
/* /*
Remove target table from main select and name resolution Remove target table from main select and name resolution
context. This can't be done earlier as it will break view merging in context. This can't be done earlier as it will break view merging in
@ -2984,9 +2967,8 @@ case SQLCOM_PREPARE:
*/ */
lex->unlink_first_table(&link_to_local); lex->unlink_first_table(&link_to_local);
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */ /* Store reference to table in case of LOCK TABLES */
if (create_info.tmp_table()) create_info.table= create_table->table;
thd->variables.option_bits|= OPTION_KEEP_LOG;
/* /*
select_create is currently not re-execution friendly and select_create is currently not re-execution friendly and
@ -3004,18 +2986,18 @@ case SQLCOM_PREPARE:
CREATE from SELECT give its SELECT_LEX for SELECT, CREATE from SELECT give its SELECT_LEX for SELECT,
and item_list belong to SELECT and item_list belong to SELECT
*/ */
res= handle_select(thd, lex, result, 0); if (!(res= handle_select(thd, lex, result, 0)))
{
if (create_info.tmp_table())
thd->variables.option_bits|= OPTION_KEEP_LOG;
}
delete result; delete result;
} }
lex->link_first_table_back(create_table, link_to_local); lex->link_first_table_back(create_table, link_to_local);
} }
} }
else else
{ {
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.tmp_table())
thd->variables.option_bits|= OPTION_KEEP_LOG;
/* regular create */ /* regular create */
if (create_info.options & HA_LEX_CREATE_TABLE_LIKE) if (create_info.options & HA_LEX_CREATE_TABLE_LIKE)
{ {
@ -3030,7 +3012,12 @@ case SQLCOM_PREPARE:
&create_info, &alter_info); &create_info, &alter_info);
} }
if (!res) if (!res)
{
/* So that CREATE TEMPORARY TABLE gets to binlog at commit/rollback */
if (create_info.tmp_table())
thd->variables.option_bits|= OPTION_KEEP_LOG;
my_ok(thd); my_ok(thd);
}
} }
end_with_restore_list: end_with_restore_list:
@ -7960,8 +7947,9 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
(CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0)); (CREATE_ACL | (select_lex->item_list.elements ? INSERT_ACL : 0));
/* CREATE OR REPLACE on not temporary tables require DROP_ACL */ /* CREATE OR REPLACE on not temporary tables require DROP_ACL */
if (lex->replace && !lex->create_info.tmp_table()) if ((lex->create_info.options & HA_LEX_CREATE_REPLACE) &&
want_priv= DROP_ACL; !lex->create_info.tmp_table())
want_priv|= DROP_ACL;
if (check_access(thd, want_priv, create_table->db, if (check_access(thd, want_priv, create_table->db,
&create_table->grant.privilege, &create_table->grant.privilege,
@ -8031,6 +8019,12 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
} }
error= FALSE; error= FALSE;
/*
For CREATE TABLE we should not open the table even if it exists.
If the table exists, we should either not create it or replace it
*/
lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
err: err:
DBUG_RETURN(error); DBUG_RETURN(error);
} }

View File

@ -506,13 +506,8 @@ bool Sql_cmd_alter_table_exchange_partition::
/* Don't allow to exchange with log table */ /* Don't allow to exchange with log table */
swap_table_list= table_list->next_local; swap_table_list= table_list->next_local;
if (check_if_log_table(swap_table_list->db_length, swap_table_list->db, if (check_if_log_table(swap_table_list, FALSE, "ALTER PARTITION"))
swap_table_list->table_name_length,
swap_table_list->table_name, 0))
{
my_error(ER_WRONG_USAGE, MYF(0), "PARTITION", "log table");
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
}
/* /*
Currently no MDL lock that allows both read and write and is upgradeable Currently no MDL lock that allows both read and write and is upgradeable

View File

@ -84,12 +84,8 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
for (to_table= 0, ren_table= table_list; ren_table; for (to_table= 0, ren_table= table_list; ren_table;
to_table= 1 - to_table, ren_table= ren_table->next_local) to_table= 1 - to_table, ren_table= ren_table->next_local)
{ {
int log_table_rename= 0; int log_table_rename;
if ((log_table_rename= check_if_log_table(ren_table, TRUE, NullS)))
if ((log_table_rename=
check_if_log_table(ren_table->db_length, ren_table->db,
ren_table->table_name_length,
ren_table->table_name, 1)))
{ {
/* /*
as we use log_table_rename as an array index, we need it to start as we use log_table_rename as an array index, we need it to start

View File

@ -2031,33 +2031,29 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
bool error; bool error;
Drop_table_error_handler err_handler; Drop_table_error_handler err_handler;
TABLE_LIST *table; TABLE_LIST *table;
DBUG_ENTER("mysql_rm_table"); DBUG_ENTER("mysql_rm_table");
/* Disable drop of enabled log tables, must be done before name locking */ /* Disable drop of enabled log tables, must be done before name locking */
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
{ {
if (check_if_log_table(table->db_length, table->db, if (check_if_log_table(table, TRUE, "DROP"))
table->table_name_length, table->table_name, true))
{
my_error(ER_BAD_LOG_STATEMENT, MYF(0), "DROP");
DBUG_RETURN(true); DBUG_RETURN(true);
}
}
if (!in_bootstrap)
{
for (table= tables; table; table= table->next_local)
{
LEX_STRING db_name= { table->db, table->db_length };
LEX_STRING table_name= { table->table_name, table->table_name_length };
if (table->open_type == OT_BASE_ONLY || !find_temporary_table(thd, table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
} }
if (!drop_temporary) if (!drop_temporary)
{ {
if (!in_bootstrap)
{
for (table= tables; table; table= table->next_local)
{
LEX_STRING db_name= { table->db, table->db_length };
LEX_STRING table_name= { table->table_name, table->table_name_length };
if (table->open_type == OT_BASE_ONLY ||
!find_temporary_table(thd, table))
(void) delete_statistics_for_table(thd, &db_name, &table_name);
}
}
if (!thd->locked_tables_mode) if (!thd->locked_tables_mode)
{ {
if (lock_table_names(thd, tables, NULL, if (lock_table_names(thd, tables, NULL,
@ -2286,7 +2282,7 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
for (table= tables; table; table= table->next_local) for (table= tables; table; table= table->next_local)
{ {
bool is_trans; bool is_trans= 0;
char *db=table->db; char *db=table->db;
size_t db_length= table->db_length; size_t db_length= table->db_length;
handlerton *table_type= 0; handlerton *table_type= 0;
@ -2311,12 +2307,16 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists,
. 1 - a temporary table was not found. . 1 - a temporary table was not found.
. -1 - a temporary table is used by an outer statement. . -1 - a temporary table is used by an outer statement.
*/ */
if (table->open_type == OT_BASE_ONLY) if (table->open_type == OT_BASE_ONLY || !is_temporary_table(table))
error= 1; error= 1;
else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1) else
{ {
DBUG_ASSERT(thd->in_sub_stmt); if ((error= drop_temporary_table(thd, table->table, &is_trans)) == -1)
goto err; {
DBUG_ASSERT(thd->in_sub_stmt);
goto err;
}
table->table= 0;
} }
if ((drop_temporary && if_exists) || !error) if ((drop_temporary && if_exists) || !error)
@ -4517,12 +4517,13 @@ err:
way to ensure that concurrent operations won't intervene. way to ensure that concurrent operations won't intervene.
mysql_create_table() is a wrapper that can be used for this. mysql_create_table() is a wrapper that can be used for this.
@retval false OK @retval 0 OK
@retval true error @retval 1 error
@retval -1 table existed but IF EXISTS was used
*/ */
static static
bool create_table_impl(THD *thd, int create_table_impl(THD *thd,
const char *db, const char *table_name, const char *db, const char *table_name,
const char *path, const char *path,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
@ -4535,7 +4536,7 @@ bool create_table_impl(THD *thd,
{ {
const char *alias; const char *alias;
handler *file= 0; handler *file= 0;
bool error= TRUE; int error= 1;
bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY; bool frm_only= create_table_mode == C_ALTER_TABLE_FRM_ONLY;
bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only; bool internal_tmp_table= create_table_mode == C_ALTER_TABLE || frm_only;
DBUG_ENTER("mysql_create_table_no_lock"); DBUG_ENTER("mysql_create_table_no_lock");
@ -4565,22 +4566,66 @@ bool create_table_impl(THD *thd,
/* Check if table exists */ /* Check if table exists */
if (create_info->tmp_table()) if (create_info->tmp_table())
{ {
if (find_temporary_table(thd, db, table_name)) TABLE *tmp_table;
if ((tmp_table= find_temporary_table(thd, db, table_name)))
{ {
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) if (create_info->options & HA_LEX_CREATE_REPLACE)
{
bool is_trans;
/*
We are using CREATE OR REPLACE on an existing temporary table
Remove the old table so that we can re-create it.
*/
if (drop_temporary_table(thd, tmp_table, &is_trans))
goto err;
}
else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
goto warn; goto warn;
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias); else
goto err; {
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), alias);
goto err;
}
} }
} }
else else
{ {
if (!internal_tmp_table && ha_table_exists(thd, db, table_name)) if (!internal_tmp_table && ha_table_exists(thd, db, table_name))
{ {
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS) if (create_info->options & HA_LEX_CREATE_REPLACE)
{
TABLE_LIST table_list;
table_list.init_one_table(db, strlen(db), table_name,
strlen(table_name), table_name,
TL_WRITE_ALLOW_WRITE);
table_list.table= create_info->table;
if (check_if_log_table(&table_list, TRUE, "CREATE OR REPLACE"))
goto err;
/*
Rollback the empty transaction started in mysql_create_table()
call to open_and_lock_tables() when we are using LOCK TABLES.
*/
(void) trans_rollback_stmt(thd);
/* Remove normal table without logging */
if (mysql_rm_table_no_locks(thd, &table_list, 0, 0, 0, 1))
goto err;
/*
The test of query_tables is to ensure we have any tables in the
select part
*/
if (thd->lex->query_tables &&
restart_trans_for_tables(thd, thd->lex->query_tables->next_global))
goto err;
}
else if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
goto warn; goto warn;
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name); else
goto err; {
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
goto err;
}
} }
} }
@ -4702,14 +4747,14 @@ bool create_table_impl(THD *thd,
} }
#endif #endif
error= FALSE; error= 0;
err: err:
THD_STAGE_INFO(thd, stage_after_create); THD_STAGE_INFO(thd, stage_after_create);
delete file; delete file;
DBUG_RETURN(error); DBUG_RETURN(error);
warn: warn:
error= FALSE; error= -1;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE, push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR), ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
alias); alias);
@ -4720,7 +4765,8 @@ warn:
Simple wrapper around create_table_impl() to be used Simple wrapper around create_table_impl() to be used
in various version of CREATE TABLE statement. in various version of CREATE TABLE statement.
*/ */
bool mysql_create_table_no_lock(THD *thd,
int mysql_create_table_no_lock(THD *thd,
const char *db, const char *table_name, const char *db, const char *table_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
Alter_info *alter_info, bool *is_trans, Alter_info *alter_info, bool *is_trans,
@ -4728,6 +4774,7 @@ bool mysql_create_table_no_lock(THD *thd,
{ {
KEY *not_used_1; KEY *not_used_1;
uint not_used_2; uint not_used_2;
int res;
char path[FN_REFLEN + 1]; char path[FN_REFLEN + 1];
LEX_CUSTRING frm= {0,0}; LEX_CUSTRING frm= {0,0};
@ -4747,9 +4794,9 @@ bool mysql_create_table_no_lock(THD *thd,
} }
} }
bool res= create_table_impl(thd, db, table_name, path, create_info, res= create_table_impl(thd, db, table_name, path, create_info,
alter_info, create_table_mode, is_trans, alter_info, create_table_mode, is_trans,
&not_used_1, &not_used_2, &frm); &not_used_1, &not_used_2, &frm);
my_free(const_cast<uchar*>(frm.str)); my_free(const_cast<uchar*>(frm.str));
return res; return res;
} }
@ -4772,15 +4819,21 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
const char *table_name= create_table->table_name; const char *table_name= create_table->table_name;
bool is_trans= FALSE; bool is_trans= FALSE;
int create_table_mode; int create_table_mode;
TABLE_LIST *pos_in_locked_tables= 0;
DBUG_ENTER("mysql_create_table"); DBUG_ENTER("mysql_create_table");
DBUG_ASSERT(create_table == thd->lex->query_tables);
/* Open or obtain an exclusive metadata lock on table being created */ /* Open or obtain an exclusive metadata lock on table being created */
if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0)) if (open_and_lock_tables(thd, thd->lex->query_tables, FALSE, 0))
{ {
/* is_error() may be 0 if table existed and we generated a warning */ /* is_error() may be 0 if table existed and we generated a warning */
DBUG_RETURN(thd->is_error()); DBUG_RETURN(thd->is_error());
} }
/* The following is needed only in case of lock tables */
if ((create_info->table= thd->lex->query_tables->table))
pos_in_locked_tables= create_info->table->pos_in_locked_tables;
/* Got lock. */ /* Got lock. */
DEBUG_SYNC(thd, "locked_table_name"); DEBUG_SYNC(thd, "locked_table_name");
@ -4791,9 +4844,25 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
promote_first_timestamp_column(&alter_info->create_list); promote_first_timestamp_column(&alter_info->create_list);
if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info, if (mysql_create_table_no_lock(thd, db, table_name, create_info, alter_info,
&is_trans, create_table_mode)) &is_trans, create_table_mode) > 0)
DBUG_RETURN(1); DBUG_RETURN(1);
/*
Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES
on a non temporary table
*/
if (thd->locked_tables_mode && pos_in_locked_tables &&
(create_info->options & HA_LEX_CREATE_REPLACE))
{
/*
Add back the deleted table and re-created table as a locked table
This should always work as we have a meta lock on the table.
*/
thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
if (thd->locked_tables_list.reopen_tables(thd))
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
}
/* In RBR we don't need to log CREATE TEMPORARY TABLE */ /* In RBR we don't need to log CREATE TEMPORARY TABLE */
if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table()) if (thd->is_current_stmt_binlog_format_row() && create_info->tmp_table())
DBUG_RETURN(0); DBUG_RETURN(0);
@ -4986,10 +5055,12 @@ mysql_rename_table(handlerton *base, const char *old_db,
TRUE error TRUE error
*/ */
bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table, bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
TABLE_LIST* src_table,
HA_CREATE_INFO *create_info) HA_CREATE_INFO *create_info)
{ {
HA_CREATE_INFO local_create_info; HA_CREATE_INFO local_create_info;
TABLE_LIST *pos_in_locked_tables= 0;
Alter_info local_alter_info; Alter_info local_alter_info;
Alter_table_ctx local_alter_ctx; // Not used Alter_table_ctx local_alter_ctx; // Not used
bool res= TRUE; bool res= TRUE;
@ -4997,7 +5068,6 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
uint not_used; uint not_used;
DBUG_ENTER("mysql_create_like_table"); DBUG_ENTER("mysql_create_like_table");
/* /*
We the open source table to get its description in HA_CREATE_INFO We the open source table to get its description in HA_CREATE_INFO
and Alter_info objects. This also acquires a shared metadata lock and Alter_info objects. This also acquires a shared metadata lock
@ -5041,7 +5111,9 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
if (src_table->schema_table) if (src_table->schema_table)
local_create_info.max_rows= 0; local_create_info.max_rows= 0;
/* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */ /* Set IF NOT EXISTS option as in the CREATE TABLE LIKE statement. */
local_create_info.options|= create_info->options&HA_LEX_CREATE_IF_NOT_EXISTS; local_create_info.options|= (create_info->options &
(HA_LEX_CREATE_IF_NOT_EXISTS |
HA_LEX_CREATE_REPLACE));
/* Replace type of source table with one specified in the statement. */ /* Replace type of source table with one specified in the statement. */
local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE; local_create_info.options&= ~HA_LEX_CREATE_TMP_TABLE;
local_create_info.options|= create_info->tmp_table(); local_create_info.options|= create_info->tmp_table();
@ -5053,11 +5125,39 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
*/ */
local_create_info.data_file_name= local_create_info.index_file_name= NULL; local_create_info.data_file_name= local_create_info.index_file_name= NULL;
if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name, /* The following is needed only in case of lock tables */
&local_create_info, &local_alter_info, if ((local_create_info.table= thd->lex->query_tables->table))
&is_trans, C_ORDINARY_CREATE))) pos_in_locked_tables= local_create_info.table->pos_in_locked_tables;
if ((res= (mysql_create_table_no_lock(thd, table->db, table->table_name,
&local_create_info, &local_alter_info,
&is_trans, C_ORDINARY_CREATE) > 0)))
goto err; goto err;
/*
Check if we are doing CREATE OR REPLACE TABLE under LOCK TABLES
on a non temporary table
*/
if (thd->locked_tables_mode && pos_in_locked_tables &&
(create_info->options & HA_LEX_CREATE_REPLACE))
{
/*
Add back the deleted table and re-created table as a locked table
This should always work as we have a meta lock on the table.
*/
thd->locked_tables_list.add_back_last_deleted_lock(pos_in_locked_tables);
if (thd->locked_tables_list.reopen_tables(thd))
thd->locked_tables_list.unlink_all_closed_tables(thd, NULL, 0);
else
{
/*
Get pointer to the newly opened table. We need this to ensure we
don't reopen the table when doing statment logging below.
*/
table->table= pos_in_locked_tables->table;
}
}
/* /*
Ensure that we have an exclusive lock on target table if we are creating Ensure that we have an exclusive lock on target table if we are creating
non-temporary table. non-temporary table.
@ -5108,6 +5208,11 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
{ {
if (!table->table) if (!table->table)
{ {
TABLE_LIST::enum_open_strategy save_open_strategy;
int open_res;
/* Force the newly created table to be opened */
save_open_strategy= table->open_strategy;
table->open_strategy= TABLE_LIST::OPEN_NORMAL;
/* /*
In order for store_create_info() to work we need to open In order for store_create_info() to work we need to open
@ -5117,11 +5222,20 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
lock on this table. The table will be closed by lock on this table. The table will be closed by
close_thread_table() at the end of this branch. close_thread_table() at the end of this branch.
*/ */
if (open_table(thd, table, thd->mem_root, &ot_ctx)) open_res= open_table(thd, table, thd->mem_root, &ot_ctx);
/* Restore */
table->open_strategy= save_open_strategy;
if (open_res)
goto err; goto err;
new_table= TRUE; new_table= TRUE;
} }
}
/*
We have to re-test if the table was a view as the view may not
have been opened until just above.
*/
if (!table->view)
{
int result __attribute__((unused))= int result __attribute__((unused))=
store_create_info(thd, table, &query, store_create_info(thd, table, &query,
create_info, FALSE /* show_database */); create_info, FALSE /* show_database */);
@ -7726,9 +7840,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
it is the case. it is the case.
TODO: this design is obsolete and will be removed. TODO: this design is obsolete and will be removed.
*/ */
int table_kind= check_if_log_table(table_list->db_length, table_list->db, int table_kind= check_if_log_table(table_list, FALSE, NullS);
table_list->table_name_length,
table_list->table_name, false);
if (table_kind) if (table_kind)
{ {

View File

@ -187,11 +187,11 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
#define C_ALTER_TABLE_FRM_ONLY -2 #define C_ALTER_TABLE_FRM_ONLY -2
#define C_ASSISTED_DISCOVERY -3 #define C_ASSISTED_DISCOVERY -3
bool mysql_create_table_no_lock(THD *thd, const char *db, int mysql_create_table_no_lock(THD *thd, const char *db,
const char *table_name, const char *table_name,
HA_CREATE_INFO *create_info, HA_CREATE_INFO *create_info,
Alter_info *alter_info, bool *is_trans, Alter_info *alter_info, bool *is_trans,
int create_table_mode); int create_table_mode);
handler *mysql_create_frm_image(THD *thd, handler *mysql_create_frm_image(THD *thd,
const char *db, const char *table_name, const char *db, const char *table_name,

View File

@ -1664,7 +1664,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <num> %type <num>
type type_with_opt_collate int_type real_type order_dir lock_option type type_with_opt_collate int_type real_type order_dir lock_option
udf_type opt_if_exists opt_local opt_table_options table_options udf_type opt_if_exists opt_local opt_table_options table_options
table_option opt_if_not_exists opt_no_write_to_binlog table_option opt_if_not_exists create_or_replace opt_no_write_to_binlog
opt_temporary all_or_any opt_distinct opt_temporary all_or_any opt_distinct
opt_ignore_leaves fulltext_options spatial_type union_option opt_ignore_leaves fulltext_options spatial_type union_option
field_def field_def
@ -1843,7 +1843,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
statement sp_suid statement sp_suid
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
opt_field_or_var_spec fields_or_vars opt_load_data_set_spec opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
view_replace_or_algorithm view_replace
view_algorithm view_or_trigger_or_sp_or_event view_algorithm view_or_trigger_or_sp_or_event
definer_tail no_definer_tail definer_tail no_definer_tail
view_suid view_tail view_list_opt view_list view_select view_suid view_tail view_list_opt view_list view_select
@ -2341,25 +2340,29 @@ connection_name:
/* create a table */ /* create a table */
create: create:
CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident create_or_replace opt_table_options TABLE_SYM opt_if_not_exists table_ident
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
lex->sql_command= SQLCOM_CREATE_TABLE; lex->sql_command= SQLCOM_CREATE_TABLE;
if ($1 && $4)
{
my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE", "IF NOT EXISTS");
MYSQL_YYABORT;
}
if (!lex->select_lex.add_table_to_list(thd, $5, NULL, if (!lex->select_lex.add_table_to_list(thd, $5, NULL,
TL_OPTION_UPDATING, TL_OPTION_UPDATING,
TL_WRITE, MDL_EXCLUSIVE)) TL_WRITE, MDL_EXCLUSIVE))
MYSQL_YYABORT; MYSQL_YYABORT;
/*
For CREATE TABLE, an non-existing table is not an error.
Instruct open_tables() to just take an MDL lock if the
table does not exist.
*/
lex->query_tables->open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
lex->alter_info.reset(); lex->alter_info.reset();
lex->col_list.empty(); lex->col_list.empty();
lex->change=NullS; lex->change=NullS;
bzero((char*) &lex->create_info,sizeof(lex->create_info)); bzero((char*) &lex->create_info,sizeof(lex->create_info));
lex->create_info.options=$2 | $4; /*
For CREATE TABLE we should not open the table even if it exists.
If the table exists, we should either not create it or replace it
*/
lex->query_tables->open_strategy= TABLE_LIST::OPEN_STUB;
lex->create_info.options= ($1 | $2 | $4);
lex->create_info.default_table_charset= NULL; lex->create_info.default_table_charset= NULL;
lex->name.str= 0; lex->name.str= 0;
lex->name.length= 0; lex->name.length= 0;
@ -2428,14 +2431,22 @@ create:
lex->name= $4; lex->name= $4;
lex->create_info.options=$3; lex->create_info.options=$3;
} }
| CREATE | create_or_replace
{ {
Lex->create_view_mode= VIEW_CREATE_NEW; Lex->create_view_mode= ($1 == 0 ? VIEW_CREATE_NEW :
VIEW_CREATE_OR_REPLACE);
Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED;
Lex->create_view_suid= TRUE; Lex->create_view_suid= TRUE;
} }
view_or_trigger_or_sp_or_event view_or_trigger_or_sp_or_event
{} {
if ($1 && Lex->sql_command != SQLCOM_CREATE_VIEW)
{
my_error(ER_WRONG_USAGE, MYF(0), "OR REPLACE",
"TRIGGERS / SP / EVENT");
MYSQL_YYABORT;
}
}
| CREATE USER clear_privileges grant_list | CREATE USER clear_privileges grant_list
{ {
Lex->sql_command = SQLCOM_CREATE_USER; Lex->sql_command = SQLCOM_CREATE_USER;
@ -5515,6 +5526,17 @@ opt_if_not_exists:
} }
; ;
create_or_replace:
CREATE /* empty */
{
$$= 0;
}
| CREATE OR_SYM REPLACE
{
$$= HA_LEX_CREATE_REPLACE;
}
;
opt_create_table_options: opt_create_table_options:
/* empty */ /* empty */
| create_table_options | create_table_options
@ -15799,7 +15821,7 @@ view_or_trigger_or_sp_or_event:
{} {}
| no_definer no_definer_tail | no_definer no_definer_tail
{} {}
| view_replace_or_algorithm definer_opt view_tail | view_algorithm definer_opt view_tail
{} {}
; ;
@ -15858,20 +15880,6 @@ definer:
**************************************************************************/ **************************************************************************/
view_replace_or_algorithm:
view_replace
{}
| view_replace view_algorithm
{}
| view_algorithm
{}
;
view_replace:
OR_SYM REPLACE
{ Lex->create_view_mode= VIEW_CREATE_OR_REPLACE; }
;
view_algorithm: view_algorithm:
ALGORITHM_SYM EQ UNDEFINED_SYM ALGORITHM_SYM EQ UNDEFINED_SYM
{ Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; } { Lex->create_view_algorithm= DTYPE_ALGORITHM_UNDEFINED; }

View File

@ -1951,7 +1951,7 @@ struct TABLE_LIST
Indicates that if TABLE_LIST object corresponds to the table/view Indicates that if TABLE_LIST object corresponds to the table/view
which requires special handling. which requires special handling.
*/ */
enum enum enum_open_strategy
{ {
/* Normal open. */ /* Normal open. */
OPEN_NORMAL= 0, OPEN_NORMAL= 0,

View File

@ -196,6 +196,7 @@ static void check_unused(THD *thd)
TABLE *entry; TABLE *entry;
TABLE_SHARE *share; TABLE_SHARE *share;
TDC_iterator tdc_it; TDC_iterator tdc_it;
DBUG_ENTER("check_unused");
tdc_it.init(); tdc_it.init();
mysql_mutex_lock(&LOCK_open); mysql_mutex_lock(&LOCK_open);
@ -221,6 +222,7 @@ static void check_unused(THD *thd)
} }
mysql_mutex_unlock(&LOCK_open); mysql_mutex_unlock(&LOCK_open);
tdc_it.deinit(); tdc_it.deinit();
DBUG_VOID_RETURN;
} }
#else #else
#define check_unused(A) #define check_unused(A)