Merge bk-internal.mysql.com:/home/bk/mysql-5.1-runtime
into mockturtle.local:/home/dlenev/src/mysql-5.1-like-2 sql/sql_parse.cc: Auto merged
This commit is contained in:
commit
4b9b1edae7
@ -162,3 +162,86 @@ t1 CREATE TABLE `t1` (
|
||||
`j` int(11) DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t1, t2, t3;
|
||||
drop table if exists t1,t2;
|
||||
create table t1 (i int);
|
||||
set session debug="+d,sleep_create_like_before_check_if_exists";
|
||||
reset master;
|
||||
create table t2 like t1;;
|
||||
insert into t1 values (1);
|
||||
drop table t1;
|
||||
show create table t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
`i` int(11) DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t2;
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query 1 # use `test`; insert into t1 values (1)
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
create table t1 (i int);
|
||||
set session debug="-d,sleep_create_like_before_check_if_exists:+d,sleep_create_like_before_copy";
|
||||
create table t2 like t1;;
|
||||
create table if not exists t2 (j int);
|
||||
Warnings:
|
||||
Note 1050 Table 't2' already exists
|
||||
show create table t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
`i` int(11) DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
drop table t2;
|
||||
reset master;
|
||||
create table t2 like t1;;
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
create table t1 (i int);
|
||||
set session debug="-d,sleep_create_like_before_copy:+d,sleep_create_like_before_ha_create";
|
||||
reset master;
|
||||
create table t2 like t1;;
|
||||
insert into t2 values (1);
|
||||
drop table t2;
|
||||
create table t2 like t1;;
|
||||
drop table t2;
|
||||
create table t2 like t1;;
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; insert into t2 values (1)
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
create table t1 (i int);
|
||||
set session debug="-d,sleep_create_like_before_ha_create:+d,sleep_create_like_before_binlogging";
|
||||
reset master;
|
||||
create table t2 like t1;;
|
||||
insert into t2 values (1);
|
||||
drop table t2;
|
||||
create table t2 like t1;;
|
||||
drop table t2;
|
||||
create table t2 like t1;;
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
Log_name Pos Event_type Server_id End_log_pos Info
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; insert into t2 values (1)
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
master-bin.000001 # Query 1 # use `test`; create table t2 like t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t1
|
||||
master-bin.000001 # Query 1 # use `test`; drop table t2
|
||||
set session debug="-d,sleep_create_like_before_binlogging";
|
@ -371,7 +371,7 @@ ERROR 42S01: Table 't3' already exists
|
||||
create table non_existing_database.t1 like t1;
|
||||
ERROR 42000: Unknown database 'non_existing_database'
|
||||
create table t3 like non_existing_table;
|
||||
ERROR 42S02: Unknown table 'non_existing_table'
|
||||
ERROR 42S02: Table 'test.non_existing_table' doesn't exist
|
||||
create temporary table t3 like t1;
|
||||
ERROR 42S01: Table 't3' already exists
|
||||
drop table t1, t2, t3;
|
||||
|
@ -381,3 +381,26 @@ drop table t2;
|
||||
REVOKE ALL PRIVILEGES, GRANT OPTION FROM `a@`@localhost;
|
||||
drop user `a@`@localhost;
|
||||
SET GLOBAL log_bin_trust_function_creators = 0;
|
||||
drop database if exists mysqltest_1;
|
||||
drop database if exists mysqltest_2;
|
||||
drop user mysqltest_u1@localhost;
|
||||
create database mysqltest_1;
|
||||
create database mysqltest_2;
|
||||
grant all on mysqltest_1.* to mysqltest_u1@localhost;
|
||||
use mysqltest_2;
|
||||
create table t1 (i int);
|
||||
show create table mysqltest_2.t1;
|
||||
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
|
||||
create table t1 like mysqltest_2.t1;
|
||||
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
|
||||
grant select on mysqltest_2.t1 to mysqltest_u1@localhost;
|
||||
show create table mysqltest_2.t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`i` int(11) DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
create table t1 like mysqltest_2.t1;
|
||||
use test;
|
||||
drop database mysqltest_1;
|
||||
drop database mysqltest_2;
|
||||
drop user mysqltest_u1@localhost;
|
||||
|
@ -1,12 +1,17 @@
|
||||
# Tests for various aspects of CREATE TABLE ... SELECT implementation
|
||||
# Tests for various concurrency-related aspects of CREATE TABLE ... SELECT
|
||||
# and CREATE TABLE like implementation.
|
||||
#
|
||||
# Note that we don't test general CREATE TABLE ... SELECT functionality here as
|
||||
# it is already covered by create.test. We are more interested in extreme cases.
|
||||
# Note that we don't test general CREATE TABLE ... SELECT/LIKE functionality
|
||||
# here as it is already covered by create.test. We are more interested in
|
||||
# extreme cases.
|
||||
#
|
||||
# This test takes rather long time so let us run it only in --big-test mode
|
||||
--source include/big_test.inc
|
||||
# We are using some debug-only features in this test
|
||||
--source include/have_debug.inc
|
||||
# Some of tests below also use binlog to check that statements are
|
||||
# executed and logged in correct order
|
||||
--source include/have_binlog_format_mixed_or_statement.inc
|
||||
|
||||
# Create auxilliary connections
|
||||
connect (addconroot1, localhost, root,,);
|
||||
@ -20,7 +25,7 @@ drop table if exists t1,t2,t3,t4,t5;
|
||||
|
||||
|
||||
#
|
||||
# Tests for concurrency problems.
|
||||
# Tests for concurrency problems in CREATE TABLE ... SELECT
|
||||
#
|
||||
# We introduce delays between various stages of table creation
|
||||
# and check that other statements dealing with this table cannot
|
||||
@ -266,3 +271,122 @@ connection default;
|
||||
select * from t1;
|
||||
show create table t1;
|
||||
drop table t1, t2, t3;
|
||||
|
||||
|
||||
# Tests for possible concurrency issues with CREATE TABLE ... LIKE
|
||||
#
|
||||
# Bug #18950 "create table like does not obtain LOCK_open"
|
||||
# Bug #23667 "CREATE TABLE LIKE is not isolated from alteration by other
|
||||
# connections"
|
||||
#
|
||||
# Again the idea of this test is that we introduce artificial delays on
|
||||
# various stages of table creation and check that concurrent statements
|
||||
# for tables from CREATE TABLE ... LIKE are not interfering.
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2;
|
||||
--enable_warnings
|
||||
|
||||
# What happens if some statements sneak in right after we have
|
||||
# opened source table ?
|
||||
create table t1 (i int);
|
||||
set session debug="+d,sleep_create_like_before_check_if_exists";
|
||||
# Reset binlog to have clear start
|
||||
reset master;
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
# DML on source table should be allowed to run concurrently
|
||||
insert into t1 values (1);
|
||||
# And DDL should wait
|
||||
drop table t1;
|
||||
connection default;
|
||||
--reap
|
||||
show create table t2;
|
||||
drop table t2;
|
||||
# Let us check that statements were executed/binlogged in correct order
|
||||
--replace_column 2 # 5 #
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
|
||||
# Now let us check the gap between check for target table
|
||||
# existance and copying of .frm file.
|
||||
create table t1 (i int);
|
||||
set session debug="-d,sleep_create_like_before_check_if_exists:+d,sleep_create_like_before_copy";
|
||||
# It should be impossible to create target table concurrently
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
create table if not exists t2 (j int);
|
||||
connection default;
|
||||
--reap
|
||||
show create table t2;
|
||||
drop table t2;
|
||||
# And concurrent DDL on the source table should be still disallowed
|
||||
reset master;
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
drop table t1;
|
||||
connection default;
|
||||
--reap
|
||||
drop table t2;
|
||||
--replace_column 2 # 5 #
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
|
||||
# And now he gap between copying of .frm file and ha_create_table() call.
|
||||
create table t1 (i int);
|
||||
set session debug="-d,sleep_create_like_before_copy:+d,sleep_create_like_before_ha_create";
|
||||
# Both DML and DDL on target table should wait till operation completes
|
||||
reset master;
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
insert into t2 values (1);
|
||||
connection default;
|
||||
--reap
|
||||
drop table t2;
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
drop table t2;
|
||||
connection default;
|
||||
--reap
|
||||
# Concurrent DDL on the source table still waits
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
drop table t1;
|
||||
connection default;
|
||||
--reap
|
||||
drop table t2;
|
||||
--replace_column 2 # 5 #
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
|
||||
# Finally we check the gap between ha_create_table() and binlogging
|
||||
create table t1 (i int);
|
||||
set session debug="-d,sleep_create_like_before_ha_create:+d,sleep_create_like_before_binlogging";
|
||||
reset master;
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
insert into t2 values (1);
|
||||
connection default;
|
||||
--reap
|
||||
drop table t2;
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
drop table t2;
|
||||
connection default;
|
||||
--reap
|
||||
--send create table t2 like t1;
|
||||
connection addconroot1;
|
||||
--sleep 2
|
||||
drop table t1;
|
||||
connection default;
|
||||
--reap
|
||||
drop table t2;
|
||||
--replace_column 2 # 5 #
|
||||
show binlog events in 'master-bin.000001' from 106;
|
||||
|
||||
set session debug="-d,sleep_create_like_before_binlogging";
|
@ -306,7 +306,7 @@ create table t3 like t1;
|
||||
create table t3 like mysqltest.t3;
|
||||
--error 1049
|
||||
create table non_existing_database.t1 like t1;
|
||||
--error 1051
|
||||
--error ER_NO_SUCH_TABLE
|
||||
create table t3 like non_existing_table;
|
||||
--error 1050
|
||||
create temporary table t3 like t1;
|
||||
|
@ -30,7 +30,6 @@ rpl_ddl : BUG#26418 2007-03-01 mleich Slave out of sync after C
|
||||
rpl_ndb_innodb2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
|
||||
rpl_ndb_myisam2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
|
||||
rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly
|
||||
synchronization : Bug#24529 Test 'synchronization' fails on Mac pushbuild; Also on Linux 64 bit.
|
||||
|
||||
# the below testcase have been reworked to avoid the bug, test contains comment, keep bug open
|
||||
#ndb_binlog_ddl_multi : BUG#18976 2006-04-10 kent CRBR: multiple binlog, second binlog may miss schema log events
|
||||
|
@ -513,3 +513,44 @@ REVOKE ALL PRIVILEGES, GRANT OPTION FROM `a@`@localhost;
|
||||
drop user `a@`@localhost;
|
||||
|
||||
SET GLOBAL log_bin_trust_function_creators = 0;
|
||||
|
||||
|
||||
#
|
||||
# Bug#25578 "CREATE TABLE LIKE does not require any privileges on source table"
|
||||
#
|
||||
--disable_warnings
|
||||
drop database if exists mysqltest_1;
|
||||
drop database if exists mysqltest_2;
|
||||
--enable_warnings
|
||||
--error 0,ER_CANNOT_USER
|
||||
drop user mysqltest_u1@localhost;
|
||||
|
||||
create database mysqltest_1;
|
||||
create database mysqltest_2;
|
||||
grant all on mysqltest_1.* to mysqltest_u1@localhost;
|
||||
use mysqltest_2;
|
||||
create table t1 (i int);
|
||||
|
||||
# Connect as user with all rights on mysqltest_1 but with no rights on mysqltest_2.
|
||||
connect (user1,localhost,mysqltest_u1,,mysqltest_1);
|
||||
connection user1;
|
||||
# As expected error is emitted
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
show create table mysqltest_2.t1;
|
||||
# This should emit error as well
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
create table t1 like mysqltest_2.t1;
|
||||
|
||||
# Now let us check that SELECT privilege on the source is enough
|
||||
connection default;
|
||||
grant select on mysqltest_2.t1 to mysqltest_u1@localhost;
|
||||
connection user1;
|
||||
show create table mysqltest_2.t1;
|
||||
create table t1 like mysqltest_2.t1;
|
||||
|
||||
# Clean-up
|
||||
connection default;
|
||||
use test;
|
||||
drop database mysqltest_1;
|
||||
drop database mysqltest_2;
|
||||
drop user mysqltest_u1@localhost;
|
||||
|
@ -223,6 +223,7 @@
|
||||
|
||||
#define HA_LEX_CREATE_TMP_TABLE 1
|
||||
#define HA_LEX_CREATE_IF_NOT_EXISTS 2
|
||||
#define HA_LEX_CREATE_TABLE_LIKE 4
|
||||
#define HA_OPTION_NO_CHECKSUM (1L << 17)
|
||||
#define HA_OPTION_NO_DELAY_KEY_WRITE (1L << 18)
|
||||
#define HA_MAX_REC_LENGTH 65535
|
||||
|
@ -978,9 +978,8 @@ bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
|
||||
uint order_num, ORDER *order, bool ignore,
|
||||
ALTER_INFO *alter_info, bool do_send_ok);
|
||||
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list, bool do_send_ok);
|
||||
bool mysql_create_like_table(THD *thd, TABLE_LIST *table,
|
||||
HA_CREATE_INFO *create_info,
|
||||
Table_ident *src_table);
|
||||
bool mysql_create_like_table(THD *thd, TABLE_LIST *table, TABLE_LIST *src_table,
|
||||
HA_CREATE_INFO *create_info);
|
||||
bool mysql_rename_table(handlerton *base, const char *old_db,
|
||||
const char * old_name, const char *new_db,
|
||||
const char * new_name, uint flags);
|
||||
|
@ -1066,7 +1066,6 @@ typedef struct st_lex : public Query_tables_list
|
||||
|
||||
char *length,*dec,*change;
|
||||
LEX_STRING name;
|
||||
Table_ident *like_name;
|
||||
char *help_arg;
|
||||
char *backup_dir; /* For RESTORE/BACKUP */
|
||||
char* to_log; /* For PURGE MASTER LOGS TO */
|
||||
|
@ -39,6 +39,7 @@
|
||||
"FUNCTION" : "PROCEDURE")
|
||||
|
||||
static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables);
|
||||
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
|
||||
|
||||
const char *any_db="*any*"; // Special symbol for check_access
|
||||
|
||||
@ -2231,9 +2232,9 @@ mysql_execute_command(THD *thd)
|
||||
if (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)
|
||||
thd->options|= OPTION_KEEP_LOG;
|
||||
/* regular create */
|
||||
if (lex->like_name)
|
||||
res= mysql_create_like_table(thd, create_table, &lex->create_info,
|
||||
lex->like_name);
|
||||
if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
|
||||
res= mysql_create_like_table(thd, create_table, select_tables,
|
||||
&lex->create_info);
|
||||
else
|
||||
{
|
||||
res= mysql_create_table(thd, create_table->db,
|
||||
@ -2423,12 +2424,7 @@ end_with_restore_list:
|
||||
/* Ignore temporary tables if this is "SHOW CREATE VIEW" */
|
||||
if (lex->only_view)
|
||||
first_table->skip_temporary= 1;
|
||||
|
||||
if (check_access(thd, SELECT_ACL | EXTRA_ACL, first_table->db,
|
||||
&first_table->grant.privilege, 0, 0,
|
||||
test(first_table->schema_table)))
|
||||
goto error;
|
||||
if (grant_option && check_grant(thd, SELECT_ACL, all_tables, 2, UINT_MAX, 0))
|
||||
if (check_show_create_table_access(thd, first_table))
|
||||
goto error;
|
||||
res= mysqld_show_create(thd, first_table);
|
||||
break;
|
||||
@ -6845,6 +6841,25 @@ bool insert_precheck(THD *thd, TABLE_LIST *tables)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Check privileges for SHOW CREATE TABLE statement.
|
||||
|
||||
@param thd Thread context
|
||||
@param table Target table
|
||||
|
||||
@retval TRUE Failure
|
||||
@retval FALSE Success
|
||||
*/
|
||||
|
||||
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table)
|
||||
{
|
||||
return check_access(thd, SELECT_ACL | EXTRA_ACL, table->db,
|
||||
&table->grant.privilege, 0, 0,
|
||||
test(table->schema_table)) ||
|
||||
grant_option && check_grant(thd, SELECT_ACL, table, 2, UINT_MAX, 0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
CREATE TABLE query pre-check
|
||||
|
||||
@ -6910,6 +6925,11 @@ bool create_table_precheck(THD *thd, TABLE_LIST *tables,
|
||||
if (tables && check_table_access(thd, SELECT_ACL, tables,0))
|
||||
goto err;
|
||||
}
|
||||
else if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
|
||||
{
|
||||
if (check_show_create_table_access(thd, tables))
|
||||
goto err;
|
||||
}
|
||||
error= FALSE;
|
||||
|
||||
err:
|
||||
|
@ -3776,20 +3776,15 @@ bool mysql_unpack_partition(THD *thd,
|
||||
ha_legacy_type(default_db_type)));
|
||||
if (is_create_table_ind && old_lex->sql_command == SQLCOM_CREATE_TABLE)
|
||||
{
|
||||
if (old_lex->like_name)
|
||||
if (old_lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
|
||||
{
|
||||
/*
|
||||
This code is executed when we do a CREATE TABLE t1 LIKE t2
|
||||
old_lex->like_name contains the t2 and the table we are opening has
|
||||
name t1.
|
||||
This code is executed when we create table in CREATE TABLE t1 LIKE t2.
|
||||
old_lex->query_tables contains table list element for t2 and the table
|
||||
we are opening has name t1.
|
||||
*/
|
||||
Table_ident *table_ident= old_lex->like_name;
|
||||
char *src_db= table_ident->db.str ? table_ident->db.str : thd->db;
|
||||
char *src_table= table_ident->table.str;
|
||||
char buf[FN_REFLEN];
|
||||
build_table_filename(buf, sizeof(buf), src_db, src_table, "", 0);
|
||||
if (partition_default_handling(table, part_info,
|
||||
FALSE, buf))
|
||||
if (partition_default_handling(table, part_info, FALSE,
|
||||
old_lex->query_tables->table->s->path.str))
|
||||
{
|
||||
result= TRUE;
|
||||
goto end;
|
||||
|
137
sql/sql_table.cc
137
sql/sql_table.cc
@ -4665,114 +4665,51 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
|
||||
SYNOPSIS
|
||||
mysql_create_like_table()
|
||||
thd Thread object
|
||||
table Table list (one table only)
|
||||
table Table list element for target table
|
||||
src_table Table list element for source table
|
||||
create_info Create info
|
||||
table_ident Src table_ident
|
||||
|
||||
RETURN VALUES
|
||||
FALSE OK
|
||||
TRUE error
|
||||
*/
|
||||
|
||||
bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
HA_CREATE_INFO *lex_create_info,
|
||||
Table_ident *table_ident)
|
||||
bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
HA_CREATE_INFO *lex_create_info)
|
||||
{
|
||||
TABLE *tmp_table, *name_lock= 0;
|
||||
TABLE *name_lock= 0;
|
||||
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
|
||||
char src_table_name_buff[FN_REFLEN], src_db_name_buff[FN_REFLEN];
|
||||
uint dst_path_length;
|
||||
char *db= table->db;
|
||||
char *table_name= table->table_name;
|
||||
char *src_db;
|
||||
char *src_table= table_ident->table.str;
|
||||
int err;
|
||||
bool res= TRUE;
|
||||
enum legacy_db_type not_used;
|
||||
uint not_used;
|
||||
HA_CREATE_INFO *create_info;
|
||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||
char tmp_path[FN_REFLEN];
|
||||
#endif
|
||||
char ts_name[FN_LEN];
|
||||
TABLE_LIST src_tables_list;
|
||||
DBUG_ENTER("mysql_create_like_table");
|
||||
|
||||
if (!(create_info= copy_create_info(lex_create_info)))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
DBUG_ASSERT(table_ident->db.str); /* Must be set in the parser */
|
||||
src_db= table_ident->db.str;
|
||||
|
||||
/* CREATE TABLE ... LIKE is not allowed for views. */
|
||||
src_table->required_type= FRMTYPE_TABLE;
|
||||
|
||||
/*
|
||||
Validate the source table
|
||||
By opening source table we guarantee that it exists and no concurrent
|
||||
DDL operation will mess with it. Later we also take an exclusive
|
||||
name-lock on target table name, which makes copying of .frm file,
|
||||
call to ha_create_table() and binlogging atomic against concurrent DML
|
||||
and DDL operations on target table. Thus by holding both these "locks"
|
||||
we ensure that our statement is properly isolated from all concurrent
|
||||
operations which matter.
|
||||
*/
|
||||
if (check_string_char_length(&table_ident->table, "", NAME_CHAR_LEN,
|
||||
system_charset_info, 1) ||
|
||||
(table_ident->table.length &&
|
||||
check_table_name(src_table,table_ident->table.length)))
|
||||
{
|
||||
my_error(ER_WRONG_TABLE_NAME, MYF(0), src_table);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
if (!src_db || check_db_name(&table_ident->db))
|
||||
{
|
||||
my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL");
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
|
||||
if ((tmp_table= find_temporary_table(thd, src_db, src_table)))
|
||||
strxmov(src_path, tmp_table->s->path.str, reg_ext, NullS);
|
||||
else
|
||||
{
|
||||
build_table_filename(src_path, sizeof(src_path),
|
||||
src_db, src_table, reg_ext, 0);
|
||||
/* Resolve symlinks (for windows) */
|
||||
unpack_filename(src_path, src_path);
|
||||
if (lower_case_table_names)
|
||||
my_casedn_str(files_charset_info, src_path);
|
||||
if (access(src_path, F_OK))
|
||||
{
|
||||
my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
create like should be not allowed for Views, Triggers, ...
|
||||
*/
|
||||
if (mysql_frm_type(thd, src_path, ¬_used) != FRMTYPE_TABLE)
|
||||
{
|
||||
my_error(ER_WRONG_OBJECT, MYF(0), src_db, src_table, "BASE TABLE");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (lower_case_table_names)
|
||||
{
|
||||
if (src_db)
|
||||
{
|
||||
strmake(src_db_name_buff, src_db,
|
||||
min(sizeof(src_db_name_buff) - 1, table_ident->db.length));
|
||||
my_casedn_str(files_charset_info, src_db_name_buff);
|
||||
src_db= src_db_name_buff;
|
||||
}
|
||||
if (src_table)
|
||||
{
|
||||
strmake(src_table_name_buff, src_table,
|
||||
min(sizeof(src_table_name_buff) - 1, table_ident->table.length));
|
||||
my_casedn_str(files_charset_info, src_table_name_buff);
|
||||
src_table= src_table_name_buff;
|
||||
}
|
||||
}
|
||||
|
||||
bzero((gptr)&src_tables_list, sizeof(src_tables_list));
|
||||
src_tables_list.db= src_db;
|
||||
src_tables_list.db_length= table_ident->db.length;
|
||||
src_tables_list.lock_type= TL_READ;
|
||||
src_tables_list.table_name= src_table;
|
||||
src_tables_list.alias= src_table;
|
||||
|
||||
if (simple_open_n_lock_tables(thd, &src_tables_list))
|
||||
if (open_tables(thd, &src_table, ¬_used, 0))
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
/*
|
||||
@ -4781,17 +4718,19 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
Add something to get possible tablespace info from src table,
|
||||
it can get valid tablespace name only for disk-base ndb table
|
||||
*/
|
||||
if ((src_tables_list.table->file->get_tablespace_name(thd, ts_name, FN_LEN)))
|
||||
if ((src_table->table->file->get_tablespace_name(thd, ts_name, FN_LEN)))
|
||||
{
|
||||
create_info->tablespace= ts_name;
|
||||
create_info->storage_media= HA_SM_DISK;
|
||||
}
|
||||
|
||||
/*
|
||||
Validate the destination table
|
||||
strxmov(src_path, src_table->table->s->path.str, reg_ext, NullS);
|
||||
|
||||
skip the destination table name checking as this is already
|
||||
validated.
|
||||
DBUG_EXECUTE_IF("sleep_create_like_before_check_if_exists", my_sleep(6000000););
|
||||
|
||||
/*
|
||||
Check that destination tables does not exist. Note that its name
|
||||
was already checked when it was added to the table list.
|
||||
*/
|
||||
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
||||
{
|
||||
@ -4812,15 +4751,29 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
goto table_exists;
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
|
||||
|
||||
/*
|
||||
Create a new table by copying from source table
|
||||
|
||||
Altough exclusive name-lock on target table protects us from concurrent
|
||||
DML and DDL operations on it we still want to wrap .FRM creation and call
|
||||
to ha_create_table() in critical section protected by LOCK_open in order
|
||||
to provide minimal atomicity against operations which disregard name-locks,
|
||||
like I_S implementation, for example. This is a temporary and should not
|
||||
be copied. Instead we should fix our code to always honor name-locks.
|
||||
|
||||
Also some engines (e.g. NDB cluster) require that LOCK_open should be held
|
||||
during the call to ha_create_table(). See bug #28614 for more info.
|
||||
*/
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE)))
|
||||
{
|
||||
if (my_errno == ENOENT)
|
||||
my_error(ER_BAD_DB_ERROR,MYF(0),db);
|
||||
else
|
||||
my_error(ER_CANT_CREATE_FILE,MYF(0),dst_path,my_errno);
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -4842,10 +4795,12 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
strmov(src_path, tmp_path);
|
||||
my_copy(src_path, dst_path, MYF(MY_DONT_OVERWRITE_FILE));
|
||||
#endif
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_like_before_ha_create", my_sleep(6000000););
|
||||
|
||||
dst_path[dst_path_length - reg_ext_length]= '\0'; // Remove .frm
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
err= ha_create_table(thd, dst_path, db, table_name, create_info, 1);
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
||||
{
|
||||
if (err || !open_temporary_table(thd, dst_path, db, table_name, 1))
|
||||
@ -4862,6 +4817,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
goto err; /* purecov: inspected */
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_like_before_binlogging", my_sleep(6000000););
|
||||
|
||||
/*
|
||||
We have to write the query before we unlock the tables.
|
||||
*/
|
||||
@ -4881,14 +4838,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
|
||||
3 temporary normal Nothing
|
||||
4 temporary temporary Nothing
|
||||
==== ========= ========= ==============================
|
||||
|
||||
The variable 'tmp_table' below is used to see if the source
|
||||
table is a temporary table: if it is set, then the source table
|
||||
was a temporary table and we can take apropriate actions.
|
||||
*/
|
||||
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
if (tmp_table) // Case 2
|
||||
if (src_table->table->s->tmp_table) // Case 2
|
||||
{
|
||||
char buf[2048];
|
||||
String query(buf, sizeof(buf), system_charset_info);
|
||||
|
@ -1579,7 +1579,6 @@ create:
|
||||
lex->create_info.default_table_charset= NULL;
|
||||
lex->name.str= 0;
|
||||
lex->name.length= 0;
|
||||
lex->like_name= 0;
|
||||
}
|
||||
create2
|
||||
{
|
||||
@ -3603,27 +3602,15 @@ create2:
|
||||
create3 {}
|
||||
| LIKE table_ident
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
if (!(lex->like_name= $2))
|
||||
Lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
|
||||
if (!Lex->select_lex.add_table_to_list(YYTHD, $2, NULL, 0, TL_READ))
|
||||
MYSQL_YYABORT;
|
||||
if ($2->db.str == NULL &&
|
||||
thd->copy_db_to(&($2->db.str), &($2->db.length)))
|
||||
{
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
}
|
||||
| '(' LIKE table_ident ')'
|
||||
{
|
||||
THD *thd= YYTHD;
|
||||
LEX *lex= thd->lex;
|
||||
if (!(lex->like_name= $3))
|
||||
Lex->create_info.options|= HA_LEX_CREATE_TABLE_LIKE;
|
||||
if (!Lex->select_lex.add_table_to_list(YYTHD, $3, NULL, 0, TL_READ))
|
||||
MYSQL_YYABORT;
|
||||
if ($3->db.str == NULL &&
|
||||
thd->copy_db_to(&($3->db.str), &($3->db.length)))
|
||||
{
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
@ -5112,7 +5099,6 @@ alter:
|
||||
lex->key_list.empty();
|
||||
lex->col_list.empty();
|
||||
lex->select_lex.init_order();
|
||||
lex->like_name= 0;
|
||||
lex->select_lex.db=
|
||||
((TABLE_LIST*) lex->select_lex.table_list.first)->db;
|
||||
bzero((char*) &lex->create_info,sizeof(lex->create_info));
|
||||
|
Loading…
x
Reference in New Issue
Block a user