diff options
Diffstat (limited to 'client/mysqldump.c')
-rw-r--r-- | client/mysqldump.c | 295 |
1 files changed, 233 insertions, 62 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c index 907b6233590..5705571777a 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' */ @@ -142,14 +143,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[] = @@ -476,7 +469,10 @@ static void write_header(FILE *sql_file, char *db_name) if (opt_xml) { fputs("<?xml version=\"1.0\"?>\n", sql_file); - fputs("<mysqldump>\n", sql_file); + fputs("<mysqldump ", sql_file); + fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", + sql_file); + fputs(">\n", sql_file); check_io(sql_file); } else if (!opt_compact) @@ -543,30 +539,29 @@ static void write_footer(FILE *sql_file) } } /* write_footer */ +static void free_table_ent(char *key) -static void free_table_ent(TABLE_RULE_ENT* e) { - my_free((gptr) e, MYF(0)); + my_free((gptr) key, 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, + (hash_free_key) free_table_ent, 0)) exit(EX_EOM); } - static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) @@ -639,25 +634,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; } @@ -828,7 +813,8 @@ static void DB_error(MYSQL *mysql, const char *when) SYNOPSIS mysql_query_with_error_report() mysql_con connection to use - res if non zero, result will be put there with mysql_store_result + res if non zero, result will be put there with + mysql_store_result() query query to send to server RETURN VALUES @@ -981,14 +967,41 @@ static char *quote_name(const char *name, char *buff, my_bool force) } /* 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) { char *to= buff; *to++= '\''; while (*name) { - if (*name == '\'' || *name == '_' || *name == '\\' || *name == '%') + if (*name == '\\') + { + *to++='\\'; + *to++='\\'; + *to++='\\'; + } + else if (*name == '\'' || *name == '_' || *name == '%') *to++= '\\'; *to++= *name++; } @@ -1074,6 +1087,40 @@ static void print_xml_tag1(FILE * xml_file, const char* sbeg, /* + Print xml tag with for a field that is null + + SYNOPSIS + print_xml_null_tag() + xml_file - output file + sbeg - line beginning + stag_atr - tag and attribute + sval - value of attribute + send - line ending + + DESCRIPTION + Print tag with one attribute to the xml_file. Format is: + <stag_atr="sval" xsi:nil="true"/> + NOTE + sval MUST be a NULL terminated string. + sval string will be qouted before output. +*/ + +static void print_xml_null_tag(FILE * xml_file, const char* sbeg, + const char* stag_atr, const char* sval, + const char* send) +{ + fputs(sbeg, xml_file); + fputs("<", xml_file); + fputs(stag_atr, xml_file); + fputs("\"", xml_file); + print_quoted_xml(xml_file, sval, strlen(sval)); + fputs("\" xsi:nil=\"true\" />", xml_file); + fputs(send, xml_file); + check_io(xml_file); +} + + +/* Print xml tag with many attributes. SYNOPSIS @@ -1139,6 +1186,7 @@ static uint get_table_structure(char *table, char *db) FILE *sql_file = md_result_file; int len; DBUG_ENTER("get_table_structure"); + DBUG_PRINT("enter", ("db: %s, table: %s", db, table)); if (!insert_pat_inited) { @@ -1212,7 +1260,54 @@ static uint get_table_structure(char *table, char *db) if (strcmp(field->name, "View") == 0) { if (verbose) - fprintf(stderr, "-- It's a view, skipped\n"); + fprintf(stderr, "-- It's a view, create dummy table for view\n"); + + mysql_free_result(tableRes); + + /* Create a dummy table for the view. ie. a table which has the + same columns as the view should have. This table is dropped + just before the view is created. The table is used to handle the + case where a view references another view, which hasn't yet been + created(during the load of the dump). BUG#10927 */ + + /* Create temp table by selecting from the view */ + my_snprintf(query_buff, sizeof(query_buff), + "CREATE TEMPORARY TABLE %s SELECT * FROM %s WHERE 0", + result_table, result_table); + if (mysql_query_with_error_report(sock, 0, query_buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + + /* Get CREATE statement for the temp table */ + my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE TABLE %s", + result_table); + if (mysql_query_with_error_report(sock, 0, query_buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + tableRes= mysql_store_result(sock); + row= mysql_fetch_row(tableRes); + + if (opt_drop) + fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n",opt_quoted_table); + + /* Print CREATE statement but remove TEMPORARY */ + fprintf(sql_file, "CREATE %s;\n", row[1]+17); + check_io(sql_file); + + mysql_free_result(tableRes); + + /* Drop the temp table */ + my_snprintf(buff, sizeof(buff), + "DROP TEMPORARY TABLE %s", result_table); + if (mysql_query_with_error_report(sock, 0, buff)) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } was_views= 1; DBUG_RETURN(0); } @@ -1592,6 +1687,26 @@ static void dump_table(uint numFields, char *table) const char *table_type; int error= 0; + /* Check --no-data flag */ + if (dFlag) + { + if (verbose) + fprintf(stderr, + "-- Skipping dump data for table '%s', --no-data was used\n", + table); + return; + } + + /* Check that there are any fields in the table */ + if (numFields == 0) + { + if (verbose) + fprintf(stderr, + "-- Skipping dump data for table '%s', it has no fields\n", + table); + return; + } + result_table= quote_name(table,table_buff, 1); opt_quoted_table= quote_name(table, table_buff2, 0); @@ -1912,7 +2027,14 @@ static void dump_table(uint numFields, char *table) } } else - fputs("NULL", md_result_file); + { + /* The field value is NULL */ + if (!opt_xml) + fputs("NULL", md_result_file); + else + print_xml_null_tag(md_result_file, "\t\t", "field name=", + field->name, "\n"); + } check_io(md_result_file); } } @@ -2201,8 +2323,7 @@ static int dump_all_tables_in_db(char *database) if (include_table(hash_key, end - hash_key)) { numrows = get_table_structure(table, database); - if (!dFlag && numrows > 0) - dump_table(numrows,table); + dump_table(numrows,table); my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); order_by= 0; } @@ -2327,27 +2448,61 @@ static int get_actual_table_name(const char *old_table_name, static int dump_selected_tables(char *db, char **table_names, int tables) { - uint numrows; - int i; + uint numrows, i; char table_buff[NAME_LEN*+3]; + char new_table_name[NAME_LEN]; + DYNAMIC_STRING lock_tables_query; + HASH dump_tables; + char *table_name; + 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, (hash_free_key) free_table_ent, + 0)) + exit(EX_EOM); + + init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024); + for (; tables > 0 ; tables-- , table_names++) { - DYNAMIC_STRING query; + /* the table name passed on commandline may be wrong case */ + if (!get_actual_table_name(*table_names, + new_table_name, sizeof(new_table_name))) + { + /* 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 */,"); + } - init_dynamic_string(&query, "LOCK TABLES ", 256, 1024); - for (i=0 ; i < tables ; i++) + /* 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); + + } + else { - dynstr_append(&query, quote_name(table_names[i], table_buff, 1)); - dynstr_append(&query, " READ /*!32311 LOCAL */,"); + 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 (mysql_real_query(sock, query.str, query.length-1)) + } + + if (lock_tables) + { + if (mysql_real_query(sock, lock_tables_query.str, + lock_tables_query.length-1)) DB_error(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)) @@ -2356,25 +2511,28 @@ 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 (i=0 ; i < tables ; i++) - { - char new_table_name[NAME_LEN]; - /* the table name passed on commandline may be wrong case */ - if (!get_actual_table_name( table_names[i], new_table_name, - sizeof(new_table_name))) - { - numrows= get_table_structure(new_table_name, db); - dump_table(numrows, new_table_name); - } - my_free(order_by, MYF(MY_ALLOW_ZERO_PTR)); - order_by= 0; + /* Dump each selected table */ + for (i= 0; i < dump_tables.records; i++) + { + table_name= hash_element(&dump_tables, i); + DBUG_PRINT("info",("Dumping table %s", table_name)); + numrows= get_table_structure(table_name, db); + dump_table(numrows, table_name); } + + /* Dump each selected view */ if (was_views) { - for (i=0 ; i < tables ; i++) - get_view_structure(table_names[i], db); + for(i=0; i < dump_tables.records; i++) + { + table_name= hash_element(&dump_tables, i); + get_view_structure(table_name, db); + } } + 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); @@ -2382,7 +2540,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 */ @@ -2403,6 +2561,7 @@ static int do_show_master_status(MYSQL *mysql_con) row = mysql_fetch_row(master); if (row && row[0] && row[1]) { + /* SHOW MASTER STATUS reports file and position */ if (opt_comments) fprintf(md_result_file, "\n--\n-- Position to start replication or point-in-time " @@ -2412,6 +2571,14 @@ static int do_show_master_status(MYSQL *mysql_con) comment_prefix, row[0], row[1]); check_io(md_result_file); } + else if (!ignore_errors) + { + /* SHOW MASTER STATUS reports nothing and --force is not enabled */ + my_printf_error(0, "Error: Binlogging on server not active", + MYF(0), mysql_error(mysql_con)); + mysql_free_result(master); + return 1; + } mysql_free_result(master); } return 0; @@ -2752,6 +2919,7 @@ static my_bool get_view_structure(char *table, char* db) } if (opt_drop) { + fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table); fprintf(sql_file, "DROP VIEW IF EXISTS %s;\n", opt_quoted_table); check_io(sql_file); } @@ -2775,8 +2943,9 @@ int main(int argc, char **argv) { compatible_mode_normal_str[0]= 0; default_charset= (char *)mysql_universal_client_charset; + bzero((char*) &ignore_table, sizeof(ignore_table)); - MY_INIT(argv[0]); + MY_INIT("mysqldump"); if (get_options(&argc, &argv)) { my_end(0); @@ -2833,6 +3002,8 @@ err: if (md_result_file != stdout) my_fclose(md_result_file, MYF(0)); my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); + if (hash_inited(&ignore_table)) + hash_free(&ignore_table); if (extended_insert) dynstr_free(&extended_row); if (insert_pat_inited) |