Commit c2a84d5f authored by unknown's avatar unknown

patch


client/mysqldump.c:
  Add description of quote_for_like
  Add quoting of \ to \\\\ in quote_for_like
  Add DBUG_*
  Rearranged code in dump_selected_tables so the first thing it will do is to check that the tables to dump are available
  Unless --force is used, program will exit if not all specified tables can be found
  Add files to dump to HASH table for easy iteration
  Simpler handling of ignore_table list.
  Add new error code used when table user selected to dump  can not be found in db
client/mysqltest.c:
  Make it possible to exec a command that fails by setting --error <errno> before the command to exec.
  Check that the error returned from executed program matches the expected error.
  Add DBUG_* printouts
mysql-test/mysql-test-run.sh:
  export MYSQL_DUMP_DIR used in "--replace_result"
mysql-test/r/mysqldump.result:
  Added test for illegal / nonexisting table and database names
mysql-test/t/mysqldump.test:
  Added test for illegal / nonexisting table and database names
parent 29397de1
...@@ -57,6 +57,7 @@ ...@@ -57,6 +57,7 @@
#define EX_CONSCHECK 3 #define EX_CONSCHECK 3
#define EX_EOM 4 #define EX_EOM 4
#define EX_EOF 5 /* ferror for output file was got */ #define EX_EOF 5 /* ferror for output file was got */
#define EX_ILLEGAL_TABLE 6
/* index into 'show fields from table' */ /* index into 'show fields from table' */
...@@ -140,14 +141,6 @@ const char *compatible_mode_names[]= ...@@ -140,14 +141,6 @@ const char *compatible_mode_names[]=
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
"", compatible_mode_names, NULL}; "", compatible_mode_names, NULL};
#define TABLE_RULE_HASH_SIZE 16
typedef struct st_table_rule_ent
{
char* key; /* dbname.tablename */
uint key_len;
} TABLE_RULE_ENT;
HASH ignore_table; HASH ignore_table;
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
...@@ -538,29 +531,21 @@ static void write_footer(FILE *sql_file) ...@@ -538,29 +531,21 @@ static void write_footer(FILE *sql_file)
} /* write_footer */ } /* write_footer */
static void free_table_ent(TABLE_RULE_ENT* e) byte* get_table_key(const char *entry, uint *length,
{ my_bool not_used __attribute__((unused)))
my_free((gptr) e, MYF(0));
}
static byte* get_table_key(TABLE_RULE_ENT* e, uint* len,
my_bool not_used __attribute__((unused)))
{ {
*len= e->key_len; *length= strlen(entry);
return (byte*)e->key; return (byte*) entry;
} }
void init_table_rule_hash(HASH* h) void init_table_rule_hash(HASH* h)
{ {
if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0, if(hash_init(h, charset_info, 16, 0, 0,
(hash_get_key) get_table_key, (hash_get_key) get_table_key, 0, 0))
(hash_free_key) free_table_ent, 0))
exit(EX_EOM); exit(EX_EOM);
} }
static my_bool static my_bool
get_one_option(int optid, const struct my_option *opt __attribute__((unused)), get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
char *argument) char *argument)
...@@ -633,25 +618,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ...@@ -633,25 +618,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break; break;
case (int) OPT_IGNORE_TABLE: case (int) OPT_IGNORE_TABLE:
{ {
uint len= (uint)strlen(argument);
TABLE_RULE_ENT* e;
if (!strchr(argument, '.')) if (!strchr(argument, '.'))
{ {
fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n"); fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
exit(1); exit(1);
} }
/* len is always > 0 because we know the there exists a '.' */
e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + len, MYF(MY_WME));
if (!e)
exit(EX_EOM);
e->key= (char*)e + sizeof(TABLE_RULE_ENT);
e->key_len= len;
memcpy(e->key, argument, len);
if (!hash_inited(&ignore_table)) if (!hash_inited(&ignore_table))
init_table_rule_hash(&ignore_table); init_table_rule_hash(&ignore_table);
if(my_hash_insert(&ignore_table, (byte*)e)) if (my_hash_insert(&ignore_table, (byte*)my_strdup(argument, MYF(0))))
exit(EX_EOM); exit(EX_EOM);
break; break;
} }
...@@ -955,7 +930,28 @@ static char *quote_name(const char *name, char *buff, my_bool force) ...@@ -955,7 +930,28 @@ static char *quote_name(const char *name, char *buff, my_bool force)
return buff; return buff;
} /* quote_name */ } /* quote_name */
/*
Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
SYNOPSIS
quote_for_like
name - name of the table
buff - quoted name of the table
DESCRIPTION
Quote \, _, ' and % characters
Note: Because MySQL uses the C escape syntax in strings
(for example, '\n' to represent newline), you must double
any '\' that you use in your LIKE strings. For example, to
search for '\n', specify it as '\\n'. To search for '\', specify
it as '\\\\' (the backslashes are stripped once by the parser
and another time when the pattern match is done, leaving a
single backslash to be matched).
Example: "t\1" => "t\\\\1"
*/
static char *quote_for_like(const char *name, char *buff) static char *quote_for_like(const char *name, char *buff)
{ {
...@@ -963,7 +959,13 @@ static char *quote_for_like(const char *name, char *buff) ...@@ -963,7 +959,13 @@ static char *quote_for_like(const char *name, char *buff)
*to++= '\''; *to++= '\'';
while (*name) while (*name)
{ {
if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%') if (*name == '\\')
{
*to++='\\';
*to++='\\';
*to++='\\';
}
else if (*name == '\'' || *name == '_' || *name == '%')
*to++= '\\'; *to++= '\\';
*to++= *name++; *to++= *name++;
} }
...@@ -1114,6 +1116,7 @@ static uint getTableStructure(char *table, char* db) ...@@ -1114,6 +1116,7 @@ static uint getTableStructure(char *table, char* db)
FILE *sql_file = md_result_file; FILE *sql_file = md_result_file;
int len; int len;
DBUG_ENTER("getTableStructure"); DBUG_ENTER("getTableStructure");
DBUG_PRINT("enter", ("db: %s, table: %s", db, table));
if (!insert_pat_inited) if (!insert_pat_inited)
{ {
...@@ -2165,6 +2168,7 @@ static int get_actual_table_name(const char *old_table_name, ...@@ -2165,6 +2168,7 @@ static int get_actual_table_name(const char *old_table_name,
char query[50 + 2*NAME_LEN]; char query[50 + 2*NAME_LEN];
char show_name_buff[FN_REFLEN]; char show_name_buff[FN_REFLEN];
DBUG_ENTER("get_actual_table_name"); DBUG_ENTER("get_actual_table_name");
DBUG_PRINT("enter", ("old_table_name: %s", old_table_name));
/* Check memory for quote_for_like() */ /* Check memory for quote_for_like() */
DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff)); DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
...@@ -2186,36 +2190,72 @@ static int get_actual_table_name(const char *old_table_name, ...@@ -2186,36 +2190,72 @@ static int get_actual_table_name(const char *old_table_name,
row= mysql_fetch_row( tableRes ); row= mysql_fetch_row( tableRes );
strmake(new_table_name, row[0], buf_size-1); strmake(new_table_name, row[0], buf_size-1);
retval = 0; retval = 0;
DBUG_PRINT("info", ("new_table_name: %s", new_table_name));
} }
mysql_free_result(tableRes); mysql_free_result(tableRes);
} }
return retval; DBUG_PRINT("exit", ("retval: %d", retval));
DBUG_RETURN(retval);
} }
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, i;
char table_buff[NAME_LEN*+3]; char table_buff[NAME_LEN*+3];
char new_table_name[NAME_LEN];
DYNAMIC_STRING lock_tables_query;
HASH dump_tables;
DBUG_ENTER("dump_selected_tables");
if (init_dumping(db)) if (init_dumping(db))
return 1; return 1;
if (lock_tables)
/* Init hash table for storing the actual name of tables to dump */
if (hash_init(&dump_tables, charset_info, 16, 0, 0,
(hash_get_key) get_table_key, 0, 0))
exit(EX_EOM);
init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024);
for (; tables > 0 ; tables-- , table_names++)
{ {
DYNAMIC_STRING query;
int i;
init_dynamic_string(&query, "LOCK TABLES ", 256, 1024); /* the table name passed on commandline may be wrong case */
for (i=0 ; i < tables ; i++) if (!get_actual_table_name( *table_names,
new_table_name, sizeof(new_table_name) ))
{ {
dynstr_append(&query, quote_name(table_names[i], table_buff, 1)); /* Add found table name to lock_tables_query */
dynstr_append(&query, " READ /*!32311 LOCAL */,"); if (lock_tables)
{
dynstr_append(&lock_tables_query,
quote_name(new_table_name, table_buff, 1));
dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,");
}
/* Add found table name to dump_tables list */
if (my_hash_insert(&dump_tables,
(byte*)my_strdup(new_table_name, MYF(0))))
exit(EX_EOM);
} }
if (mysql_real_query(sock, query.str, query.length-1)) else
{
my_printf_error(0,"Couldn't find table: \"%s\"\n", MYF(0),
*table_names);
safe_exit(EX_ILLEGAL_TABLE);
/* We shall countinue here, if --force was given */
}
}
if (lock_tables)
{
if (mysql_real_query(sock, lock_tables_query.str,
lock_tables_query.length-1))
DBerror(sock, "when doing LOCK TABLES"); DBerror(sock, "when doing LOCK TABLES");
/* We shall countinue here, if --force was given */ /* We shall countinue here, if --force was given */
dynstr_free(&query);
} }
dynstr_free(&lock_tables_query);
if (flush_logs) if (flush_logs)
{ {
if (mysql_refresh(sock, REFRESH_LOG)) if (mysql_refresh(sock, REFRESH_LOG))
...@@ -2224,20 +2264,20 @@ static int dump_selected_tables(char *db, char **table_names, int tables) ...@@ -2224,20 +2264,20 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
} }
if (opt_xml) if (opt_xml)
print_xml_tag1(md_result_file, "", "database name=", db, "\n"); print_xml_tag1(md_result_file, "", "database name=", db, "\n");
for (; tables > 0 ; tables-- , table_names++)
/* Dump each selected table */
const char *table_name;
for (i= 0 ; i < dump_tables.records ; i++)
{ {
char new_table_name[NAME_LEN]; table_name= hash_element(&dump_tables, i);
DBUG_PRINT("info",("Dumping table %s", table_name));
/* the table name passed on commandline may be wrong case */ numrows = getTableStructure(table_name, db);
if (!get_actual_table_name( *table_names, new_table_name, sizeof(new_table_name) )) if (!dFlag && numrows > 0)
{ dumpTable(numrows, table_name);
numrows = getTableStructure(new_table_name, db);
if (!dFlag && numrows > 0)
dumpTable(numrows, new_table_name);
}
my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
order_by= 0;
} }
hash_free(&dump_tables);
my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
order_by= 0;
if (opt_xml) if (opt_xml)
{ {
fputs("</database>\n", md_result_file); fputs("</database>\n", md_result_file);
...@@ -2245,7 +2285,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) ...@@ -2245,7 +2285,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
} }
if (lock_tables) if (lock_tables)
mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); mysql_query_with_error_report(sock, 0, "UNLOCK TABLES");
return 0; DBUG_RETURN(0);
} /* dump_selected_tables */ } /* dump_selected_tables */
......
...@@ -781,7 +781,7 @@ int var_set(const char *var_name, const char *var_name_end, ...@@ -781,7 +781,7 @@ int var_set(const char *var_name, const char *var_name_end,
} }
else else
v = var_reg + digit; v = var_reg + digit;
return eval_expr(v, var_val, (const char**)&var_val_end); DBUG_RETURN(eval_expr(v, var_val, (const char**)&var_val_end));
} }
...@@ -955,9 +955,38 @@ static void do_exec(struct st_query* q) ...@@ -955,9 +955,38 @@ static void do_exec(struct st_query* q)
replace_dynstr_append_mem(ds, buf, strlen(buf)); replace_dynstr_append_mem(ds, buf, strlen(buf));
} }
error= pclose(res_file); error= pclose(res_file);
if (error != 0) if (error != 0)
die("command \"%s\" failed", cmd); {
uint status= WEXITSTATUS(error);
if(q->abort_on_error)
die("At line %u: command \"%s\" failed", start_lineno, cmd);
else
{
DBUG_PRINT("info",
("error: %d, status: %d", error, status));
bool ok= 0;
uint i;
for (i=0 ; (uint) i < q->expected_errors ; i++)
{
DBUG_PRINT("info", ("expected error: %d", q->expected_errno[i].code.errnum));
if ((q->expected_errno[i].type == ERR_ERRNO) &&
(q->expected_errno[i].code.errnum == status))
ok= 1;
verbose_msg("At line %u: command \"%s\" failed with expected error: %d",
start_lineno, cmd, status);
}
if (!ok)
die("At line: %u: command \"%s\" failed with wrong error: %d",
start_lineno, cmd, status);
}
}
else if (q->expected_errno[0].type == ERR_ERRNO &&
q->expected_errno[0].code.errnum != 0)
{
/* Error code we wanted was != 0, i.e. not an expected success */
die("At line: %u: command \"%s\" succeeded - should have failed with errno %d...",
start_lineno, cmd, q->expected_errno[0].code.errnum);
}
if (!disable_result_log) if (!disable_result_log)
{ {
......
...@@ -688,6 +688,9 @@ MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --soc ...@@ -688,6 +688,9 @@ MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --soc
if [ "x$USE_EMBEDDED_SERVER" = "x1" ]; then if [ "x$USE_EMBEDDED_SERVER" = "x1" ]; then
MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST -A --language=$LANGUAGE -A --datadir=$SLAVE_MYDDIR -A --character-sets-dir=$CHARSETSDIR" MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST -A --language=$LANGUAGE -A --datadir=$SLAVE_MYDDIR -A --character-sets-dir=$CHARSETSDIR"
fi fi
# Save path and name of mysqldump
MYSQL_DUMP_DIR="$MYSQL_DUMP"
export MYSQL_DUMP_DIR
MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT" MYSQL_DUMP="$MYSQL_DUMP --no-defaults -uroot --socket=$MASTER_MYSOCK --password=$DBPASSWD $EXTRA_MYSQLDUMP_OPT"
MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR $EXTRA_MYSQLBINLOG_OPT" MYSQL_BINLOG="$MYSQL_BINLOG --no-defaults --local-load=$MYSQL_TMP_DIR $EXTRA_MYSQLBINLOG_OPT"
MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD --basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose" MYSQL_FIX_SYSTEM_TABLES="$MYSQL_FIX_SYSTEM_TABLES --no-defaults --host=localhost --port=$MASTER_MYPORT --socket=$MASTER_MYSOCK --user=root --password=$DBPASSWD --basedir=$BASEDIR --bindir=$CLIENT_BINDIR --verbose"
......
...@@ -1409,3 +1409,30 @@ CREATE TABLE `t2` ( ...@@ -1409,3 +1409,30 @@ CREATE TABLE `t2` (
DROP TABLE t1, t2; DROP TABLE t1, t2;
DROP DATABASE mysqldump_test_db; DROP DATABASE mysqldump_test_db;
create database mysqldump_test_db;
use mysqldump_test_db;
create table t1(a varchar(30) primary key, b int not null);
create table t2(a varchar(30) primary key, b int not null);
create table t3(a varchar(30) primary key, b int not null);
test_sequence
------ Testing with illegal table names ------
MYSQL_DUMP_DIR: Couldn't find table: "\d-2-1.sql"
MYSQL_DUMP_DIR: Couldn't find table: "\t1"
MYSQL_DUMP_DIR: Couldn't find table: "\t1"
MYSQL_DUMP_DIR: Couldn't find table: "\\t1"
MYSQL_DUMP_DIR: Couldn't find table: "t\1"
MYSQL_DUMP_DIR: Couldn't find table: "t\1"
MYSQL_DUMP_DIR: Couldn't find table: "t/1"
test_sequence
------ Testing with illegal database names ------
MYSQL_DUMP_DIR: Got error: 1049: Unknown database 'mysqldump_test_d' when selecting the database
MYSQL_DUMP_DIR: Got error: 1102: Incorrect database name 'mysqld\ump_test_db' when selecting the database
drop table t1, t2, t3;
drop database mysqldump_test_db;
...@@ -558,3 +558,81 @@ INSERT INTO t2 VALUES (1), (2); ...@@ -558,3 +558,81 @@ INSERT INTO t2 VALUES (1), (2);
--exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db t1 t2 --exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db t1 t2
DROP TABLE t1, t2; DROP TABLE t1, t2;
DROP DATABASE mysqldump_test_db; DROP DATABASE mysqldump_test_db;
#
# Testing with tables and databases that don't exists
# or contains illegal characters
# (Bug #9358 mysqldump crashes if tablename starts with \)
#
create database mysqldump_test_db;
use mysqldump_test_db;
create table t1(a varchar(30) primary key, b int not null);
create table t2(a varchar(30) primary key, b int not null);
create table t3(a varchar(30) primary key, b int not null);
--disable_query_log
select '------ Testing with illegal table names ------' as test_sequence ;
--enable_query_log
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\d-2-1.sql" 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\t1" 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\t1" 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "\\\\t1" 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\1" 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t\\1" 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_db "t/1" 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1"
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T%1"
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T'1"
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_1"
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 6
--exec $MYSQL_DUMP --compact --skip-comments "mysqldump_test_db" "T_"
--disable_query_log
select '------ Testing with illegal database names ------' as test_sequence ;
--enable_query_log
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 2
--exec $MYSQL_DUMP --compact --skip-comments mysqldump_test_d 2>&1
--replace_result $MYSQL_DUMP_DIR MYSQL_DUMP_DIR
--error 2
--exec $MYSQL_DUMP --compact --skip-comments "mysqld\ump_test_db" 2>&1
drop table t1, t2, t3;
drop database mysqldump_test_db;
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