BACKUP TABLE TO 'directory'

RESTORE TABLE FROM 'directory'
log on slave when it connects to the master
parent 243579e8
......@@ -46,7 +46,7 @@ enum enum_server_command {COM_SLEEP,COM_QUIT,COM_INIT_DB,COM_QUERY,
COM_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL,
COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT,
COM_CHANGE_USER, COM_BINLOG_DUMP,
COM_TABLE_DUMP};
COM_TABLE_DUMP, COM_CONNECT_OUT};
#define NOT_NULL_FLAG 1 /* Field can't be NULL */
#define PRI_KEY_FLAG 2 /* Field is part of a primary key */
......
......@@ -328,6 +328,86 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
}
int ha_myisam::restore(THD* thd, HA_CHECK_OPT *check_opt)
{
HA_CHECK_OPT tmp_check_opt;
char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
int backup_dir_len = strlen(backup_dir);
char* table_name = table->real_name;
int table_name_len = strlen(table_name);
if(backup_dir_len + table_name_len + 4 >= FN_REFLEN)
return HA_ADMIN_INVALID;
memcpy(src_path, backup_dir, backup_dir_len);
char* p = src_path + backup_dir_len;
*p++ = '/';
memcpy(p, table_name, table_name_len);
p += table_name_len;
*p = 0;
fn_format(src_path, src_path, "", MI_NAME_DEXT, 4);
MY_STAT stat_area;
int error = 0;
char* errmsg = "";
if(my_copy(src_path, fn_format(dst_path, table->path, "",
MI_NAME_DEXT, 4), MYF(MY_WME)))
{
error = HA_ADMIN_FAILED;
errmsg = "failed in my_copy( Error %d)";
goto err;
}
tmp_check_opt.init();
tmp_check_opt.quick = 1;
return repair(thd, &tmp_check_opt);
err:
{
MI_CHECK param;
myisamchk_init(&param);
param.thd = thd;
param.op_name = (char*)"restore";
param.table_name = table->table_name;
param.testflag = 0;
mi_check_print_error(&param,errmsg, errno );
return error;
}
}
int ha_myisam::backup(THD* thd, HA_CHECK_OPT *check_opt)
{
char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
int backup_dir_len = strlen(backup_dir);
char* table_name = table->real_name;
int table_name_len = strlen(table_name);
if(backup_dir_len + table_name_len + 4 >= FN_REFLEN)
return HA_ADMIN_INVALID;
memcpy(dst_path, backup_dir, backup_dir_len);
char* p = dst_path + backup_dir_len;
*p++ = '/';
memcpy(p, table_name, table_name_len);
p += table_name_len;
*p = 0;
if(my_copy(fn_format(src_path, table->path,"", reg_ext, 4),
fn_format(dst_path, dst_path, "", reg_ext, 4),
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )))
{
return HA_ADMIN_FAILED;
}
*p = 0;
*(fn_ext(src_path)) = 0;
if(my_copy(fn_format(src_path, src_path,"", MI_NAME_DEXT, 4),
fn_format(dst_path, dst_path, "", MI_NAME_DEXT, 4),
MYF(MY_WME | MY_HOLD_ORIGINAL_MODES )) )
return HA_ADMIN_FAILED;
return HA_ADMIN_OK;
}
int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
{
......
......@@ -96,6 +96,8 @@ class ha_myisam: public handler
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int repair(THD* thd, HA_CHECK_OPT* check_opt);
int optimize(THD* thd, HA_CHECK_OPT* check_opt);
int restore(THD* thd, HA_CHECK_OPT* check_opt);
int backup(THD* thd, HA_CHECK_OPT* check_opt);
int dump(THD* thd, int fd);
int net_read_dump(NET* net);
};
......@@ -337,6 +337,16 @@ int handler::check(THD* thd, HA_CHECK_OPT* check_opt)
return HA_ADMIN_NOT_IMPLEMENTED;
}
int handler::backup(THD* thd, HA_CHECK_OPT* check_opt)
{
return HA_ADMIN_NOT_IMPLEMENTED;
}
int handler::restore(THD* thd, HA_CHECK_OPT* check_opt)
{
return HA_ADMIN_NOT_IMPLEMENTED;
}
int handler::repair(THD* thd, HA_CHECK_OPT* check_opt)
{
return HA_ADMIN_NOT_IMPLEMENTED;
......
......@@ -33,6 +33,7 @@
#define HA_ADMIN_FAILED -2
#define HA_ADMIN_CORRUPT -3
#define HA_ADMIN_INTERNAL_ERROR -4
#define HA_ADMIN_INVALID -5
/* Bits in bas_flag to show what database can do */
......@@ -248,6 +249,8 @@ public:
virtual int repair(THD* thd, HA_CHECK_OPT* check_opt);
virtual int optimize(THD* thd,HA_CHECK_OPT* check_opt);
virtual int analyze(THD* thd, HA_CHECK_OPT* check_opt);
virtual int backup(THD* thd, HA_CHECK_OPT* check_opt);
virtual int restore(THD* thd, HA_CHECK_OPT* check_opt);
virtual int dump(THD* thd, int fd = -1) { return ER_DUMP_NOT_IMPLEMENTED; }
virtual void deactivate_non_unique_index(ha_rows rows) {}
virtual bool activate_all_index(THD *thd) {return 0;}
......
......@@ -62,6 +62,7 @@ static SYMBOL symbols[] = {
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
{ "AUTOCOMMIT", SYM(AUTOCOMMIT),0,0},
{ "BACKUP", SYM(BACKUP_SYM),0,0},
{ "BEGIN", SYM(BEGIN_SYM),0,0},
{ "BERKELEYDB", SYM(BERKELEY_DB_SYM),0,0},
{ "BDB", SYM(BERKELEY_DB_SYM),0,0},
......@@ -247,6 +248,7 @@ static SYMBOL symbols[] = {
{ "RENAME", SYM(RENAME),0,0},
{ "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0},
{ "RETURNS", SYM(UDF_RETURNS_SYM),0,0},
{ "REVOKE", SYM(REVOKE),0,0},
......
......@@ -239,6 +239,13 @@ void close_connection(NET *net,uint errcode=0,bool lock=1);
bool check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0,
bool no_grant=0);
int generate_table(THD *thd, TABLE_LIST *table_list,
TABLE *locked_table);
int mysql_backup_table(THD* thd, TABLE_LIST* table_list);
int mysql_restore_table(THD* thd, TABLE_LIST* table_list);
int mysql_check_table(THD* thd, TABLE_LIST* table_list,
HA_CHECK_OPT* check_opt);
int mysql_repair_table(THD* thd, TABLE_LIST* table_list,
......
......@@ -926,6 +926,8 @@ static void safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
safe_sleep(thd, mi->connect_retry);
}
mysql_log.write(COM_CONNECT_OUT, "%s@%s:%d", mi->user, mi->host, mi->port);
}
// will try to connect until successful
......
......@@ -24,7 +24,7 @@
This will work even if the .ISM and .ISD tables are destroyed
*/
static int generate_table(THD *thd, TABLE_LIST *table_list,
int generate_table(THD *thd, TABLE_LIST *table_list,
TABLE *locked_table)
{
char path[FN_REFLEN];
......
......@@ -47,7 +47,7 @@ enum enum_sql_command {
SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_SHOW_CREATE,
SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE
};
enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
......@@ -135,6 +135,7 @@ typedef struct st_lex {
udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options
LEX_MASTER_INFO mi; // used by CHANGE MASTER
char* backup_dir; // used by BACKUP / RESTORE
} LEX;
......
......@@ -60,7 +60,7 @@ const char *command_name[]={
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user",
"Binlog Dump","Start Slave", "Abort Slave"
"Binlog Dump","Table Dump", "Connect Out"
};
bool volatile abort_slave = 0;
......@@ -927,6 +927,25 @@ mysql_execute_command(void)
#endif
break;
}
case SQLCOM_BACKUP_TABLE:
{
if (check_db_used(thd,tables) ||
check_table_access(thd,SELECT_ACL, tables) ||
check_access(thd, FILE_ACL, any_db))
goto error; /* purecov: inspected */
res = mysql_backup_table(thd, tables);
break;
}
case SQLCOM_RESTORE_TABLE:
{
if (check_db_used(thd,tables) ||
check_table_access(thd,INSERT_ACL, tables) ||
check_access(thd, FILE_ACL, any_db))
goto error; /* purecov: inspected */
res = mysql_restore_table(thd, tables);
break;
}
case SQLCOM_CHANGE_MASTER:
{
if(check_access(thd, PROCESS_ACL, any_db))
......
......@@ -717,6 +717,78 @@ bool close_cached_table(THD *thd,TABLE *table)
DBUG_RETURN(result);
}
static int send_check_errmsg(THD* thd, TABLE_LIST* table,
const char* operator_name, const char* errmsg)
{
String* packet = &thd->packet;
packet->length(0);
net_store_data(packet, table->name);
net_store_data(packet, (char*)operator_name);
net_store_data(packet, "error");
net_store_data(packet, errmsg);
thd->net.last_error[0]=0;
if (my_net_write(&thd->net, (char*) thd->packet.ptr(),
packet->length()))
return -1;
return 1;
}
static int prepare_for_restore(THD* thd, TABLE_LIST* table)
{
String *packet = &thd->packet;
if(table->table) // do not overwrite existing tables on restore
{
return send_check_errmsg(thd, table, "restore",
"table exists, will not overwrite on restore"
);
}
else
{
char* backup_dir = thd->lex.backup_dir;
char src_path[FN_REFLEN], dst_path[FN_REFLEN];
int backup_dir_len = strlen(backup_dir);
char* table_name = table->name;
int table_name_len = strlen(table_name);
char* db = thd->db ? thd->db : table->db;
if(backup_dir_len + table_name_len + 4 >= FN_REFLEN)
return -1; // protect buffer overflow
memcpy(src_path, backup_dir, backup_dir_len);
char* p = src_path + backup_dir_len;
*p++ = '/';
memcpy(p, table_name, table_name_len);
p += table_name_len;
*p = 0;
sprintf(dst_path, "%s/%s/%s", mysql_real_data_home, db, table_name);
if(my_copy(fn_format(src_path, src_path, "", reg_ext, 4),
fn_format(dst_path, dst_path, "", reg_ext, 4),
MYF(MY_WME)))
{
return send_check_errmsg(thd, table, "restore",
"Failed copying .frm file");
}
bool save_no_send_ok = thd->net.no_send_ok;
thd->net.no_send_ok = 1;
// generate table will try to send OK which messes up the output
// for the client
if(generate_table(thd, table, 0))
{
thd->net.no_send_ok = save_no_send_ok;
return send_check_errmsg(thd, table, "restore",
"Failed generating table from .frm file");
}
thd->net.no_send_ok = save_no_send_ok;
}
return 0;
}
static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT* check_opt,
......@@ -751,6 +823,19 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
table->table = open_ltable(thd, table, lock_type);
packet->length(0);
if(operator_func == &handler::restore)
{
switch(prepare_for_restore(thd, table))
{
case 1: continue; // error, message written to net
case -1: goto err; // error, message could be written to net
default: ;// should be 0 otherwise
}
// now we should be able to open the partially restored table
// to finish the restore in the handler later on
table->table = open_ltable(thd, table, lock_type);
}
if (!table->table)
{
......@@ -811,6 +896,11 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
net_store_data(packet, "Corrupt");
break;
case HA_ADMIN_INVALID:
net_store_data(packet, "error");
net_store_data(packet, "Invalid argument");
break;
default: // Probably HA_ADMIN_INTERNAL_ERROR
net_store_data(packet, "error");
net_store_data(packet, "Unknown - internal error during operation");
......@@ -829,6 +919,22 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
DBUG_RETURN(-1);
}
int mysql_backup_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_backup_table");
DBUG_RETURN(mysql_admin_table(thd, table_list, 0,
TL_READ, 1,
"backup",
&handler::backup));
}
int mysql_restore_table(THD* thd, TABLE_LIST* table_list)
{
DBUG_ENTER("mysql_restore_table");
DBUG_RETURN(mysql_admin_table(thd, table_list, 0,
TL_WRITE, 1,
"restore",
&handler::restore));
}
int mysql_repair_table(THD* thd, TABLE_LIST* tables, HA_CHECK_OPT* check_opt)
{
......
......@@ -127,6 +127,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token AUTO_INC
%token AUTOCOMMIT
%token AVG_ROW_LENGTH
%token BACKUP_SYM
%token BERKELEY_DB_SYM
%token BINARY
%token BIT_SYM
......@@ -237,6 +238,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token REGEXP
%token RELOAD
%token RENAME
%token RESTORE_SYM
%token RESTRICT
%token REVOKE
%token ROWS_SYM
......@@ -488,7 +490,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
query verb_clause create change select drop insert replace insert2
insert_values update delete show describe load alter optimize flush
begin commit rollback slave master_def master_defs
repair analyze check rename
repair restore backup analyze check rename
field_list field_list_item field_spec kill
select_item_list select_item values_list no_braces
limit_clause delete_limit_clause fields opt_values values
......@@ -526,6 +528,7 @@ query:
verb_clause:
alter
| analyze
| backup
| begin
| change
| check
......@@ -544,6 +547,7 @@ verb_clause:
| rename
| repair
| replace
| restore
| revoke
| rollback
| select
......@@ -1084,6 +1088,26 @@ slave:
Lex->type = 0;
};
restore:
RESTORE_SYM table_or_tables
{
Lex->sql_command = SQLCOM_RESTORE_TABLE;
}
table_list FROM TEXT_STRING
{
Lex->backup_dir = $6.str;
}
backup:
BACKUP_SYM table_or_tables
{
Lex->sql_command = SQLCOM_BACKUP_TABLE;
}
table_list TO_SYM TEXT_STRING
{
Lex->backup_dir = $6.str;
}
repair:
REPAIR table_or_tables
{
......@@ -2348,6 +2372,7 @@ keyword:
| AUTOCOMMIT {}
| AVG_ROW_LENGTH {}
| AVG_SYM {}
| BACKUP_SYM {}
| BEGIN_SYM {}
| BIT_SYM {}
| BOOL_SYM {}
......@@ -2412,6 +2437,7 @@ keyword:
| RAID_TYPE {}
| RELOAD {}
| REPAIR {}
| RESTORE_SYM {}
| ROLLBACK_SYM {}
| ROWS_SYM {}
| ROW_FORMAT_SYM {}
......
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