From 39636f48f088d3c92a7493c5aa046be11a48c6a0 Mon Sep 17 00:00:00 2001 From: "msvensson@neptunus.(none)[msvensson]" <> Date: Tue, 21 Jun 2005 14:19:56 +0200 Subject: [PATCH] patch --- client/mysqldump.c | 156 +++++++++++++++++++++------------- client/mysqltest.c | 35 +++++++- mysql-test/mysql-test-run.sh | 3 + mysql-test/r/mysqldump.result | 27 ++++++ mysql-test/t/mysqldump.test | 78 +++++++++++++++++ 5 files changed, 238 insertions(+), 61 deletions(-) diff --git a/client/mysqldump.c b/client/mysqldump.c index 7b18b1d92d..207235983d 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -57,6 +57,7 @@ #define EX_CONSCHECK 3 #define EX_EOM 4 #define EX_EOF 5 /* ferror for output file was got */ +#define EX_ILLEGAL_TABLE 6 /* index into 'show fields from table' */ @@ -140,14 +141,6 @@ const char *compatible_mode_names[]= TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1, "", 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; static struct my_option my_long_options[] = @@ -538,29 +531,21 @@ static void write_footer(FILE *sql_file) } /* write_footer */ -static void free_table_ent(TABLE_RULE_ENT* e) -{ - my_free((gptr) e, MYF(0)); -} - - -static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, - my_bool not_used __attribute__((unused))) +byte* get_table_key(const char *entry, uint *length, + my_bool not_used __attribute__((unused))) { - *len= e->key_len; - return (byte*)e->key; + *length= strlen(entry); + return (byte*) entry; } void init_table_rule_hash(HASH* h) { - if(hash_init(h, charset_info, TABLE_RULE_HASH_SIZE, 0, 0, - (hash_get_key) get_table_key, - (hash_free_key) free_table_ent, 0)) + if(hash_init(h, charset_info, 16, 0, 0, + (hash_get_key) get_table_key, 0, 0)) exit(EX_EOM); } - static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -633,25 +618,15 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case (int) OPT_IGNORE_TABLE: { - uint len= (uint)strlen(argument); - TABLE_RULE_ENT* e; if (!strchr(argument, '.')) { fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n"); 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)) 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); break; } @@ -955,7 +930,28 @@ static char *quote_name(const char *name, char *buff, my_bool force) return buff; } /* 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) { @@ -963,7 +959,13 @@ static char *quote_for_like(const char *name, char *buff) *to++= '\''; while (*name) { - if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%') + if (*name == '\\') + { + *to++='\\'; + *to++='\\'; + *to++='\\'; + } + else if (*name == '\'' || *name == '_' || *name == '%') *to++= '\\'; *to++= *name++; } @@ -1114,6 +1116,7 @@ static uint getTableStructure(char *table, char* db) FILE *sql_file = md_result_file; int len; DBUG_ENTER("getTableStructure"); + DBUG_PRINT("enter", ("db: %s, table: %s", db, table)); if (!insert_pat_inited) { @@ -2165,6 +2168,7 @@ static int get_actual_table_name(const char *old_table_name, char query[50 + 2*NAME_LEN]; char show_name_buff[FN_REFLEN]; DBUG_ENTER("get_actual_table_name"); + DBUG_PRINT("enter", ("old_table_name: %s", old_table_name)); /* Check memory for quote_for_like() */ 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, row= mysql_fetch_row( tableRes ); strmake(new_table_name, row[0], buf_size-1); retval = 0; + DBUG_PRINT("info", ("new_table_name: %s", new_table_name)); } 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) { - uint numrows; + uint numrows, i; 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)) 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); - for (i=0 ; i < tables ; i++) + /* the table name passed on commandline may be wrong case */ + 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)); - dynstr_append(&query, " READ /*!32311 LOCAL */,"); + /* Add found table name to lock_tables_query */ + 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"); /* We shall countinue here, if --force was given */ - dynstr_free(&query); } + dynstr_free(&lock_tables_query); if (flush_logs) { if (mysql_refresh(sock, REFRESH_LOG)) @@ -2224,20 +2264,20 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } if (opt_xml) 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]; - - /* the table name passed on commandline may be wrong case */ - if (!get_actual_table_name( *table_names, new_table_name, sizeof(new_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; + table_name= hash_element(&dump_tables, i); + DBUG_PRINT("info",("Dumping table %s", table_name)); + numrows = getTableStructure(table_name, db); + if (!dFlag && numrows > 0) + dumpTable(numrows, table_name); } + hash_free(&dump_tables); + my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); + order_by= 0; if (opt_xml) { fputs("</database>\n", md_result_file); @@ -2245,7 +2285,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) } if (lock_tables) mysql_query_with_error_report(sock, 0, "UNLOCK TABLES"); - return 0; + DBUG_RETURN(0); } /* dump_selected_tables */ diff --git a/client/mysqltest.c b/client/mysqltest.c index e60d9ecd1c..3c238b57a0 100644 --- a/client/mysqltest.c +++ b/client/mysqltest.c @@ -781,7 +781,7 @@ int var_set(const char *var_name, const char *var_name_end, } else 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) replace_dynstr_append_mem(ds, buf, strlen(buf)); } error= pclose(res_file); - 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) { diff --git a/mysql-test/mysql-test-run.sh b/mysql-test/mysql-test-run.sh index 3f7e7d2220..6071a753c8 100644 --- a/mysql-test/mysql-test-run.sh +++ b/mysql-test/mysql-test-run.sh @@ -688,6 +688,9 @@ MYSQL_CLIENT_TEST="$MYSQL_CLIENT_TEST --no-defaults --testcase --user=root --soc 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" 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_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" diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index f66647bdbf..50399c91ec 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -1409,3 +1409,30 @@ CREATE TABLE `t2` ( DROP TABLE t1, t2; 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; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 5a35c32831..349b1e9623 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -558,3 +558,81 @@ INSERT INTO t2 VALUES (1), (2); --exec $MYSQL_DUMP --skip-comments --no-data mysqldump_test_db t1 t2 DROP TABLE t1, t2; 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; + + -- 2.30.9