summaryrefslogtreecommitdiff
path: root/client/mysqldump.c
diff options
context:
space:
mode:
Diffstat (limited to 'client/mysqldump.c')
-rw-r--r--client/mysqldump.c600
1 files changed, 464 insertions, 136 deletions
diff --git a/client/mysqldump.c b/client/mysqldump.c
index 07afc3119b5..260a6e0113b 100644
--- a/client/mysqldump.c
+++ b/client/mysqldump.c
@@ -39,7 +39,7 @@
** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
*/
-#define DUMP_VERSION "10.14"
+#define DUMP_VERSION "10.15"
#include <my_global.h>
#include <my_sys.h>
@@ -87,14 +87,16 @@
/* Chars needed to store LONGLONG, excluding trailing '\0'. */
#define LONGLONG_LEN 20
+/* Max length GTID position that we will output. */
+#define MAX_GTID_LENGTH 1024
+
static void add_load_option(DYNAMIC_STRING *str, const char *option,
const char *option_value);
-static ulong find_set(TYPELIB *lib, const char *x, size_t length,
- char **err_pos, uint *err_len);
+static ulong find_set(TYPELIB *, const char *, size_t, char **, uint *);
static char *alloc_query_str(ulong size);
static void field_escape(DYNAMIC_STRING* in, const char *from);
-static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
+static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_no_data_med= 1,
quick= 1, extended_insert= 1,
lock_tables=1,ignore_errors=0,flush_logs=0,flush_privileges=0,
opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
@@ -134,10 +136,23 @@ static ulong opt_compatible_mode= 0;
#define MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL 2
static uint opt_mysql_port= 0, opt_master_data;
static uint opt_slave_data;
+static uint opt_use_gtid;
static uint my_end_arg;
static char * opt_mysql_unix_port=0;
static int first_error=0;
+/*
+ multi_source is 0 if old server or 2 if server that support multi source
+ This is choosen this was as multi_source has 2 extra columns first in
+ SHOW ALL SLAVES STATUS.
+*/
+static uint multi_source= 0;
static DYNAMIC_STRING extended_row;
+static DYNAMIC_STRING dynamic_where;
+static MYSQL_RES *get_table_name_result= NULL;
+static MEM_ROOT glob_root;
+static MYSQL_RES *routine_res, *routine_list_res;
+
+
#include <sslopt-vars.h>
FILE *md_result_file= 0;
FILE *stderror_file=0;
@@ -193,6 +208,8 @@ const char *compatible_mode_names[]=
TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
"", compatible_mode_names, NULL};
+#define MED_ENGINES "MRG_MyISAM, MRG_ISAM, CONNECT, OQGRAPH, SPIDER, VP, FEDERATED"
+
HASH ignore_table;
static struct my_option my_long_options[] =
@@ -226,8 +243,8 @@ static struct my_option my_long_options[] =
&opt_slave_apply, &opt_slave_apply, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
{"character-sets-dir", OPT_CHARSETS_DIR,
- "Directory for character set files.", (char**) &charsets_dir,
- (char**) &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
+ "Directory for character set files.", &charsets_dir,
+ &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"comments", 'i', "Write additional information.",
&opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG,
1, 0, 0, 0, 0, 0},
@@ -264,8 +281,8 @@ static struct my_option my_long_options[] =
{"debug", '#', "This is a non-debug version. Catch this and exit.",
0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
#else
- {"debug", '#', "Output debug log.", (char**) &default_dbug_option,
- (char**) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
+ {"debug", '#', "Output debug log.", &default_dbug_option,
+ &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
#endif
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
&debug_check_flag, &debug_check_flag, 0,
@@ -340,6 +357,13 @@ static struct my_option my_long_options[] =
{"force", 'f', "Continue even if we get an SQL error.",
&ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0},
+ {"gtid", OPT_USE_GTID, "Used together with --master-data=1 or --dump-slave=1."
+ "When enabled, the output from those options will set the GTID position "
+ "instead of the binlog file and offset; the file/offset will appear only as "
+ "a comment. When disabled, the GTID position will still appear in the "
+ "output, but only commented.",
+ &opt_use_gtid, &opt_use_gtid, 0, GET_BOOL, NO_ARG,
+ 0, 0, 0, 0, 0, 0},
{"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0},
{"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
@@ -412,6 +436,9 @@ static struct my_option my_long_options[] =
NO_ARG, 0, 0, 0, 0, 0, 0},
{"no-data", 'd', "No row information.", &opt_no_data,
&opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"no-data-med", 0, "No row information for engines that "
+ "Manage External Data (" MED_ENGINES ").", &opt_no_data_med,
+ &opt_no_data_med, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
{"no-set-names", 'N', "Same as --skip-set-charset.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"opt", OPT_OPTIMIZE,
@@ -889,7 +916,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
&err_ptr, &err_len);
if (err_len)
{
- strmake(buff, err_ptr, min(sizeof(buff) - 1, err_len));
+ strmake(buff, err_ptr, MY_MIN(sizeof(buff) - 1, err_len));
fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
exit(1);
}
@@ -1215,6 +1242,90 @@ check_consistent_binlog_pos(char *binlog_pos_file, char *binlog_pos_offset)
return (found == 2);
}
+
+/*
+ Get the GTID position corresponding to a given old-style binlog position.
+ This uses BINLOG_GTID_POS(). The advantage is that the GTID position can
+ be obtained completely non-blocking in this way (without the need for
+ FLUSH TABLES WITH READ LOCK), as the old-style position can be obtained
+ with START TRANSACTION WITH CONSISTENT SNAPSHOT.
+
+ Returns 0 if ok, non-zero if error.
+*/
+static int
+get_binlog_gtid_pos(char *binlog_pos_file, char *binlog_pos_offset,
+ char *out_gtid_pos)
+{
+ DYNAMIC_STRING query;
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int err;
+ char file_buf[FN_REFLEN*2+1], offset_buf[LONGLONG_LEN*2+1];
+ size_t len_pos_file= strlen(binlog_pos_file);
+ size_t len_pos_offset= strlen(binlog_pos_offset);
+
+ if (len_pos_file >= FN_REFLEN || len_pos_offset > LONGLONG_LEN)
+ return 0;
+ mysql_real_escape_string(mysql, file_buf, binlog_pos_file, len_pos_file);
+ mysql_real_escape_string(mysql, offset_buf, binlog_pos_offset, len_pos_offset);
+ init_dynamic_string_checked(&query, "SELECT BINLOG_GTID_POS('", 256, 1024);
+ dynstr_append_checked(&query, file_buf);
+ dynstr_append_checked(&query, "', '");
+ dynstr_append_checked(&query, offset_buf);
+ dynstr_append_checked(&query, "')");
+
+ err= mysql_query_with_error_report(mysql, &res, query.str);
+ dynstr_free(&query);
+ if (err)
+ return err;
+
+ err= 1;
+ if ((row= mysql_fetch_row(res)))
+ {
+ strmake(out_gtid_pos, row[0], MAX_GTID_LENGTH-1);
+ err= 0;
+ }
+ mysql_free_result(res);
+
+ return err;
+}
+
+
+/*
+ Get the GTID position on a master or slave.
+ The parameter MASTER is non-zero to get the position on a master
+ (@@gtid_binlog_pos) or zero for a slave (@@gtid_slave_pos).
+
+ This uses the @@gtid_binlog_pos or @@gtid_slave_pos, so requires FLUSH TABLES
+ WITH READ LOCK or similar to be consistent.
+
+ Returns 0 if ok, non-zero for error.
+*/
+static int
+get_gtid_pos(char *out_gtid_pos, int master)
+{
+ MYSQL_RES *res;
+ MYSQL_ROW row;
+ int found;
+
+ if (mysql_query_with_error_report(mysql, &res,
+ (master ?
+ "SELECT @@GLOBAL.gtid_binlog_pos" :
+ "SELECT @@GLOBAL.gtid_slave_pos")))
+ return 1;
+
+ found= 0;
+ if ((row= mysql_fetch_row(res)))
+ {
+ strmake(out_gtid_pos, row[0], MAX_GTID_LENGTH-1);
+ found++;
+ }
+ mysql_free_result(res);
+
+ return (found != 1);
+}
+
+
static char *my_case_str(const char *str,
size_t str_len,
const char *token,
@@ -1500,14 +1611,26 @@ static void free_resources()
{
if (md_result_file && md_result_file != stdout)
my_fclose(md_result_file, MYF(0));
+ if (get_table_name_result)
+ mysql_free_result(get_table_name_result);
+ if (routine_res)
+ mysql_free_result(routine_res);
+ if (routine_list_res)
+ mysql_free_result(routine_list_res);
+ if (mysql)
+ {
+ mysql_close(mysql);
+ mysql= 0;
+ }
+ my_free(order_by);
my_free(opt_password);
my_free(current_host);
+ free_root(&glob_root, MYF(0));
if (my_hash_inited(&ignore_table))
my_hash_free(&ignore_table);
- if (extended_insert)
- dynstr_free(&extended_row);
- if (insert_pat_inited)
- dynstr_free(&insert_pat);
+ dynstr_free(&extended_row);
+ dynstr_free(&dynamic_where);
+ dynstr_free(&insert_pat);
if (defaults_argv)
free_defaults(defaults_argv);
mysql_library_end();
@@ -1524,8 +1647,6 @@ static void maybe_exit(int error)
ignore_errors= 1; /* don't want to recurse, if something fails below */
if (opt_slave_data)
do_start_slave_sql(mysql);
- if (mysql)
- mysql_close(mysql);
free_resources();
exit(error);
}
@@ -1546,8 +1667,12 @@ static int connect_to_db(char *host, char *user,char *passwd)
mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
#ifdef HAVE_OPENSSL
if (opt_use_ssl)
+ {
mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
opt_ssl_capath, opt_ssl_cipher);
+ mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
+ mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
+ }
mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
(char*)&opt_ssl_verify_server_cert);
#endif
@@ -1565,6 +1690,9 @@ static int connect_to_db(char *host, char *user,char *passwd)
if (opt_default_auth && *opt_default_auth)
mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
+ mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
+ mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
+ "program_name", "mysqldump");
mysql= &mysql_connection; /* So we can mysql_close() it properly */
if (!mysql_real_connect(&mysql_connection,host,user,passwd,
NULL,opt_mysql_port,opt_mysql_unix_port, 0))
@@ -1611,6 +1739,7 @@ static void dbDisconnect(char *host)
{
verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
mysql_close(mysql);
+ mysql= 0;
} /* dbDisconnect */
@@ -2318,7 +2447,6 @@ static uint dump_routines_for_db(char *db)
char *routine_name;
int i;
FILE *sql_file= md_result_file;
- MYSQL_RES *routine_res, *routine_list_res;
MYSQL_ROW row, routine_list_row;
char db_cl_name[MY_CS_NAME_SIZE];
@@ -2374,7 +2502,11 @@ static uint dump_routines_for_db(char *db)
routine_type[i], routine_name);
if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
+ {
+ mysql_free_result(routine_list_res);
+ routine_list_res= 0;
DBUG_RETURN(1);
+ }
while ((row= mysql_fetch_row(routine_res)))
{
@@ -2392,7 +2524,8 @@ static uint dump_routines_for_db(char *db)
print_comment(sql_file, 1,
"-- does %s have permissions on mysql.proc?\n\n",
fix_for_comment(current_user));
- maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!", current_user, query_buff);
+ maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!",
+ current_user, query_buff);
}
else if (strlen(row[2]))
{
@@ -2415,6 +2548,9 @@ static uint dump_routines_for_db(char *db)
if (switch_db_collation(sql_file, db, ";",
db_cl_name, row[5], &db_cl_altered))
{
+ mysql_free_result(routine_res);
+ mysql_free_result(routine_list_res);
+ routine_res= routine_list_res= 0;
DBUG_RETURN(1);
}
@@ -2460,17 +2596,24 @@ static uint dump_routines_for_db(char *db)
if (db_cl_altered)
{
if (restore_db_collation(sql_file, db, ";", db_cl_name))
+ {
+ mysql_free_result(routine_res);
+ mysql_free_result(routine_list_res);
+ routine_res= routine_list_res= 0;
DBUG_RETURN(1);
+ }
}
}
}
} /* end of routine printing */
mysql_free_result(routine_res);
+ routine_res= 0;
} /* end of list of routines */
}
mysql_free_result(routine_list_res);
+ routine_list_res= 0;
} /* end of for i (0 .. 1) */
if (opt_xml)
@@ -2592,13 +2735,20 @@ static uint get_table_structure(char *table, char *db, char *table_type,
if (switch_character_set_results(mysql, "binary") ||
mysql_query_with_error_report(mysql, &result, buff) ||
switch_character_set_results(mysql, default_charset))
+ {
+ my_free(order_by);
+ order_by= 0;
DBUG_RETURN(0);
+ }
if (path)
{
if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
+ {
+ my_free(order_by);
+ order_by= 0;
DBUG_RETURN(0);
-
+ }
write_header(sql_file, db);
}
@@ -2667,6 +2817,8 @@ static uint get_table_structure(char *table, char *db, char *table_type,
my_free(scv_buff);
+ if (path)
+ my_fclose(sql_file, MYF(MY_WME));
DBUG_RETURN(0);
}
else
@@ -3168,10 +3320,6 @@ static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
continue;
}
- query_str= cover_definer_clause(row[2], strlen(row[2]),
- C_STRING_WITH_LEN("50017"),
- C_STRING_WITH_LEN("50003"),
- C_STRING_WITH_LEN(" TRIGGER"));
if (switch_db_collation(sql_file, db_name, ";",
db_cl_name, row[5], &db_cl_altered))
DBUG_RETURN(TRUE);
@@ -3183,12 +3331,18 @@ static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
switch_sql_mode(sql_file, ";", row[1]);
+ query_str= cover_definer_clause(row[2], strlen(row[2]),
+ C_STRING_WITH_LEN("50017"),
+ C_STRING_WITH_LEN("50003"),
+ C_STRING_WITH_LEN(" TRIGGER"));
fprintf(sql_file,
"DELIMITER ;;\n"
"/*!50003 %s */;;\n"
"DELIMITER ;\n",
(const char *) (query_str != NULL ? query_str : row[2]));
+ my_free(query_str);
+
restore_sql_mode(sql_file, ";");
restore_cs_variables(sql_file, ";");
@@ -3197,8 +3351,6 @@ static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
if (restore_db_collation(sql_file, db_name, ";", db_cl_name))
DBUG_RETURN(TRUE);
}
-
- my_free(query_str);
}
DBUG_RETURN(FALSE);
@@ -3289,13 +3441,14 @@ static int dump_triggers_for_table(char *table_name, char *db_name)
{
MYSQL_RES *show_create_trigger_rs= mysql_store_result(mysql);
- if (!show_create_trigger_rs ||
- dump_trigger(sql_file, show_create_trigger_rs, db_name, db_cl_name))
- goto done;
-
+ int error= (!show_create_trigger_rs ||
+ dump_trigger(sql_file, show_create_trigger_rs, db_name,
+ db_cl_name));
mysql_free_result(show_create_trigger_rs);
+ if (error)
+ goto done;
}
-
+
}
if (opt_xml)
@@ -3542,12 +3695,14 @@ static void dump_table(char *table, char *db)
{
dynstr_append_checked(&query_string, " ORDER BY ");
dynstr_append_checked(&query_string, order_by);
+ my_free(order_by);
+ order_by= 0;
}
if (mysql_real_query(mysql, query_string.str, query_string.length))
{
- DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
dynstr_free(&query_string);
+ DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
DBUG_VOID_RETURN;
}
}
@@ -3573,6 +3728,8 @@ static void dump_table(char *table, char *db)
dynstr_append_checked(&query_string, " ORDER BY ");
dynstr_append_checked(&query_string, order_by);
+ my_free(order_by);
+ order_by= 0;
}
if (!opt_xml && !opt_compact)
@@ -3582,6 +3739,7 @@ static void dump_table(char *table, char *db)
}
if (mysql_query_with_error_report(mysql, 0, query_string.str))
{
+ dynstr_free(&query_string);
DB_error(mysql, "when retrieving data from server");
goto err;
}
@@ -3591,6 +3749,7 @@ static void dump_table(char *table, char *db)
res=mysql_store_result(mysql);
if (!res)
{
+ dynstr_free(&query_string);
DB_error(mysql, "when retrieving data from server");
goto err;
}
@@ -3906,23 +4065,22 @@ err:
static char *getTableName(int reset)
{
- static MYSQL_RES *res= NULL;
- MYSQL_ROW row;
+ MYSQL_ROW row;
- if (!res)
+ if (!get_table_name_result)
{
- if (!(res= mysql_list_tables(mysql,NullS)))
+ if (!(get_table_name_result= mysql_list_tables(mysql,NullS)))
return(NULL);
}
- if ((row= mysql_fetch_row(res)))
+ if ((row= mysql_fetch_row(get_table_name_result)))
return((char*) row[0]);
if (reset)
- mysql_data_seek(res,0); /* We want to read again */
+ mysql_data_seek(get_table_name_result,0); /* We want to read again */
else
{
- mysql_free_result(res);
- res= NULL;
+ mysql_free_result(get_table_name_result);
+ get_table_name_result= NULL;
}
return(NULL);
} /* getTableName */
@@ -3939,46 +4097,44 @@ static int dump_all_tablespaces()
static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
{
- DYNAMIC_STRING where;
int r;
int i;
char name_buff[NAME_LEN*2+3];
mysql_real_escape_string(mysql, name_buff, db, (ulong)strlen(db));
- init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
+ init_dynamic_string_checked(&dynamic_where, " AND TABLESPACE_NAME IN ("
"SELECT DISTINCT TABLESPACE_NAME FROM"
" INFORMATION_SCHEMA.PARTITIONS"
" WHERE"
" TABLE_SCHEMA='", 256, 1024);
- dynstr_append_checked(&where, name_buff);
- dynstr_append_checked(&where, "' AND TABLE_NAME IN (");
+ dynstr_append_checked(&dynamic_where, name_buff);
+ dynstr_append_checked(&dynamic_where, "' AND TABLE_NAME IN (");
for (i=0 ; i<tables ; i++)
{
mysql_real_escape_string(mysql, name_buff,
table_names[i], (ulong)strlen(table_names[i]));
- dynstr_append_checked(&where, "'");
- dynstr_append_checked(&where, name_buff);
- dynstr_append_checked(&where, "',");
+ dynstr_append_checked(&dynamic_where, "'");
+ dynstr_append_checked(&dynamic_where, name_buff);
+ dynstr_append_checked(&dynamic_where, "',");
}
- dynstr_trunc(&where, 1);
- dynstr_append_checked(&where,"))");
+ dynstr_trunc(&dynamic_where, 1);
+ dynstr_append_checked(&dynamic_where,"))");
- DBUG_PRINT("info",("Dump TS for Tables where: %s",where.str));
- r= dump_tablespaces(where.str);
- dynstr_free(&where);
+ DBUG_PRINT("info",("Dump TS for Tables where: %s",dynamic_where.str));
+ r= dump_tablespaces(dynamic_where.str);
+ dynstr_free(&dynamic_where);
return r;
}
static int dump_tablespaces_for_databases(char** databases)
{
- DYNAMIC_STRING where;
int r;
int i;
- init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
+ init_dynamic_string_checked(&dynamic_where, " AND TABLESPACE_NAME IN ("
"SELECT DISTINCT TABLESPACE_NAME FROM"
" INFORMATION_SCHEMA.PARTITIONS"
" WHERE"
@@ -3989,16 +4145,16 @@ static int dump_tablespaces_for_databases(char** databases)
char db_name_buff[NAME_LEN*2+3];
mysql_real_escape_string(mysql, db_name_buff,
databases[i], (ulong)strlen(databases[i]));
- dynstr_append_checked(&where, "'");
- dynstr_append_checked(&where, db_name_buff);
- dynstr_append_checked(&where, "',");
+ dynstr_append_checked(&dynamic_where, "'");
+ dynstr_append_checked(&dynamic_where, db_name_buff);
+ dynstr_append_checked(&dynamic_where, "',");
}
- dynstr_trunc(&where, 1);
- dynstr_append_checked(&where,"))");
+ dynstr_trunc(&dynamic_where, 1);
+ dynstr_append_checked(&dynamic_where,"))");
- DBUG_PRINT("info",("Dump TS for DBs where: %s",where.str));
- r= dump_tablespaces(where.str);
- dynstr_free(&where);
+ DBUG_PRINT("info",("Dump TS for DBs where: %s",dynamic_where.str));
+ r= dump_tablespaces(dynamic_where.str);
+ dynstr_free(&dynamic_where);
return r;
}
@@ -4408,9 +4564,12 @@ static int dump_all_tables_in_db(char *database)
}
}
if (numrows && mysql_real_query(mysql, query.str, query.length-1))
+ {
+ dynstr_free(&query);
DB_error(mysql, "when using LOCK TABLES");
- /* We shall continue here, if --force was given */
- dynstr_free(&query);
+ /* We shall continue here, if --force was given */
+ }
+ dynstr_free(&query); /* Safe to call twice */
}
if (flush_logs)
{
@@ -4420,6 +4579,14 @@ static int dump_all_tables_in_db(char *database)
else
verbose_msg("-- dump_all_tables_in_db : logs flushed successfully!\n");
}
+ if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
+ {
+ verbose_msg("-- Setting savepoint...\n");
+ if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp"))
+ {
+ DBUG_RETURN(1);
+ }
+ }
while ((table= getTableName(0)))
{
char *end= strmov(afterdot, table);
@@ -4437,6 +4604,23 @@ static int dump_all_tables_in_db(char *database)
maybe_exit(EX_MYSQLERR);
}
}
+
+ /**
+ ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata
+ lock on table which was already dumped. This allows to avoid blocking
+ concurrent DDL on this table without sacrificing correctness, as we
+ won't access table second time and dumps created by --single-transaction
+ mode have validity point at the start of transaction anyway.
+ Note that this doesn't make --single-transaction mode with concurrent
+ DDL safe in general case. It just improves situation for people for whom
+ it might be working.
+ */
+ if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
+ {
+ verbose_msg("-- Rolling back to savepoint sp...\n");
+ if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp"))
+ maybe_exit(EX_MYSQLERR);
+ }
}
else
{
@@ -4459,6 +4643,14 @@ static int dump_all_tables_in_db(char *database)
}
}
}
+
+ if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
+ {
+ verbose_msg("-- Releasing savepoint...\n");
+ if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp"))
+ DBUG_RETURN(1);
+ }
+
if (opt_events && mysql_get_server_version(mysql) >= 50106)
{
DBUG_PRINT("info", ("Dumping events for database %s", database));
@@ -4628,22 +4820,22 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
{
char table_buff[NAME_LEN*2+3];
DYNAMIC_STRING lock_tables_query;
- MEM_ROOT root;
char **dump_tables, **pos, **end;
DBUG_ENTER("dump_selected_tables");
if (init_dumping(db, init_dumping_tables))
DBUG_RETURN(1);
- init_alloc_root(&root, 8192, 0);
- if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
+ init_alloc_root(&glob_root, 8192, 0, MYF(0));
+ if (!(dump_tables= pos= (char**) alloc_root(&glob_root,
+ tables * sizeof(char *))))
die(EX_EOM, "alloc_root failure.");
init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
for (; tables > 0 ; tables-- , table_names++)
{
/* the table name passed on commandline may be wrong case */
- if ((*pos= get_actual_table_name(*table_names, &root)))
+ if ((*pos= get_actual_table_name(*table_names, &glob_root)))
{
/* Add found table name to lock_tables_query */
if (lock_tables)
@@ -4658,7 +4850,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
if (!ignore_errors)
{
dynstr_free(&lock_tables_query);
- free_root(&root, MYF(0));
+ free_root(&glob_root, MYF(0));
}
maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names);
/* We shall countinue here, if --force was given */
@@ -4679,7 +4871,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
if (!ignore_errors)
{
dynstr_free(&lock_tables_query);
- free_root(&root, MYF(0));
+ free_root(&glob_root, MYF(0));
}
DB_error(mysql, "when doing LOCK TABLES");
/* We shall countinue here, if --force was given */
@@ -4691,7 +4883,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
if (mysql_refresh(mysql, REFRESH_LOG))
{
if (!ignore_errors)
- free_root(&root, MYF(0));
+ free_root(&glob_root, MYF(0));
DB_error(mysql, "when doing refresh");
}
/* We shall countinue here, if --force was given */
@@ -4701,12 +4893,23 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
if (opt_xml)
print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
+
/* obtain dump of routines (procs/functions) */
if (opt_routines && mysql_get_server_version(mysql) >= 50009)
{
DBUG_PRINT("info", ("Dumping routines for database %s", db));
dump_routines_for_db(db);
}
+
+ if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
+ {
+ verbose_msg("-- Setting savepoint...\n");
+ if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp"))
+ {
+ free_root(&glob_root, MYF(0));
+ DBUG_RETURN(1);
+ }
+ }
/* Dump each selected table */
for (pos= dump_tables; pos < end; pos++)
{
@@ -4719,9 +4922,42 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
{
if (path)
my_fclose(md_result_file, MYF(MY_WME));
+ if (!ignore_errors)
+ free_root(&glob_root, MYF(0));
maybe_exit(EX_MYSQLERR);
}
}
+
+ /**
+ ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata
+ lock on table which was already dumped. This allows to avoid blocking
+ concurrent DDL on this table without sacrificing correctness, as we
+ won't access table second time and dumps created by --single-transaction
+ mode have validity point at the start of transaction anyway.
+ Note that this doesn't make --single-transaction mode with concurrent
+ DDL safe in general case. It just improves situation for people for whom
+ it might be working.
+ */
+ if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
+ {
+ verbose_msg("-- Rolling back to savepoint sp...\n");
+ if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp"))
+ {
+ if (!ignore_errors)
+ free_root(&glob_root, MYF(0));
+ maybe_exit(EX_MYSQLERR);
+ }
+ }
+ }
+
+ if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
+ {
+ verbose_msg("-- Releasing savepoint...\n");
+ if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp"))
+ {
+ free_root(&glob_root, MYF(0));
+ DBUG_RETURN(1);
+ }
}
/* Dump each selected view */
@@ -4735,9 +4971,7 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
DBUG_PRINT("info", ("Dumping events for database %s", db));
dump_events_for_db(db);
}
- free_root(&root, MYF(0));
- my_free(order_by);
- order_by= 0;
+ free_root(&glob_root, MYF(0));
if (opt_xml)
{
fputs("</database>\n", md_result_file);
@@ -4749,12 +4983,14 @@ static int dump_selected_tables(char *db, char **table_names, int tables)
} /* dump_selected_tables */
-static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos)
+static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos,
+ int have_mariadb_gtid, int use_gtid)
{
MYSQL_ROW row;
MYSQL_RES *UNINIT_VAR(master);
char binlog_pos_file[FN_REFLEN];
char binlog_pos_offset[LONGLONG_LEN+1];
+ char gtid_pos[MAX_GTID_LENGTH];
char *file, *offset;
const char *comment_prefix=
(opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
@@ -4765,10 +5001,14 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos)
return 1;
file= binlog_pos_file;
offset= binlog_pos_offset;
+ if (have_mariadb_gtid &&
+ get_binlog_gtid_pos(binlog_pos_file, binlog_pos_offset, gtid_pos))
+ return 1;
}
else
{
- if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
+ if (mysql_query_with_error_report(mysql_con, &master,
+ "SHOW MASTER STATUS"))
return 1;
row= mysql_fetch_row(master);
@@ -4793,6 +5033,9 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos)
return 0;
}
}
+
+ if (have_mariadb_gtid && get_gtid_pos(gtid_pos, 1))
+ return 1;
}
/* SHOW MASTER STATUS reports file and position */
@@ -4801,7 +5044,19 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos)
"recovery from\n--\n\n");
fprintf(md_result_file,
"%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
- comment_prefix, file, offset);
+ (use_gtid ? "-- " : comment_prefix), file, offset);
+ if (have_mariadb_gtid)
+ {
+ print_comment(md_result_file, 0,
+ "\n--\n-- GTID to start replication from\n--\n\n");
+ if (use_gtid)
+ fprintf(md_result_file,
+ "%sCHANGE MASTER TO MASTER_USE_GTID=slave_pos;\n",
+ comment_prefix);
+ fprintf(md_result_file,
+ "%sSET GLOBAL gtid_slave_pos='%s';\n",
+ (!use_gtid ? "-- " : comment_prefix), gtid_pos);
+ }
check_io(md_result_file);
if (!consistent_binlog_pos)
@@ -4813,29 +5068,37 @@ static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos)
static int do_stop_slave_sql(MYSQL *mysql_con)
{
MYSQL_RES *slave;
- /* We need to check if the slave sql is running in the first place */
- if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
+ MYSQL_ROW row;
+
+ if (mysql_query_with_error_report(mysql_con, &slave,
+ multi_source ?
+ "SHOW ALL SLAVES STATUS" :
+ "SHOW SLAVE STATUS"))
return(1);
- else
+
+ /* Loop over all slaves */
+ while ((row= mysql_fetch_row(slave)))
{
- MYSQL_ROW row= mysql_fetch_row(slave);
- if (row && row[11])
+ if (row[11 + multi_source])
{
/* if SLAVE SQL is not running, we don't stop it */
- if (!strcmp(row[11],"No"))
+ if (strcmp(row[11 + multi_source], "No"))
{
- mysql_free_result(slave);
- /* Silently assume that they don't have the slave running */
- return(0);
+ char query[160];
+ if (multi_source)
+ sprintf(query, "STOP SLAVE '%.80s' SQL_THREAD", row[0]);
+ else
+ strmov(query, "STOP SLAVE SQL_THREAD");
+
+ if (mysql_query_with_error_report(mysql_con, 0, query))
+ {
+ mysql_free_result(slave);
+ return 1;
+ }
}
}
}
mysql_free_result(slave);
-
- /* now, stop slave if running */
- if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
- return(1);
-
return(0);
}
@@ -4844,7 +5107,10 @@ static int add_stop_slave(void)
if (opt_comments)
fprintf(md_result_file,
"\n--\n-- stop slave statement to make a recovery dump)\n--\n\n");
- fprintf(md_result_file, "STOP SLAVE;\n");
+ if (multi_source)
+ fprintf(md_result_file, "STOP ALL SLAVES;\n");
+ else
+ fprintf(md_result_file, "STOP SLAVE;\n");
return(0);
}
@@ -4853,16 +5119,28 @@ static int add_slave_statements(void)
if (opt_comments)
fprintf(md_result_file,
"\n--\n-- start slave statement to make a recovery dump)\n--\n\n");
- fprintf(md_result_file, "START SLAVE;\n");
+ if (multi_source)
+ fprintf(md_result_file, "START ALL SLAVES;\n");
+ else
+ fprintf(md_result_file, "START SLAVE;\n");
return(0);
}
-static int do_show_slave_status(MYSQL *mysql_con)
+static int do_show_slave_status(MYSQL *mysql_con, int use_gtid,
+ int have_mariadb_gtid)
{
- MYSQL_RES *slave= 0;
+ MYSQL_RES *UNINIT_VAR(slave);
+ MYSQL_ROW row;
const char *comment_prefix=
(opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "";
- if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
+ const char *gtid_comment_prefix= (use_gtid ? comment_prefix : "-- ");
+ const char *nogtid_comment_prefix= (!use_gtid ? comment_prefix : "-- ");
+ int set_gtid_done= 0;
+
+ if (mysql_query_with_error_report(mysql_con, &slave,
+ multi_source ?
+ "SHOW ALL SLAVES STATUS" :
+ "SHOW SLAVE STATUS"))
{
if (!ignore_errors)
{
@@ -4872,65 +5150,103 @@ static int do_show_slave_status(MYSQL *mysql_con)
mysql_free_result(slave);
return 1;
}
- else
+
+ while ((row= mysql_fetch_row(slave)))
{
- MYSQL_ROW row= mysql_fetch_row(slave);
- if (row && row[9] && row[21])
+ if (multi_source && !set_gtid_done)
{
+ char gtid_pos[MAX_GTID_LENGTH];
+ if (have_mariadb_gtid && get_gtid_pos(gtid_pos, 0))
+ return 1;
+ if (opt_comments)
+ fprintf(md_result_file, "\n--\n-- Gtid position to start replication "
+ "from\n--\n\n");
+ fprintf(md_result_file, "%sSET GLOBAL gtid_slave_pos='%s';\n",
+ gtid_comment_prefix, gtid_pos);
+ set_gtid_done= 1;
+ }
+ if (row[9 + multi_source] && row[21 + multi_source])
+ {
+ if (use_gtid)
+ {
+ if (multi_source)
+ fprintf(md_result_file, "%sCHANGE MASTER '%.80s' TO "
+ "MASTER_USE_GTID=slave_pos;\n", gtid_comment_prefix, row[0]);
+ else
+ fprintf(md_result_file, "%sCHANGE MASTER TO "
+ "MASTER_USE_GTID=slave_pos;\n", gtid_comment_prefix);
+ }
+
/* SHOW MASTER STATUS reports file and position */
if (opt_comments)
fprintf(md_result_file,
"\n--\n-- Position to start replication or point-in-time "
"recovery from (the master of this slave)\n--\n\n");
- fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix);
-
+ if (multi_source)
+ fprintf(md_result_file, "%sCHANGE MASTER '%.80s' TO ",
+ nogtid_comment_prefix, row[0]);
+ else
+ fprintf(md_result_file, "%sCHANGE MASTER TO ", nogtid_comment_prefix);
+
if (opt_include_master_host_port)
{
- if (row[1])
- fprintf(md_result_file, "MASTER_HOST='%s', ", row[1]);
+ if (row[1 + multi_source])
+ fprintf(md_result_file, "MASTER_HOST='%s', ", row[1 + multi_source]);
if (row[3])
- fprintf(md_result_file, "MASTER_PORT=%s, ", row[3]);
+ fprintf(md_result_file, "MASTER_PORT=%s, ", row[3 + multi_source]);
}
fprintf(md_result_file,
- "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]);
+ "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
+ row[9 + multi_source], row[21 + multi_source]);
check_io(md_result_file);
}
- mysql_free_result(slave);
}
+ mysql_free_result(slave);
return 0;
}
static int do_start_slave_sql(MYSQL *mysql_con)
{
MYSQL_RES *slave;
+ MYSQL_ROW row;
+ int error= 0;
+ DBUG_ENTER("do_start_slave_sql");
+
/* We need to check if the slave sql is stopped in the first place */
- if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
- return(1);
- else
+ if (mysql_query_with_error_report(mysql_con, &slave,
+ multi_source ?
+ "SHOW ALL SLAVES STATUS" :
+ "SHOW SLAVE STATUS"))
+ DBUG_RETURN(1);
+
+ while ((row= mysql_fetch_row(slave)))
{
- MYSQL_ROW row= mysql_fetch_row(slave);
- if (row && row[11])
+ DBUG_PRINT("info", ("Connection: '%s' status: '%s'",
+ multi_source ? row[0] : "", row[11 + multi_source]));
+ if (row[11 + multi_source])
{
/* if SLAVE SQL is not running, we don't start it */
- if (!strcmp(row[11],"Yes"))
+ if (strcmp(row[11 + multi_source], "Yes"))
{
- mysql_free_result(slave);
- /* Silently assume that they don't have the slave running */
- return(0);
+ char query[160];
+ if (multi_source)
+ sprintf(query, "START SLAVE '%.80s'", row[0]);
+ else
+ strmov(query, "START SLAVE");
+
+ if (mysql_query_with_error_report(mysql_con, 0, query))
+ {
+ fprintf(stderr, "%s: Error: Unable to start slave '%s'\n",
+ my_progname_short, multi_source ? row[0] : "");
+ error= 1;
+ }
}
}
}
mysql_free_result(slave);
-
- /* now, start slave if stopped */
- if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE"))
- {
- fprintf(stderr, "%s: Error: Unable to start slave\n", my_progname_short);
- return 1;
- }
- return(0);
+ DBUG_RETURN(error);
}
@@ -4944,12 +5260,13 @@ static int do_flush_tables_read_lock(MYSQL *mysql_con)
FLUSH TABLES is to lower the probability of a stage where both mysqldump
and most client connections are stalled. Of course, if a second long
update starts between the two FLUSHes, we have that bad stall.
+
+ We use the LOCAL option, as we do not want the FLUSH TABLES replicated to
+ other servers.
*/
return
- ( mysql_query_with_error_report(mysql_con, 0,
- ((opt_master_data != 0) ?
- "FLUSH /*!40101 LOCAL */ TABLES" :
- "FLUSH TABLES")) ||
+ ( mysql_query_with_error_report(mysql_con, 0,
+ "FLUSH /*!40101 LOCAL */ TABLES") ||
mysql_query_with_error_report(mysql_con, 0,
"FLUSH TABLES WITH READ LOCK") );
}
@@ -5054,9 +5371,9 @@ static ulong find_set(TYPELIB *lib, const char *x, size_t length,
for (; pos != end && *pos != ','; pos++) ;
var_len= (uint) (pos - start);
- strmake(buff, start, min(sizeof(buff) - 1, var_len));
+ strmake(buff, start, MY_MIN(sizeof(buff) - 1, var_len));
find= find_type(buff, lib, FIND_TYPE_BASIC);
- if (!find)
+ if (find <= 0)
{
*err_pos= (char*) start;
*err_len= var_len;
@@ -5178,11 +5495,12 @@ char check_if_ignore_table(const char *table_name, char *table_type)
/*
If these two types, we do want to skip dumping the table
*/
- if (!opt_no_data &&
- (!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") ||
- !strcmp(table_type,"MRG_ISAM") ||
- !strcmp(table_type,"FEDERATED")))
- result= IGNORE_DATA;
+ if (!opt_no_data && opt_no_data_med)
+ {
+ const char *found= strstr(" " MED_ENGINES ",", table_type);
+ if (found && found[-1] == ' ' && found[strlen(table_type)] == ',')
+ result= IGNORE_DATA;
+ }
}
mysql_free_result(res);
DBUG_RETURN(result);
@@ -5511,8 +5829,7 @@ static my_bool get_view_structure(char *table, char* db)
dynstr_free(&ds_view);
}
- if (switch_character_set_results(mysql, default_charset))
- DBUG_RETURN(1);
+ switch_character_set_results(mysql, default_charset);
/* If a separate .sql file was opened, close it now */
if (sql_file != md_result_file)
@@ -5569,6 +5886,7 @@ int main(int argc, char **argv)
char bin_log_name[FN_REFLEN];
int exit_code;
int consistent_binlog_pos= 0;
+ int have_mariadb_gtid= 0;
MY_INIT(argv[0]);
sf_leaking_memory=1; /* don't report memory leaks on early exits */
@@ -5607,6 +5925,13 @@ int main(int argc, char **argv)
if (!path)
write_header(md_result_file, *argv);
+ /* Check if the server support multi source */
+ if (mysql_get_server_version(mysql) >= 100000)
+ {
+ multi_source= 2;
+ have_mariadb_gtid= 1;
+ }
+
if (opt_slave_data && do_stop_slave_sql(mysql))
goto err;
@@ -5652,9 +5977,12 @@ int main(int argc, char **argv)
/* Add 'STOP SLAVE to beginning of dump */
if (opt_slave_apply && add_stop_slave())
goto err;
- if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos))
+
+ if (opt_master_data && do_show_master_status(mysql, consistent_binlog_pos,
+ have_mariadb_gtid, opt_use_gtid))
goto err;
- if (opt_slave_data && do_show_slave_status(mysql))
+ if (opt_slave_data && do_show_slave_status(mysql, opt_use_gtid,
+ have_mariadb_gtid))
goto err;
if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
goto err;