summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sasha@mysql.sashanet.com>2000-09-14 16:34:50 -0600
committerunknown <sasha@mysql.sashanet.com>2000-09-14 16:34:50 -0600
commit2fdcf82ec5acae2bfd03ea00d1158ec5f9d51573 (patch)
tree6f789a128f7f2f981c423d22a6bebd80ccf71633 /sql
parent51fc63837a558cbf8d0ce6007012492dd71696de (diff)
downloadmariadb-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.cc80
-rw-r--r--sql/ha_myisam.h2
-rw-r--r--sql/handler.cc10
-rw-r--r--sql/handler.h3
-rw-r--r--sql/lex.h2
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sql_delete.cc2
-rw-r--r--sql/sql_lex.h5
-rw-r--r--sql/sql_parse.cc21
-rw-r--r--sql/sql_table.cc106
-rw-r--r--sql/sql_yacc.yy28
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(&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)
{
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 {}