From 967fac4ef6270d4cd458c8f40024b58c167c1c04 Mon Sep 17 00:00:00 2001 From: "lars@mysql.com" <> Date: Mon, 27 Dec 2004 19:10:30 +0100 Subject: [PATCH] WL#2319 V2: Exclude tables from dump - Added a hash to keep track of database-table pairs. - Specified database-table tables do not get dumped --- client/client_priv.h | 1 + client/mysqldump.c | 106 +++++++++++++++++++++++++++++++--- mysql-test/r/mysqldump.result | 33 +++++++++++ mysql-test/t/mysqldump.test | 12 ++++ 4 files changed, 145 insertions(+), 7 deletions(-) diff --git a/client/client_priv.h b/client/client_priv.h index e86a56f58c1..95f4d105156 100644 --- a/client/client_priv.h +++ b/client/client_priv.h @@ -49,4 +49,5 @@ enum options_client #ifdef HAVE_NDBCLUSTER_DB ,OPT_NDBCLUSTER,OPT_NDB_CONNECTSTRING #endif + ,OPT_IGNORE_TABLE }; diff --git a/client/mysqldump.c b/client/mysqldump.c index be2abd19822..ffdb84397e9 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "client_priv.h" #include "mysql.h" @@ -128,6 +129,16 @@ 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; + +my_bool ignore_table_inited; +HASH ignore_table; static struct my_option my_long_options[] = { @@ -233,6 +244,11 @@ static struct my_option my_long_options[] = (gptr*) &opt_hex_blob, (gptr*) &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", (gptr*) ¤t_host, (gptr*) ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"ignore-table", OPT_IGNORE_TABLE, + "Do not dump the specified table. To specify more than one table to ignore, " + "use the directive multiple times, once for each table. Each table must " + "be specified with both database and table names, e.g. --ignore-table=database.table", + 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"lines-terminated-by", OPT_LTB, "Lines in the i.file are terminated by ...", (gptr*) &lines_terminated, (gptr*) &lines_terminated, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -502,6 +518,32 @@ 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))) +{ + *len= e->key_len; + return (byte*)e->key; +} + + +void init_table_rule_hash(HASH* h, bool* h_inited) +{ + 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)) + { + fprintf(stderr, "Internal hash initialization error\n"); + exit(1); + } + *h_inited= 1; +} + static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), @@ -573,6 +615,37 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), case (int) OPT_TABLES: opt_databases=0; break; + case (int) OPT_IGNORE_TABLE: + { + const char* dot = strchr(argument, '.'); + if (!dot) + { + fprintf(stderr, "Illegal use of option --ignore-table=.\n"); + exit(1); + } + // len is always > 0 because we know the there exists a '.' + uint len= (uint)strlen(argument); + TABLE_RULE_ENT* e= (TABLE_RULE_ENT*)my_malloc(sizeof(TABLE_RULE_ENT) + + len, MYF(MY_WME)); + if (!e) + { + fprintf(stderr, "Internal memory allocation error\n"); + exit(1); + } + e->key= (char*)e + sizeof(TABLE_RULE_ENT); + e->key_len= len; + memcpy(e->key, argument, len); + + if (!ignore_table_inited) + init_table_rule_hash(&ignore_table, &ignore_table_inited); + + if(my_hash_insert(&ignore_table, (byte*)e)) + { + fprintf(stderr, "Internal hash insert error\n"); + exit(1); + } + break; + } case (int) OPT_COMPATIBLE: { char buff[255]; @@ -1946,6 +2019,15 @@ static int init_dumping(char *database) } /* init_dumping */ +my_bool include_table(byte* hash_key, uint len) +{ + if (ignore_table_inited && + hash_search(&ignore_table, (byte*) hash_key, len)) + return FALSE; + + return TRUE; +} + static int dump_all_tables_in_db(char *database) { @@ -1953,6 +2035,12 @@ static int dump_all_tables_in_db(char *database) uint numrows; char table_buff[NAME_LEN*2+3]; + char hash_key[2*NAME_LEN+2]; /* "db.tablename" */ + char *afterdot; + + afterdot= strmov(hash_key, database); + *afterdot++= '.'; + if (init_dumping(database)) return 1; if (opt_xml) @@ -1961,7 +2049,7 @@ static int dump_all_tables_in_db(char *database) { DYNAMIC_STRING query; 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, quote_name(table, table_buff, 1)); dynstr_append(&query, " READ /*!32311 LOCAL */,"); @@ -1977,13 +2065,17 @@ static int dump_all_tables_in_db(char *database) DBerror(sock, "when doing refresh"); /* We shall continue here, if --force was given */ } - while ((table = getTableName(0))) + while ((table= getTableName(0))) { - numrows = getTableStructure(table, database); - if (!dFlag && numrows > 0) - dumpTable(numrows,table); - my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); - order_by= 0; + char *end= strmov(afterdot, table); + if (include_table(hash_key, end - hash_key)) + { + numrows = getTableStructure(table, database); + if (!dFlag && numrows > 0) + dumpTable(numrows,table); + my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); + order_by= 0; + } } if (opt_xml) { diff --git a/mysql-test/r/mysqldump.result b/mysql-test/r/mysqldump.result index 57e04d38fc1..623bd2a0f3c 100644 --- a/mysql-test/r/mysqldump.result +++ b/mysql-test/r/mysqldump.result @@ -480,3 +480,36 @@ UNLOCK TABLES; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; DROP TABLE t1; +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (4),(5),(6); + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE="NO_AUTO_VALUE_ON_ZERO" */; +DROP TABLE IF EXISTS `t2`; +CREATE TABLE `t2` ( + `a` int(11) default NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1; + + +/*!40000 ALTER TABLE `t2` DISABLE KEYS */; +LOCK TABLES `t2` WRITE; +INSERT INTO `t2` VALUES (4),(5),(6); +UNLOCK TABLES; +/*!40000 ALTER TABLE `t2` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; + +DROP TABLE t1; +DROP TABLE t2; diff --git a/mysql-test/t/mysqldump.test b/mysql-test/t/mysqldump.test index 07b33689196..255ae50a8ca 100644 --- a/mysql-test/t/mysqldump.test +++ b/mysql-test/t/mysqldump.test @@ -153,3 +153,15 @@ INSERT INTO t1 VALUES (_latin1 ' --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=cp850 --compatible=mysql323 test t1 --exec $MYSQL_DUMP --character-sets-dir=$CHARSETSDIR --skip-comments --default-character-set=utf8 --compatible=mysql323 test t1 DROP TABLE t1; + +# +# WL #2319: Exclude Tables from dump +# + +CREATE TABLE t1 (a int); +CREATE TABLE t2 (a int); +INSERT INTO t1 VALUES (1),(2),(3); +INSERT INTO t2 VALUES (4),(5),(6); +--exec $MYSQL_DUMP --skip-comments --ignore-table=test.t1 test +DROP TABLE t1; +DROP TABLE t2;