diff options
Diffstat (limited to 'client/mysqldump.c')
-rw-r--r-- | client/mysqldump.c | 313 |
1 files changed, 300 insertions, 13 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c index 5ecf334c9f7..dc7527c9c73 100644 --- a/client/mysqldump.c +++ b/client/mysqldump.c @@ -50,6 +50,7 @@ #include "mysql.h" #include "mysql_version.h" #include "mysqld_error.h" +#include "../sql/ha_ndbcluster_tables.h" /* Exit codes */ @@ -95,7 +96,10 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_single_transaction=0, opt_comments= 0, opt_compact= 0, opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0, opt_complete_insert= 0, opt_drop_database= 0, - opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1; + opt_replace_into= 0, + opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1, + opt_events= 0, + opt_alltspcs=0; static ulong opt_max_allowed_packet, opt_net_buffer_length; static MYSQL mysql_connection,*mysql=0; static my_bool insert_pat_inited=0; @@ -132,7 +136,6 @@ static CHARSET_INFO *charset_info= &my_charset_latin1; const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace"; /* have we seen any VIEWs during table scanning? */ my_bool seen_views= 0; - const char *compatible_mode_names[]= { "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2", @@ -163,6 +166,10 @@ static struct my_option my_long_options[] = "Dump all the databases. This will be same as --databases with all databases selected.", (gptr*) &opt_alldbs, (gptr*) &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"all-tablespaces", 'Y', + "Dump all the tablespaces.", + (gptr*) &opt_alltspcs, (gptr*) &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, {"add-drop-database", OPT_DROP_DATABASE, "Add a 'DROP DATABASE' before each create.", (gptr*) &opt_drop_database, (gptr*) &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, @@ -227,6 +234,9 @@ static struct my_option my_long_options[] = {"disable-keys", 'K', "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER TABLE tb_name ENABLE KEYS */; will be put in the output.", (gptr*) &opt_disable_keys, (gptr*) &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"events", 'E', "Dump events.", + (gptr*) &opt_events, (gptr*) &opt_events, 0, GET_BOOL, + NO_ARG, 0, 0, 0, 0, 0, 0}, {"extended-insert", 'e', "Allows utilization of the new, much faster INSERT syntax.", (gptr*) &extended_insert, (gptr*) &extended_insert, 0, GET_BOOL, NO_ARG, @@ -343,6 +353,9 @@ static struct my_option my_long_options[] = {"quote-names",'Q', "Quote table and column names with backticks (`).", (gptr*) &opt_quoted, (gptr*) &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, + {"replace", OPT_MYSQL_REPLACE_INTO, "Use REPLACE INTO instead of INSERT INTO.", + (gptr*) &opt_replace_into, (gptr*) &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, + 0, 0}, {"result-file", 'r', "Direct output to a given file. This option should be used in MSDOS, because it prevents new line '\\n' from being converted to '\\r\\n' (carriage return + line feed).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, @@ -1260,9 +1273,136 @@ static void print_xml_row(FILE *xml_file, const char *row_name, check_io(xml_file); } + +/* + create_delimiter + Generate a new (null-terminated) string that does not exist in query + and is therefore suitable for use as a query delimiter. Store this + delimiter in delimiter_buff . + + This is quite simple in that it doesn't even try to parse statements as an + interpreter would. It merely returns a string that is not in the query, which + is much more than adequate for constructing a delimiter. + + RETURN + ptr to the delimiter on Success + NULL on Failure +*/ +static char *create_delimiter(char *query, char *delimiter_buff, + int delimiter_max_size) +{ + int proposed_length; + char *presence; + + delimiter_buff[0]= ';'; /* start with one semicolon, and */ + + for (proposed_length= 2; proposed_length < delimiter_max_size; + delimiter_max_size++) { + + delimiter_buff[proposed_length-1]= ';'; /* add semicolons, until */ + delimiter_buff[proposed_length]= '\0'; + + presence = strstr(query, delimiter_buff); + if (presence == NULL) { /* the proposed delimiter is not in the query. */ + return delimiter_buff; + } + + } + return NULL; /* but if we run out of space, return nothing at all. */ +} + + +/* + dump_events_for_db + -- retrieves list of events for a given db, and prints out + the CREATE EVENT statement into the output (the dump). + + RETURN + 0 Success + 1 Error +*/ +static uint dump_events_for_db(char *db) +{ + char query_buff[QUERY_LENGTH]; + char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; + char *event_name; + char delimiter[QUERY_LENGTH], *delimit_test; + FILE *sql_file= md_result_file; + MYSQL_RES *event_res, *event_list_res; + MYSQL_ROW row, event_list_row; + DBUG_ENTER("dump_events_for_db"); + DBUG_PRINT("enter", ("db: '%s'", db)); + + mysql_real_escape_string(sock, db_name_buff, db, strlen(db)); + + /* nice comments */ + if (opt_comments) + fprintf(sql_file, "\n--\n-- Dumping events for database '%s'\n--\n", db); + + /* + not using "mysql_query_with_error_report" because we may have not + enough privileges to lock mysql.events. + */ + if (lock_tables) + mysql_query(sock, "LOCK TABLES mysql.event READ"); + + if (mysql_query_with_error_report(sock, &event_list_res, "show events")) + { + safe_exit(EX_MYSQLERR); + DBUG_RETURN(0); + } + + strcpy(delimiter, ";"); + if (mysql_num_rows(event_list_res) > 0) + { + while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL) + { + event_name= quote_name(event_list_row[1], name_buff, 0); + DBUG_PRINT("info", ("retrieving CREATE EVENT for %s", name_buff)); + my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s", + event_name); + + if (mysql_query_with_error_report(sock, &event_res, query_buff)) + DBUG_RETURN(1); + + while ((row= mysql_fetch_row(event_res)) != NULL) + { + /* + if the user has EXECUTE privilege he can see event names, but not the + event body! + */ + if (strlen(row[2]) != 0) + { + if (opt_drop) + fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n", + event_name, delimiter); + + delimit_test= create_delimiter(row[2], delimiter, sizeof(delimiter)); + if (delimit_test == NULL) { + fprintf(stderr, "%s: Warning: Can't dump event '%s'\n", + event_name, my_progname); + DBUG_RETURN(1); + } + + fprintf(sql_file, "DELIMITER %s\n", delimiter); + fprintf(sql_file, "/*!50106 %s */ %s\n", row[2], delimiter); + } + } /* end of event printing */ + } /* end of list of events */ + fprintf(sql_file, "DELIMITER ;\n"); + mysql_free_result(event_res); + } + mysql_free_result(event_list_res); + + if (lock_tables) + VOID(mysql_query_with_error_report(sock, 0, "UNLOCK TABLES")); + DBUG_RETURN(0); +} + + /* dump_routines_for_db - -- retrievs list of routines for a given db, and prints out + -- retrieves list of routines for a given db, and prints out the CREATE PROCEDURE definition into the output (the dump). This function has logic to print the appropriate syntax depending on whether @@ -1275,7 +1415,7 @@ static void print_xml_row(FILE *xml_file, const char *row_name, static uint dump_routines_for_db(char *db) { - char query_buff[512]; + char query_buff[QUERY_LENGTH]; const char *routine_type[]= {"FUNCTION", "PROCEDURE"}; char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3]; char *routine_name; @@ -1316,9 +1456,9 @@ static uint dump_routines_for_db(char *db) while ((routine_list_row= mysql_fetch_row(routine_list_res))) { + routine_name= quote_name(routine_list_row[1], name_buff, 0); DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i], name_buff)); - routine_name= quote_name(routine_list_row[1], name_buff, 0); my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s", routine_type[i], routine_name); @@ -1430,8 +1570,8 @@ static uint get_table_structure(char *table, char *db, char *table_type, my_ulonglong num_fields; char *result_table, *opt_quoted_table; const char *insert_option; - char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; - char table_buff2[NAME_LEN*2+3], query_buff[512]; + char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3]; + char table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH]; FILE *sql_file = md_result_file; int len; MYSQL_RES *result; @@ -1639,7 +1779,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, */ if (write_data) { - dynstr_append_mem(&insert_pat, "INSERT ", 7); + if (opt_replace_into) + dynstr_append_mem(&insert_pat, "REPLACE ", 8); + else + dynstr_append_mem(&insert_pat, "INSERT ", 7); dynstr_append(&insert_pat, insert_option); dynstr_append_mem(&insert_pat, "INTO ", 5); dynstr_append(&insert_pat, opt_quoted_table); @@ -1710,7 +1853,10 @@ static uint get_table_structure(char *table, char *db, char *table_type, if (write_data) { - dynstr_append_mem(&insert_pat, "INSERT ", 7); + if (opt_replace_into) + dynstr_append_mem(&insert_pat, "REPLACE ", 8); + else + dynstr_append_mem(&insert_pat, "INSERT ", 7); dynstr_append(&insert_pat, insert_option); dynstr_append_mem(&insert_pat, "INTO ", 5); dynstr_append(&insert_pat, result_table); @@ -1927,7 +2073,7 @@ static void dump_triggers_for_table (char *table, char *db) { char *result_table; char name_buff[NAME_LEN*4+3], table_buff[NAME_LEN*2+3]; - char query_buff[512]; + char query_buff[QUERY_LENGTH]; uint old_opt_compatible_mode=opt_compatible_mode; FILE *sql_file = md_result_file; MYSQL_RES *result; @@ -2581,6 +2727,130 @@ static char *getTableName(int reset) } /* getTableName */ +/* + dump all logfile groups and tablespaces +*/ + +static int dump_all_tablespaces() +{ + MYSQL_ROW row; + MYSQL_RES *tableres; + char buf[FN_REFLEN]; + int first; + + if (mysql_query_with_error_report(sock, &tableres, + "SELECT DISTINCT" + " LOGFILE_GROUP_NAME," + " FILE_NAME," + " TOTAL_EXTENTS," + " INITIAL_SIZE," + " ENGINE" + " FROM INFORMATION_SCHEMA.FILES" + " WHERE FILE_TYPE = \"UNDO LOG\"" + " ORDER BY LOGFILE_GROUP_NAME")) + return 1; + + buf[0]= 0; + while ((row= mysql_fetch_row(tableres))) + { + if (strcmp(buf, row[0]) != 0) + first= 1; + if (first) + { + if (!opt_xml && opt_comments) + { + fprintf(md_result_file,"\n--\n-- Logfile group: %s\n--\n", row[0]); + check_io(md_result_file); + } + fprintf(md_result_file, "\nCREATE"); + } + else + { + fprintf(md_result_file, "\nALTER"); + } + fprintf(md_result_file, + " LOGFILE GROUP %s\n" + " ADD UNDOFILE '%s'\n", + row[0], + row[1]); + if (first) + { + fprintf(md_result_file, + " UNDO_BUFFER_SIZE %s\n", + row[2]); + } + fprintf(md_result_file, + " INITIAL_SIZE %s\n" + " ENGINE=%s;\n", + row[3], + row[4]); + check_io(md_result_file); + if (first) + { + first= 0; + strxmov(buf, row[0], NullS); + } + } + + if (mysql_query_with_error_report(sock, &tableres, + "SELECT DISTINCT" + " TABLESPACE_NAME," + " FILE_NAME," + " LOGFILE_GROUP_NAME," + " EXTENT_SIZE," + " INITIAL_SIZE," + " ENGINE" + " FROM INFORMATION_SCHEMA.FILES" + " WHERE FILE_TYPE = \"DATAFILE\"" + " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME")) + return 1; + + buf[0]= 0; + while ((row= mysql_fetch_row(tableres))) + { + if (strcmp(buf, row[0]) != 0) + first= 1; + if (first) + { + if (!opt_xml && opt_comments) + { + fprintf(md_result_file,"\n--\n-- Tablespace: %s\n--\n", row[0]); + check_io(md_result_file); + } + fprintf(md_result_file, "\nCREATE"); + } + else + { + fprintf(md_result_file, "\nALTER"); + } + fprintf(md_result_file, + " TABLESPACE %s\n" + " ADD DATAFILE '%s'\n", + row[0], + row[1]); + if (first) + { + fprintf(md_result_file, + " USE LOGFILE GROUP %s\n" + " EXTENT_SIZE %s\n", + row[2], + row[3]); + } + fprintf(md_result_file, + " INITIAL_SIZE %s\n" + " ENGINE=%s;\n", + row[4], + row[5]); + check_io(md_result_file); + if (first) + { + first= 0; + strxmov(buf, row[0], NullS); + } + } + return 0; +} + static int dump_all_databases() { MYSQL_ROW row; @@ -2725,6 +2995,8 @@ static int dump_all_tables_in_db(char *database) afterdot= strmov(hash_key, database); *afterdot++= '.'; + if (!strcmp(database, NDB_REP_DB)) /* Skip cluster internal database */ + return 0; if (init_dumping(database)) return 1; if (opt_xml) @@ -2762,6 +3034,12 @@ static int dump_all_tables_in_db(char *database) dump_triggers_for_table(table, database); } } + if (opt_events && !opt_xml && + mysql_get_server_version(sock) >= 50106) + { + DBUG_PRINT("info", ("Dumping events for database %s", database)); + dump_events_for_db(database); + } if (opt_routines && !opt_xml && mysql_get_server_version(mysql) >= 50009) { @@ -2909,11 +3187,11 @@ static int dump_selected_tables(char *db, char **table_names, int tables) DBUG_ENTER("dump_selected_tables"); if (init_dumping(db)) - return 1; + DBUG_RETURN(1); init_alloc_root(&root, 8192, 0); if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *)))) - exit(EX_EOM); + exit(EX_EOM); init_dynamic_string(&lock_tables_query, "LOCK TABLES ", 256, 1024); for (; tables > 0 ; tables-- , table_names++) @@ -2924,7 +3202,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables) /* Add found table name to lock_tables_query */ if (lock_tables) { - dynstr_append(&lock_tables_query, quote_name(*pos, table_buff, 1)); + dynstr_append(&lock_tables_query, quote_name(*pos, table_buff, 1)); dynstr_append(&lock_tables_query, " READ /*!32311 LOCAL */,"); } pos++; @@ -2972,6 +3250,12 @@ static int dump_selected_tables(char *db, char **table_names, int tables) for (pos= dump_tables; pos < end; pos++) get_view_structure(*pos, db); } + if (opt_events && !opt_xml && + mysql_get_server_version(sock) >= 50106) + { + DBUG_PRINT("info", ("Dumping events for database %s", db)); + dump_events_for_db(db); + } /* obtain dump of routines (procs/functions) */ if (opt_routines && !opt_xml && mysql_get_server_version(mysql) >= 50009) @@ -3576,6 +3860,9 @@ int main(int argc, char **argv) if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */ goto err; + if (opt_alltspcs) + dump_all_tablespaces(); + if (opt_alldbs) dump_all_databases(); else if (argc > 1 && !opt_databases) |