Commit 15cb9cae authored by unknown's avatar unknown

Better quoting patch for mysqldump


client/mysqldump.c:
  Better quoting patch
parent f888ceb1
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
** and adapted to mysqldump 05/11/01 by Jani Tolonen ** and adapted to mysqldump 05/11/01 by Jani Tolonen
*/ */
#define DUMP_VERSION "8.22" #define DUMP_VERSION "8.23"
#include <my_global.h> #include <my_global.h>
#include <my_sys.h> #include <my_sys.h>
...@@ -165,7 +165,7 @@ static int dump_all_tables_in_db(char *db); ...@@ -165,7 +165,7 @@ static int dump_all_tables_in_db(char *db);
static int init_dumping(char *); static int init_dumping(char *);
static int dump_databases(char **); static int dump_databases(char **);
static int dump_all_databases(); static int dump_all_databases();
static char *quote_name(char *name, char *buff); static char *quote_name(const char *name, char *buff, my_bool force);
static void print_quoted_xml(FILE *output, char *fname, char *str, uint len); static void print_quoted_xml(FILE *output, char *fname, char *str, uint len);
static void print_version(void) static void print_version(void)
...@@ -615,33 +615,43 @@ static my_bool test_if_special_chars(const char *str) ...@@ -615,33 +615,43 @@ static my_bool test_if_special_chars(const char *str)
return 0; return 0;
} /* test_if_special_chars */ } /* test_if_special_chars */
static char *quote_name(char *name, char *buff)
static char *quote_name(const char *name, char *buff, my_bool force)
{ {
char *end; char *to= buff;
if (!opt_quoted && !test_if_special_chars(name)) if (!force && !opt_quoted && !test_if_special_chars(name))
return name; return (char*) name;
buff[0]=QUOTE_CHAR; *to++= QUOTE_CHAR;
end=strmov(buff+1,name); while (*name)
end[0]=QUOTE_CHAR; {
end[1]=0; if (*name == QUOTE_CHAR)
*to= QUOTE_CHAR;
*to++= *name++;
}
to[0]=QUOTE_CHAR;
to[1]=0;
return buff; return buff;
} /* quote_name */ } /* quote_name */
/* /*
** getStructure -- retrievs database structure, prints out corresponding getStructure -- retrievs database structure, prints out corresponding
** CREATE statement and fills out insert_pat. CREATE statement and fills out insert_pat.
** Return values: number of fields in table, 0 if error
RETURN
number of fields in table, 0 if error
*/ */
static uint getTableStructure(char *table, char* db) static uint getTableStructure(char *table, char* db)
{ {
MYSQL_RES *tableRes; MYSQL_RES *tableRes;
MYSQL_ROW row; MYSQL_ROW row;
my_bool init=0; my_bool init=0;
uint numFields; uint numFields;
char *strpos, *result_table; char *strpos, *result_table, *opt_quoted_table;
const char *delayed; const char *delayed;
char name_buff[NAME_LEN+3],table_buff[NAME_LEN+3]; char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
char table_buff2[NAME_LEN*2+3];
FILE *sql_file = md_result_file; FILE *sql_file = md_result_file;
DBUG_ENTER("getTableStructure"); DBUG_ENTER("getTableStructure");
...@@ -651,7 +661,8 @@ static uint getTableStructure(char *table, char* db) ...@@ -651,7 +661,8 @@ static uint getTableStructure(char *table, char* db)
fprintf(stderr, "-- Retrieving table structure for table %s...\n", table); fprintf(stderr, "-- Retrieving table structure for table %s...\n", table);
sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", opt_quoted); sprintf(insert_pat,"SET OPTION SQL_QUOTE_SHOW_CREATE=%d", opt_quoted);
result_table=quote_name(table,table_buff); result_table= quote_name(table, table_buff, 1);
opt_quoted_table= quote_name(table, table_buff2, 0);
if (!mysql_query(sock,insert_pat)) if (!mysql_query(sock,insert_pat))
{ {
/* using SHOW CREATE statement */ /* using SHOW CREATE statement */
...@@ -660,11 +671,11 @@ static uint getTableStructure(char *table, char* db) ...@@ -660,11 +671,11 @@ static uint getTableStructure(char *table, char* db)
/* Make an sql-file, if path was given iow. option -T was given */ /* Make an sql-file, if path was given iow. option -T was given */
char buff[20+FN_REFLEN]; char buff[20+FN_REFLEN];
sprintf(buff,"show create table `%s`",table); sprintf(buff,"show create table %s", result_table);
if (mysql_query(sock, buff)) if (mysql_query(sock, buff))
{ {
fprintf(stderr, "%s: Can't get CREATE TABLE for table '%s' (%s)\n", fprintf(stderr, "%s: Can't get CREATE TABLE for table %s (%s)\n",
my_progname, table, mysql_error(sock)); my_progname, result_table, mysql_error(sock));
safe_exit(EX_MYSQLERR); safe_exit(EX_MYSQLERR);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -684,10 +695,10 @@ static uint getTableStructure(char *table, char* db) ...@@ -684,10 +695,10 @@ static uint getTableStructure(char *table, char* db)
write_header(sql_file, db); write_header(sql_file, db);
} }
if (!opt_xml) if (!opt_xml)
fprintf(sql_file, "\n--\n-- Table structure for table '%s'\n--\n\n", fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
table); result_table);
if (opt_drop) if (opt_drop)
fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table); fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
tableRes=mysql_store_result(sock); tableRes=mysql_store_result(sock);
row=mysql_fetch_row(tableRes); row=mysql_fetch_row(tableRes);
...@@ -695,11 +706,11 @@ static uint getTableStructure(char *table, char* db) ...@@ -695,11 +706,11 @@ static uint getTableStructure(char *table, char* db)
fprintf(sql_file, "%s;\n", row[1]); fprintf(sql_file, "%s;\n", row[1]);
mysql_free_result(tableRes); mysql_free_result(tableRes);
} }
sprintf(insert_pat,"show fields from `%s`",table); sprintf(insert_pat,"show fields from %s", result_table);
if (mysql_query(sock,insert_pat) || !(tableRes=mysql_store_result(sock))) if (mysql_query(sock,insert_pat) || !(tableRes=mysql_store_result(sock)))
{ {
fprintf(stderr, "%s: Can't get info about table: '%s'\nerror: %s\n", fprintf(stderr, "%s: Can't get info about table: %s\nerror: %s\n",
my_progname, table, mysql_error(sock)); my_progname, result_table, mysql_error(sock));
if (path) if (path)
my_fclose(sql_file, MYF(MY_WME)); my_fclose(sql_file, MYF(MY_WME));
safe_exit(EX_MYSQLERR); safe_exit(EX_MYSQLERR);
...@@ -707,10 +718,11 @@ static uint getTableStructure(char *table, char* db) ...@@ -707,10 +718,11 @@ static uint getTableStructure(char *table, char* db)
} }
if (cFlag) if (cFlag)
sprintf(insert_pat, "INSERT %sINTO %s (", delayed, result_table); sprintf(insert_pat, "INSERT %sINTO %s (", delayed, opt_quoted_table);
else else
{ {
sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed, result_table); sprintf(insert_pat, "INSERT %sINTO %s VALUES ", delayed,
opt_quoted_table);
if (!extended_insert) if (!extended_insert)
strcat(insert_pat,"("); strcat(insert_pat,"(");
} }
...@@ -725,7 +737,7 @@ static uint getTableStructure(char *table, char* db) ...@@ -725,7 +737,7 @@ static uint getTableStructure(char *table, char* db)
} }
init=1; init=1;
if (cFlag) if (cFlag)
strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME],name_buff)); strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME], name_buff, 0));
} }
numFields = (uint) mysql_num_rows(tableRes); numFields = (uint) mysql_num_rows(tableRes);
mysql_free_result(tableRes); mysql_free_result(tableRes);
...@@ -735,11 +747,11 @@ static uint getTableStructure(char *table, char* db) ...@@ -735,11 +747,11 @@ static uint getTableStructure(char *table, char* db)
/* fprintf(stderr, "%s: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n", /* fprintf(stderr, "%s: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
my_progname, mysql_error(sock)); */ my_progname, mysql_error(sock)); */
sprintf(insert_pat,"show fields from `%s`",result_table); sprintf(insert_pat,"show fields from %s", result_table);
if (mysql_query(sock,insert_pat) || !(tableRes=mysql_store_result(sock))) if (mysql_query(sock,insert_pat) || !(tableRes=mysql_store_result(sock)))
{ {
fprintf(stderr, "%s: Can't get info about table: '%s'\nerror: %s\n", fprintf(stderr, "%s: Can't get info about table: %s\nerror: %s\n",
my_progname, table, mysql_error(sock)); my_progname, result_table, mysql_error(sock));
safe_exit(EX_MYSQLERR); safe_exit(EX_MYSQLERR);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -762,8 +774,8 @@ static uint getTableStructure(char *table, char* db) ...@@ -762,8 +774,8 @@ static uint getTableStructure(char *table, char* db)
write_header(sql_file, db); write_header(sql_file, db);
} }
if (!opt_xml) if (!opt_xml)
fprintf(sql_file, "\n--\n-- Table structure for table '%s'\n--\n\n", fprintf(sql_file, "\n--\n-- Table structure for table %s\n--\n\n",
table); result_table);
if (opt_drop) if (opt_drop)
fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table); fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",result_table);
fprintf(sql_file, "CREATE TABLE %s (\n", result_table); fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
...@@ -790,15 +802,17 @@ static uint getTableStructure(char *table, char* db) ...@@ -790,15 +802,17 @@ static uint getTableStructure(char *table, char* db)
} }
init=1; init=1;
if (cFlag) if (cFlag)
strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME],name_buff)); strpos=strmov(strpos,quote_name(row[SHOW_FIELDNAME], name_buff, 0));
if (!tFlag) if (!tFlag)
{ {
if (opt_keywords) if (opt_keywords)
fprintf(sql_file, " %s.%s %s", result_table, fprintf(sql_file, " %s.%s %s", result_table,
quote_name(row[SHOW_FIELDNAME],name_buff), row[SHOW_TYPE]); quote_name(row[SHOW_FIELDNAME],name_buff, 0),
row[SHOW_TYPE]);
else else
fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME], fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],
name_buff), row[SHOW_TYPE]); name_buff, 0),
row[SHOW_TYPE]);
if (row[SHOW_DEFAULT]) if (row[SHOW_DEFAULT])
{ {
fputs(" DEFAULT ", sql_file); fputs(" DEFAULT ", sql_file);
...@@ -817,11 +831,11 @@ static uint getTableStructure(char *table, char* db) ...@@ -817,11 +831,11 @@ static uint getTableStructure(char *table, char* db)
/* Make an sql-file, if path was given iow. option -T was given */ /* Make an sql-file, if path was given iow. option -T was given */
char buff[20+FN_REFLEN]; char buff[20+FN_REFLEN];
uint keynr,primary_key; uint keynr,primary_key;
sprintf(buff,"show keys from `%s`",table); sprintf(buff,"show keys from %s", result_table);
if (mysql_query(sock, buff)) if (mysql_query(sock, buff))
{ {
fprintf(stderr, "%s: Can't get keys for table '%s' (%s)\n", fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
my_progname, table, mysql_error(sock)); my_progname, result_table, mysql_error(sock));
if (path) if (path)
my_fclose(sql_file, MYF(MY_WME)); my_fclose(sql_file, MYF(MY_WME));
safe_exit(EX_MYSQLERR); safe_exit(EX_MYSQLERR);
...@@ -858,15 +872,15 @@ static uint getTableStructure(char *table, char* db) ...@@ -858,15 +872,15 @@ static uint getTableStructure(char *table, char* db)
putc(')', sql_file); putc(')', sql_file);
if (atoi(row[1])) /* Test if duplicate key */ if (atoi(row[1])) /* Test if duplicate key */
/* Duplicate allowed */ /* Duplicate allowed */
fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff)); fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0));
else if (keynr == primary_key) else if (keynr == primary_key)
fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */ fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
else else
fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff)); fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff,0));
} }
else else
putc(',', sql_file); putc(',', sql_file);
fputs(quote_name(row[4],name_buff), sql_file); fputs(quote_name(row[4], name_buff, 0), sql_file);
if (row[7]) if (row[7])
fprintf(sql_file, " (%s)",row[7]); /* Sub key */ fprintf(sql_file, " (%s)",row[7]); /* Sub key */
} }
...@@ -877,23 +891,23 @@ static uint getTableStructure(char *table, char* db) ...@@ -877,23 +891,23 @@ static uint getTableStructure(char *table, char* db)
/* Get MySQL specific create options */ /* Get MySQL specific create options */
if (create_options) if (create_options)
{ {
sprintf(buff,"show table status like `%s`",table); sprintf(buff,"show table status like %s",result_table);
if (mysql_query(sock, buff)) if (mysql_query(sock, buff))
{ {
if (mysql_errno(sock) != ER_PARSE_ERROR) if (mysql_errno(sock) != ER_PARSE_ERROR)
{ /* If old MySQL version */ { /* If old MySQL version */
if (verbose) if (verbose)
fprintf(stderr, fprintf(stderr,
"-- Warning: Couldn't get status information for table '%s' (%s)\n", "-- Warning: Couldn't get status information for table %s (%s)\n",
table,mysql_error(sock)); result_table,mysql_error(sock));
} }
} }
else if (!(tableRes=mysql_store_result(sock)) || else if (!(tableRes=mysql_store_result(sock)) ||
!(row=mysql_fetch_row(tableRes))) !(row=mysql_fetch_row(tableRes)))
{ {
fprintf(stderr, fprintf(stderr,
"Error: Couldn't read status information for table '%s' (%s)\n", "Error: Couldn't read status information for table %s (%s)\n",
table,mysql_error(sock)); result_table,mysql_error(sock));
} }
else else
{ {
...@@ -909,7 +923,8 @@ static uint getTableStructure(char *table, char* db) ...@@ -909,7 +923,8 @@ static uint getTableStructure(char *table, char* db)
} }
} }
if (opt_disable_keys) if (opt_disable_keys)
fprintf(sql_file,"\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",result_table); fprintf(sql_file, "\n/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
result_table);
if (cFlag) if (cFlag)
{ {
strpos=strmov(strpos,") VALUES "); strpos=strmov(strpos,") VALUES ");
...@@ -979,6 +994,7 @@ static char *field_escape(char *to,const char *from,uint length) ...@@ -979,6 +994,7 @@ static char *field_escape(char *to,const char *from,uint length)
static void dumpTable(uint numFields, char *table) static void dumpTable(uint numFields, char *table)
{ {
char query[1024], *end, buff[256],table_buff[NAME_LEN+3], *result_table; char query[1024], *end, buff[256],table_buff[NAME_LEN+3], *result_table;
char table_buff2[NAME_LEN*2+3], *opt_quoted_table;
MYSQL_RES *res; MYSQL_RES *res;
MYSQL_FIELD *field; MYSQL_FIELD *field;
MYSQL_ROW row; MYSQL_ROW row;
...@@ -986,7 +1002,8 @@ static void dumpTable(uint numFields, char *table) ...@@ -986,7 +1002,8 @@ static void dumpTable(uint numFields, char *table)
if (verbose) if (verbose)
fprintf(stderr, "-- Sending SELECT query...\n"); fprintf(stderr, "-- Sending SELECT query...\n");
result_table=quote_name(table,table_buff); result_table= quote_name(table,table_buff, 1);
opt_quoted_table= quote_name(table, table_buff2, 0);
if (path) if (path)
{ {
char filename[FN_REFLEN], tmp_path[FN_REFLEN]; char filename[FN_REFLEN], tmp_path[FN_REFLEN];
...@@ -1013,7 +1030,7 @@ static void dumpTable(uint numFields, char *table) ...@@ -1013,7 +1030,7 @@ static void dumpTable(uint numFields, char *table)
end= add_load_option(end, lines_terminated, " LINES TERMINATED BY"); end= add_load_option(end, lines_terminated, " LINES TERMINATED BY");
*end= '\0'; *end= '\0';
sprintf(buff," FROM `%s`",table); sprintf(buff," FROM %s", result_table);
end= strmov(end,buff); end= strmov(end,buff);
if (where) if (where)
end= strxmov(end, " WHERE ",where,NullS); end= strxmov(end, " WHERE ",where,NullS);
...@@ -1026,9 +1043,9 @@ static void dumpTable(uint numFields, char *table) ...@@ -1026,9 +1043,9 @@ static void dumpTable(uint numFields, char *table)
else else
{ {
if (!opt_xml) if (!opt_xml)
fprintf(md_result_file,"\n--\n-- Dumping data for table '%s'\n--\n", fprintf(md_result_file,"\n--\n-- Dumping data for table %s\n--\n",
table); result_table);
sprintf(query, "SELECT * FROM `%s`", table); sprintf(query, "SELECT * FROM %s", result_table);
if (where) if (where)
{ {
if (!opt_xml) if (!opt_xml)
...@@ -1055,14 +1072,14 @@ static void dumpTable(uint numFields, char *table) ...@@ -1055,14 +1072,14 @@ static void dumpTable(uint numFields, char *table)
fprintf(stderr, "-- Retrieving rows...\n"); fprintf(stderr, "-- Retrieving rows...\n");
if (mysql_num_fields(res) != numFields) if (mysql_num_fields(res) != numFields)
{ {
fprintf(stderr,"%s: Error in field count for table: '%s' ! Aborting.\n", fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n",
my_progname,table); my_progname, result_table);
safe_exit(EX_CONSCHECK); safe_exit(EX_CONSCHECK);
return; return;
} }
if (opt_lock) if (opt_lock)
fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", result_table); fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
total_length=net_buffer_length; /* Force row break */ total_length=net_buffer_length; /* Force row break */
row_break=0; row_break=0;
...@@ -1090,8 +1107,8 @@ static void dumpTable(uint numFields, char *table) ...@@ -1090,8 +1107,8 @@ static void dumpTable(uint numFields, char *table)
{ {
if (!(field = mysql_fetch_field(res))) if (!(field = mysql_fetch_field(res)))
{ {
sprintf(query,"%s: Not enough fields from table '%s'! Aborting.\n", sprintf(query,"%s: Not enough fields from table %s! Aborting.\n",
my_progname,table); my_progname, result_table);
fputs(query,stderr); fputs(query,stderr);
safe_exit(EX_CONSCHECK); safe_exit(EX_CONSCHECK);
return; return;
...@@ -1215,18 +1232,18 @@ static void dumpTable(uint numFields, char *table) ...@@ -1215,18 +1232,18 @@ static void dumpTable(uint numFields, char *table)
fflush(md_result_file); fflush(md_result_file);
if (mysql_errno(sock)) if (mysql_errno(sock))
{ {
sprintf(query,"%s: Error %d: %s when dumping table '%s' at row: %ld\n", sprintf(query,"%s: Error %d: %s when dumping table %s at row: %ld\n",
my_progname, my_progname,
mysql_errno(sock), mysql_errno(sock),
mysql_error(sock), mysql_error(sock),
table, result_table,
rownr); rownr);
fputs(query,stderr); fputs(query,stderr);
safe_exit(EX_CONSCHECK); safe_exit(EX_CONSCHECK);
return; return;
} }
if (opt_disable_keys) if (opt_disable_keys)
fprintf(md_result_file,"\n/*!40000 ALTER TABLE %s ENABLE KEYS */;\n", fprintf(md_result_file, "\n/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
result_table); result_table);
if (opt_lock) if (opt_lock)
fputs("UNLOCK TABLES;\n", md_result_file); fputs("UNLOCK TABLES;\n", md_result_file);
...@@ -1351,7 +1368,7 @@ static int dump_all_tables_in_db(char *database) ...@@ -1351,7 +1368,7 @@ static int dump_all_tables_in_db(char *database)
{ {
char *table; char *table;
uint numrows; uint numrows;
char table_buff[NAME_LEN+3]; char table_buff[NAME_LEN*2+3];
if (init_dumping(database)) if (init_dumping(database))
return 1; return 1;
...@@ -1361,9 +1378,8 @@ static int dump_all_tables_in_db(char *database) ...@@ -1361,9 +1378,8 @@ static int dump_all_tables_in_db(char *database)
init_dynamic_string(&query, "LOCK TABLES ", 256, 1024); init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
for (numrows=0 ; (table = getTableName(1)) ; numrows++) for (numrows=0 ; (table = getTableName(1)) ; numrows++)
{ {
dynstr_append(&query, "`"); dynstr_append(&query, quote_name(table, table_buff, 1));
dynstr_append(&query, table); dynstr_append(&query, " READ /*!32311 LOCAL */,");
dynstr_append(&query, "` READ /*!32311 LOCAL */,");
} }
if (numrows && mysql_real_query(sock, query.str, query.length-1)) if (numrows && mysql_real_query(sock, query.str, query.length-1))
DBerror(sock, "when using LOCK TABLES"); DBerror(sock, "when using LOCK TABLES");
...@@ -1392,7 +1408,7 @@ static int dump_all_tables_in_db(char *database) ...@@ -1392,7 +1408,7 @@ static int dump_all_tables_in_db(char *database)
static int dump_selected_tables(char *db, char **table_names, int tables) static int dump_selected_tables(char *db, char **table_names, int tables)
{ {
uint numrows; uint numrows;
char table_buff[NAME_LEN+3]; char table_buff[NAME_LEN*+3];
if (init_dumping(db)) if (init_dumping(db))
return 1; return 1;
...@@ -1404,9 +1420,8 @@ static int dump_selected_tables(char *db, char **table_names, int tables) ...@@ -1404,9 +1420,8 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
init_dynamic_string(&query, "LOCK TABLES ", 256, 1024); init_dynamic_string(&query, "LOCK TABLES ", 256, 1024);
for (i=0 ; i < tables ; i++) for (i=0 ; i < tables ; i++)
{ {
dynstr_append(&query, "`"); dynstr_append(&query, quote_name(table_names[i], table_buff, 1));
dynstr_append(&query, table_names[i]); dynstr_append(&query, " READ /*!32311 LOCAL */,");
dynstr_append(&query, "` READ /*!32311 LOCAL */,");
} }
if (mysql_real_query(sock, query.str, query.length-1)) if (mysql_real_query(sock, query.str, query.length-1))
DBerror(sock, "when doing LOCK TABLES"); DBerror(sock, "when doing LOCK TABLES");
......
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