diff options
author | unknown <sasha@mysql.sashanet.com> | 2000-09-14 16:34:50 -0600 |
---|---|---|
committer | unknown <sasha@mysql.sashanet.com> | 2000-09-14 16:34:50 -0600 |
commit | 2fdcf82ec5acae2bfd03ea00d1158ec5f9d51573 (patch) | |
tree | 6f789a128f7f2f981c423d22a6bebd80ccf71633 /sql | |
parent | 51fc63837a558cbf8d0ce6007012492dd71696de (diff) | |
download | mariadb-git-2fdcf82ec5acae2bfd03ea00d1158ec5f9d51573.tar.gz |
BACKUP TABLE TO 'directory'
RESTORE TABLE FROM 'directory'
log on slave when it connects to the master
include/mysql_com.h:
Added COM_CONNECT_OUT so we can log on the slave when
connects to the master
sql/ha_myisam.cc:
added restore() and backup()
sql/ha_myisam.h:
Added restore() and backup()
sql/handler.cc:
restore()/backup()
sql/handler.h:
restore()/backup()
sql/lex.h:
BACKUP/RESTORE
sql/mysql_priv.h:
gave global ( non-static) scope to generate_table()
added mysql_backup_table()/mysql_restore_table()
sql/slave.cc:
Log when slave connects to the master on the slave
sql/sql_delete.cc:
changed the scope of generate_table() from static to global
sql/sql_lex.h:
changes for BACKUP TABLE/RESTORE TABLE
sql/sql_parse.cc:
Changes for BACKUP TABLE/RESTORE TABLE
sql/sql_table.cc:
Changes for BACKUP TABLE/RESTORE TABLE
sql/sql_yacc.yy:
BACKUP TABLE/ RESTORE TABLE
Diffstat (limited to 'sql')
-rw-r--r-- | sql/ha_myisam.cc | 80 | ||||
-rw-r--r-- | sql/ha_myisam.h | 2 | ||||
-rw-r--r-- | sql/handler.cc | 10 | ||||
-rw-r--r-- | sql/handler.h | 3 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/mysql_priv.h | 7 | ||||
-rw-r--r-- | sql/slave.cc | 2 | ||||
-rw-r--r-- | sql/sql_delete.cc | 2 | ||||
-rw-r--r-- | sql/sql_lex.h | 5 | ||||
-rw-r--r-- | sql/sql_parse.cc | 21 | ||||
-rw-r--r-- | sql/sql_table.cc | 106 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 28 |
12 files changed, 263 insertions, 5 deletions
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2c89b5303ac..9e95d2829a4 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -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(¶m); + param.thd = thd; + param.op_name = (char*)"restore"; + param.table_name = table->table_name; + param.testflag = 0; + mi_check_print_error(¶m,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) { diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index c8f097e792f..00f63a99edd 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -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); }; diff --git a/sql/handler.cc b/sql/handler.cc index ed4613d754f..ccd958664a7 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -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; diff --git a/sql/handler.h b/sql/handler.h index 70b05f0c7f7..a831bb8a769 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -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;} diff --git a/sql/lex.h b/sql/lex.h index 2be54a56b1a..5ea58c4cd80 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -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}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 3b5c87fcab2..258e0c98317 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -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, diff --git a/sql/slave.cc b/sql/slave.cc index b1eb5dea021..6a70f22212b 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -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 diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5d21a089283..64e823d53a5 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -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]; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 083bc8a83b5..5f5490e11e6 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -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, @@ -134,7 +134,8 @@ typedef struct st_lex { THD *thd; udf_func udf; HA_CHECK_OPT check_opt; // check/repair options - LEX_MASTER_INFO mi; // used by CHANGE MASTER + LEX_MASTER_INFO mi; // used by CHANGE MASTER + char* backup_dir; // used by BACKUP / RESTORE } LEX; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a2ef4354521..720a3f2193d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -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)) diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a3da4daa9f4..d83e4c2e7f0 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -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,7 +823,20 @@ 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) { const char *err_msg; @@ -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) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index d4fec1289ba..883b610d856 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -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 {} |