Commit f45f6063 authored by rmfalves's avatar rmfalves Committed by Daniel Black

MDEV-22200: maridb-dump add --header option

This adds a header row in txt files exported by mariadb-dump --tab

Reviewed by: Daniel Black and Dan Lenski
parent baf276e6
...@@ -129,6 +129,7 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_no_data_m ...@@ -129,6 +129,7 @@ static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0, opt_no_data_m
opt_include_master_host_port= 0, opt_include_master_host_port= 0,
opt_events= 0, opt_comments_used= 0, opt_events= 0, opt_comments_used= 0,
opt_alltspcs=0, opt_notspcs= 0, opt_logging, opt_alltspcs=0, opt_notspcs= 0, opt_logging,
opt_header=0,
opt_drop_trigger= 0; opt_drop_trigger= 0;
#define OPT_SYSTEM_ALL 1 #define OPT_SYSTEM_ALL 1
#define OPT_SYSTEM_USERS 2 #define OPT_SYSTEM_USERS 2
...@@ -150,7 +151,7 @@ static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0, ...@@ -150,7 +151,7 @@ static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0,
static ulong opt_max_allowed_packet, opt_net_buffer_length; static ulong opt_max_allowed_packet, opt_net_buffer_length;
static double opt_max_statement_time= 0.0; static double opt_max_statement_time= 0.0;
static MYSQL mysql_connection,*mysql=0; static MYSQL mysql_connection,*mysql=0;
static DYNAMIC_STRING insert_pat, select_field_names; static DYNAMIC_STRING insert_pat, select_field_names, select_field_names_for_header;
static char *opt_password=0,*current_user=0, static char *opt_password=0,*current_user=0,
*current_host=0,*path=0,*fields_terminated=0, *current_host=0,*path=0,*fields_terminated=0,
*lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0, *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
...@@ -412,6 +413,8 @@ static struct my_option my_long_options[] = ...@@ -412,6 +413,8 @@ static struct my_option my_long_options[] =
"output, but only commented.", "output, but only commented.",
&opt_use_gtid, &opt_use_gtid, 0, GET_BOOL, NO_ARG, &opt_use_gtid, &opt_use_gtid, 0, GET_BOOL, NO_ARG,
0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0, 0},
{"header", 0, "Used together with --tab. When enabled, adds header with column names to the top of output txt files.",
&opt_header, &opt_header, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG, {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 0, 0, 0, 0, 0, 0}, NO_ARG, 0, 0, 0, 0, 0, 0},
{"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, " {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
...@@ -1297,6 +1300,12 @@ static int get_options(int *argc, char ***argv) ...@@ -1297,6 +1300,12 @@ static int get_options(int *argc, char ***argv)
"%s: You must use option --tab with --fields-...\n", my_progname_short); "%s: You must use option --tab with --fields-...\n", my_progname_short);
return(EX_USAGE); return(EX_USAGE);
} }
if (!path && opt_header)
{
fprintf(stderr,
"%s: You must use option --tab with --header\n", my_progname_short);
return(EX_USAGE);
}
/* We don't delete master logs if slave data option */ /* We don't delete master logs if slave data option */
if (opt_slave_data) if (opt_slave_data)
...@@ -1952,6 +1961,7 @@ static void free_resources() ...@@ -1952,6 +1961,7 @@ static void free_resources()
dynstr_free(&dynamic_where); dynstr_free(&dynamic_where);
dynstr_free(&insert_pat); dynstr_free(&insert_pat);
dynstr_free(&select_field_names); dynstr_free(&select_field_names);
dynstr_free(&select_field_names_for_header);
if (defaults_argv) if (defaults_argv)
free_defaults(defaults_argv); free_defaults(defaults_argv);
mysql_library_end(); mysql_library_end();
...@@ -2092,7 +2102,7 @@ static my_bool test_if_special_chars(const char *str) ...@@ -2092,7 +2102,7 @@ static my_bool test_if_special_chars(const char *str)
/* /*
quote_name(name, buff, force) quote(name, buff, force, quote_c)
Quotes a string, if it requires quoting. To force quoting regardless Quotes a string, if it requires quoting. To force quoting regardless
of the characters within the string, the force flag can be set to true. of the characters within the string, the force flag can be set to true.
...@@ -2102,16 +2112,17 @@ static my_bool test_if_special_chars(const char *str) ...@@ -2102,16 +2112,17 @@ static my_bool test_if_special_chars(const char *str)
name Unquoted string containing that which will be quoted name Unquoted string containing that which will be quoted
buff The buffer that contains the quoted value, also returned buff The buffer that contains the quoted value, also returned
force Flag to make it ignore 'test_if_special_chars' force Flag to make it ignore 'test_if_special_chars'
quote_c Charater to use as the enclosing quote
Returns Returns
A pointer to the quoted string, or the original string if nothing has A pointer to the quoted string, or the original string if nothing has
changed. changed.
*/ */
static char *quote_name(const char *name, char *buff, my_bool force) static char *quote(const char *name, char *buff, my_bool force, char quote_c)
{ {
char *to= buff; char *to= buff;
char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`'; char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : quote_c;
if (!force && !opt_quoted && !test_if_special_chars(name)) if (!force && !opt_quoted && !test_if_special_chars(name))
return (char*) name; return (char*) name;
...@@ -2125,7 +2136,29 @@ static char *quote_name(const char *name, char *buff, my_bool force) ...@@ -2125,7 +2136,29 @@ static char *quote_name(const char *name, char *buff, my_bool force)
to[0]= qtype; to[0]= qtype;
to[1]= 0; to[1]= 0;
return buff; return buff;
} /* quote_name */ } /* quote */
/*
quote_name(name, buff, force)
quote() with the ` character
*/
static char *quote_name(const char *name, char *buff, my_bool force)
{
return quote(name, buff, force, '`');
}
/*
quote_string(name, buff, force)
quote() with the ' character
*/
static char *quote_string(const char *name, char *buff)
{
return quote(name, buff, 0, '\'');
}
/* /*
...@@ -3126,9 +3159,15 @@ static uint get_table_structure(const char *table, const char *db, char *table_t ...@@ -3126,9 +3159,15 @@ static uint get_table_structure(const char *table, const char *db, char *table_t
{ {
select_field_names_inited= 1; select_field_names_inited= 1;
init_dynamic_string_checked(&select_field_names, "", 1024, 1024); init_dynamic_string_checked(&select_field_names, "", 1024, 1024);
if (opt_header)
init_dynamic_string_checked(&select_field_names_for_header, "", 1024, 1024);
} }
else else
{
dynstr_set_checked(&select_field_names, ""); dynstr_set_checked(&select_field_names, "");
if (opt_header)
dynstr_set_checked(&select_field_names_for_header, "");
}
insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " : insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " :
delayed ? " DELAYED " : opt_ignore ? " IGNORE " : ""); delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "");
...@@ -3382,10 +3421,15 @@ static uint get_table_structure(const char *table, const char *db, char *table_t ...@@ -3382,10 +3421,15 @@ static uint get_table_structure(const char *table, const char *db, char *table_t
if (init) if (init)
{ {
dynstr_append_checked(&select_field_names, ", "); dynstr_append_checked(&select_field_names, ", ");
if (opt_header)
dynstr_append_checked(&select_field_names_for_header, ", ");
} }
init=1; init=1;
dynstr_append_checked(&select_field_names, dynstr_append_checked(&select_field_names,
quote_name(row[SHOW_FIELDNAME], name_buff, 0)); quote_name(row[SHOW_FIELDNAME], name_buff, 0));
if (opt_header)
dynstr_append_checked(&select_field_names_for_header,
quote_string(row[SHOW_FIELDNAME], name_buff));
} }
init=0; init=0;
/* /*
...@@ -3482,9 +3526,15 @@ static uint get_table_structure(const char *table, const char *db, char *table_t ...@@ -3482,9 +3526,15 @@ static uint get_table_structure(const char *table, const char *db, char *table_t
if (init) if (init)
{ {
dynstr_append_checked(&select_field_names, ", "); dynstr_append_checked(&select_field_names, ", ");
if (opt_header)
dynstr_append_checked(&select_field_names_for_header, ", ");
} }
dynstr_append_checked(&select_field_names, dynstr_append_checked(&select_field_names,
quote_name(row[SHOW_FIELDNAME], name_buff, 0)); quote_name(row[SHOW_FIELDNAME], name_buff, 0));
if (opt_header)
dynstr_append_checked(&select_field_names_for_header,
quote_string(row[SHOW_FIELDNAME], name_buff));
init=1; init=1;
} }
init=0; init=0;
...@@ -4132,7 +4182,6 @@ static void dump_table(const char *table, const char *db, const uchar *hash_key, ...@@ -4132,7 +4182,6 @@ static void dump_table(const char *table, const char *db, const uchar *hash_key,
if (path) if (path)
{ {
char filename[FN_REFLEN], tmp_path[FN_REFLEN]; char filename[FN_REFLEN], tmp_path[FN_REFLEN];
/* /*
Convert the path to native os format Convert the path to native os format
and resolve to the full filepath. and resolve to the full filepath.
...@@ -4170,8 +4219,16 @@ static void dump_table(const char *table, const char *db, const uchar *hash_key, ...@@ -4170,8 +4219,16 @@ static void dump_table(const char *table, const char *db, const uchar *hash_key,
add_load_option(&query_string, " ESCAPED BY ", escaped); add_load_option(&query_string, " ESCAPED BY ", escaped);
add_load_option(&query_string, " LINES TERMINATED BY ", lines_terminated); add_load_option(&query_string, " LINES TERMINATED BY ", lines_terminated);
if (opt_header)
{
dynstr_append_checked(&query_string, " FROM (SELECT 0 AS `_$is_data_row$_`,");
dynstr_append_checked(&query_string, select_field_names_for_header.str);
dynstr_append_checked(&query_string, " UNION ALL SELECT 1 AS `_$is_data_row$_`,");
dynstr_append_checked(&query_string, select_field_names.str);
}
dynstr_append_checked(&query_string, " FROM "); dynstr_append_checked(&query_string, " FROM ");
dynstr_append_checked(&query_string, result_table); dynstr_append_checked(&query_string, result_table);
if (versioned) if (versioned)
vers_append_system_time(&query_string); vers_append_system_time(&query_string);
...@@ -4180,9 +4237,14 @@ static void dump_table(const char *table, const char *db, const uchar *hash_key, ...@@ -4180,9 +4237,14 @@ static void dump_table(const char *table, const char *db, const uchar *hash_key,
dynstr_append_checked(&query_string, " WHERE "); dynstr_append_checked(&query_string, " WHERE ");
dynstr_append_checked(&query_string, where); dynstr_append_checked(&query_string, where);
} }
if (opt_header)
dynstr_append_checked(&query_string, ") s ORDER BY `_$is_data_row$_`");
if (order_by) if (order_by)
{ {
if (opt_header)
dynstr_append_checked(&query_string, ",");
else
dynstr_append_checked(&query_string, " ORDER BY "); dynstr_append_checked(&query_string, " ORDER BY ");
dynstr_append_checked(&query_string, order_by); dynstr_append_checked(&query_string, order_by);
my_free(order_by); my_free(order_by);
......
...@@ -1003,6 +1003,21 @@ Available from MariaDB 10.0.13, and is used together with \fB\-\-master\-data\fR ...@@ -1003,6 +1003,21 @@ Available from MariaDB 10.0.13, and is used together with \fB\-\-master\-data\fR
.sp -1 .sp -1
.IP \(bu 2.3 .IP \(bu 2.3
.\} .\}
.\" mysqldump: header option
.\" header option: mysqldump
\fB\-\-header\fR
.sp
Used together with --tab. When enabled, adds header with column names to the top of output txt files.
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
.\" mysqldump: hex-blob option .\" mysqldump: hex-blob option
.\" hex-blob option: mysqldump .\" hex-blob option: mysqldump
\fB\-\-hex\-blob\fR \fB\-\-hex\-blob\fR
......
CREATE TABLE `courses` (
`course_id` smallint(20) PRIMARY KEY,
`name` varchar(50),
`description` varchar(100),
`num_years` tinyint(1),
`escape_çÇÁá!#%"'` varchar(10)
);
desc courses;
Field Type Null Key Default Extra
course_id smallint(20) NO PRI NULL
name varchar(50) YES NULL
description varchar(100) YES NULL
num_years tinyint(1) YES NULL
escape_çÇÁá!#%"' varchar(10) YES NULL
INSERT INTO `courses` VALUES (5, 'Course 1', 'Course Description 1', 3, NULL);
#
# Dump only data rows into outfile with default options
#
5 Course 1 Course Description 1 3 \N
#
# Dump header and data rows into outfile with default options
#
course_id name description num_years escape_çÇÁá!#%"'
5 Course 1 Course Description 1 3 \N
#
# Dump header and data rows into outfile with comma delimited fields
#
course_id,name,description,num_years,escape_çÇÁá!#%"'
5,Course 1,Course Description 1,3,\N
#
# Dump header and data rows into outfile with single quote enclosed fields
#
'course_id' 'name' 'description' 'num_years' 'escape_çÇÁá!#%"\''
'5' 'Course 1' 'Course Description 1' '3' \N
#
# Dump header and data rows into outfile with optional single quote enclosed fields
#
'course_id' 'name' 'description' 'num_years' 'escape_çÇÁá!#%"\''
'5' 'Course 1' 'Course Description 1' '3' \N
#
# Dump header and data rows into outfile with semicolon terminated data rows
#
course_id name description num_years escape_çÇÁá!#%"';5 Course 1 Course Description 1 3 \N;
#
# Dump header and data rows into outfile with several options above combined
#
'course_id','name','description','num_years','escape_çÇÁá!#%"\'';'5','Course 1','Course Description 1','3',\N;
'course_id','name','description','num_years','escape_çÇÁá!#%"\'';'5','Course 1','Course Description 1','3',\N;INSERT INTO `courses` VALUES (4, 'Course 2', 'Course Description 2', 4, NULL);
INSERT INTO `courses` VALUES (3, 'Course 3', 'Course Description 3', 3, NULL);
INSERT INTO `courses` VALUES (2, 'Course 4', 'Course Description 4', 5, NULL);
INSERT INTO `courses` VALUES (1, 'Course 5', 'Course Description 5', 3, NULL);
#
# Dump data rows into outfile with --where clause
#
2 Course 4 Course Description 4 5 \N
#
# Dump header and data rows into outfile with --where clause. The header must remain on top and not meddle among data rows
#
course_id name description num_years escape_çÇÁá!#%"'
2 Course 4 Course Description 4 5 \N
#
# Dump data rows ordered by primary key.
#
1 Course 5 Course Description 5 3 \N
2 Course 4 Course Description 4 5 \N
3 Course 3 Course Description 3 3 \N
4 Course 2 Course Description 2 4 \N
5 Course 1 Course Description 1 3 \N
#
# Dump header and data rows ordered by primary key. The header must remain on top and not meddle among data rows
#
course_id name description num_years escape_çÇÁá!#%"'
1 Course 5 Course Description 5 3 \N
2 Course 4 Course Description 4 5 \N
3 Course 3 Course Description 3 3 \N
4 Course 2 Course Description 2 4 \N
5 Course 1 Course Description 1 3 \N
#
# Dump data rows from an empty table, must generate no output
#
DELETE FROM `courses`;
#
# Dump header and data rows from an empty table, must generate a single header line as output
#
course_id name description num_years escape_çÇÁá!#%"'
#
# Use header without the --tab option. Must produce an error
#
DROP TABLE `courses`;
--source include/not_embedded.inc
CREATE TABLE `courses` (
`course_id` smallint(20) PRIMARY KEY,
`name` varchar(50),
`description` varchar(100),
`num_years` tinyint(1),
`escape_çÇÁá!#%"'` varchar(10)
);
desc courses;
INSERT INTO `courses` VALUES (5, 'Course 1', 'Course Description 1', 3, NULL);
--echo #
--echo # Dump only data rows into outfile with default options
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows into outfile with default options
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows into outfile with comma delimited fields
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header --fields-terminated-by , test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows into outfile with single quote enclosed fields
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header --fields-enclosed-by \' test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows into outfile with optional single quote enclosed fields
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header --fields-optionally-enclosed-by \' test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows into outfile with semicolon terminated data rows
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header --lines-terminated-by \; test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo
--echo #
--echo # Dump header and data rows into outfile with several options above combined
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header --fields-terminated-by , --fields-enclosed-by \' --lines-terminated-by \; test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header --fields-terminated-by , --fields-optionally-enclosed-by \' --lines-terminated-by \; test
--cat_file $MYSQLTEST_VARDIR/courses.txt
INSERT INTO `courses` VALUES (4, 'Course 2', 'Course Description 2', 4, NULL);
INSERT INTO `courses` VALUES (3, 'Course 3', 'Course Description 3', 3, NULL);
INSERT INTO `courses` VALUES (2, 'Course 4', 'Course Description 4', 5, NULL);
INSERT INTO `courses` VALUES (1, 'Course 5', 'Course Description 5', 3, NULL);
--echo
--echo #
--echo # Dump data rows into outfile with --where clause
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --where "num_years=5" test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows into outfile with --where clause. The header must remain on top and not meddle among data rows
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --where "num_years=5" --header test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump data rows ordered by primary key.
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --order-by-primary test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows ordered by primary key. The header must remain on top and not meddle among data rows
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --order-by-primary --header test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump data rows from an empty table, must generate no output
--echo #
DELETE FROM `courses`;
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Dump header and data rows from an empty table, must generate a single header line as output
--echo #
--exec $MYSQL_DUMP -u root --tab $MYSQLTEST_VARDIR/ --header test
--cat_file $MYSQLTEST_VARDIR/courses.txt
--echo #
--echo # Use header without the --tab option. Must produce an error
--echo #
--error 1
--exec $MYSQL_DUMP -u root --header test
DROP TABLE `courses`;
--remove_file $MYSQLTEST_VARDIR/courses.txt
--remove_file $MYSQLTEST_VARDIR/courses.sql
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment