Commit 075a75af authored by kostja@vajra.(none)'s avatar kostja@vajra.(none)

Merge bk-internal.mysql.com:/home/bk/mysql-5.0

into  vajra.(none):/opt/local/work/mysql-5.0-runtime
parents 43b2dc18 c07b3670
......@@ -380,3 +380,27 @@ drop function f2;
drop table t2;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM `a@`@localhost;
drop user `a@`@localhost;
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;
End of 5.0 tests
......@@ -1030,7 +1030,7 @@ select bug12329();
bug12329()
101
execute stmt1;
ERROR HY000: Table 't2' was not locked with LOCK TABLES
ERROR 42S02: Table 'test.t2' doesn't exist
deallocate prepare stmt1;
drop function bug12329;
drop table t1, t2;
......@@ -1152,12 +1152,12 @@ create trigger t1_ai after insert on t1 for each row insert into t2 values (new.
create view v1 as select * from t1;
drop table t2;
insert into v1 values (1);
ERROR HY000: Table 't2' was not locked with LOCK TABLES
ERROR 42S02: Table 'test.t2' doesn't exist
drop trigger t1_ai;
create function bug11555_1() returns int return (select max(i) from t2);
create trigger t1_ai after insert on t1 for each row set @a:=bug11555_1();
insert into v1 values (2);
ERROR HY000: Table 't2' was not locked with LOCK TABLES
ERROR 42S02: Table 'test.t2' doesn't exist
drop function bug11555_1;
drop table t1;
drop view v1;
......
......@@ -254,4 +254,17 @@ execute stmt;
deallocate prepare stmt;
drop function bug19634;
drop table t1, t2, t3;
drop table if exists bug_27907_logs;
drop table if exists bug_27907_t1;
create table bug_27907_logs (a int);
create table bug_27907_t1 (a int);
create trigger bug_27907_t1_ai after insert on bug_27907_t1
for each row
begin
insert into bug_27907_logs (a) values (1);
end|
drop table bug_27907_logs;
insert into bug_27907_t1(a) values (1);
ERROR 42S02: Table 'test.bug_27907_logs' doesn't exist
drop table bug_27907_t1;
End of 5.0 tests
......@@ -820,9 +820,9 @@ call p1();
drop trigger t1_bi;
create trigger t1_bi after insert on t1 for each row insert into t3 values (new.id);
execute stmt1;
ERROR HY000: Table 't3' was not locked with LOCK TABLES
ERROR 42S02: Table 'test.t3' doesn't exist
call p1();
ERROR HY000: Table 't3' was not locked with LOCK TABLES
ERROR 42S02: Table 'test.t3' doesn't exist
deallocate prepare stmt1;
drop procedure p1;
drop table t1, t2, t3;
......
......@@ -513,3 +513,47 @@ disconnect bug13310;
connection default;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM `a@`@localhost;
drop user `a@`@localhost;
#
# 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;
--echo End of 5.0 tests
......@@ -1454,7 +1454,7 @@ select bug12329();
# Until we implement proper mechanism for invalidation of PS/SP when table
# or SP's are changed the following statement will fail with 'Table ... was
# not locked' error (this mechanism should be based on the new TDC).
--error 1100
--error ER_NO_SUCH_TABLE
execute stmt1;
deallocate prepare stmt1;
drop function bug12329;
......@@ -1639,13 +1639,13 @@ create trigger t1_ai after insert on t1 for each row insert into t2 values (new.
create view v1 as select * from t1;
drop table t2;
# Limitation, the desired error is ER_VIEW_INVALID
--error ER_TABLE_NOT_LOCKED
--error ER_NO_SUCH_TABLE
insert into v1 values (1);
drop trigger t1_ai;
create function bug11555_1() returns int return (select max(i) from t2);
create trigger t1_ai after insert on t1 for each row set @a:=bug11555_1();
# Limitation, the desired error is ER_VIEW_INVALID
--error ER_TABLE_NOT_LOCKED
--error ER_NO_SUCH_TABLE
insert into v1 values (2);
drop function bug11555_1;
drop table t1;
......
......@@ -301,5 +301,36 @@ deallocate prepare stmt;
drop function bug19634;
drop table t1, t2, t3;
#
# Bug #27907 Misleading error message when opening/locking tables
#
--disable_warnings
drop table if exists bug_27907_logs;
drop table if exists bug_27907_t1;
--enable_warnings
create table bug_27907_logs (a int);
create table bug_27907_t1 (a int);
delimiter |;
create trigger bug_27907_t1_ai after insert on bug_27907_t1
for each row
begin
insert into bug_27907_logs (a) values (1);
end|
delimiter ;|
drop table bug_27907_logs;
#
# was failing before with error ER_NOT_LOCKED
#
--error ER_NO_SUCH_TABLE
insert into bug_27907_t1(a) values (1);
drop table bug_27907_t1;
--echo End of 5.0 tests
......@@ -1000,9 +1000,9 @@ create trigger t1_bi after insert on t1 for each row insert into t3 values (new.
# Until we implement proper mechanism for invalidation of PS/SP when table
# or SP's are changed these two statements will fail with 'Table ... was
# not locked' error (this mechanism should be based on the new TDC).
--error 1100 #ER_TABLE_NOT_LOCKED
--error ER_NO_SUCH_TABLE
execute stmt1;
--error 1100 #ER_TABLE_NOT_LOCKED
--error ER_NO_SUCH_TABLE
call p1();
deallocate prepare stmt1;
drop procedure p1;
......
......@@ -162,6 +162,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
......
......@@ -816,9 +816,8 @@ bool mysql_alter_table(THD *thd, char *new_db, char *new_name,
Alter_info *alter_info,
uint order_num, ORDER *order, bool ignore);
bool mysql_recreate_table(THD *thd, TABLE_LIST *table_list);
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(enum db_type base,
const char *old_db,
const char * old_name,
......
......@@ -1669,10 +1669,17 @@ TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT *mem_root,
VOID(pthread_mutex_unlock(&LOCK_open));
}
}
if ((thd->locked_tables) && (thd->locked_tables->lock_count > 0))
my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
else
/*
No table in the locked tables list. In case of explicit LOCK TABLES
this can happen if a user did not include the able into the list.
In case of pre-locked mode locked tables list is generated automatically,
so we may only end up here if the table did not exist when
locked tables list was created.
*/
if (thd->prelocked_mode == PRELOCKED)
my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
else
my_error(ER_TABLE_NOT_LOCKED, MYF(0), alias);
DBUG_RETURN(0);
}
......
......@@ -75,6 +75,7 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables);
static void remove_escape(char *name);
static bool append_file_to_dir(THD *thd, const char **filename_ptr,
const char *table_name);
static bool check_show_create_table_access(THD *thd, TABLE_LIST *table);
const char *any_db="*any*"; // Special symbol for check_access
......@@ -3080,9 +3081,9 @@ mysql_execute_command(THD *thd)
else
{
/* regular create */
if (lex->name)
res= mysql_create_like_table(thd, create_table, &create_info,
(Table_ident *)lex->name);
if (lex->create_info.options & HA_LEX_CREATE_TABLE_LIKE)
res= mysql_create_like_table(thd, create_table, select_tables,
&create_info);
else
{
res= mysql_create_table(thd, create_table->db,
......@@ -3319,11 +3320,7 @@ mysql_execute_command(THD *thd)
first_table->skip_temporary= 1;
if (check_db_used(thd, all_tables) ||
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))
check_show_create_table_access(thd, first_table))
goto error;
res= mysqld_show_create(thd, first_table);
break;
......@@ -7519,6 +7516,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
......@@ -7583,6 +7599,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:
......
......@@ -2718,7 +2718,8 @@ 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
......@@ -2727,61 +2728,52 @@ bool mysql_preload_keys(THD* thd, TABLE_LIST* tables)
TRUE error
*/
bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
HA_CREATE_INFO *create_info,
Table_ident *table_ident)
bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST *src_table,
HA_CREATE_INFO *create_info)
{
TABLE **tmp_table;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
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;
db_type not_used;
TABLE_LIST src_tables_list;
DBUG_ENTER("mysql_create_like_table");
DBUG_ASSERT(table_ident->db.str); /* Must be set in the parser */
src_db= table_ident->db.str;
/*
Validate the source table
By taking name-lock on the source table and holding LOCK_open mutex we
ensure that no concurrent DDL operation will mess with this table. Note
that holding only name-lock is not enough for this, because it won't block
other DDL statements that only take name-locks on the table and don't
open it (simple name-locks are not exclusive between each other).
Unfortunately, simply opening this table is not enough for our purproses,
since in 5.0 ALTER TABLE may change .FRM files on disk even if there are
connections that still have old version of table open. This 'optimization'
was removed in 5.1 so there we open the source table instead of taking
name-lock on it.
We also have to acquire LOCK_open to make copying of .frm file, call to
ha_create_table() and binlogging atomic against concurrent DML and DDL
operations on the target table.
*/
if (table_ident->table.length > NAME_LEN ||
(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(src_db))
{
my_error(ER_WRONG_DB_NAME, MYF(0), src_db ? src_db : "NULL");
DBUG_RETURN(-1);
}
bzero((gptr)&src_tables_list, sizeof(src_tables_list));
src_tables_list.db= src_db;
src_tables_list.table_name= src_table;
if (lock_and_wait_for_table_name(thd, &src_tables_list))
if (lock_and_wait_for_table_name(thd, src_table))
goto err;
if ((tmp_table= find_temporary_table(thd, src_db, src_table)))
pthread_mutex_lock(&LOCK_open);
if ((tmp_table= find_temporary_table(thd, src_table->db,
src_table->table_name)))
strxmov(src_path, (*tmp_table)->s->path, reg_ext, NullS);
else
{
strxmov(src_path, mysql_data_home, "/", src_db, "/", src_table,
reg_ext, NullS);
strxmov(src_path, mysql_data_home, "/", src_table->db, "/",
src_table->table_name, reg_ext, NullS);
/* Resolve symlinks (for windows) */
fn_format(src_path, src_path, "", "", MYF(MY_UNPACK_FILENAME));
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);
my_error(ER_BAD_TABLE_ERROR, MYF(0), src_table->table_name);
goto err;
}
}
......@@ -2791,10 +2783,13 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
*/
if (mysql_frm_type(thd, src_path, &not_used) != FRMTYPE_TABLE)
{
my_error(ER_WRONG_OBJECT, MYF(0), src_db, src_table, "BASE TABLE");
my_error(ER_WRONG_OBJECT, MYF(0), src_table->db, src_table->table_name,
"BASE TABLE");
goto err;
}
DBUG_EXECUTE_IF("sleep_create_like_before_check_if_exists", my_sleep(6000000););
/*
Validate the destination table
......@@ -2810,27 +2805,22 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
}
else
{
bool exists;
strxmov(dst_path, mysql_data_home, "/", db, "/", table_name,
reg_ext, NullS);
fn_format(dst_path, dst_path, "", "", MYF(MY_UNPACK_FILENAME));
/*
Note that this critical section should actually cover most
of mysql_create_like_table() function. See bugs #18950 and
#23667 for more information.
Also note that starting from 5.1 we obtain name-lock on
target table instead of inspecting table cache for presence
Note that starting from 5.1 we obtain name-lock on target
table instead of inspecting table cache for presence
of open placeholders (see comment in mysql_create_table()).
*/
pthread_mutex_lock(&LOCK_open);
exists= (table_cache_has_open_placeholder(thd, db, table_name) ||
!access(dst_path, F_OK));
pthread_mutex_unlock(&LOCK_open);
if (exists)
if (table_cache_has_open_placeholder(thd, db, table_name) ||
!access(dst_path, F_OK))
goto table_exists;
}
DBUG_EXECUTE_IF("sleep_create_like_before_copy", my_sleep(6000000););
/*
Create a new table by copying from source table
*/
......@@ -2843,6 +2833,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
goto err;
}
DBUG_EXECUTE_IF("sleep_create_like_before_ha_create", my_sleep(6000000););
/*
As mysql_truncate don't work on a new table at this stage of
creation, instead create the table directly (for both normal
......@@ -2867,6 +2859,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););
// Must be written before unlock
if (mysql_bin_log.is_open())
{
......@@ -2891,8 +2885,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), table_name);
err:
pthread_mutex_lock(&LOCK_open);
unlock_table_name(thd, &src_tables_list);
unlock_table_name(thd, src_table);
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(res);
}
......
......@@ -1483,7 +1483,6 @@ create:
lex->create_info.options=$2 | $4;
lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type;
lex->create_info.default_table_charset= NULL;
lex->name=0;
}
create2
{ Lex->current_select= &Lex->select_lex; }
......@@ -2763,27 +2762,15 @@ create2:
| opt_create_table_options create3 {}
| LIKE table_ident
{
LEX *lex=Lex;
THD *thd= lex->thd;
if (!(lex->name= (char *)$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 ')'
{
LEX *lex=Lex;
THD *thd= lex->thd;
if (!(lex->name= (char *)$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;
}
}
;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment