Commit c43b3af7 authored by monty@narttu.mysql.fi's avatar monty@narttu.mysql.fi

Don't allow BACKUP TABLE to overwrite files

Fixed memory leak when replication restarts in debug mode
parent 8c51eb2c
...@@ -73,6 +73,7 @@ extern int NEAR my_errno; /* Last error in mysys */ ...@@ -73,6 +73,7 @@ extern int NEAR my_errno; /* Last error in mysys */
#define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */ #define MY_FREE_ON_ERROR 128 /* my_realloc() ; Free old ptr on error */
#define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */ #define MY_HOLD_ON_ERROR 256 /* my_realloc() ; Return old ptr on error */
#define MY_THREADSAFE 128 /* pread/pwrite: Don't allow interrupts */ #define MY_THREADSAFE 128 /* pread/pwrite: Don't allow interrupts */
#define MY_DONT_OVERWRITE_FILE 1024 /* my_copy; Don't overwrite file */
#define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */ #define MY_CHECK_ERROR 1 /* Params to my_end; Check open-close */
#define MY_GIVE_INFO 2 /* Give time info about process*/ #define MY_GIVE_INFO 2 /* Give time info about process*/
......
...@@ -604,7 +604,7 @@ start_slave() ...@@ -604,7 +604,7 @@ start_slave()
$EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT" $EXTRA_SLAVE_OPT $EXTRA_SLAVE_MYSQLD_OPT"
if [ x$DO_DDD = x1 ] if [ x$DO_DDD = x1 ]
then then
$ECHO "set args $master_args" > $GDB_SLAVE_INIT $ECHO "set args $slave_args" > $GDB_SLAVE_INIT
ddd --debugger "gdb -x $GDB_SLAVE_INIT" $SLAVE_MYSQLD & ddd --debugger "gdb -x $GDB_SLAVE_INIT" $SLAVE_MYSQLD &
prompt_user "Hit enter to continue after you've started the slave" prompt_user "Hit enter to continue after you've started the slave"
elif [ x$DO_GDB = x1 ] elif [ x$DO_GDB = x1 ]
...@@ -746,7 +746,7 @@ run_testcase () ...@@ -746,7 +746,7 @@ run_testcase ()
stop_master stop_master
start_master start_master
else else
if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] ; if [ ! -z "$EXTRA_MASTER_OPT" ] || [ x$MASTER_RUNNING != x1 ] || [ -f $master_init_script ]
then then
EXTRA_MASTER_OPT="" EXTRA_MASTER_OPT=""
stop_master stop_master
......
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 backup error Failed copying .frm file: errno = X test.t4 backup error Failed copying .frm file (errno: X)
test.t1 backup status Operation failed test.t4 backup status Operation failed
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 backup status OK test.t4 backup status OK
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 restore status OK test.t4 backup error Failed copying .frm file (errno: X)
test.t4 backup status Operation failed
Table Op Msg_type Msg_text
test.t4 restore status OK
count(*) count(*)
0 0
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
...@@ -18,7 +21,6 @@ n ...@@ -18,7 +21,6 @@ n
45 45
67 67
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 backup status OK
test.t2 backup status OK test.t2 backup status OK
test.t3 backup status OK test.t3 backup status OK
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
...@@ -40,4 +42,4 @@ k ...@@ -40,4 +42,4 @@ k
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 restore status OK test.t1 restore status OK
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 backup status OK test.t5 backup status OK
#!/bin/sh
if [ "$MYSQL_TEST_DIR" ]
then
rm -f $MYSQL_TEST_DIR/var/tmp/*.frm $MYSQL_TEST_DIR/var/tmp/*.MY?
fi
#
# This test is a bit tricky as we can't use backup table to overwrite an old
# table
#
connect (con1,localhost,root,,); connect (con1,localhost,root,,);
connect (con2,localhost,root,,); connect (con2,localhost,root,,);
connection con1; connection con1;
set SQL_LOG_BIN=0; set SQL_LOG_BIN=0;
drop table if exists t1; drop table if exists t1,t2,t3,t4;
create table t4(n int);
--replace_result "errno: 2" "errno: X" "errno: 22" "errno: X" "errno: 23" "errno: X"
backup table t4 to '../bogus';
backup table t4 to '../tmp';
--replace_result "errno: 17" "errno: X"
backup table t4 to '../tmp';
drop table t4;
restore table t4 from '../tmp';
select count(*) from t4;
create table t1(n int); create table t1(n int);
--replace_result "errno = 2" "errno = X" "errno = 22" "errno = X" "errno = 23" "errno = X"
backup table t1 to '../bogus';
backup table t1 to '../tmp';
drop table t1;
restore table t1 from '../tmp';
select count(*) from t1;
insert into t1 values (23),(45),(67); insert into t1 values (23),(45),(67);
backup table t1 to '../tmp'; backup table t1 to '../tmp';
drop table t1; drop table t1;
...@@ -20,29 +28,24 @@ create table t2(m int not null primary key); ...@@ -20,29 +28,24 @@ create table t2(m int not null primary key);
create table t3(k int not null primary key); create table t3(k int not null primary key);
insert into t2 values (123),(145),(167); insert into t2 values (123),(145),(167);
insert into t3 values (223),(245),(267); insert into t3 values (223),(245),(267);
backup table t1,t2,t3 to '../tmp'; backup table t2,t3 to '../tmp';
drop table t1,t2,t3; drop table t1,t2,t3;
restore table t1,t2,t3 from '../tmp'; restore table t1,t2,t3 from '../tmp';
select n from t1; select n from t1;
select m from t2; select m from t2;
select k from t3; select k from t3;
drop table t1,t2,t3; drop table t1,t2,t3,t4;
restore table t1 from '../tmp'; restore table t1 from '../tmp';
connection con2; connection con2;
rename table t1 to t5;
--send --send
lock tables t1 write; lock tables t5 write;
connection con1; connection con1;
--send --send
backup table t1 to '../tmp'; backup table t5 to '../tmp';
connection con2; connection con2;
reap; reap;
unlock tables; unlock tables;
connection con1; connection con1;
reap; reap;
drop table t1; drop table t5;
...@@ -32,17 +32,29 @@ struct utimbuf { ...@@ -32,17 +32,29 @@ struct utimbuf {
#endif #endif
/* /*
int my_copy(const char *from, const char *to, myf MyFlags)
NOTES
Ordinary ownership and accesstimes are copied from 'from-file' Ordinary ownership and accesstimes are copied from 'from-file'
if MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then If MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then
the modes of to-file isn't changed the modes of to-file isn't changed
Dont set MY_FNABP or MY_NABP bits on when calling this function ! If MyFlags & MY_DONT_OVERWRITE_FILE is set, we will give an error
*/ if the file existed.
WARNING
Don't set MY_FNABP or MY_NABP bits on when calling this function !
RETURN
0 ok
# Error
*/
int my_copy(const char *from, const char *to, myf MyFlags) int my_copy(const char *from, const char *to, myf MyFlags)
{ {
uint Count; uint Count;
int new_file_stat; int new_file_stat, create_flag;
File from_file,to_file; File from_file,to_file;
char buff[IO_SIZE]; char buff[IO_SIZE];
struct stat stat_buff,new_stat_buff; struct stat stat_buff,new_stat_buff;
...@@ -63,8 +75,10 @@ int my_copy(const char *from, const char *to, myf MyFlags) ...@@ -63,8 +75,10 @@ int my_copy(const char *from, const char *to, myf MyFlags)
} }
if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat) if (MyFlags & MY_HOLD_ORIGINAL_MODES && !new_file_stat)
stat_buff=new_stat_buff; stat_buff=new_stat_buff;
create_flag= (MyFlags & MY_DONT_OVERWRITE_FILE) ? O_EXCL : O_TRUNC;
if ((to_file= my_create(to,(int) stat_buff.st_mode, if ((to_file= my_create(to,(int) stat_buff.st_mode,
O_WRONLY | O_TRUNC | O_BINARY | O_SHARE, O_WRONLY | create_flag | O_BINARY | O_SHARE,
MyFlags)) < 0) MyFlags)) < 0)
goto err; goto err;
......
...@@ -420,37 +420,37 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -420,37 +420,37 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
if (!fn_format(dst_path, table_name, backup_dir, reg_ext, 4 + 64)) if (!fn_format(dst_path, table_name, backup_dir, reg_ext, 4 + 64))
{ {
errmsg = "Failed in fn_format() for .frm file: errno = %d"; errmsg = "Failed in fn_format() for .frm file (errno: %d)";
error = HA_ADMIN_INVALID; error = HA_ADMIN_INVALID;
goto err; goto err;
} }
if (my_copy(fn_format(src_path, table->path,"", reg_ext, 4), if (my_copy(fn_format(src_path, table->path,"", reg_ext, 4),
dst_path, dst_path,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES ))) MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
{ {
error = HA_ADMIN_FAILED; error = HA_ADMIN_FAILED;
errmsg = "Failed copying .frm file: errno = %d"; errmsg = "Failed copying .frm file (errno: %d)";
goto err; goto err;
} }
if (!fn_format(dst_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64)) if (!fn_format(dst_path, table_name, backup_dir, MI_NAME_DEXT, 4 + 64))
{ {
errmsg = "Failed in fn_format() for .MYD file: errno = %d"; errmsg = "Failed in fn_format() for .MYD file (errno: %d)";
error = HA_ADMIN_INVALID; error = HA_ADMIN_INVALID;
goto err; goto err;
} }
if (my_copy(fn_format(src_path, table->path,"", MI_NAME_DEXT, 4), if (my_copy(fn_format(src_path, table->path,"", MI_NAME_DEXT, 4),
dst_path, dst_path,
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) ) MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_DONT_OVERWRITE_FILE)))
{ {
errmsg = "Failed copying .MYD file: errno = %d"; errmsg = "Failed copying .MYD file (errno: %d)";
error= HA_ADMIN_FAILED; error= HA_ADMIN_FAILED;
goto err; goto err;
} }
return HA_ADMIN_OK; return HA_ADMIN_OK;
err: err:
{ {
MI_CHECK param; MI_CHECK param;
myisamchk_init(&param); myisamchk_init(&param);
...@@ -459,7 +459,7 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt) ...@@ -459,7 +459,7 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
param.db_name = table->table_cache_key; param.db_name = table->table_cache_key;
param.table_name = table->table_name; param.table_name = table->table_name;
param.testflag = 0; param.testflag = 0;
mi_check_print_error(&param,errmsg, errno ); mi_check_print_error(&param, errmsg, my_errno);
return error; return error;
} }
} }
......
...@@ -1270,6 +1270,17 @@ This may also be a network problem, or just a bug in the master or slave code.\ ...@@ -1270,6 +1270,17 @@ This may also be a network problem, or just a bug in the master or slave code.\
pthread_handler_decl(handle_slave,arg __attribute__((unused))) pthread_handler_decl(handle_slave,arg __attribute__((unused)))
{ {
// needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
my_thread_init();
if (!server_id)
{
pthread_cond_broadcast(&COND_slave_start);
sql_print_error("Server id not set, will not start slave");
my_thread_end();
pthread_exit((void*)1);
}
DBUG_ENTER("handle_slave");
#ifndef DBUG_OFF #ifndef DBUG_OFF
slave_begin: slave_begin:
#endif #endif
...@@ -1278,18 +1289,12 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1278,18 +1289,12 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
char llbuff[22]; char llbuff[22];
pthread_mutex_lock(&LOCK_slave); pthread_mutex_lock(&LOCK_slave);
if (!server_id)
{
pthread_cond_broadcast(&COND_slave_start);
pthread_mutex_unlock(&LOCK_slave);
sql_print_error("Server id not set, will not start slave");
pthread_exit((void*)1);
}
if(slave_running) if (slave_running)
{ {
pthread_cond_broadcast(&COND_slave_start); pthread_cond_broadcast(&COND_slave_start);
pthread_mutex_unlock(&LOCK_slave); pthread_mutex_unlock(&LOCK_slave);
my_thread_end();
pthread_exit((void*)1); // safety just in case pthread_exit((void*)1); // safety just in case
} }
slave_running = 1; slave_running = 1;
...@@ -1304,11 +1309,8 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1304,11 +1309,8 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
bool retried_once = 0; bool retried_once = 0;
ulonglong last_failed_pos = 0; ulonglong last_failed_pos = 0;
// needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
my_thread_init();
slave_thd = thd = new THD; // note that contructor of THD uses DBUG_ ! slave_thd = thd = new THD; // note that contructor of THD uses DBUG_ !
thd->set_time(); thd->set_time();
DBUG_ENTER("handle_slave");
pthread_detach_this_thread(); pthread_detach_this_thread();
if (init_slave_thread(thd) || init_master_info(&glob_mi)) if (init_slave_thread(thd) || init_master_info(&glob_mi))
...@@ -1518,18 +1520,18 @@ position %s", ...@@ -1518,18 +1520,18 @@ position %s",
abort_slave = 0; abort_slave = 0;
save_temporary_tables = thd->temporary_tables; save_temporary_tables = thd->temporary_tables;
thd->temporary_tables = 0; // remove tempation from destructor to close them thd->temporary_tables = 0; // remove tempation from destructor to close them
pthread_cond_broadcast(&COND_slave_stopped); // tell the world we are done
pthread_mutex_unlock(&LOCK_slave);
net_end(&thd->net); // destructor will not free it, because we are weird net_end(&thd->net); // destructor will not free it, because we are weird
slave_thd = 0; slave_thd = 0;
(void) pthread_mutex_lock(&LOCK_thread_count); (void) pthread_mutex_lock(&LOCK_thread_count);
delete thd; delete thd;
(void) pthread_mutex_unlock(&LOCK_thread_count); (void) pthread_mutex_unlock(&LOCK_thread_count);
my_thread_end(); pthread_mutex_unlock(&LOCK_slave);
pthread_cond_broadcast(&COND_slave_stopped); // tell the world we are done
#ifndef DBUG_OFF #ifndef DBUG_OFF
if(abort_slave_event_count && !events_till_abort) if(abort_slave_event_count && !events_till_abort)
goto slave_begin; goto slave_begin;
#endif #endif
my_thread_end();
pthread_exit(0); pthread_exit(0);
DBUG_RETURN(0); // Can't return anything here DBUG_RETURN(0); // Can't return anything here
} }
......
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