mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Don't allow BACKUP TABLE to overwrite files
Fixed memory leak when replication restarts in debug mode
This commit is contained in:
@ -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()
|
|||||||
$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 ()
|
|||||||
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
|
||||||
|
@ -1,10 +1,13 @@
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
||||||
|
5
mysql-test/t/backup-master.sh
Executable file
5
mysql-test/t/backup-master.sh
Executable file
@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
if [ "$MYSQL_TEST_DIR" ]
|
||||||
|
then
|
||||||
|
rm -f $MYSQL_TEST_DIR/var/tmp/*.frm $MYSQL_TEST_DIR/var/tmp/*.MY?
|
||||||
|
fi
|
@ -1,15 +1,23 @@
|
|||||||
|
#
|
||||||
|
# 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);
|
|||||||
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 {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Ordinary ownership and accesstimes are copied from 'from-file'
|
int my_copy(const char *from, const char *to, myf MyFlags)
|
||||||
if MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then
|
|
||||||
the modes of to-file isn't changed
|
NOTES
|
||||||
Dont set MY_FNABP or MY_NABP bits on when calling this function !
|
Ordinary ownership and accesstimes are copied from 'from-file'
|
||||||
*/
|
If MyFlags & MY_HOLD_ORIGINAL_MODES is set and to-file exists then
|
||||||
|
the modes of to-file isn't changed
|
||||||
|
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)
|
|||||||
}
|
}
|
||||||
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;
|
||||||
|
|
||||||
|
@ -419,38 +419,38 @@ int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
|
|||||||
const char* errmsg = "";
|
const char* errmsg = "";
|
||||||
|
|
||||||
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(¶m);
|
myisamchk_init(¶m);
|
||||||
@ -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(¶m,errmsg, errno );
|
mi_check_print_error(¶m, errmsg, my_errno);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
34
sql/slave.cc
34
sql/slave.cc
@ -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,20 +1289,14 @@ 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)
|
|
||||||
|
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);
|
||||||
sql_print_error("Server id not set, will not start slave");
|
my_thread_end();
|
||||||
pthread_exit((void*)1);
|
pthread_exit((void*)1); // safety just in case
|
||||||
}
|
}
|
||||||
|
|
||||||
if(slave_running)
|
|
||||||
{
|
|
||||||
pthread_cond_broadcast(&COND_slave_start);
|
|
||||||
pthread_mutex_unlock(&LOCK_slave);
|
|
||||||
pthread_exit((void*)1); // safety just in case
|
|
||||||
}
|
|
||||||
slave_running = 1;
|
slave_running = 1;
|
||||||
abort_slave = 0;
|
abort_slave = 0;
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
@ -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",
|
|||||||
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
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user