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, ...@@ -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_PROCESS_INFO,COM_CONNECT,COM_PROCESS_KILL,
COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT, COM_DEBUG,COM_PING,COM_TIME,COM_DELAYED_INSERT,
COM_CHANGE_USER, COM_BINLOG_DUMP, 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 NOT_NULL_FLAG 1 /* Field can't be NULL */
#define PRI_KEY_FLAG 2 /* Field is part of a primary key */ #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) ...@@ -328,6 +328,86 @@ int ha_myisam::analyze(THD *thd, HA_CHECK_OPT* check_opt)
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK; 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) int ha_myisam::repair(THD* thd, HA_CHECK_OPT *check_opt)
{ {
......
...@@ -96,6 +96,8 @@ class ha_myisam: public handler ...@@ -96,6 +96,8 @@ class ha_myisam: public handler
int analyze(THD* thd,HA_CHECK_OPT* check_opt); int analyze(THD* thd,HA_CHECK_OPT* check_opt);
int repair(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 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 dump(THD* thd, int fd);
int net_read_dump(NET* net); int net_read_dump(NET* net);
}; };
...@@ -337,6 +337,16 @@ int handler::check(THD* thd, HA_CHECK_OPT* check_opt) ...@@ -337,6 +337,16 @@ int handler::check(THD* thd, HA_CHECK_OPT* check_opt)
return HA_ADMIN_NOT_IMPLEMENTED; 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) int handler::repair(THD* thd, HA_CHECK_OPT* check_opt)
{ {
return HA_ADMIN_NOT_IMPLEMENTED; return HA_ADMIN_NOT_IMPLEMENTED;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define HA_ADMIN_FAILED -2 #define HA_ADMIN_FAILED -2
#define HA_ADMIN_CORRUPT -3 #define HA_ADMIN_CORRUPT -3
#define HA_ADMIN_INTERNAL_ERROR -4 #define HA_ADMIN_INTERNAL_ERROR -4
#define HA_ADMIN_INVALID -5
/* Bits in bas_flag to show what database can do */ /* Bits in bas_flag to show what database can do */
...@@ -248,6 +249,8 @@ public: ...@@ -248,6 +249,8 @@ public:
virtual int repair(THD* thd, HA_CHECK_OPT* check_opt); virtual int repair(THD* thd, HA_CHECK_OPT* check_opt);
virtual int optimize(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 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 int dump(THD* thd, int fd = -1) { return ER_DUMP_NOT_IMPLEMENTED; }
virtual void deactivate_non_unique_index(ha_rows rows) {} virtual void deactivate_non_unique_index(ha_rows rows) {}
virtual bool activate_all_index(THD *thd) {return 0;} virtual bool activate_all_index(THD *thd) {return 0;}
......
...@@ -62,6 +62,7 @@ static SYMBOL symbols[] = { ...@@ -62,6 +62,7 @@ static SYMBOL symbols[] = {
{ "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0}, { "AVG_ROW_LENGTH", SYM(AVG_ROW_LENGTH),0,0},
{ "AUTO_INCREMENT", SYM(AUTO_INC),0,0}, { "AUTO_INCREMENT", SYM(AUTO_INC),0,0},
{ "AUTOCOMMIT", SYM(AUTOCOMMIT),0,0}, { "AUTOCOMMIT", SYM(AUTOCOMMIT),0,0},
{ "BACKUP", SYM(BACKUP_SYM),0,0},
{ "BEGIN", SYM(BEGIN_SYM),0,0}, { "BEGIN", SYM(BEGIN_SYM),0,0},
{ "BERKELEYDB", SYM(BERKELEY_DB_SYM),0,0}, { "BERKELEYDB", SYM(BERKELEY_DB_SYM),0,0},
{ "BDB", SYM(BERKELEY_DB_SYM),0,0}, { "BDB", SYM(BERKELEY_DB_SYM),0,0},
...@@ -247,6 +248,7 @@ static SYMBOL symbols[] = { ...@@ -247,6 +248,7 @@ static SYMBOL symbols[] = {
{ "RENAME", SYM(RENAME),0,0}, { "RENAME", SYM(RENAME),0,0},
{ "REPAIR", SYM(REPAIR),0,0}, { "REPAIR", SYM(REPAIR),0,0},
{ "REPLACE", SYM(REPLACE),0,0}, { "REPLACE", SYM(REPLACE),0,0},
{ "RESTORE", SYM(RESTORE_SYM),0,0},
{ "RESTRICT", SYM(RESTRICT),0,0}, { "RESTRICT", SYM(RESTRICT),0,0},
{ "RETURNS", SYM(UDF_RETURNS_SYM),0,0}, { "RETURNS", SYM(UDF_RETURNS_SYM),0,0},
{ "REVOKE", SYM(REVOKE),0,0}, { "REVOKE", SYM(REVOKE),0,0},
......
...@@ -239,6 +239,13 @@ void close_connection(NET *net,uint errcode=0,bool lock=1); ...@@ -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 check_access(THD *thd,uint access,const char *db=0,uint *save_priv=0,
bool no_grant=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, int mysql_check_table(THD* thd, TABLE_LIST* table_list,
HA_CHECK_OPT* check_opt); HA_CHECK_OPT* check_opt);
int mysql_repair_table(THD* thd, TABLE_LIST* table_list, 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) ...@@ -926,6 +926,8 @@ static void safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi)
safe_sleep(thd, mi->connect_retry); 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 // will try to connect until successful
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
This will work even if the .ISM and .ISD tables are destroyed 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) TABLE *locked_table)
{ {
char path[FN_REFLEN]; char path[FN_REFLEN];
......
...@@ -47,7 +47,7 @@ enum enum_sql_command { ...@@ -47,7 +47,7 @@ enum enum_sql_command {
SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_SHOW_CREATE, SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_SHOW_CREATE,
SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, SQLCOM_CHANGE_MASTER, 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, enum lex_states { STATE_START, STATE_CHAR, STATE_IDENT,
...@@ -135,6 +135,7 @@ typedef struct st_lex { ...@@ -135,6 +135,7 @@ typedef struct st_lex {
udf_func udf; udf_func udf;
HA_CHECK_OPT check_opt; // check/repair options 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; } LEX;
......
...@@ -60,7 +60,7 @@ const char *command_name[]={ ...@@ -60,7 +60,7 @@ const char *command_name[]={
"Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB", "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB",
"Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist", "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist",
"Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", "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; bool volatile abort_slave = 0;
...@@ -927,6 +927,25 @@ mysql_execute_command(void) ...@@ -927,6 +927,25 @@ mysql_execute_command(void)
#endif #endif
break; 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: case SQLCOM_CHANGE_MASTER:
{ {
if(check_access(thd, PROCESS_ACL, any_db)) if(check_access(thd, PROCESS_ACL, any_db))
......
...@@ -717,6 +717,78 @@ bool close_cached_table(THD *thd,TABLE *table) ...@@ -717,6 +717,78 @@ bool close_cached_table(THD *thd,TABLE *table)
DBUG_RETURN(result); 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, static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
HA_CHECK_OPT* check_opt, HA_CHECK_OPT* check_opt,
...@@ -751,6 +823,19 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -751,6 +823,19 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
table->table = open_ltable(thd, table, lock_type); table->table = open_ltable(thd, table, lock_type);
packet->length(0); 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) if (!table->table)
{ {
...@@ -811,6 +896,11 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -811,6 +896,11 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
net_store_data(packet, "Corrupt"); net_store_data(packet, "Corrupt");
break; break;
case HA_ADMIN_INVALID:
net_store_data(packet, "error");
net_store_data(packet, "Invalid argument");
break;
default: // Probably HA_ADMIN_INTERNAL_ERROR default: // Probably HA_ADMIN_INTERNAL_ERROR
net_store_data(packet, "error"); net_store_data(packet, "error");
net_store_data(packet, "Unknown - internal error during operation"); net_store_data(packet, "Unknown - internal error during operation");
...@@ -829,6 +919,22 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, ...@@ -829,6 +919,22 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
DBUG_RETURN(-1); 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) 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); ...@@ -127,6 +127,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token AUTO_INC %token AUTO_INC
%token AUTOCOMMIT %token AUTOCOMMIT
%token AVG_ROW_LENGTH %token AVG_ROW_LENGTH
%token BACKUP_SYM
%token BERKELEY_DB_SYM %token BERKELEY_DB_SYM
%token BINARY %token BINARY
%token BIT_SYM %token BIT_SYM
...@@ -237,6 +238,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -237,6 +238,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token REGEXP %token REGEXP
%token RELOAD %token RELOAD
%token RENAME %token RENAME
%token RESTORE_SYM
%token RESTRICT %token RESTRICT
%token REVOKE %token REVOKE
%token ROWS_SYM %token ROWS_SYM
...@@ -488,7 +490,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -488,7 +490,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
query verb_clause create change select drop insert replace insert2 query verb_clause create change select drop insert replace insert2
insert_values update delete show describe load alter optimize flush insert_values update delete show describe load alter optimize flush
begin commit rollback slave master_def master_defs 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 field_list field_list_item field_spec kill
select_item_list select_item values_list no_braces select_item_list select_item values_list no_braces
limit_clause delete_limit_clause fields opt_values values limit_clause delete_limit_clause fields opt_values values
...@@ -526,6 +528,7 @@ query: ...@@ -526,6 +528,7 @@ query:
verb_clause: verb_clause:
alter alter
| analyze | analyze
| backup
| begin | begin
| change | change
| check | check
...@@ -544,6 +547,7 @@ verb_clause: ...@@ -544,6 +547,7 @@ verb_clause:
| rename | rename
| repair | repair
| replace | replace
| restore
| revoke | revoke
| rollback | rollback
| select | select
...@@ -1084,6 +1088,26 @@ slave: ...@@ -1084,6 +1088,26 @@ slave:
Lex->type = 0; 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:
REPAIR table_or_tables REPAIR table_or_tables
{ {
...@@ -2348,6 +2372,7 @@ keyword: ...@@ -2348,6 +2372,7 @@ keyword:
| AUTOCOMMIT {} | AUTOCOMMIT {}
| AVG_ROW_LENGTH {} | AVG_ROW_LENGTH {}
| AVG_SYM {} | AVG_SYM {}
| BACKUP_SYM {}
| BEGIN_SYM {} | BEGIN_SYM {}
| BIT_SYM {} | BIT_SYM {}
| BOOL_SYM {} | BOOL_SYM {}
...@@ -2412,6 +2437,7 @@ keyword: ...@@ -2412,6 +2437,7 @@ keyword:
| RAID_TYPE {} | RAID_TYPE {}
| RELOAD {} | RELOAD {}
| REPAIR {} | REPAIR {}
| RESTORE_SYM {}
| ROLLBACK_SYM {} | ROLLBACK_SYM {}
| ROWS_SYM {} | ROWS_SYM {}
| ROW_FORMAT_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