1 /*
2 Copyright (c) 2000, 2021, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25 /* mysqldump.c - Dump a tables contents and format to an ASCII file
26 **
27 ** The author's original notes follow :-
28 **
29 ** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
30 ** DATE: December 3, 1994
31 ** WARRANTY: None, expressed, impressed, implied
32 ** or other
33 ** STATUS: Public domain
34 ** Adapted and optimized for MySQL by
35 ** Michael Widenius, Sinisa Milivojevic, Jani Tolonen
36 ** -w --where added 9/10/98 by Jim Faucette
37 ** slave code by David Saez Padros <david@ols.es>
38 ** master/autocommit code by Brian Aker <brian@tangent.org>
39 ** SSL by
40 ** Andrei Errapart <andreie@no.spam.ee>
41 ** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee>
42 ** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up
43 ** and adapted to mysqldump 05/11/01 by Jani Tolonen
44 ** Added --single-transaction option 06/06/2002 by Peter Zaitsev
45 ** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
46 */
47
48 #define DUMP_VERSION "10.13"
49
50 #include <my_global.h>
51 #include <my_sys.h>
52 #include <my_user.h>
53 #include <m_string.h>
54 #include <m_ctype.h>
55 #include <hash.h>
56 #include <stdarg.h>
57 #include <my_list.h>
58
59 #include "client_priv.h"
60 #include "my_default.h"
61 #include "mysql.h"
62 #include "mysql_version.h"
63 #include "mysqld_error.h"
64
65 #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
66
67 /* Exit codes */
68
69 #define EX_USAGE 1
70 #define EX_MYSQLERR 2
71 #define EX_CONSCHECK 3
72 #define EX_EOM 4
73 #define EX_EOF 5 /* ferror for output file was got */
74 #define EX_ILLEGAL_TABLE 6
75
76 /* index into 'show fields from table' */
77
78 #define SHOW_FIELDNAME 0
79 #define SHOW_TYPE 1
80 #define SHOW_NULL 2
81 #define SHOW_DEFAULT 4
82 #define SHOW_EXTRA 5
83
84 /* Size of buffer for dump's select query */
85 #define QUERY_LENGTH 1536
86
87 /* Size of comment buffer. */
88 #define COMMENT_LENGTH 2048
89
90 /* ignore table flags */
91 #define IGNORE_NONE 0x00 /* no ignore */
92 #define IGNORE_DATA 0x01 /* don't dump data for this table */
93
94 /* Chars needed to store LONGLONG, excluding trailing '\0'. */
95 #define LONGLONG_LEN 20
96
97 typedef enum {
98 KEY_TYPE_NONE,
99 KEY_TYPE_PRIMARY,
100 KEY_TYPE_UNIQUE,
101 KEY_TYPE_NON_UNIQUE,
102 KEY_TYPE_CONSTRAINT
103 } key_type_t;
104
105 /* Maximum number of fields per table */
106 #define MAX_FIELDS 4000
107
108 static void add_load_option(DYNAMIC_STRING *str, const char *option,
109 const char *option_value);
110 static ulong find_set(TYPELIB *lib, const char *x, size_t length,
111 char **err_pos, uint *err_len);
112 static char *alloc_query_str(size_t size);
113
114 static void field_escape(DYNAMIC_STRING* in, const char *from);
115 static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
116 quick= 1, extended_insert= 1,
117 lock_tables= 1, opt_force= 0, flush_logs= 0,
118 flush_privileges= 0,
119 opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
120 create_options=1,opt_quoted=0,opt_databases=0,
121 opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
122 opt_set_charset=0, opt_dump_date=1,
123 opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
124 opt_delete_master_logs=0, tty_password=0,
125 opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
126 opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0,
127 opt_complete_insert= 0, opt_drop_database= 0,
128 opt_replace_into= 0,
129 opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1,
130 opt_slave_apply= 0,
131 opt_include_master_host_port= 0,
132 opt_events= 0, opt_comments_used= 0,
133 opt_alltspcs=0, opt_notspcs= 0, opt_drop_trigger= 0,
134 opt_compressed_columns= 0,
135 opt_compressed_columns_with_dictionaries= 0,
136 opt_drop_compression_dictionary= 1,
137 opt_order_by_primary_desc= 0,
138 opt_skip_mysql_schema=0, opt_secure_auth= TRUE;
139 static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0;
140 static ulong opt_max_allowed_packet, opt_net_buffer_length;
141 static MYSQL mysql_connection,*mysql=0;
142 static DYNAMIC_STRING insert_pat;
143 static char *opt_password=0,*current_user=0,
144 *current_host=0,*path=0,*fields_terminated=0,
145 *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
146 *where=0, *order_by=0,
147 *opt_compatible_mode_str= 0,
148 *err_ptr= 0, *opt_ignore_error= 0,
149 *log_error_file= NULL;
150 #ifndef NDEBUG
151 static char *start_sql_file= NULL, *finish_sql_file= NULL;
152 #endif
153 static char **defaults_argv= 0;
154 static char compatible_mode_normal_str[255];
155 /* Server supports character_set_results session variable? */
156 static my_bool server_supports_switching_charsets= TRUE;
157 static ulong opt_compatible_mode= 0;
158 #define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
159 #define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
160 #define MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL 1
161 #define MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL 2
162 static uint opt_enable_cleartext_plugin= 0;
163 static my_bool using_opt_enable_cleartext_plugin= 0;
164 static uint opt_mysql_port= 0, opt_master_data;
165 static uint opt_slave_data;
166 static uint my_end_arg;
167 static char * opt_mysql_unix_port=0;
168 static char *opt_bind_addr = NULL;
169 static int first_error=0;
170 static uint opt_lock_for_backup= 0;
171 #include <sslopt-vars.h>
172 #include <caching_sha2_passwordopt-vars.h>
173 FILE *md_result_file= 0;
174 FILE *stderror_file=0;
175
176 const char *set_gtid_purged_mode_names[]=
177 {"OFF", "AUTO", "ON", NullS};
178 static TYPELIB set_gtid_purged_mode_typelib=
179 {array_elements(set_gtid_purged_mode_names) -1, "",
180 set_gtid_purged_mode_names, NULL};
181 static enum enum_set_gtid_purged_mode {
182 SET_GTID_PURGED_OFF= 0,
183 SET_GTID_PURGED_AUTO =1,
184 SET_GTID_PURGED_ON=2
185 } opt_set_gtid_purged_mode= SET_GTID_PURGED_AUTO;
186
187 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
188 static char *shared_memory_base_name=0;
189 #endif
190 static uint opt_protocol= 0;
191 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
192
193 DYNAMIC_ARRAY ignore_error;
194 static int parse_ignore_error();
195
196 static my_bool opt_innodb_optimize_keys= FALSE;
197
198 /*
199 Dynamic_string wrapper functions. In this file use these
200 wrappers, they will terminate the process if there is
201 an allocation failure.
202 */
203 static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
204 size_t init_alloc, size_t alloc_increment);
205 static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src);
206 static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str);
207 static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
208 size_t length);
209 static void dynstr_realloc_checked(DYNAMIC_STRING *str, size_t additional_size);
210 /*
211 Constant for detection of default value of default_charset.
212 If default_charset is equal to mysql_universal_client_charset, then
213 it is the default value which assigned at the very beginning of main().
214 */
215 static const char *mysql_universal_client_charset=
216 MYSQL_UNIVERSAL_CLIENT_CHARSET;
217 static char *default_charset;
218 static CHARSET_INFO *charset_info= &my_charset_latin1;
219 const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
220 /* have we seen any VIEWs during table scanning? */
221 my_bool seen_views= 0;
222 static DYNAMIC_STRING gtid_executed_buffer;
223 static my_bool gtid_executed_buffer_inited= 0;
224 const char *compatible_mode_names[]=
225 {
226 "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
227 "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
228 "ANSI",
229 NullS
230 };
231 #define MASK_ANSI_QUOTES \
232 (\
233 (1<<2) | /* POSTGRESQL */\
234 (1<<3) | /* ORACLE */\
235 (1<<4) | /* MSSQL */\
236 (1<<5) | /* DB2 */\
237 (1<<6) | /* MAXDB */\
238 (1<<10) /* ANSI */\
239 )
240 TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
241 "", compatible_mode_names, NULL};
242
243 HASH ignore_table;
244 static HASH processed_compression_dictionaries;
245
246 static LIST *skipped_keys_list = NULL;
247 static LIST *alter_constraints_list = NULL;
248
249 static struct my_option my_long_options[] =
250 {
251 {"all-databases", 'A',
252 "Dump all the databases. This will be same as --databases with all databases selected.",
253 &opt_alldbs, &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
254 0, 0},
255 {"all-tablespaces", 'Y',
256 "Dump all the tablespaces.",
257 &opt_alltspcs, &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
258 0, 0},
259 {"no-tablespaces", 'y',
260 "Do not dump any tablespace information.",
261 &opt_notspcs, &opt_notspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
262 0, 0},
263 {"add-drop-database", OPT_DROP_DATABASE, "Add a DROP DATABASE before each create.",
264 &opt_drop_database, &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
265 0},
266 {"add-drop-table", OPT_DROP, "Add a DROP TABLE before each create.",
267 &opt_drop, &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
268 0},
269 {"add-drop-trigger", 0, "Add a DROP TRIGGER before each create.",
270 &opt_drop_trigger, &opt_drop_trigger, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
271 0},
272 {"add-locks", OPT_LOCKS, "Add locks around INSERT statements.",
273 &opt_lock, &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
274 0},
275 {"allow-keywords", OPT_KEYWORDS,
276 "Allow creation of column names that are keywords.", &opt_keywords,
277 &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
278 {"apply-slave-statements", OPT_MYSQLDUMP_SLAVE_APPLY,
279 "Adds 'STOP SLAVE' prior to 'CHANGE MASTER' and 'START SLAVE' to bottom of dump.",
280 &opt_slave_apply, &opt_slave_apply, 0, GET_BOOL, NO_ARG,
281 0, 0, 0, 0, 0, 0},
282 {"lock-for-backup", OPT_LOCK_FOR_BACKUP, "Use lightweight metadata locks "
283 "to block updates to non-transactional tables and DDL to all tables. "
284 "This works only with --single-transaction, otherwise this option is "
285 "automatically converted to --lock-all-tables.", &opt_lock_for_backup,
286 &opt_lock_for_backup, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
287 {"bind-address", 0, "IP address to bind to.",
288 (uchar**) &opt_bind_addr, (uchar**) &opt_bind_addr, 0, GET_STR,
289 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
290 {"character-sets-dir", OPT_CHARSETS_DIR,
291 "Directory for character set files.", &charsets_dir,
292 &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
293 {"comments", 'i', "Write additional information.",
294 &opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG,
295 1, 0, 0, 0, 0, 0},
296 {"compatible", OPT_COMPATIBLE,
297 "Change the dump to be compatible with a given mode. By default tables "
298 "are dumped in a format optimized for MySQL. Legal modes are: ansi, "
299 "mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, "
300 "no_table_options, no_field_options. One can use several modes separated "
301 "by commas. Note: Requires MySQL server version 4.1.0 or higher. "
302 "This option is ignored with earlier server versions.",
303 &opt_compatible_mode_str, &opt_compatible_mode_str, 0,
304 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
305 {"compact", OPT_COMPACT,
306 "Give less verbose output (useful for debugging). Disables structure "
307 "comments and header/footer constructs. Enables options --skip-add-"
308 "drop-table --skip-add-locks --skip-comments --skip-disable-keys "
309 "--skip-set-charset.",
310 &opt_compact, &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
311 {"complete-insert", 'c', "Use complete insert statements.",
312 &opt_complete_insert, &opt_complete_insert, 0, GET_BOOL,
313 NO_ARG, 0, 0, 0, 0, 0, 0},
314 {"compress", 'C', "Use compression in server/client protocol.",
315 &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
316 0, 0, 0},
317 {"create-options", 'a',
318 "Include all MySQL specific create options.",
319 &create_options, &create_options, 0, GET_BOOL, NO_ARG, 1,
320 0, 0, 0, 0, 0},
321 {"databases", 'B',
322 "Dump several databases. Note the difference in usage; in this case no tables are given. All name arguments are regarded as database names. 'USE db_name;' will be included in the output.",
323 &opt_databases, &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0,
324 0, 0, 0, 0},
325 #ifdef NDEBUG
326 {"debug", '#', "This is a non-debug version. Catch this and exit.",
327 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
328 {"debug-check", OPT_DEBUG_CHECK, "This is a non-debug version. Catch this and exit.",
329 0, 0, 0,
330 GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
331 {"debug-info", OPT_DEBUG_INFO, "This is a non-debug version. Catch this and exit.", 0,
332 0, 0, GET_DISABLED, NO_ARG, 0, 0, 0, 0, 0, 0},
333 #else
334 {"debug", '#', "Output debug log.", &default_dbug_option,
335 &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
336 {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
337 &debug_check_flag, &debug_check_flag, 0,
338 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
339 {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
340 &debug_info_flag, &debug_info_flag,
341 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
342 #endif
343 {"default-character-set", OPT_DEFAULT_CHARSET,
344 "Set the default character set.", &default_charset,
345 &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
346 {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
347 "Delete logs on master after backup. This automatically enables --master-data.",
348 &opt_delete_master_logs, &opt_delete_master_logs, 0,
349 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
350 {"disable-keys", 'K',
351 "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER "
352 "TABLE tb_name ENABLE KEYS */; will be put in the output.", &opt_disable_keys,
353 &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
354 {"dump-slave", OPT_MYSQLDUMP_SLAVE_DATA,
355 "This causes the binary log position and filename of the master to be "
356 "appended to the dumped data output. Setting the value to 1, will print"
357 "it as a CHANGE MASTER command in the dumped data output; if equal"
358 " to 2, that command will be prefixed with a comment symbol. "
359 "This option will turn --lock-all-tables on, unless "
360 "--single-transaction is specified too (in which case a "
361 "global read lock is only taken a short time at the beginning of the dump "
362 "- don't forget to read about --single-transaction below). In all cases "
363 "any action on logs will happen at the exact moment of the dump."
364 "Option automatically turns --lock-tables off.",
365 &opt_slave_data, &opt_slave_data, 0,
366 GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL, 0, 0, 0},
367 {"events", 'E', "Dump events.",
368 &opt_events, &opt_events, 0, GET_BOOL,
369 NO_ARG, 0, 0, 0, 0, 0, 0},
370 {"extended-insert", 'e',
371 "Use multiple-row INSERT syntax that include several VALUES lists.",
372 &extended_insert, &extended_insert, 0, GET_BOOL, NO_ARG,
373 1, 0, 0, 0, 0, 0},
374 {"fields-terminated-by", OPT_FTB,
375 "Fields in the output file are terminated by the given string.",
376 &fields_terminated, &fields_terminated, 0,
377 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
378 {"fields-enclosed-by", OPT_ENC,
379 "Fields in the output file are enclosed by the given character.",
380 &enclosed, &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
381 {"fields-optionally-enclosed-by", OPT_O_ENC,
382 "Fields in the output file are optionally enclosed by the given character.",
383 &opt_enclosed, &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
384 {"fields-escaped-by", OPT_ESC,
385 "Fields in the output file are escaped by the given character.",
386 &escaped, &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
387 {"flush-logs", 'F', "Flush logs file in server before starting dump. "
388 "Note that if you dump many databases at once (using the option "
389 "--databases= or --all-databases), the logs will be flushed for "
390 "each database dumped. The exception is when using --lock-all-tables "
391 "or --master-data: "
392 "in this case the logs will be flushed only once, corresponding "
393 "to the moment all tables are locked. So if you want your dump and "
394 "the log flush to happen at the same exact moment you should use "
395 "--lock-all-tables or --master-data with --flush-logs.",
396 &flush_logs, &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
397 0, 0},
398 {"flush-privileges", OPT_ESC, "Emit a FLUSH PRIVILEGES statement "
399 "after dumping the mysql database. This option should be used any "
400 "time the dump contains the mysql database and any other database "
401 "that depends on the data in the mysql database for proper restore. ",
402 &flush_privileges, &flush_privileges, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
403 0, 0},
404 {"force", 'f', "Continue even if we get an SQL error.",
405 &opt_force, &opt_force, 0, GET_BOOL, NO_ARG,
406 0, 0, 0, 0, 0, 0},
407 {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
408 NO_ARG, 0, 0, 0, 0, 0, 0},
409 {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
410 "VARBINARY, BLOB) in hexadecimal format.",
411 &opt_hex_blob, &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
412 {"host", 'h', "Connect to host.", ¤t_host,
413 ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
414 {"ignore-error", OPT_MYSQLDUMP_IGNORE_ERROR, "A comma-separated list of "
415 "error numbers to be ignored if encountered during dump.",
416 &opt_ignore_error, &opt_ignore_error, 0, GET_STR_ALLOC, REQUIRED_ARG, 0,
417 0, 0, 0, 0, 0},
418 {"ignore-table", OPT_IGNORE_TABLE,
419 "Do not dump the specified table. To specify more than one table to ignore, "
420 "use the directive multiple times, once for each table. Each table must "
421 "be specified with both database and table names, e.g., "
422 "--ignore-table=database.table.",
423 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
424 {"include-master-host-port", OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT,
425 "Adds 'MASTER_HOST=<host>, MASTER_PORT=<port>' to 'CHANGE MASTER TO..' "
426 "in dump produced with --dump-slave.", &opt_include_master_host_port,
427 &opt_include_master_host_port, 0, GET_BOOL, NO_ARG,
428 0, 0, 0, 0, 0, 0},
429 {"innodb-optimize-keys", OPT_INNODB_OPTIMIZE_KEYS,
430 "Use InnoDB fast index creation by creating secondary indexes after "
431 "dumping the data.",
432 &opt_innodb_optimize_keys, &opt_innodb_optimize_keys, 0, GET_BOOL, NO_ARG,
433 0, 0, 0, 0, 0, 0},
434 {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
435 &opt_ignore, &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
436 0, 0},
437 {"lines-terminated-by", OPT_LTB,
438 "Lines in the output file are terminated by the given string.",
439 &lines_terminated, &lines_terminated, 0, GET_STR,
440 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
441 {"lock-all-tables", 'x', "Locks all tables across all databases. This "
442 "is achieved by taking a global read lock for the duration of the whole "
443 "dump. Automatically turns --single-transaction and --lock-tables off.",
444 &opt_lock_all_tables, &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
445 0, 0, 0, 0, 0, 0},
446 {"lock-tables", 'l', "Lock all tables for read.", &lock_tables,
447 &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
448 {"log-error", OPT_ERROR_LOG_FILE, "Append warnings and errors to given file.",
449 &log_error_file, &log_error_file, 0, GET_STR,
450 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
451 {"master-data", OPT_MASTER_DATA,
452 "This causes the binary log position and filename to be appended to the "
453 "output. If equal to 1, will print it as a CHANGE MASTER command; if equal"
454 " to 2, that command will be prefixed with a comment symbol. "
455 "This option will turn --lock-all-tables on, unless --single-transaction "
456 "is specified too (on servers that don't provide Binlog_snapshot_file and "
457 "Binlog_snapshot_position status variables this will still take a "
458 "global read lock for a short time at the beginning of the dump; "
459 "don't forget to read about --single-transaction below). In all cases, "
460 "any action on logs will happen at the exact moment of the dump. "
461 "Option automatically turns --lock-tables off.",
462 &opt_master_data, &opt_master_data, 0,
463 GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
464 {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
465 "The maximum packet length to send to or receive from server.",
466 &opt_max_allowed_packet, &opt_max_allowed_packet, 0,
467 GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096,
468 (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
469 {"net_buffer_length", OPT_NET_BUFFER_LENGTH,
470 "The buffer size for TCP/IP and socket communication.",
471 &opt_net_buffer_length, &opt_net_buffer_length, 0,
472 GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L,
473 MALLOC_OVERHEAD-1024, 1024, 0},
474 {"no-autocommit", OPT_AUTOCOMMIT,
475 "Wrap tables with autocommit/commit statements.",
476 &opt_autocommit, &opt_autocommit, 0, GET_BOOL, NO_ARG,
477 0, 0, 0, 0, 0, 0},
478 {"no-create-db", 'n',
479 "Suppress the CREATE DATABASE ... IF EXISTS statement that normally is "
480 "output for each dumped database if --all-databases or --databases is "
481 "given.",
482 &opt_create_db, &opt_create_db, 0,
483 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
484 {"no-create-info", 't', "Don't write table creation info.",
485 &opt_no_create_info, &opt_no_create_info, 0, GET_BOOL,
486 NO_ARG, 0, 0, 0, 0, 0, 0},
487 {"no-data", 'd', "No row information.", &opt_no_data,
488 &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
489 {"no-set-names", 'N', "Same as --skip-set-charset.",
490 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
491 {"opt", OPT_OPTIMIZE,
492 "Same as --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys. Enabled by default, disable with --skip-opt.",
493 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
494 {"order-by-primary", OPT_ORDER_BY_PRIMARY,
495 "Sorts each table's rows by primary key, or first unique key, if such a key exists. Useful when dumping a MyISAM table to be loaded into an InnoDB table, but will make the dump itself take considerably longer.",
496 &opt_order_by_primary, &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
497 {"order-by-primary-desc", OPT_ORDER_BY_PRIMARY_DESC,
498 "Taking backup ORDER BY primary key DESC.",
499 &opt_order_by_primary_desc, &opt_order_by_primary_desc, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
500 {"password", 'p',
501 "Password to use when connecting to server. If password is not given it's solicited on the tty.",
502 0, 0, 0, GET_PASSWORD, OPT_ARG, 0, 0, 0, 0, 0, 0},
503 #ifdef _WIN32
504 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
505 NO_ARG, 0, 0, 0, 0, 0, 0},
506 #endif
507 {"port", 'P', "Port number to use for connection.", &opt_mysql_port,
508 &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
509 0},
510 {"protocol", OPT_MYSQL_PROTOCOL,
511 "The protocol to use for connection (tcp, socket, pipe, memory).",
512 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
513 {"quick", 'q', "Don't buffer query, dump directly to stdout.",
514 &quick, &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
515 {"quote-names",'Q', "Quote table and column names with backticks (`).",
516 &opt_quoted, &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
517 0, 0},
518 {"replace", OPT_MYSQL_REPLACE_INTO, "Use REPLACE INTO instead of INSERT INTO.",
519 &opt_replace_into, &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
520 0, 0},
521 {"result-file", 'r',
522 "Direct output to a given file. This option should be used in systems "
523 "(e.g., DOS, Windows) that use carriage-return linefeed pairs (\\r\\n) "
524 "to separate text lines. This option ensures that only a single newline "
525 "is used.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
526 {"routines", 'R', "Dump stored routines (functions and procedures).",
527 &opt_routines, &opt_routines, 0, GET_BOOL,
528 NO_ARG, 0, 0, 0, 0, 0, 0},
529 {"set-charset", OPT_SET_CHARSET,
530 "Add 'SET NAMES default_character_set' to the output.",
531 &opt_set_charset, &opt_set_charset, 0, GET_BOOL, NO_ARG, 1,
532 0, 0, 0, 0, 0},
533 {"set-gtid-purged", OPT_SET_GTID_PURGED,
534 "Add 'SET @@GLOBAL.GTID_PURGED' to the output. Possible values for "
535 "this option are ON, OFF and AUTO. If ON is used and GTIDs "
536 "are not enabled on the server, an error is generated. If OFF is "
537 "used, this option does nothing. If AUTO is used and GTIDs are enabled "
538 "on the server, 'SET @@GLOBAL.GTID_PURGED' is added to the output. "
539 "If GTIDs are disabled, AUTO does nothing. If no value is supplied "
540 "then the default (AUTO) value will be considered.",
541 0, 0, 0, GET_STR, OPT_ARG,
542 0, 0, 0, 0, 0, 0},
543 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
544 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
545 "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name,
546 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
547 #endif
548 /*
549 Note that the combination --single-transaction --master-data
550 will give bullet-proof binlog position only if server >=4.1.3. That's the
551 old "FLUSH TABLES WITH READ LOCK does not block commit" fixed bug.
552 */
553 {"single-transaction", OPT_TRANSACTION,
554 "Creates a consistent snapshot by dumping all tables in a single "
555 "transaction. Works ONLY for tables stored in storage engines which "
556 "support multiversioning (currently only InnoDB does); the dump is NOT "
557 "guaranteed to be consistent for other storage engines. "
558 "While a --single-transaction dump is in process, to ensure a valid "
559 "dump file (correct table contents and binary log position), no other "
560 "connection should use the following statements: ALTER TABLE, DROP "
561 "TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not "
562 "isolated from them. Option automatically turns off --lock-tables.",
563 &opt_single_transaction, &opt_single_transaction, 0,
564 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
565 {"dump-date", OPT_DUMP_DATE, "Put a dump date to the end of the output.",
566 &opt_dump_date, &opt_dump_date, 0,
567 GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
568 {"skip_mysql_schema", OPT_SKIP_MYSQL_SCHEMA, "Skip adding DROP DATABASE for mysql schema.",
569 &opt_skip_mysql_schema, &opt_skip_mysql_schema, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
570 0},
571 {"skip-opt", OPT_SKIP_OPTIMIZATION,
572 "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
573 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
574 {"socket", 'S', "The socket file to use for connection.",
575 &opt_mysql_unix_port, &opt_mysql_unix_port, 0,
576 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
577 {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
578 " uses old (pre-4.1.1) protocol. Deprecated. Always TRUE",
579 &opt_secure_auth, &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
580 #ifndef NDEBUG
581 {"start-sql-file", OPT_START_SQL_FILE, "Execute SQL statements from the file"
582 " at the mysqldump start. Each line has to contain one statement terminated"
583 " with a semicolon. Line length limit is 1023 characters.",
584 &start_sql_file, &start_sql_file, 0, GET_STR,
585 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
586 {"finish-sql-file", OPT_FINISH_SQL_FILE, "Execute SQL statements from the file"
587 " at the mysqldump finish. Each line has to contain one statement terminated"
588 " with a semicolon. Line length limit is 1023 characters.",
589 &finish_sql_file, &finish_sql_file, 0, GET_STR,
590 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
591 #endif // DEBUF_OFF
592 #include <sslopt-longopts.h>
593 #include <caching_sha2_passwordopt-longopts.h>
594 {"tab",'T',
595 "Create tab-separated textfile for each table to given path. (Create .sql "
596 "and .txt files.) NOTE: This only works if mysqldump is run on the same "
597 "machine as the mysqld server.",
598 &path, &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
599 {"tables", OPT_TABLES, "Overrides option --databases (-B).",
600 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
601 {"triggers", OPT_TRIGGERS, "Dump triggers for each dumped table.",
602 &opt_dump_triggers, &opt_dump_triggers, 0, GET_BOOL,
603 NO_ARG, 1, 0, 0, 0, 0, 0},
604 {"tz-utc", OPT_TZ_UTC,
605 "SET TIME_ZONE='+00:00' at top of dump to allow dumping of TIMESTAMP data when a server has data in different time zones or data is being moved between servers with different time zones.",
606 &opt_tz_utc, &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
607 {"user", 'u', "User for login if not current user.",
608 ¤t_user, ¤t_user, 0, GET_STR, REQUIRED_ARG,
609 0, 0, 0, 0, 0, 0},
610 {"verbose", 'v', "Print info about the various stages.",
611 &verbose, &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
612 {"version",'V', "Output version information and exit.", 0, 0, 0,
613 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
614 {"where", 'w', "Dump only selected records. Quotes are mandatory.",
615 &where, &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
616 {"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG,
617 NO_ARG, 0, 0, 0, 0, 0, 0},
618 {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
619 &opt_plugin_dir, &opt_plugin_dir, 0,
620 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
621 {"default_auth", OPT_DEFAULT_AUTH,
622 "Default authentication client-side plugin to use.",
623 &opt_default_auth, &opt_default_auth, 0,
624 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
625 {"enable_cleartext_plugin", OPT_ENABLE_CLEARTEXT_PLUGIN,
626 "Enable/disable the clear text authentication plugin.",
627 &opt_enable_cleartext_plugin, &opt_enable_cleartext_plugin,
628 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0},
629 {"enable-compressed-columns", OPT_ENABLE_COMPRESSED_COLUMNS,
630 "Enable compressed columns extensions.",
631 &opt_compressed_columns, &opt_compressed_columns, 0, GET_BOOL, NO_ARG,
632 0, 0, 0, 0, 0, 0},
633 {"enable-compressed-columns-with-dictionaries",
634 OPT_ENABLE_COMPRESSED_COLUMNS_WITH_DICTIONARIES,
635 "Enable dictionaries for compressed columns extensions.",
636 &opt_compressed_columns_with_dictionaries,
637 &opt_compressed_columns_with_dictionaries, 0, GET_BOOL, NO_ARG,
638 0, 0, 0, 0, 0, 0},
639 {"add-drop-compression-dictionary", OPT_DROP_COMPRESSION_DICTIONARY,
640 "Add a DROP COMPRESSION_DICTIONARY before each create.",
641 &opt_drop_compression_dictionary,
642 &opt_drop_compression_dictionary, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
643 0},
644 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
645 };
646
647 static const char *load_default_groups[]= { "mysqldump","client",0 };
648
649 static void maybe_exit(int error);
650 static void die(int error, const char* reason, ...);
651 static void maybe_die(int error, const char* reason, ...);
652 static void write_header(FILE *sql_file, char *db_name);
653 static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
654 const char *prefix,const char *name,
655 int string_value);
656 static int dump_selected_tables(char *db, char **table_names, int tables);
657 static int dump_all_tables_in_db(char *db);
658 static int init_dumping_views(char *, my_bool);
659 static int init_dumping_tables(char *, my_bool);
660 static int init_dumping(char *, int init_func(char*, my_bool));
661 static int dump_databases(char **);
662 static int dump_all_databases();
663 static char *quote_name(const char *name, char *buff, my_bool force);
664 char check_if_ignore_table(const char *table_name, char *table_type);
665 static char *primary_key_fields(const char *table_name, const my_bool desc);
666 static my_bool get_view_structure(char *table, char* db);
667 static my_bool dump_all_views_in_db(char *database);
668 static int dump_all_tablespaces();
669 static int dump_tablespaces_for_tables(char *db, char **table_names, int tables);
670 static int dump_tablespaces_for_databases(char** databases);
671 static int dump_tablespaces(char* ts_where);
672 static void print_comment(FILE *sql_file, my_bool is_error, const char *format,
673 ...);
674 static char const* fix_identifier_with_newline(char const* object_name,
675 my_bool* freemem);
676
677 /*
678 Print the supplied message if in verbose mode
679
680 SYNOPSIS
681 verbose_msg()
682 fmt format specifier
683 ... variable number of parameters
684 */
685
verbose_msg(const char * fmt,...)686 static void verbose_msg(const char *fmt, ...)
687 {
688 va_list args;
689 DBUG_ENTER("verbose_msg");
690
691 if (!verbose)
692 DBUG_VOID_RETURN;
693
694 va_start(args, fmt);
695 vfprintf(stderr, fmt, args);
696 va_end(args);
697
698 fflush(stderr);
699
700 DBUG_VOID_RETURN;
701 }
702
703 /*
704 exit with message if ferror(file)
705
706 SYNOPSIS
707 check_io()
708 file - checked file
709 */
710
check_io(FILE * file)711 void check_io(FILE *file)
712 {
713 if (ferror(file) || errno == 5)
714 die(EX_EOF, "Got errno %d on write", errno);
715 }
716
print_version(void)717 static void print_version(void)
718 {
719 printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
720 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
721 } /* print_version */
722
723
short_usage_sub(void)724 static void short_usage_sub(void)
725 {
726 printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
727 printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
728 my_progname);
729 printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
730 }
731
732
usage(void)733 static void usage(void)
734 {
735 struct my_option *optp;
736 print_version();
737 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
738 puts("Dumping structure and contents of MySQL databases and tables.");
739 short_usage_sub();
740 print_defaults("my",load_default_groups);
741 /*
742 Turn default for zombies off so that the help on how to
743 turn them off text won't show up.
744 This is safe to do since it's followed by a call to exit().
745 */
746 for (optp= my_long_options; optp->name; optp++)
747 {
748 if (optp->id == OPT_SECURE_AUTH)
749 {
750 optp->def_value= 0;
751 break;
752 }
753 }
754 my_print_help(my_long_options);
755 my_print_variables(my_long_options);
756 } /* usage */
757
758
short_usage(void)759 static void short_usage(void)
760 {
761 short_usage_sub();
762 printf("For more options, use %s --help\n", my_progname);
763 }
764
765
write_header(FILE * sql_file,char * db_name)766 static void write_header(FILE *sql_file, char *db_name)
767 {
768 if (opt_xml)
769 {
770 fputs("<?xml version=\"1.0\"?>\n", sql_file);
771 /*
772 Schema reference. Allows use of xsi:nil for NULL values and
773 xsi:type to define an element's data type.
774 */
775 fputs("<mysqldump ", sql_file);
776 fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
777 sql_file);
778 fputs(">\n", sql_file);
779 check_io(sql_file);
780 }
781 else if (!opt_compact)
782 {
783 my_bool freemem= FALSE;
784 char const* text= fix_identifier_with_newline(db_name, &freemem);
785
786 print_comment(sql_file, 0,
787 "-- MySQL dump %s Distrib %s, for %s (%s)\n--\n",
788 DUMP_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE,
789 MACHINE_TYPE);
790 print_comment(sql_file, 0, "-- Host: %s Database: %s\n",
791 current_host ? current_host : "localhost",
792 text);
793
794 if (freemem)
795 my_free((void*)text);
796
797 print_comment(sql_file, 0,
798 "-- ------------------------------------------------------\n"
799 );
800 print_comment(sql_file, 0, "-- Server version\t%s\n",
801 mysql_get_server_info(&mysql_connection));
802
803 if (opt_set_charset)
804 fprintf(sql_file,
805 "\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
806 "\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
807 "\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
808 "\n/*!40101 SET NAMES %s */;\n",default_charset);
809
810 if (opt_tz_utc)
811 {
812 fprintf(sql_file, "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n");
813 fprintf(sql_file, "/*!40103 SET TIME_ZONE='+00:00' */;\n");
814 }
815
816 if (!path)
817 {
818 fprintf(md_result_file,"\
819 /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n\
820 /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n\
821 ");
822 }
823 fprintf(sql_file,
824 "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
825 "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
826 path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
827 compatible_mode_normal_str);
828
829 // This is specifically to allow MyRocks to bulk load a dump faster
830 // We have no interest in anything earlier than 5.7 and 17 being the
831 // current release. 5.7.8 and after can only use P_S for session_variables
832 // and never I_S. So we first check that P_S is present and the
833 // session_variables table exists. If no, we simply skip the optimization
834 // assuming that MyRocks isn't present either. If it is, ohh well, bulk
835 // loader will not be invoked.
836 fprintf(sql_file,
837 "/*!50717 SELECT COUNT(*) INTO @rocksdb_has_p_s_session_variables"
838 " FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA ="
839 " 'performance_schema' AND TABLE_NAME = 'session_variables'"
840 " */;\n"
841 "/*!50717 SET @rocksdb_get_is_supported = IF"
842 " (@rocksdb_has_p_s_session_variables, 'SELECT COUNT(*) INTO"
843 " @rocksdb_is_supported FROM performance_schema.session_variables"
844 " WHERE VARIABLE_NAME=\\'rocksdb_bulk_load\\'', 'SELECT 0') */;\n"
845 "/*!50717 PREPARE s FROM @rocksdb_get_is_supported */;\n"
846 "/*!50717 EXECUTE s */;\n"
847 "/*!50717 DEALLOCATE PREPARE s */;\n"
848 "/*!50717 SET @rocksdb_enable_bulk_load = IF"
849 " (@rocksdb_is_supported, 'SET SESSION rocksdb_bulk_load = 1',"
850 " 'SET @rocksdb_dummy_bulk_load = 0') */;\n"
851 "/*!50717 PREPARE s FROM @rocksdb_enable_bulk_load */;\n"
852 "/*!50717 EXECUTE s */;\n"
853 "/*!50717 DEALLOCATE PREPARE s */;\n");
854
855
856 check_io(sql_file);
857 }
858 } /* write_header */
859
860
write_footer(FILE * sql_file)861 static void write_footer(FILE *sql_file)
862 {
863 if (opt_xml)
864 {
865 fputs("</mysqldump>\n", sql_file);
866 check_io(sql_file);
867 }
868 else if (!opt_compact)
869 {
870 fprintf(sql_file,
871 "/*!50112 SET @disable_bulk_load = IF (@is_rocksdb_supported,"
872 " 'SET SESSION rocksdb_bulk_load = @old_rocksdb_bulk_load',"
873 " 'SET @dummy_rocksdb_bulk_load = 0') */;\n"
874 "/*!50112 PREPARE s FROM @disable_bulk_load */;\n"
875 "/*!50112 EXECUTE s */;\n"
876 "/*!50112 DEALLOCATE PREPARE s */;\n");
877
878
879 if (opt_tz_utc)
880 fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n");
881
882 fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
883 if (!path)
884 {
885 fprintf(md_result_file,"\
886 /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
887 /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
888 }
889 if (opt_set_charset)
890 fprintf(sql_file,
891 "/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
892 "/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
893 "/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
894 fprintf(sql_file,
895 "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
896 fputs("\n", sql_file);
897
898 if (opt_dump_date)
899 {
900 char time_str[20];
901 get_date(time_str, GETDATE_DATE_TIME, 0);
902 print_comment(sql_file, 0, "-- Dump completed on %s\n", time_str);
903 }
904 else
905 print_comment(sql_file, 0, "-- Dump completed\n");
906
907 check_io(sql_file);
908 }
909 } /* write_footer */
910
911
get_table_key(const char * entry,size_t * length,my_bool not_used MY_ATTRIBUTE ((unused)))912 uchar* get_table_key(const char *entry, size_t *length,
913 my_bool not_used MY_ATTRIBUTE((unused)))
914 {
915 *length= strlen(entry);
916 return (uchar*) entry;
917 }
918
919
920 static my_bool
get_one_option(int optid,const struct my_option * opt MY_ATTRIBUTE ((unused)),char * argument)921 get_one_option(int optid, const struct my_option *opt MY_ATTRIBUTE((unused)),
922 char *argument)
923 {
924 switch (optid) {
925 case 'p':
926 if (argument == disabled_my_option)
927 argument= (char*) ""; /* Don't require password */
928 if (argument)
929 {
930 char *start=argument;
931 my_free(opt_password);
932 opt_password=my_strdup(PSI_NOT_INSTRUMENTED,
933 argument,MYF(MY_FAE));
934 while (*argument) *argument++= 'x'; /* Destroy argument */
935 if (*start)
936 start[1]=0; /* Cut length of argument */
937 tty_password= 0;
938 }
939 else
940 tty_password=1;
941 break;
942 case 'r':
943 if (!(md_result_file= my_fopen(argument, O_WRONLY | FILE_BINARY,
944 MYF(MY_WME))))
945 exit(1);
946 break;
947 case 'W':
948 #ifdef _WIN32
949 opt_protocol= MYSQL_PROTOCOL_PIPE;
950 #endif
951 break;
952 case 'N':
953 opt_set_charset= 0;
954 break;
955 case 'T':
956 opt_disable_keys=0;
957
958 if (strlen(argument) >= FN_REFLEN)
959 {
960 /*
961 This check is made because the some the file functions below
962 have FN_REFLEN sized stack allocated buffers and will cause
963 a crash even if the input destination buffer is large enough
964 to hold the output.
965 */
966 die(EX_USAGE, "Input filename too long: %s", argument);
967 }
968
969 break;
970 case '#':
971 DBUG_PUSH(argument ? argument : default_dbug_option);
972 debug_check_flag= 1;
973 break;
974 #include <sslopt-case.h>
975 case 'V': print_version(); exit(0);
976 case 'X':
977 opt_xml= 1;
978 extended_insert= opt_drop= opt_lock=
979 opt_disable_keys= opt_autocommit= opt_create_db= 0;
980 break;
981 case 'i':
982 opt_comments_used= 1;
983 break;
984 case 'I':
985 case '?':
986 usage();
987 exit(0);
988 case (int) OPT_MASTER_DATA:
989 if (!argument) /* work like in old versions */
990 opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL;
991 break;
992 case (int) OPT_MYSQLDUMP_SLAVE_DATA:
993 if (!argument) /* work like in old versions */
994 opt_slave_data= MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL;
995 break;
996 case (int) OPT_OPTIMIZE:
997 extended_insert= opt_drop= opt_lock= quick= create_options=
998 opt_disable_keys= lock_tables= opt_set_charset= 1;
999 break;
1000 case (int) OPT_SKIP_OPTIMIZATION:
1001 extended_insert= opt_drop= opt_lock= quick= create_options=
1002 opt_disable_keys= lock_tables= opt_set_charset= 0;
1003 break;
1004 case (int) OPT_COMPACT:
1005 if (opt_compact)
1006 {
1007 opt_comments= opt_drop= opt_disable_keys= opt_lock= 0;
1008 opt_set_charset= 0;
1009 }
1010 break;
1011 case (int) OPT_TABLES:
1012 opt_databases=0;
1013 break;
1014 case (int) OPT_IGNORE_TABLE:
1015 {
1016 if (!strchr(argument, '.'))
1017 {
1018 fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
1019 exit(1);
1020 }
1021 if (my_hash_insert(&ignore_table, (uchar*)my_strdup(PSI_NOT_INSTRUMENTED,
1022 argument, MYF(0))))
1023 exit(EX_EOM);
1024 break;
1025 }
1026 case (int) OPT_COMPATIBLE:
1027 {
1028 char buff[255];
1029 char *end= compatible_mode_normal_str;
1030 int i;
1031 ulong mode;
1032 uint err_len;
1033
1034 opt_quoted= 1;
1035 opt_set_charset= 0;
1036 opt_compatible_mode_str= argument;
1037 opt_compatible_mode= find_set(&compatible_mode_typelib,
1038 argument, strlen(argument),
1039 &err_ptr, &err_len);
1040 if (err_len)
1041 {
1042 strmake(buff, err_ptr, MY_MIN(sizeof(buff) - 1, err_len));
1043 fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
1044 exit(1);
1045 }
1046 #if !defined(NDEBUG)
1047 {
1048 size_t size_for_sql_mode= 0;
1049 const char **ptr;
1050 for (ptr= compatible_mode_names; *ptr; ptr++)
1051 size_for_sql_mode+= strlen(*ptr);
1052 size_for_sql_mode+= sizeof(compatible_mode_names)-1;
1053 assert(sizeof(compatible_mode_normal_str)>=size_for_sql_mode);
1054 }
1055 #endif
1056 mode= opt_compatible_mode;
1057 for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++)
1058 {
1059 if (mode & 1)
1060 {
1061 end= my_stpcpy(end, compatible_mode_names[i]);
1062 end= my_stpcpy(end, ",");
1063 }
1064 }
1065 if (end!=compatible_mode_normal_str)
1066 end[-1]= 0;
1067 /*
1068 Set charset to the default compiled value if it hasn't
1069 been reset yet by --default-character-set=xxx.
1070 */
1071 if (default_charset == mysql_universal_client_charset)
1072 default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
1073 break;
1074 }
1075 case (int) OPT_ENABLE_CLEARTEXT_PLUGIN:
1076 using_opt_enable_cleartext_plugin= TRUE;
1077 break;
1078 case (int) OPT_MYSQL_PROTOCOL:
1079 opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
1080 opt->name);
1081 break;
1082 case (int) OPT_SET_GTID_PURGED:
1083 {
1084 if (argument)
1085 opt_set_gtid_purged_mode= find_type_or_exit(argument,
1086 &set_gtid_purged_mode_typelib,
1087 opt->name)-1;
1088 break;
1089 }
1090 case (int) OPT_MYSQLDUMP_IGNORE_ERROR:
1091 /* Store the supplied list of errors into an array. */
1092 if (parse_ignore_error())
1093 exit(EX_EOM);
1094 break;
1095 case OPT_SECURE_AUTH:
1096 /* --secure-auth is a zombie option. */
1097 if (!opt_secure_auth)
1098 {
1099 fprintf(stderr, "mysqldump: [ERROR] --skip-secure-auth is not supported.\n");
1100 exit(1);
1101 }
1102 else
1103 CLIENT_WARN_DEPRECATED_NO_REPLACEMENT("--secure-auth");
1104 break;
1105 }
1106 return 0;
1107 }
1108
get_options(int * argc,char *** argv)1109 static int get_options(int *argc, char ***argv)
1110 {
1111 int ho_error;
1112
1113 if (mysql_get_option(NULL, MYSQL_OPT_MAX_ALLOWED_PACKET, &opt_max_allowed_packet) ||
1114 mysql_get_option(NULL, MYSQL_OPT_NET_BUFFER_LENGTH, &opt_max_allowed_packet))
1115 {
1116 exit(1);
1117 }
1118
1119 md_result_file= stdout;
1120 my_getopt_use_args_separator= TRUE;
1121 if (load_defaults("my",load_default_groups,argc,argv))
1122 return 1;
1123 my_getopt_use_args_separator= FALSE;
1124
1125 defaults_argv= *argv;
1126
1127 if (my_hash_init(&ignore_table, charset_info, 16, 0, 0,
1128 (my_hash_get_key) get_table_key, my_free, 0,
1129 PSI_NOT_INSTRUMENTED))
1130 return(EX_EOM);
1131 /* Don't copy internal log tables */
1132 if (my_hash_insert(&ignore_table,
1133 (uchar*) my_strdup(PSI_NOT_INSTRUMENTED,
1134 "mysql.apply_status", MYF(MY_WME))) ||
1135 my_hash_insert(&ignore_table,
1136 (uchar*) my_strdup(PSI_NOT_INSTRUMENTED,
1137 "mysql.schema", MYF(MY_WME))) ||
1138 my_hash_insert(&ignore_table,
1139 (uchar*) my_strdup(PSI_NOT_INSTRUMENTED,
1140 "mysql.general_log", MYF(MY_WME))) ||
1141 my_hash_insert(&ignore_table,
1142 (uchar*) my_strdup(PSI_NOT_INSTRUMENTED,
1143 "mysql.slow_log", MYF(MY_WME))))
1144 return(EX_EOM);
1145
1146 if (my_hash_init(&processed_compression_dictionaries, charset_info, 16, 0,
1147 0, (my_hash_get_key)get_table_key, my_free, 0, PSI_NOT_INSTRUMENTED))
1148 return(EX_EOM);
1149
1150 if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
1151 return(ho_error);
1152
1153 if (mysql_options(NULL, MYSQL_OPT_MAX_ALLOWED_PACKET, &opt_max_allowed_packet) ||
1154 mysql_options(NULL, MYSQL_OPT_NET_BUFFER_LENGTH, &opt_net_buffer_length))
1155 {
1156 exit(1);
1157 }
1158
1159 if (debug_info_flag)
1160 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1161 if (debug_check_flag)
1162 my_end_arg= MY_CHECK_ERROR;
1163
1164 if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
1165 fields_terminated))
1166 {
1167 fprintf(stderr,
1168 "%s: You must use option --tab with --fields-...\n", my_progname);
1169 return(EX_USAGE);
1170 }
1171
1172 if (opt_lock_for_backup && opt_lock_all_tables)
1173 {
1174 fprintf(stderr, "%s: You can't use --lock-for-backup and "
1175 "--lock-all-tables at the same time.\n", my_progname);
1176 return(EX_USAGE);
1177 }
1178
1179 /*
1180 Convert --lock-for-backup to --lock-all-tables if --single-transaction is
1181 not specified.
1182 */
1183 if (!opt_single_transaction && opt_lock_for_backup)
1184 {
1185 opt_lock_all_tables= 1;
1186 opt_lock_for_backup= 0;
1187 }
1188
1189 /* We don't delete master logs if slave data option */
1190 if (opt_slave_data)
1191 {
1192 opt_lock_all_tables= !opt_single_transaction;
1193 opt_master_data= 0;
1194 opt_delete_master_logs= 0;
1195 }
1196
1197 /* Ensure consistency of the set of binlog & locking options */
1198 if (opt_delete_master_logs && !opt_master_data)
1199 opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL;
1200 if (opt_single_transaction && opt_lock_all_tables)
1201 {
1202 fprintf(stderr, "%s: You can't use --single-transaction and "
1203 "--lock-all-tables at the same time.\n", my_progname);
1204 return(EX_USAGE);
1205 }
1206 if (opt_master_data)
1207 {
1208 opt_lock_all_tables= !opt_single_transaction;
1209 opt_slave_data= 0;
1210 }
1211 if (opt_single_transaction || opt_lock_all_tables)
1212 lock_tables= 0;
1213 if (enclosed && opt_enclosed)
1214 {
1215 fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
1216 return(EX_USAGE);
1217 }
1218 if ((opt_databases || opt_alldbs) && path)
1219 {
1220 fprintf(stderr,
1221 "%s: --databases or --all-databases can't be used with --tab.\n",
1222 my_progname);
1223 return(EX_USAGE);
1224 }
1225 if (strcmp(default_charset, charset_info->csname) &&
1226 !(charset_info= get_charset_by_csname(default_charset,
1227 MY_CS_PRIMARY, MYF(MY_WME))))
1228 exit(1);
1229 if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
1230 {
1231 short_usage();
1232 return EX_USAGE;
1233 }
1234 if (tty_password)
1235 opt_password=get_tty_password(NullS);
1236 return(0);
1237 } /* get_options */
1238
1239
1240 /*
1241 ** DB_error -- prints mysql error message and exits the program.
1242 */
DB_error(MYSQL * mysql_arg,const char * when)1243 static void DB_error(MYSQL *mysql_arg, const char *when)
1244 {
1245 DBUG_ENTER("DB_error");
1246 maybe_die(EX_MYSQLERR, "Got error: %d: %s %s",
1247 mysql_errno(mysql_arg), mysql_error(mysql_arg), when);
1248 DBUG_VOID_RETURN;
1249 }
1250
1251
1252
1253 /*
1254 Prints out an error message and kills the process.
1255
1256 SYNOPSIS
1257 die()
1258 error_num - process return value
1259 fmt_reason - a format string for use by my_vsnprintf.
1260 ... - variable arguments for above fmt_reason string
1261
1262 DESCRIPTION
1263 This call prints out the formatted error message to stderr and then
1264 terminates the process.
1265 */
die(int error_num,const char * fmt_reason,...)1266 static void die(int error_num, const char* fmt_reason, ...)
1267 {
1268 char buffer[1000];
1269 va_list args;
1270 va_start(args,fmt_reason);
1271 my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
1272 va_end(args);
1273
1274 fprintf(stderr, "%s: %s\n", my_progname, buffer);
1275 fflush(stderr);
1276
1277 /* force the exit */
1278 opt_force= 0;
1279 if (opt_ignore_error)
1280 my_free(opt_ignore_error);
1281 opt_ignore_error= 0;
1282
1283 maybe_exit(error_num);
1284 }
1285
1286
1287 /*
1288 Prints out an error message and maybe kills the process.
1289
1290 SYNOPSIS
1291 maybe_die()
1292 error_num - process return value
1293 fmt_reason - a format string for use by my_vsnprintf.
1294 ... - variable arguments for above fmt_reason string
1295
1296 DESCRIPTION
1297 This call prints out the formatted error message to stderr and then
1298 terminates the process, unless the --force command line option is used.
1299
1300 This call should be used for non-fatal errors (such as database
1301 errors) that the code may still be able to continue to the next unit
1302 of work.
1303
1304 */
maybe_die(int error_num,const char * fmt_reason,...)1305 static void maybe_die(int error_num, const char* fmt_reason, ...)
1306 {
1307 char buffer[1000];
1308 va_list args;
1309 va_start(args,fmt_reason);
1310 my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
1311 va_end(args);
1312
1313 fprintf(stderr, "%s: %s\n", my_progname, buffer);
1314 fflush(stderr);
1315
1316 maybe_exit(error_num);
1317 }
1318
1319
1320
1321 /*
1322 Sends a query to server, optionally reads result, prints error message if
1323 some.
1324
1325 SYNOPSIS
1326 mysql_query_with_error_report()
1327 mysql_con connection to use
1328 res if non zero, result will be put there with
1329 mysql_store_result()
1330 query query to send to server
1331
1332 RETURN VALUES
1333 0 query sending and (if res!=0) result reading went ok
1334 1 error
1335 */
1336
mysql_query_with_error_report(MYSQL * mysql_con,MYSQL_RES ** res,const char * query)1337 static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
1338 const char *query)
1339 {
1340 if (mysql_query(mysql_con, query) ||
1341 (res && !((*res)= mysql_store_result(mysql_con))))
1342 {
1343 maybe_die(EX_MYSQLERR, "Couldn't execute '%s': %s (%d)",
1344 query, mysql_error(mysql_con), mysql_errno(mysql_con));
1345 return 1;
1346 }
1347 return 0;
1348 }
1349
1350
fetch_db_collation(const char * db_name,char * db_cl_name,int db_cl_size)1351 static int fetch_db_collation(const char *db_name,
1352 char *db_cl_name,
1353 int db_cl_size)
1354 {
1355 my_bool err_status= FALSE;
1356 char query[QUERY_LENGTH];
1357 MYSQL_RES *db_cl_res;
1358 MYSQL_ROW db_cl_row;
1359 char quoted_database_buf[NAME_LEN*2+3];
1360 char *qdatabase= quote_name(db_name, quoted_database_buf, 1);
1361
1362 my_snprintf(query, sizeof (query), "use %s", qdatabase);
1363
1364 if (mysql_query_with_error_report(mysql, NULL, query))
1365 return 1;
1366
1367 if (mysql_query_with_error_report(mysql, &db_cl_res,
1368 "select @@collation_database"))
1369 return 1;
1370
1371 do
1372 {
1373 if (mysql_num_rows(db_cl_res) != 1)
1374 {
1375 err_status= TRUE;
1376 break;
1377 }
1378
1379 if (!(db_cl_row= mysql_fetch_row(db_cl_res)))
1380 {
1381 err_status= TRUE;
1382 break;
1383 }
1384
1385 strncpy(db_cl_name, db_cl_row[0], db_cl_size-1);
1386 db_cl_name[db_cl_size - 1]= 0;
1387
1388 } while (FALSE);
1389
1390 mysql_free_result(db_cl_res);
1391
1392 return err_status ? 1 : 0;
1393 }
1394
1395 /*
1396 Check if server supports binlog_snapshot_gtid_executed.
1397 Returns 1 supported, 0 if not.
1398 */
1399 static int
consistent_gtid_executed_supported(MYSQL * mysql_con)1400 consistent_gtid_executed_supported(MYSQL *mysql_con)
1401 {
1402 MYSQL_RES *res;
1403 MYSQL_ROW row;
1404 int found = 0;
1405
1406 if (mysql_query_with_error_report(
1407 mysql_con, &res, "SHOW STATUS LIKE 'binlog_snapshot_gtid_executed'"))
1408 return 0;
1409
1410 while ((row= mysql_fetch_row(res)))
1411 {
1412 if (0 == strcmp(row[0], "Binlog_snapshot_gtid_executed"))
1413 {
1414 found= 1;
1415 break;
1416 }
1417 }
1418 mysql_free_result(res);
1419
1420 return found;
1421 }
1422
1423 /*
1424 Check if server supports non-blocking binlog position using the
1425 binlog_snapshot_file and binlog_snapshot_position status variables. If it
1426 does, also return the position obtained if output pointers are non-NULL.
1427 Returns 1 if position available, 0 if not.
1428 */
1429 static int
check_consistent_binlog_pos(char * binlog_pos_file,char * binlog_pos_offset)1430 check_consistent_binlog_pos(char *binlog_pos_file, char *binlog_pos_offset)
1431 {
1432 MYSQL_RES *res;
1433 MYSQL_ROW row;
1434 int found;
1435
1436 if (mysql_query_with_error_report(mysql, &res,
1437 "SHOW STATUS LIKE 'binlog_snapshot_%'"))
1438 return 0;
1439
1440 found= 0;
1441 while ((row= mysql_fetch_row(res)))
1442 {
1443 if (0 == strcmp(row[0], "Binlog_snapshot_file"))
1444 {
1445 if (binlog_pos_file)
1446 strmake(binlog_pos_file, row[1], FN_REFLEN-1);
1447 found++;
1448 }
1449 else if (0 == strcmp(row[0], "Binlog_snapshot_position"))
1450 {
1451 if (binlog_pos_offset)
1452 strmake(binlog_pos_offset, row[1], LONGLONG_LEN);
1453 found++;
1454 }
1455 }
1456 mysql_free_result(res);
1457
1458 return (found == 2);
1459 }
1460
my_case_str(const char * str,size_t str_len,const char * token,size_t token_len)1461 static char *my_case_str(const char *str,
1462 size_t str_len,
1463 const char *token,
1464 size_t token_len)
1465 {
1466 my_match_t match;
1467
1468 uint status= my_charset_latin1.coll->instr(&my_charset_latin1,
1469 str, str_len,
1470 token, token_len,
1471 &match, 1);
1472
1473 return status ? (char *) str + match.end : NULL;
1474 }
1475
1476
switch_db_collation(FILE * sql_file,const char * db_name,const char * delimiter,const char * current_db_cl_name,const char * required_db_cl_name,int * db_cl_altered)1477 static int switch_db_collation(FILE *sql_file,
1478 const char *db_name,
1479 const char *delimiter,
1480 const char *current_db_cl_name,
1481 const char *required_db_cl_name,
1482 int *db_cl_altered)
1483 {
1484 if (strcmp(current_db_cl_name, required_db_cl_name) != 0)
1485 {
1486 char quoted_db_buf[NAME_LEN * 2 + 3];
1487 char *quoted_db_name= quote_name(db_name, quoted_db_buf, FALSE);
1488
1489 CHARSET_INFO *db_cl= get_charset_by_name(required_db_cl_name, MYF(0));
1490
1491 if (!db_cl)
1492 return 1;
1493
1494 fprintf(sql_file,
1495 "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n",
1496 (const char *) quoted_db_name,
1497 (const char *) db_cl->csname,
1498 (const char *) db_cl->name,
1499 (const char *) delimiter);
1500
1501 *db_cl_altered= 1;
1502
1503 return 0;
1504 }
1505
1506 *db_cl_altered= 0;
1507
1508 return 0;
1509 }
1510
1511
restore_db_collation(FILE * sql_file,const char * db_name,const char * delimiter,const char * db_cl_name)1512 static int restore_db_collation(FILE *sql_file,
1513 const char *db_name,
1514 const char *delimiter,
1515 const char *db_cl_name)
1516 {
1517 char quoted_db_buf[NAME_LEN * 2 + 3];
1518 char *quoted_db_name= quote_name(db_name, quoted_db_buf, FALSE);
1519
1520 CHARSET_INFO *db_cl= get_charset_by_name(db_cl_name, MYF(0));
1521
1522 if (!db_cl)
1523 return 1;
1524
1525 fprintf(sql_file,
1526 "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n",
1527 (const char *) quoted_db_name,
1528 (const char *) db_cl->csname,
1529 (const char *) db_cl->name,
1530 (const char *) delimiter);
1531
1532 return 0;
1533 }
1534
1535
switch_cs_variables(FILE * sql_file,const char * delimiter,const char * character_set_client,const char * character_set_results,const char * collation_connection)1536 static void switch_cs_variables(FILE *sql_file,
1537 const char *delimiter,
1538 const char *character_set_client,
1539 const char *character_set_results,
1540 const char *collation_connection)
1541 {
1542 fprintf(sql_file,
1543 "/*!50003 SET @saved_cs_client = @@character_set_client */ %s\n"
1544 "/*!50003 SET @saved_cs_results = @@character_set_results */ %s\n"
1545 "/*!50003 SET @saved_col_connection = @@collation_connection */ %s\n"
1546 "/*!50003 SET character_set_client = %s */ %s\n"
1547 "/*!50003 SET character_set_results = %s */ %s\n"
1548 "/*!50003 SET collation_connection = %s */ %s\n",
1549 (const char *) delimiter,
1550 (const char *) delimiter,
1551 (const char *) delimiter,
1552
1553 (const char *) character_set_client,
1554 (const char *) delimiter,
1555
1556 (const char *) character_set_results,
1557 (const char *) delimiter,
1558
1559 (const char *) collation_connection,
1560 (const char *) delimiter);
1561 }
1562
1563
restore_cs_variables(FILE * sql_file,const char * delimiter)1564 static void restore_cs_variables(FILE *sql_file,
1565 const char *delimiter)
1566 {
1567 fprintf(sql_file,
1568 "/*!50003 SET character_set_client = @saved_cs_client */ %s\n"
1569 "/*!50003 SET character_set_results = @saved_cs_results */ %s\n"
1570 "/*!50003 SET collation_connection = @saved_col_connection */ %s\n",
1571 (const char *) delimiter,
1572 (const char *) delimiter,
1573 (const char *) delimiter);
1574 }
1575
1576 /*
1577 This function will remove specific sql mode.
1578
1579 @param[in] sql_mode Original sql mode from where input mode needs to
1580 be removed.
1581 @param[in] replace_mode sql mode which needs to be removed from original
1582 sql mode.
1583 @param[in] replace_len length of sql mode which needs to be removed.
1584
1585 @retval 1 replace_mode is not present
1586 0 replace_mode is removed successfully
1587 */
remove_sql_mode(char * sql_mode,const char * replace_mode,size_t replace_len)1588 static int remove_sql_mode(char* sql_mode, const char* replace_mode,
1589 size_t replace_len) {
1590 char *start = strstr(sql_mode, replace_mode);
1591 /* nothing to replace */
1592 if (!start)
1593 return 1;
1594 /* sql mode to replace is the only sql mode present or the last one */
1595 if (strlen(start) == replace_len) {
1596 if (start == sql_mode)
1597 *start = 0;
1598 else
1599 start[-1] = 0;
1600 }
1601 else {
1602 const char *next = start + replace_len + 1;
1603 memmove(start, next, strlen(next) + 1);
1604 }
1605 return 0;
1606 }
1607
switch_sql_mode(FILE * sql_file,const char * delimiter,const char * sql_mode)1608 static void switch_sql_mode(FILE *sql_file,
1609 const char *delimiter,
1610 const char *sql_mode)
1611 {
1612 fprintf(sql_file,
1613 "/*!50003 SET @saved_sql_mode = @@sql_mode */ %s\n"
1614 "/*!50003 SET sql_mode = '%s' */ %s\n",
1615 (const char *) delimiter,
1616
1617 (const char *) sql_mode,
1618 (const char *) delimiter);
1619 }
1620
1621
restore_sql_mode(FILE * sql_file,const char * delimiter)1622 static void restore_sql_mode(FILE *sql_file,
1623 const char *delimiter)
1624 {
1625 fprintf(sql_file,
1626 "/*!50003 SET sql_mode = @saved_sql_mode */ %s\n",
1627 (const char *) delimiter);
1628 }
1629
1630
switch_time_zone(FILE * sql_file,const char * delimiter,const char * time_zone)1631 static void switch_time_zone(FILE *sql_file,
1632 const char *delimiter,
1633 const char *time_zone)
1634 {
1635 fprintf(sql_file,
1636 "/*!50003 SET @saved_time_zone = @@time_zone */ %s\n"
1637 "/*!50003 SET time_zone = '%s' */ %s\n",
1638 (const char *) delimiter,
1639
1640 (const char *) time_zone,
1641 (const char *) delimiter);
1642 }
1643
1644
restore_time_zone(FILE * sql_file,const char * delimiter)1645 static void restore_time_zone(FILE *sql_file,
1646 const char *delimiter)
1647 {
1648 fprintf(sql_file,
1649 "/*!50003 SET time_zone = @saved_time_zone */ %s\n",
1650 (const char *) delimiter);
1651 }
1652
1653
1654 /**
1655 Switch charset for results to some specified charset. If the server does not
1656 support character_set_results variable, nothing can be done here. As for
1657 whether something should be done here, future new callers of this function
1658 should be aware that the server lacking the facility of switching charsets is
1659 treated as success.
1660
1661 @note If the server lacks support, then nothing is changed and no error
1662 condition is returned.
1663
1664 @returns whether there was an error or not
1665 */
switch_character_set_results(MYSQL * mysql,const char * cs_name)1666 static int switch_character_set_results(MYSQL *mysql, const char *cs_name)
1667 {
1668 char query_buffer[QUERY_LENGTH];
1669 size_t query_length;
1670
1671 /* Server lacks facility. This is not an error, by arbitrary decision . */
1672 if (!server_supports_switching_charsets)
1673 return FALSE;
1674
1675 query_length= my_snprintf(query_buffer,
1676 sizeof (query_buffer),
1677 "SET SESSION character_set_results = '%s'",
1678 (const char *) cs_name);
1679
1680 return mysql_real_query(mysql, query_buffer, (ulong)query_length);
1681 }
1682
1683 /**
1684 Rewrite statement, enclosing DEFINER clause in version-specific comment.
1685
1686 This function parses any CREATE statement and encloses DEFINER-clause in
1687 version-specific comment:
1688 input query: CREATE DEFINER=a@b FUNCTION ...
1689 rewritten query: CREATE * / / *!50020 DEFINER=a@b * / / *!50003 FUNCTION ...
1690
1691 @note This function will go away when WL#3995 is implemented.
1692
1693 @param[in] stmt_str CREATE statement string.
1694 @param[in] stmt_length Length of the stmt_str.
1695 @param[in] definer_version_str Minimal MySQL version number when
1696 DEFINER clause is supported in the
1697 given statement.
1698 @param[in] definer_version_length Length of definer_version_str.
1699 @param[in] stmt_version_str Minimal MySQL version number when the
1700 given statement is supported.
1701 @param[in] stmt_version_length Length of stmt_version_str.
1702 @param[in] keyword_str Keyword to look for after CREATE.
1703 @param[in] keyword_length Length of keyword_str.
1704
1705 @return pointer to the new allocated query string.
1706 */
1707
cover_definer_clause(const char * stmt_str,size_t stmt_length,const char * definer_version_str,size_t definer_version_length,const char * stmt_version_str,size_t stmt_version_length,const char * keyword_str,size_t keyword_length)1708 static char *cover_definer_clause(const char *stmt_str,
1709 size_t stmt_length,
1710 const char *definer_version_str,
1711 size_t definer_version_length,
1712 const char *stmt_version_str,
1713 size_t stmt_version_length,
1714 const char *keyword_str,
1715 size_t keyword_length)
1716 {
1717 char *definer_begin= my_case_str(stmt_str, stmt_length,
1718 C_STRING_WITH_LEN(" DEFINER"));
1719 char *definer_end= NULL;
1720
1721 char *query_str= NULL;
1722 char *query_ptr;
1723 LEX_CSTRING comment= { C_STRING_WITH_LEN("*/ /*!") };
1724
1725 if (!definer_begin)
1726 return NULL;
1727
1728 definer_end= my_case_str(definer_begin, strlen(definer_begin),
1729 keyword_str, keyword_length);
1730
1731 if (!definer_end)
1732 return NULL;
1733
1734 /*
1735 Allocate memory for new query string: original string
1736 from SHOW statement and version-specific comments.
1737 */
1738 query_str= alloc_query_str(stmt_length + 23);
1739
1740 query_ptr= my_stpncpy(query_str, stmt_str, definer_begin - stmt_str);
1741 query_ptr= my_stpncpy(query_ptr, comment.str, comment.length + 1);
1742 query_ptr= my_stpncpy(query_ptr, definer_version_str, definer_version_length);
1743 query_ptr= my_stpncpy(query_ptr, definer_begin, definer_end - definer_begin);
1744 query_ptr= my_stpncpy(query_ptr, comment.str, comment.length + 1);
1745 query_ptr= my_stpncpy(query_ptr, stmt_version_str, stmt_version_length);
1746 query_ptr= strxmov(query_ptr, definer_end, NullS);
1747
1748 return query_str;
1749 }
1750
1751 /*
1752 Open a new .sql file to dump the table or view into
1753
1754 SYNOPSIS
1755 open_sql_file_for_table
1756 name name of the table or view
1757 flags flags (as per "man 2 open")
1758
1759 RETURN VALUES
1760 0 Failed to open file
1761 > 0 Handle of the open file
1762 */
open_sql_file_for_table(const char * table,int flags)1763 static FILE* open_sql_file_for_table(const char* table, int flags)
1764 {
1765 FILE* res;
1766 char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1767 /*
1768 We need to reset processed compression dictionaries container
1769 each time a new SQL file is created (for --tab option).
1770 */
1771 my_hash_reset(&processed_compression_dictionaries);
1772 convert_dirname(tmp_path,path,NullS);
1773 res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
1774 flags, MYF(MY_WME));
1775 return res;
1776 }
1777
1778
free_resources()1779 static void free_resources()
1780 {
1781 if (md_result_file && md_result_file != stdout)
1782 my_fclose(md_result_file, MYF(0));
1783 my_free(opt_password);
1784 if (my_hash_inited(&ignore_table))
1785 my_hash_free(&ignore_table);
1786 if (my_hash_inited(&processed_compression_dictionaries))
1787 my_hash_free(&processed_compression_dictionaries);
1788 if (insert_pat_inited)
1789 dynstr_free(&insert_pat);
1790 if (defaults_argv)
1791 free_defaults(defaults_argv);
1792 if (opt_ignore_error)
1793 my_free(opt_ignore_error);
1794 delete_dynamic(&ignore_error);
1795 if (gtid_executed_buffer_inited)
1796 dynstr_free(>id_executed_buffer);
1797 my_end(my_end_arg);
1798 }
1799
1800 /**
1801 Parse the list of error numbers to be ignored and store into a dynamic
1802 array.
1803
1804 @return Operation status
1805 @retval 0 Success
1806 @retval >0 Failure
1807 */
1808 static
parse_ignore_error()1809 int parse_ignore_error()
1810 {
1811 const char *search= ",";
1812 char *token;
1813 uint my_err;
1814
1815 DBUG_ENTER("parse_ignore_error");
1816
1817 if (my_init_dynamic_array(&ignore_error,
1818 PSI_NOT_INSTRUMENTED,
1819 sizeof(uint), NULL, 12, 12))
1820 goto error;
1821
1822 token= strtok(opt_ignore_error, search);
1823
1824 while (token != NULL)
1825 {
1826 my_err= atoi(token);
1827 // filter out 0s, if any
1828 if (my_err != 0)
1829 {
1830 if (insert_dynamic(&ignore_error, &my_err))
1831 goto error;
1832 }
1833 token= strtok(NULL, search);
1834 }
1835 DBUG_RETURN(0);
1836
1837 error:
1838 DBUG_RETURN(EX_EOM);
1839 }
1840
1841 /**
1842 Check if the last error should be ignored.
1843 @retval 1 yes
1844 0 no
1845 */
do_ignore_error()1846 static my_bool do_ignore_error()
1847 {
1848 uint i, last_errno, *my_err;
1849 my_bool found= 0;
1850
1851 DBUG_ENTER("do_ignore_error");
1852
1853 last_errno= mysql_errno(mysql);
1854
1855 if (last_errno == 0)
1856 goto done;
1857
1858 for (i= 0; i < ignore_error.elements; i++)
1859 {
1860 my_err= dynamic_element(&ignore_error, i, uint *);
1861 if (last_errno == *my_err)
1862 {
1863 found= 1;
1864 break;
1865 }
1866 }
1867 done:
1868 DBUG_RETURN(found);
1869 }
1870
maybe_exit(int error)1871 static void maybe_exit(int error)
1872 {
1873 if (!first_error)
1874 first_error= error;
1875
1876 /*
1877 Return if --force is used; else return only if the
1878 last error number is in the list of error numbers
1879 specified using --ignore-error option.
1880 */
1881 if (opt_force || (opt_ignore_error && do_ignore_error()))
1882 return;
1883 if (mysql)
1884 mysql_close(mysql);
1885 free_resources();
1886 exit(error);
1887 }
1888
1889
1890 /*
1891 db_connect -- connects to the host and selects DB.
1892 */
1893
connect_to_db(char * host,char * user,char * passwd)1894 static int connect_to_db(char *host, char *user,char *passwd)
1895 {
1896 char buff[20+FN_REFLEN];
1897 DBUG_ENTER("connect_to_db");
1898
1899 verbose_msg("-- Connecting to %s...\n", host ? host : "localhost");
1900 mysql_init(&mysql_connection);
1901 if (opt_compress)
1902 mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
1903 SSL_SET_OPTIONS(&mysql_connection);
1904 if (opt_protocol)
1905 mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
1906 if (opt_bind_addr)
1907 mysql_options(&mysql_connection,MYSQL_OPT_BIND,opt_bind_addr);
1908 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
1909 if (shared_memory_base_name)
1910 mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
1911 #endif
1912 mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
1913
1914 if (opt_plugin_dir && *opt_plugin_dir)
1915 mysql_options(&mysql_connection, MYSQL_PLUGIN_DIR, opt_plugin_dir);
1916
1917 if (opt_default_auth && *opt_default_auth)
1918 mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
1919
1920 if (using_opt_enable_cleartext_plugin)
1921 mysql_options(&mysql_connection, MYSQL_ENABLE_CLEARTEXT_PLUGIN,
1922 (char *) &opt_enable_cleartext_plugin);
1923
1924 mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
1925 mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
1926 "program_name", "mysqldump");
1927
1928 set_server_public_key(&mysql_connection);
1929 set_get_server_public_key_option(&mysql_connection);
1930
1931 if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
1932 NULL,opt_mysql_port,opt_mysql_unix_port,
1933 0)))
1934 {
1935 DB_error(&mysql_connection, "when trying to connect");
1936 DBUG_RETURN(1);
1937 }
1938 if ((mysql_get_server_version(&mysql_connection) < 40100) ||
1939 (opt_compatible_mode & 3))
1940 {
1941 /* Don't dump SET NAMES with a pre-4.1 server (bug#7997). */
1942 opt_set_charset= 0;
1943
1944 /* Don't switch charsets for 4.1 and earlier. (bug#34192). */
1945 server_supports_switching_charsets= FALSE;
1946 }
1947 /*
1948 As we're going to set SQL_MODE, it would be lost on reconnect, so we
1949 cannot reconnect.
1950 */
1951 mysql->reconnect= 0;
1952 my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
1953 compatible_mode_normal_str);
1954 if (mysql_query_with_error_report(mysql, 0, buff))
1955 DBUG_RETURN(1);
1956 /*
1957 set time_zone to UTC to allow dumping date types between servers with
1958 different time zone settings
1959 */
1960 if (opt_tz_utc)
1961 {
1962 my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */");
1963 if (mysql_query_with_error_report(mysql, 0, buff))
1964 DBUG_RETURN(1);
1965 }
1966 DBUG_RETURN(0);
1967 } /* connect_to_db */
1968
1969
1970 /*
1971 ** dbDisconnect -- disconnects from the host.
1972 */
dbDisconnect(char * host)1973 static void dbDisconnect(char *host)
1974 {
1975 verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
1976 mysql_close(mysql);
1977 } /* dbDisconnect */
1978
1979
unescape(FILE * file,char * pos,size_t length)1980 static void unescape(FILE *file,char *pos, size_t length)
1981 {
1982 char *tmp;
1983 DBUG_ENTER("unescape");
1984 if (!(tmp=(char*) my_malloc(PSI_NOT_INSTRUMENTED,
1985 length*2+1, MYF(MY_WME))))
1986 die(EX_MYSQLERR, "Couldn't allocate memory");
1987
1988 mysql_real_escape_string_quote(&mysql_connection, tmp, pos, (ulong)length, '\'');
1989 fputc('\'', file);
1990 fputs(tmp, file);
1991 fputc('\'', file);
1992 check_io(file);
1993 my_free(tmp);
1994 DBUG_VOID_RETURN;
1995 } /* unescape */
1996
1997
test_if_special_chars(const char * str)1998 static my_bool test_if_special_chars(const char *str)
1999 {
2000 for ( ; *str ; str++)
2001 if (!my_isvar(charset_info,*str) && *str != '$')
2002 return 1;
2003 return 0;
2004 } /* test_if_special_chars */
2005
2006
2007
2008 /*
2009 quote_name(name, buff, force)
2010
2011 Quotes char string, taking into account compatible mode
2012
2013 Args
2014
2015 name Unquoted string containing that which will be quoted
2016 buff The buffer that contains the quoted value, also returned
2017 force Flag to make it ignore 'test_if_special_chars'
2018
2019 Returns
2020
2021 buff quoted string
2022
2023 */
quote_name(const char * name,char * buff,my_bool force)2024 static char *quote_name(const char *name, char *buff, my_bool force)
2025 {
2026 char *to= buff;
2027 char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';
2028
2029 if (!force && !opt_quoted && !test_if_special_chars(name))
2030 return (char*) name;
2031 *to++= qtype;
2032 while (*name)
2033 {
2034 if (*name == qtype)
2035 *to++= qtype;
2036 *to++= *name++;
2037 }
2038 to[0]= qtype;
2039 to[1]= 0;
2040 return buff;
2041 } /* quote_name */
2042
2043 /**
2044 Unquotes char string, taking into account compatible mode
2045
2046 @param opt_quoted_name Optionally quoted string
2047 @param buff The buffer that will contain the unquoted value,
2048 may be returned
2049
2050 @return Pointer to unquoted string (either original opt_quoted_name or
2051 buff).
2052 */
unquote_name(const char * opt_quoted_name,char * buff)2053 static char *unquote_name(const char *opt_quoted_name, char *buff)
2054 {
2055 char *to= buff;
2056 const char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';
2057
2058 if (!opt_quoted)
2059 return (char*)opt_quoted_name;
2060 if (*opt_quoted_name != qtype)
2061 {
2062 assert(strchr(opt_quoted_name, qtype) == 0);
2063 return (char*)opt_quoted_name;
2064 }
2065
2066 ++opt_quoted_name;
2067 while (*opt_quoted_name)
2068 {
2069 if (*opt_quoted_name == qtype)
2070 {
2071 ++opt_quoted_name;
2072 if (*opt_quoted_name == qtype)
2073 *to++= qtype;
2074 else
2075 {
2076 assert(*opt_quoted_name == '\0');
2077 }
2078 }
2079 else
2080 {
2081 *to++= *opt_quoted_name++;
2082 }
2083 }
2084 to[0]= 0;
2085 return buff;
2086 } /* unquote_name */
2087
2088
2089 /*
2090 Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
2091
2092 SYNOPSIS
2093 quote_for_like()
2094 name name of the table
2095 buff quoted name of the table
2096
2097 DESCRIPTION
2098 Quote \, _, ' and % characters
2099
2100 Note: Because MySQL uses the C escape syntax in strings
2101 (for example, '\n' to represent newline), you must double
2102 any '\' that you use in your LIKE strings. For example, to
2103 search for '\n', specify it as '\\n'. To search for '\', specify
2104 it as '\\\\' (the backslashes are stripped once by the parser
2105 and another time when the pattern match is done, leaving a
2106 single backslash to be matched).
2107
2108 Example: "t\1" => "t\\\\1"
2109
2110 */
quote_for_like(const char * name,char * buff)2111 static char *quote_for_like(const char *name, char *buff)
2112 {
2113 char *to= buff;
2114 *to++= '\'';
2115 while (*name)
2116 {
2117 if (*name == '\\')
2118 {
2119 *to++='\\';
2120 *to++='\\';
2121 *to++='\\';
2122 }
2123 else if (*name == '\'' || *name == '_' || *name == '%')
2124 *to++= '\\';
2125 *to++= *name++;
2126 }
2127 to[0]= '\'';
2128 to[1]= 0;
2129 return buff;
2130 }
2131
2132
2133 /**
2134 Quote and print a string.
2135
2136 @param xml_file - Output file.
2137 @param str - String to print.
2138 @param len - Its length.
2139 @param is_attribute_name - A check for attribute name or value.
2140
2141 @description
2142 Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
2143 */
2144
print_quoted_xml(FILE * xml_file,const char * str,size_t len,my_bool is_attribute_name)2145 static void print_quoted_xml(FILE *xml_file, const char *str, size_t len,
2146 my_bool is_attribute_name)
2147 {
2148 const char *end;
2149
2150 for (end= str + len; str != end; str++)
2151 {
2152 switch (*str) {
2153 case '<':
2154 fputs("<", xml_file);
2155 break;
2156 case '>':
2157 fputs(">", xml_file);
2158 break;
2159 case '&':
2160 fputs("&", xml_file);
2161 break;
2162 case '\"':
2163 fputs(""", xml_file);
2164 break;
2165 case ' ':
2166 /* Attribute names cannot contain spaces. */
2167 if (is_attribute_name)
2168 {
2169 fputs("_", xml_file);
2170 break;
2171 }
2172 /* fall through */
2173 default:
2174 fputc(*str, xml_file);
2175 break;
2176 }
2177 }
2178 check_io(xml_file);
2179 }
2180
2181
2182 /*
2183 Print xml tag. Optionally add attribute(s).
2184
2185 SYNOPSIS
2186 print_xml_tag(xml_file, sbeg, send, tag_name, first_attribute_name,
2187 ..., attribute_name_n, attribute_value_n, NullS)
2188 xml_file - output file
2189 sbeg - line beginning
2190 line_end - line ending
2191 tag_name - XML tag name.
2192 first_attribute_name - tag and first attribute
2193 first_attribute_value - (Implied) value of first attribute
2194 attribute_name_n - attribute n
2195 attribute_value_n - value of attribute n
2196
2197 DESCRIPTION
2198 Print XML tag with any number of attribute="value" pairs to the xml_file.
2199
2200 Format is:
2201 sbeg<tag_name first_attribute_name="first_attribute_value" ...
2202 attribute_name_n="attribute_value_n">send
2203 NOTE
2204 Additional arguments must be present in attribute/value pairs.
2205 The last argument should be the null character pointer.
2206 All attribute_value arguments MUST be NULL terminated strings.
2207 All attribute_value arguments will be quoted before output.
2208 */
2209
print_xml_tag(FILE * xml_file,const char * sbeg,const char * line_end,const char * tag_name,const char * first_attribute_name,...)2210 static void print_xml_tag(FILE * xml_file, const char* sbeg,
2211 const char* line_end,
2212 const char* tag_name,
2213 const char* first_attribute_name, ...)
2214 {
2215 va_list arg_list;
2216 const char *attribute_name, *attribute_value;
2217
2218 fputs(sbeg, xml_file);
2219 fputc('<', xml_file);
2220 fputs(tag_name, xml_file);
2221
2222 va_start(arg_list, first_attribute_name);
2223 attribute_name= first_attribute_name;
2224 while (attribute_name != NullS)
2225 {
2226 attribute_value= va_arg(arg_list, char *);
2227 assert(attribute_value != NullS);
2228
2229 fputc(' ', xml_file);
2230 fputs(attribute_name, xml_file);
2231 fputc('\"', xml_file);
2232
2233 print_quoted_xml(xml_file, attribute_value, strlen(attribute_value), 0);
2234 fputc('\"', xml_file);
2235
2236 attribute_name= va_arg(arg_list, char *);
2237 }
2238 va_end(arg_list);
2239
2240 fputc('>', xml_file);
2241 fputs(line_end, xml_file);
2242 check_io(xml_file);
2243 }
2244
2245
2246 /*
2247 Print xml tag with for a field that is null
2248
2249 SYNOPSIS
2250 print_xml_null_tag()
2251 xml_file - output file
2252 sbeg - line beginning
2253 stag_atr - tag and attribute
2254 sval - value of attribute
2255 line_end - line ending
2256
2257 DESCRIPTION
2258 Print tag with one attribute to the xml_file. Format is:
2259 <stag_atr="sval" xsi:nil="true"/>
2260 NOTE
2261 sval MUST be a NULL terminated string.
2262 sval string will be qouted before output.
2263 */
2264
print_xml_null_tag(FILE * xml_file,const char * sbeg,const char * stag_atr,const char * sval,const char * line_end)2265 static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
2266 const char* stag_atr, const char* sval,
2267 const char* line_end)
2268 {
2269 fputs(sbeg, xml_file);
2270 fputs("<", xml_file);
2271 fputs(stag_atr, xml_file);
2272 fputs("\"", xml_file);
2273 print_quoted_xml(xml_file, sval, strlen(sval), 0);
2274 fputs("\" xsi:nil=\"true\" />", xml_file);
2275 fputs(line_end, xml_file);
2276 check_io(xml_file);
2277 }
2278
2279
2280 /**
2281 Print xml CDATA section.
2282
2283 @param xml_file - output file
2284 @param str - string to print
2285 @param len - length of the string
2286
2287 @note
2288 This function also takes care of the presence of '[[>'
2289 string in the str. If found, the CDATA section is broken
2290 into two CDATA sections, <![CDATA[]]]]> and <![CDATA[>]].
2291 */
2292
print_xml_cdata(FILE * xml_file,const char * str,ulong len)2293 static void print_xml_cdata(FILE *xml_file, const char *str, ulong len)
2294 {
2295 const char *end;
2296
2297 fputs("<![CDATA[\n", xml_file);
2298 for (end= str + len; str != end; str++)
2299 {
2300 switch(*str) {
2301 case ']':
2302 if ((*(str + 1) == ']') && (*(str + 2) =='>'))
2303 {
2304 fputs("]]]]><![CDATA[>", xml_file);
2305 str += 2;
2306 continue;
2307 }
2308 /* fall through */
2309 default:
2310 fputc(*str, xml_file);
2311 break;
2312 }
2313 }
2314 fputs("\n]]>\n", xml_file);
2315 check_io(xml_file);
2316 }
2317
2318
2319 /*
2320 Print xml tag with many attributes.
2321
2322 SYNOPSIS
2323 print_xml_row()
2324 xml_file - output file
2325 row_name - xml tag name
2326 tableRes - query result
2327 row - result row
2328 str_create - create statement header string
2329
2330 DESCRIPTION
2331 Print tag with many attribute to the xml_file. Format is:
2332 \t\t<row_name Atr1="Val1" Atr2="Val2"... />
2333 NOTE
2334 All atributes and values will be quoted before output.
2335 */
2336
print_xml_row(FILE * xml_file,const char * row_name,MYSQL_RES * tableRes,MYSQL_ROW * row,const char * str_create)2337 static void print_xml_row(FILE *xml_file, const char *row_name,
2338 MYSQL_RES *tableRes, MYSQL_ROW *row,
2339 const char *str_create)
2340 {
2341 uint i;
2342 char *create_stmt_ptr= NULL;
2343 ulong create_stmt_len= 0;
2344 MYSQL_FIELD *field;
2345 ulong *lengths= mysql_fetch_lengths(tableRes);
2346
2347 fprintf(xml_file, "\t\t<%s", row_name);
2348 check_io(xml_file);
2349 mysql_field_seek(tableRes, 0);
2350 for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
2351 {
2352 if ((*row)[i])
2353 {
2354 /* For 'create' statements, dump using CDATA. */
2355 if ((str_create) && (strcmp(str_create, field->name) == 0))
2356 {
2357 create_stmt_ptr= (*row)[i];
2358 create_stmt_len= lengths[i];
2359 }
2360 else
2361 {
2362 fputc(' ', xml_file);
2363 print_quoted_xml(xml_file, field->name, field->name_length, 1);
2364 fputs("=\"", xml_file);
2365 print_quoted_xml(xml_file, (*row)[i], lengths[i], 0);
2366 fputc('"', xml_file);
2367 check_io(xml_file);
2368 }
2369 }
2370 }
2371
2372 if (create_stmt_len)
2373 {
2374 fputs(">\n", xml_file);
2375 print_xml_cdata(xml_file, create_stmt_ptr, create_stmt_len);
2376 fprintf(xml_file, "\t\t</%s>\n", row_name);
2377 }
2378 else
2379 fputs(" />\n", xml_file);
2380
2381 check_io(xml_file);
2382 }
2383
2384
2385 /**
2386 Print xml comments.
2387
2388 @param xml_file - output file
2389 @param len - length of comment message
2390 @param comment_string - comment message
2391
2392 @description
2393 Print the comment message in the format:
2394 "<!-- \n comment string \n -->\n"
2395
2396 @note
2397 Any occurrence of continuous hyphens will be
2398 squeezed to a single hyphen.
2399 */
2400
print_xml_comment(FILE * xml_file,size_t len,const char * comment_string)2401 static void print_xml_comment(FILE *xml_file, size_t len,
2402 const char *comment_string)
2403 {
2404 const char* end;
2405
2406 fputs("<!-- ", xml_file);
2407
2408 for (end= comment_string + len; comment_string != end; comment_string++)
2409 {
2410 /*
2411 The string "--" (double-hyphen) MUST NOT occur within xml comments.
2412 */
2413 switch (*comment_string) {
2414 case '-':
2415 if (*(comment_string + 1) == '-') /* Only one hyphen allowed. */
2416 break;
2417 // Fall through.
2418 default:
2419 fputc(*comment_string, xml_file);
2420 break;
2421 }
2422 }
2423 fputs(" -->\n", xml_file);
2424 check_io(xml_file);
2425 }
2426
2427
2428
2429 /* A common printing function for xml and non-xml modes. */
2430
print_comment(FILE * sql_file,my_bool is_error,const char * format,...)2431 static void print_comment(FILE *sql_file, my_bool is_error, const char *format,
2432 ...)
2433 {
2434 static char comment_buff[COMMENT_LENGTH];
2435 va_list args;
2436
2437 /* If its an error message, print it ignoring opt_comments. */
2438 if (!is_error && !opt_comments)
2439 return;
2440
2441 va_start(args, format);
2442 my_vsnprintf(comment_buff, COMMENT_LENGTH, format, args);
2443 va_end(args);
2444
2445 if (!opt_xml)
2446 {
2447 fputs(comment_buff, sql_file);
2448 check_io(sql_file);
2449 return;
2450 }
2451
2452 print_xml_comment(sql_file, strlen(comment_buff), comment_buff);
2453 }
2454
2455 /**
2456 @brief Accepts object names and prefixes them with "-- " wherever
2457 end-of-line character ('\n') is found.
2458
2459 @param[in] object_name object name list (concatenated string)
2460 @param[out] freemem should buffer be released after usage
2461
2462 @return
2463 @retval pointer to a string with prefixed objects
2464 */
fix_identifier_with_newline(char const * object_name,my_bool * freemem)2465 static char const* fix_identifier_with_newline(char const* object_name, my_bool* freemem)
2466 {
2467 const size_t PREFIX_LENGTH= 3; // strlen ("-- ")
2468
2469 // static buffer for replacement procedure
2470 static char storage[NAME_LEN + 1];
2471 static char* buffer= storage;
2472 static size_t buffer_size= sizeof(storage) - 1;
2473 size_t index= 0;
2474 size_t required_size= 0;
2475
2476 // we presume memory allocation won't be needed
2477 *freemem= FALSE;
2478
2479 // traverse and reformat objects
2480 while (object_name && *object_name)
2481 {
2482 ++required_size;
2483 if (*object_name == '\n')
2484 required_size+= PREFIX_LENGTH;
2485
2486 // do we need dynamic (re)allocation
2487 if (required_size > buffer_size)
2488 {
2489 // new alloc size increased in COMMENT_LENGTH multiple
2490 buffer_size= COMMENT_LENGTH * (1 + required_size/COMMENT_LENGTH);
2491
2492 // is our buffer already dynamically allocated
2493 if (*freemem)
2494 {
2495 // just realloc
2496 buffer= (char*)my_realloc(PSI_NOT_INSTRUMENTED, buffer, buffer_size + 1,
2497 MYF(MY_WME));
2498 if (!buffer)
2499 exit(1);
2500 }
2501 else
2502 {
2503 // dynamic allocation + copy from static buffer
2504 buffer= (char*)my_malloc(PSI_NOT_INSTRUMENTED, buffer_size + 1,
2505 MYF(MY_WME));
2506 if (!buffer)
2507 exit(1);
2508
2509 strncpy(buffer, storage, index);
2510 *freemem= TRUE;
2511 }
2512 }
2513
2514 // copy a character
2515 buffer[index]= *object_name;
2516 ++index;
2517
2518 // prefix new lines with double dash
2519 if (*object_name == '\n')
2520 {
2521 strcpy(buffer + index, "-- ");
2522 index += PREFIX_LENGTH;
2523 }
2524
2525 ++object_name;
2526 }
2527
2528 // don't forget null termination
2529 buffer[index]= '\0';
2530 return buffer;
2531 }
2532
2533
2534 /*
2535 create_delimiter
2536 Generate a new (null-terminated) string that does not exist in query
2537 and is therefore suitable for use as a query delimiter. Store this
2538 delimiter in delimiter_buff .
2539
2540 This is quite simple in that it doesn't even try to parse statements as an
2541 interpreter would. It merely returns a string that is not in the query, which
2542 is much more than adequate for constructing a delimiter.
2543
2544 RETURN
2545 ptr to the delimiter on Success
2546 NULL on Failure
2547 */
create_delimiter(char * query,char * delimiter_buff,int delimiter_max_size)2548 static char *create_delimiter(char *query, char *delimiter_buff,
2549 int delimiter_max_size)
2550 {
2551 int proposed_length;
2552 char *presence;
2553
2554 delimiter_buff[0]= ';'; /* start with one semicolon, and */
2555
2556 for (proposed_length= 2; proposed_length < delimiter_max_size;
2557 delimiter_max_size++) {
2558
2559 delimiter_buff[proposed_length-1]= ';'; /* add semicolons, until */
2560 delimiter_buff[proposed_length]= '\0';
2561
2562 presence = strstr(query, delimiter_buff);
2563 if (presence == NULL) { /* the proposed delimiter is not in the query. */
2564 return delimiter_buff;
2565 }
2566
2567 }
2568 return NULL; /* but if we run out of space, return nothing at all. */
2569 }
2570
2571
2572 /*
2573 dump_events_for_db
2574 -- retrieves list of events for a given db, and prints out
2575 the CREATE EVENT statement into the output (the dump).
2576
2577 RETURN
2578 0 Success
2579 1 Error
2580 */
dump_events_for_db(char * db)2581 static uint dump_events_for_db(char *db)
2582 {
2583 char query_buff[QUERY_LENGTH];
2584 char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
2585 char *event_name;
2586 char delimiter[QUERY_LENGTH];
2587 FILE *sql_file= md_result_file;
2588 MYSQL_RES *event_res, *event_list_res;
2589 MYSQL_ROW row, event_list_row;
2590
2591 char db_cl_name[MY_CS_NAME_SIZE];
2592 int db_cl_altered= FALSE;
2593 my_bool freemem= FALSE;
2594 char const *text= fix_identifier_with_newline(db, &freemem);
2595
2596 DBUG_ENTER("dump_events_for_db");
2597 DBUG_PRINT("enter", ("db: '%s'", db));
2598
2599 mysql_real_escape_string_quote(mysql, db_name_buff,
2600 db, (ulong)strlen(db), '\'');
2601 /* nice comments */
2602 print_comment(sql_file, 0,
2603 "\n--\n-- Dumping events for database '%s'\n--\n",
2604 text);
2605 if (freemem)
2606 my_free((void*)text);
2607
2608 /*
2609 not using "mysql_query_with_error_report" because we may have not
2610 enough privileges to lock mysql.events.
2611 */
2612 if (lock_tables)
2613 mysql_query(mysql, "LOCK TABLES mysql.event READ");
2614
2615 if (mysql_query_with_error_report(mysql, &event_list_res, "show events"))
2616 DBUG_RETURN(0);
2617
2618 strcpy(delimiter, ";");
2619 if (mysql_num_rows(event_list_res) > 0)
2620 {
2621 if (opt_xml)
2622 fputs("\t<events>\n", sql_file);
2623 else
2624 {
2625 fprintf(sql_file, "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;\n");
2626
2627 /* Get database collation. */
2628
2629 if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
2630 DBUG_RETURN(1);
2631 }
2632
2633 if (switch_character_set_results(mysql, "binary"))
2634 DBUG_RETURN(1);
2635
2636 while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL)
2637 {
2638 event_name= quote_name(event_list_row[1], name_buff, 0);
2639 DBUG_PRINT("info", ("retrieving CREATE EVENT for %s", name_buff));
2640 my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s",
2641 event_name);
2642
2643 if (mysql_query_with_error_report(mysql, &event_res, query_buff))
2644 DBUG_RETURN(1);
2645
2646 while ((row= mysql_fetch_row(event_res)) != NULL)
2647 {
2648 if (opt_xml)
2649 {
2650 print_xml_row(sql_file, "event", event_res, &row,
2651 "Create Event");
2652 continue;
2653 }
2654
2655 /*
2656 if the user has EXECUTE privilege he can see event names, but not the
2657 event body!
2658 */
2659 if (strlen(row[3]) != 0)
2660 {
2661 char *query_str;
2662
2663 if (opt_drop)
2664 fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n",
2665 event_name, delimiter);
2666
2667 if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL)
2668 {
2669 fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n",
2670 my_progname, event_name);
2671 DBUG_RETURN(1);
2672 }
2673
2674 fprintf(sql_file, "DELIMITER %s\n", delimiter);
2675
2676 if (mysql_num_fields(event_res) >= 7)
2677 {
2678 if (switch_db_collation(sql_file, db_name_buff, delimiter,
2679 db_cl_name, row[6], &db_cl_altered))
2680 {
2681 DBUG_RETURN(1);
2682 }
2683
2684 switch_cs_variables(sql_file, delimiter,
2685 row[4], /* character_set_client */
2686 row[4], /* character_set_results */
2687 row[5]); /* collation_connection */
2688 }
2689 else
2690 {
2691 /*
2692 mysqldump is being run against the server, that does not
2693 provide character set information in SHOW CREATE
2694 statements.
2695
2696 NOTE: the dump may be incorrect, since character set
2697 information is required in order to restore event properly.
2698 */
2699
2700 fprintf(sql_file,
2701 "--\n"
2702 "-- WARNING: old server version. "
2703 "The following dump may be incomplete.\n"
2704 "--\n");
2705 }
2706 remove_sql_mode(row[1], C_STRING_WITH_LEN("NO_AUTO_CREATE_USER"));
2707 switch_sql_mode(sql_file, delimiter, row[1]);
2708
2709 switch_time_zone(sql_file, delimiter, row[2]);
2710
2711 query_str= cover_definer_clause(row[3], strlen(row[3]),
2712 C_STRING_WITH_LEN("50117"),
2713 C_STRING_WITH_LEN("50106"),
2714 C_STRING_WITH_LEN(" EVENT"));
2715
2716 fprintf(sql_file,
2717 "/*!50106 %s */ %s\n",
2718 (const char *) (query_str != NULL ? query_str : row[3]),
2719 (const char *) delimiter);
2720
2721 my_free(query_str);
2722 restore_time_zone(sql_file, delimiter);
2723 restore_sql_mode(sql_file, delimiter);
2724
2725 if (mysql_num_fields(event_res) >= 7)
2726 {
2727 restore_cs_variables(sql_file, delimiter);
2728
2729 if (db_cl_altered)
2730 {
2731 if (restore_db_collation(sql_file, db_name_buff, delimiter,
2732 db_cl_name))
2733 DBUG_RETURN(1);
2734 }
2735 }
2736 }
2737 } /* end of event printing */
2738 mysql_free_result(event_res);
2739
2740 } /* end of list of events */
2741 if (opt_xml)
2742 {
2743 fputs("\t</events>\n", sql_file);
2744 check_io(sql_file);
2745 }
2746 else
2747 {
2748 fprintf(sql_file, "DELIMITER ;\n");
2749 fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n");
2750 }
2751
2752 if (switch_character_set_results(mysql, default_charset))
2753 DBUG_RETURN(1);
2754 }
2755 mysql_free_result(event_list_res);
2756
2757 if (lock_tables)
2758 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
2759 DBUG_RETURN(0);
2760 }
2761
2762
2763 /*
2764 Print hex value for blob data.
2765
2766 SYNOPSIS
2767 print_blob_as_hex()
2768 output_file - output file
2769 str - string to print
2770 len - its length
2771
2772 DESCRIPTION
2773 Print hex value for blob data.
2774 */
2775
print_blob_as_hex(FILE * output_file,const char * str,ulong len)2776 static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
2777 {
2778 /* sakaik got the idea to to provide blob's in hex notation. */
2779 const char *ptr= str, *end= ptr + len;
2780 for (; ptr < end ; ptr++)
2781 fprintf(output_file, "%02X", *((uchar *)ptr));
2782 check_io(output_file);
2783 }
2784
2785 /*
2786 dump_routines_for_db
2787 -- retrieves list of routines for a given db, and prints out
2788 the CREATE PROCEDURE definition into the output (the dump).
2789
2790 This function has logic to print the appropriate syntax depending on whether
2791 this is a procedure or functions
2792
2793 RETURN
2794 0 Success
2795 1 Error
2796 */
2797
dump_routines_for_db(char * db)2798 static uint dump_routines_for_db(char *db)
2799 {
2800 char query_buff[QUERY_LENGTH];
2801 const char *routine_type[]= {"FUNCTION", "PROCEDURE"};
2802 char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
2803 char *routine_name;
2804 int i;
2805 FILE *sql_file= md_result_file;
2806 MYSQL_RES *routine_res, *routine_list_res;
2807 MYSQL_ROW row, routine_list_row;
2808
2809 char db_cl_name[MY_CS_NAME_SIZE];
2810 int db_cl_altered= FALSE;
2811 my_bool freemem= FALSE;
2812 char const *text= fix_identifier_with_newline(db, &freemem);
2813
2814 DBUG_ENTER("dump_routines_for_db");
2815 DBUG_PRINT("enter", ("db: '%s'", db));
2816
2817 mysql_real_escape_string_quote(mysql, db_name_buff,
2818 db, (ulong)strlen(db), '\'');
2819 /* nice comments */
2820 print_comment(sql_file, 0,
2821 "\n--\n-- Dumping routines for database '%s'\n--\n",
2822 text);
2823
2824 if (freemem)
2825 my_free((void*)text);
2826
2827 /*
2828 not using "mysql_query_with_error_report" because we may have not
2829 enough privileges to lock mysql.proc.
2830 */
2831 if (lock_tables)
2832 mysql_query(mysql, "LOCK TABLES mysql.proc READ");
2833
2834 /* Get database collation. */
2835
2836 if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
2837 DBUG_RETURN(1);
2838
2839 if (switch_character_set_results(mysql, "binary"))
2840 DBUG_RETURN(1);
2841
2842 if (opt_xml)
2843 fputs("\t<routines>\n", sql_file);
2844
2845 /* 0, retrieve and dump functions, 1, procedures */
2846 for (i= 0; i <= 1; i++)
2847 {
2848 my_snprintf(query_buff, sizeof(query_buff),
2849 "SHOW %s STATUS WHERE Db = '%s'",
2850 routine_type[i], db_name_buff);
2851
2852 if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff))
2853 DBUG_RETURN(1);
2854
2855 if (mysql_num_rows(routine_list_res))
2856 {
2857
2858 while ((routine_list_row= mysql_fetch_row(routine_list_res)))
2859 {
2860 routine_name= quote_name(routine_list_row[1], name_buff, 0);
2861 DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i],
2862 name_buff));
2863 my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s",
2864 routine_type[i], routine_name);
2865
2866 if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
2867 DBUG_RETURN(1);
2868
2869 while ((row= mysql_fetch_row(routine_res)))
2870 {
2871 /*
2872 if the user has EXECUTE privilege he see routine names, but NOT the
2873 routine body of other routines that are not the creator of!
2874 */
2875 DBUG_PRINT("info",("length of body for %s row[2] '%s' is %zu",
2876 routine_name, row[2] ? row[2] : "(null)",
2877 row[2] ? strlen(row[2]) : 0));
2878 if (row[2] == NULL)
2879 {
2880 my_bool freemem= FALSE;
2881 char const* text= fix_identifier_with_newline(current_user, &freemem);
2882
2883 print_comment(sql_file, 1, "\n-- insufficient privileges to %s\n",
2884 query_buff);
2885 print_comment(sql_file, 1,
2886 "-- does %s have permissions on mysql.proc?\n\n",
2887 text);
2888 if (freemem)
2889 my_free((void*)text);
2890
2891 maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!", current_user, query_buff);
2892 }
2893 else if (strlen(row[2]))
2894 {
2895 if (opt_xml)
2896 {
2897 if (i) // Procedures.
2898 print_xml_row(sql_file, "routine", routine_res, &row,
2899 "Create Procedure");
2900 else // Functions.
2901 print_xml_row(sql_file, "routine", routine_res, &row,
2902 "Create Function");
2903 continue;
2904 }
2905 if (opt_drop)
2906 fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n",
2907 routine_type[i], routine_name);
2908
2909 if (mysql_num_fields(routine_res) >= 6)
2910 {
2911 if (switch_db_collation(sql_file, db_name_buff, ";",
2912 db_cl_name, row[5], &db_cl_altered))
2913 {
2914 DBUG_RETURN(1);
2915 }
2916
2917 switch_cs_variables(sql_file, ";",
2918 row[3], /* character_set_client */
2919 row[3], /* character_set_results */
2920 row[4]); /* collation_connection */
2921 }
2922 else
2923 {
2924 /*
2925 mysqldump is being run against the server, that does not
2926 provide character set information in SHOW CREATE
2927 statements.
2928
2929 NOTE: the dump may be incorrect, since character set
2930 information is required in order to restore stored
2931 procedure/function properly.
2932 */
2933
2934 fprintf(sql_file,
2935 "--\n"
2936 "-- WARNING: old server version. "
2937 "The following dump may be incomplete.\n"
2938 "--\n");
2939 }
2940
2941 remove_sql_mode(row[1], C_STRING_WITH_LEN("NO_AUTO_CREATE_USER"));
2942 switch_sql_mode(sql_file, ";", row[1]);
2943
2944 fprintf(sql_file,
2945 "DELIMITER ;;\n"
2946 "%s ;;\n"
2947 "DELIMITER ;\n",
2948 (const char *) row[2]);
2949
2950 restore_sql_mode(sql_file, ";");
2951
2952 if (mysql_num_fields(routine_res) >= 6)
2953 {
2954 restore_cs_variables(sql_file, ";");
2955
2956 if (db_cl_altered)
2957 {
2958 if (restore_db_collation(sql_file, db_name_buff, ";", db_cl_name))
2959 DBUG_RETURN(1);
2960 }
2961 }
2962
2963 }
2964 } /* end of routine printing */
2965 mysql_free_result(routine_res);
2966
2967 } /* end of list of routines */
2968 }
2969 mysql_free_result(routine_list_res);
2970 } /* end of for i (0 .. 1) */
2971
2972 if (opt_xml)
2973 {
2974 fputs("\t</routines>\n", sql_file);
2975 check_io(sql_file);
2976 }
2977
2978 if (switch_character_set_results(mysql, default_charset))
2979 DBUG_RETURN(1);
2980
2981 if (lock_tables)
2982 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
2983 DBUG_RETURN(0);
2984 }
2985
2986 /* general_log or slow_log tables under mysql database */
general_log_or_slow_log_tables(const char * db,const char * table)2987 static inline my_bool general_log_or_slow_log_tables(const char *db,
2988 const char *table)
2989 {
2990 return (!my_strcasecmp(charset_info, db, "mysql")) &&
2991 (!my_strcasecmp(charset_info, table, "general_log") ||
2992 !my_strcasecmp(charset_info, table, "slow_log"));
2993 }
2994
2995 /*
2996 slave_master_info,slave_relay_log_info and gtid_executed tables under
2997 mysql database
2998 */
replication_metadata_tables(const char * db,const char * table)2999 static inline my_bool replication_metadata_tables(const char *db,
3000 const char *table)
3001 {
3002 return (!my_strcasecmp(charset_info, db, "mysql")) &&
3003 (!my_strcasecmp(charset_info, table, "slave_master_info") ||
3004 !my_strcasecmp(charset_info, table, "slave_relay_log_info") ||
3005 !my_strcasecmp(charset_info, table, "gtid_executed"));
3006 }
3007
3008 /*
3009 Find the first occurrence of a quoted identifier in a given string. Returns
3010 the pointer to the opening quote, and stores the pointer to the closing quote
3011 to the memory location pointed to by the 'end' argument,
3012
3013 If no quoted identifiers are found, returns NULL (and the value pointed to by
3014 'end' is undefined in this case).
3015 */
3016
parse_quoted_identifier(const char * str,const char ** end)3017 static const char *parse_quoted_identifier(const char *str,
3018 const char **end)
3019 {
3020 const char *from;
3021 const char *to;
3022
3023 if (!(from= strchr(str, '`')))
3024 return NULL;
3025
3026 to= from;
3027
3028 while ((to= strchr(to + 1, '`'))) {
3029 /*
3030 Double backticks represent a backtick in identifier, rather than a quote
3031 character.
3032 */
3033 if (to[1] == '`')
3034 {
3035 to++;
3036 continue;
3037 }
3038
3039 break;
3040 }
3041
3042 if (to <= from + 1)
3043 return NULL; /* Empty identifier */
3044
3045 *end= to;
3046
3047 return from;
3048 }
3049
3050 /*
3051 Parse the specified key definition string and check if the key contains an
3052 AUTO_INCREMENT column as the first key part. We only check for the first key
3053 part, because unlike MyISAM, InnoDB does not allow the AUTO_INCREMENT column
3054 as a secondary key column, i.e. the AUTO_INCREMENT column would not be
3055 considered indexed for such key specification.
3056 */
contains_autoinc_column(const char * autoinc_column,ssize_t autoinc_column_len,const char * keydef,key_type_t type)3057 static my_bool contains_autoinc_column(const char *autoinc_column,
3058 ssize_t autoinc_column_len,
3059 const char *keydef,
3060 key_type_t type)
3061 {
3062 const char *from, *to;
3063 uint idnum;
3064
3065 assert(type != KEY_TYPE_NONE);
3066
3067 if (autoinc_column == NULL)
3068 return FALSE;
3069
3070 idnum= 0;
3071
3072 /*
3073 There is only 1 iteration of the following loop for type == KEY_TYPE_PRIMARY
3074 and 2 iterations for type == KEY_TYPE_UNIQUE / KEY_TYPE_NON_UNIQUE.
3075 */
3076 while ((from= parse_quoted_identifier(keydef, &to)))
3077 {
3078 idnum++;
3079
3080 /*
3081 Skip the check if it's the first identifier and we are processing a
3082 secondary key.
3083 */
3084 if ((type == KEY_TYPE_PRIMARY || idnum != 1) &&
3085 to - from - 1 == autoinc_column_len &&
3086 !strncmp(autoinc_column, from + 1, autoinc_column_len))
3087 return TRUE;
3088
3089 /*
3090 Check only the first (for PRIMARY KEY) or the second (for secondary keys)
3091 quoted identifier.
3092 */
3093 if (idnum == 1 + MY_TEST(type != KEY_TYPE_PRIMARY))
3094 break;
3095
3096 keydef= to + 1;
3097 }
3098
3099 return FALSE;
3100 }
3101
3102
3103 /*
3104 Remove secondary/foreign key definitions from a given SHOW CREATE TABLE string
3105 and store them into a temporary list to be used later.
3106
3107 SYNOPSIS
3108 skip_secondary_keys()
3109 create_str SHOW CREATE TABLE output
3110 has_pk TRUE, if the table has PRIMARY KEY
3111 (or UNIQUE key on non-nullable columns)
3112
3113
3114 DESCRIPTION
3115
3116 Stores all lines starting with "KEY" or "UNIQUE KEY"
3117 into skipped_keys_list and removes them from the input string.
3118 Stores all CONSTRAINT/FOREIGN KEYS declarations into
3119 alter_constraints_list and removes them from the input string.
3120 */
3121
skip_secondary_keys(char * create_str,my_bool has_pk)3122 static void skip_secondary_keys(char *create_str, my_bool has_pk)
3123 {
3124 char *ptr, *strend;
3125 char *last_comma= NULL;
3126 my_bool pk_processed= FALSE;
3127 char *autoinc_column= NULL;
3128 ssize_t autoinc_column_len= 0;
3129 my_bool has_autoinc= FALSE;
3130 key_type_t type;
3131 my_bool keys_processed= FALSE;
3132
3133 strend= create_str + strlen(create_str);
3134
3135 ptr= create_str;
3136 while (*ptr && !keys_processed)
3137 {
3138 char *tmp, *orig_ptr, c;
3139
3140 orig_ptr= ptr;
3141 /* Skip leading whitespace */
3142 while (*ptr && my_isspace(charset_info, *ptr))
3143 ptr++;
3144
3145 /* Read the next line */
3146 for (tmp= ptr; *tmp != '\n' && *tmp != '\0'; tmp++);
3147
3148 c= *tmp;
3149 *tmp= '\0'; /* so strstr() only processes the current line */
3150
3151 if (!strncmp(ptr, "CONSTRAINT ", sizeof("CONSTRAINT ") - 1))
3152 type= KEY_TYPE_CONSTRAINT;
3153 else if (!strncmp(ptr, "UNIQUE KEY ", sizeof("UNIQUE KEY ") - 1))
3154 type= KEY_TYPE_UNIQUE;
3155 else if (!strncmp(ptr, "KEY ", sizeof("KEY ") - 1))
3156 type= KEY_TYPE_NON_UNIQUE;
3157 else if (!strncmp(ptr, "PRIMARY KEY ", sizeof("PRIMARY KEY ") - 1))
3158 type= KEY_TYPE_PRIMARY;
3159 else
3160 type= KEY_TYPE_NONE;
3161
3162 has_autoinc= (type != KEY_TYPE_NONE)
3163 ? contains_autoinc_column(autoinc_column, autoinc_column_len, ptr, type)
3164 : FALSE;
3165
3166 /* Is it a secondary index definition? */
3167 if (c == '\n' && !has_autoinc &&
3168 ((type == KEY_TYPE_UNIQUE && (pk_processed || !has_pk)) ||
3169 type == KEY_TYPE_NON_UNIQUE || type == KEY_TYPE_CONSTRAINT))
3170 {
3171 char *data, *end= tmp - 1;
3172
3173 /* Remove the trailing comma */
3174 if (*end == ',')
3175 end--;
3176 data= my_strndup(PSI_NOT_INSTRUMENTED, ptr, end - ptr + 1, MYF(MY_FAE));
3177
3178 if (type == KEY_TYPE_CONSTRAINT)
3179 alter_constraints_list= list_cons(data, alter_constraints_list);
3180 else
3181 skipped_keys_list= list_cons(data, skipped_keys_list);
3182
3183 memmove(orig_ptr, tmp + 1, strend - tmp);
3184 ptr= orig_ptr;
3185 strend-= tmp + 1 - ptr;
3186
3187 /* Remove the comma on the previos line */
3188 if (last_comma != NULL)
3189 {
3190 *last_comma= ' ';
3191 }
3192 }
3193 else
3194 {
3195 char *end;
3196
3197 if (last_comma != NULL && *ptr == ')')
3198 {
3199 keys_processed= TRUE;
3200 }
3201 else if (last_comma != NULL && !keys_processed)
3202 {
3203 /*
3204 It's not the last line of CREATE TABLE, so we have skipped a key
3205 definition. We have to restore the last removed comma.
3206 */
3207 *last_comma= ',';
3208 }
3209
3210 /*
3211 If we are skipping a key which indexes an AUTO_INCREMENT column, it is
3212 safe to optimize all subsequent keys, i.e. we should not be checking for
3213 that column anymore.
3214 */
3215 if (type != KEY_TYPE_NONE && has_autoinc)
3216 {
3217 assert(autoinc_column != NULL);
3218
3219 my_free(autoinc_column);
3220 autoinc_column= NULL;
3221 }
3222
3223 if ((has_pk && type == KEY_TYPE_UNIQUE && !pk_processed) ||
3224 type == KEY_TYPE_PRIMARY)
3225 pk_processed= TRUE;
3226
3227 if (strstr(ptr, "AUTO_INCREMENT") && *ptr == '`')
3228 {
3229 /*
3230 The first secondary key defined on this column later cannot be
3231 skipped, as CREATE TABLE would fail on import. Unless there is a
3232 PRIMARY KEY and it indexes that column.
3233 */
3234 for (end= ptr + 1;
3235 /* Skip double backticks as they are a part of identifier */
3236 *end != '\0' && (*end != '`' || end[1] == '`');
3237 end++)
3238 /* empty */;
3239
3240 if (*end == '`' && end > ptr + 1)
3241 {
3242 assert(autoinc_column == NULL);
3243
3244 autoinc_column_len= end - ptr - 1;
3245 autoinc_column= my_strndup(PSI_NOT_INSTRUMENTED, ptr + 1,
3246 autoinc_column_len, MYF(MY_FAE));
3247 }
3248 }
3249
3250 *tmp= c;
3251
3252 if (tmp[-1] == ',')
3253 last_comma= tmp - 1;
3254 ptr= (*tmp == '\0') ? tmp : tmp + 1;
3255 }
3256 }
3257
3258 my_free(autoinc_column);
3259 }
3260
3261 /**
3262 Removes some compressed columns extensions from the create table
3263 definition (a string produced by SHOW CREATE TABLE) depending on
3264 opt_compressed_columns and opt_compressed_columns_with_dictionaries flags.
3265 If opt_compressed_columns_with_dictionaries flags is true, in addition
3266 dictionaries list will be filled with referenced compression
3267 dictionaries.
3268
3269 @param create_str SHOW CREATE TABLE output
3270 @param dictionaries the list of dictionary names found in the
3271 create table definition
3272 */
skip_compressed_columns(char * create_str,LIST ** dictionaries)3273 static void skip_compressed_columns(char *create_str, LIST **dictionaries)
3274 {
3275 static const char prefix[]=
3276 " /*!"
3277 STRINGIFY_ARG(FIRST_SUPPORTED_COMPRESSED_COLUMNS_VERSION)
3278 " COLUMN_FORMAT COMPRESSED";
3279 static const size_t prefix_length= sizeof(prefix) - 1;
3280 static const char suffix[]= " */";
3281 static const size_t suffix_length= sizeof(suffix) - 1;
3282 static const char dictionary_keyword[]=" WITH COMPRESSION_DICTIONARY ";
3283 static const size_t dictionary_keyword_length=
3284 sizeof(dictionary_keyword) - 1;
3285
3286 char *ptr, *end_ptr, *prefix_ptr, *suffix_ptr, *dictionary_keyword_ptr;
3287
3288 DBUG_ENTER("skip_compressed_columns");
3289
3290 ptr= create_str;
3291 end_ptr= ptr + strlen(create_str);
3292 if (opt_compressed_columns_with_dictionaries && dictionaries != 0)
3293 *dictionaries= 0;
3294
3295 while ((prefix_ptr= strstr(ptr, prefix)) != 0)
3296 {
3297 suffix_ptr= strstr(prefix_ptr + prefix_length, suffix);
3298 assert(suffix_ptr != 0);
3299 if (!opt_compressed_columns_with_dictionaries)
3300 {
3301 if (!opt_compressed_columns)
3302 {
3303 /* Strip out all compressed columns extensions. */
3304 memmove(prefix_ptr, suffix_ptr + suffix_length,
3305 end_ptr - (suffix_ptr + suffix_length) + 1);
3306 end_ptr-= suffix_ptr + suffix_length - prefix_ptr;
3307 ptr= prefix_ptr;
3308 }
3309 else
3310 {
3311 /* Strip out only compression dictionary references. */
3312 memmove(prefix_ptr + prefix_length, suffix_ptr,
3313 end_ptr - suffix_ptr + 1);
3314 end_ptr-= suffix_ptr - (prefix_ptr + prefix_length);
3315 ptr= prefix_ptr + prefix_length + suffix_length;
3316 }
3317 }
3318 else
3319 {
3320 /* Do not strip out anything. Leave full column definition as is. */
3321 if (dictionaries !=0 && prefix_ptr + prefix_length != suffix_ptr)
3322 {
3323 char *dictionary_name_ptr;
3324 size_t dictionary_name_length;
3325 char opt_quoted_buff[NAME_LEN * 2 + 3],
3326 unquoted_buff[NAME_LEN * 2 + 3];
3327
3328 dictionary_keyword_ptr= strstr(prefix_ptr + prefix_length,
3329 dictionary_keyword);
3330 assert(dictionary_keyword_ptr < suffix_ptr);
3331 dictionary_name_length= suffix_ptr -
3332 (dictionary_keyword_ptr + dictionary_keyword_length);
3333
3334 strncpy(opt_quoted_buff,
3335 dictionary_keyword_ptr + dictionary_keyword_length,
3336 dictionary_name_length);
3337 opt_quoted_buff[dictionary_name_length]= '\0';
3338
3339 dictionary_name_ptr=
3340 my_strdup(PSI_NOT_INSTRUMENTED,
3341 unquote_name(opt_quoted_buff, unquoted_buff), MYF(0));
3342 if (dictionary_name_ptr == 0)
3343 die(EX_MYSQLERR, "Couldn't allocate memory");
3344
3345 list_push(*dictionaries, dictionary_name_ptr);
3346 }
3347 ptr= suffix_ptr + suffix_length;
3348 }
3349 }
3350 DBUG_VOID_RETURN;
3351 }
3352
3353
3354 /*
3355 Check if the table has a primary key defined either explicitly or
3356 implicitly (i.e. a unique key on non-nullable columns).
3357
3358 SYNOPSIS
3359 my_bool has_primary_key(const char *table_name)
3360
3361 table_name quoted table name
3362
3363 RETURNS TRUE if the table has a primary key
3364
3365 DESCRIPTION
3366 */
3367
has_primary_key(const char * table_name)3368 static my_bool has_primary_key(const char *table_name)
3369 {
3370 MYSQL_RES *res= NULL;
3371 MYSQL_ROW row;
3372 char query_buff[QUERY_LENGTH];
3373 my_bool has_pk= TRUE;
3374
3375 my_snprintf(query_buff, sizeof(query_buff),
3376 "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE "
3377 "TABLE_SCHEMA=DATABASE() AND TABLE_NAME='%s' AND "
3378 "COLUMN_KEY='PRI'", table_name);
3379 if (mysql_query(mysql, query_buff) || !(res= mysql_store_result(mysql)) ||
3380 !(row= mysql_fetch_row(res)))
3381 {
3382 fprintf(stderr, "%s: Warning: Couldn't determine if table %s has a "
3383 "primary key (%s). "
3384 "--innodb-optimize-keys may work inefficiently.\n",
3385 my_progname, table_name, mysql_error(mysql));
3386 goto cleanup;
3387 }
3388
3389 has_pk= atoi(row[0]) > 0;
3390
3391 cleanup:
3392 if (res)
3393 mysql_free_result(res);
3394
3395 return has_pk;
3396 }
3397
3398 /**
3399 Prints "CREATE COMPRESSION_DICTIONARY ..." statement for the specified
3400 dictionary name if this is the first time this dictionary is referenced.
3401
3402 @param sql_file output file
3403 @param dictionary_name dictionary name
3404 */
print_optional_create_compression_dictionary(FILE * sql_file,const char * dictionary_name)3405 static void print_optional_create_compression_dictionary(FILE* sql_file,
3406 const char *dictionary_name)
3407 {
3408 DBUG_ENTER("print_optional_create_compression_dictionary");
3409 DBUG_PRINT("enter", ("dictionary: %s", dictionary_name));
3410
3411 /*
3412 We skip this compression dictionary if it has already been processed
3413 */
3414 if (my_hash_search(&processed_compression_dictionaries,
3415 (const uchar *)dictionary_name, strlen(dictionary_name)) == 0)
3416 {
3417 static const char get_zip_dict_data_stmt[] =
3418 "SELECT `ZIP_DICT` "
3419 "FROM `INFORMATION_SCHEMA`.`XTRADB_ZIP_DICT` "
3420 "WHERE `NAME` = '%s'";
3421
3422 char quoted_buff[NAME_LEN * 2 + 3];
3423 char *quoted_dictionary_name;
3424 char query_buff[QUERY_LENGTH];
3425 MYSQL_RES *result= 0;
3426 MYSQL_ROW row;
3427 ulong *lengths;
3428
3429 if (my_hash_insert(&processed_compression_dictionaries,
3430 (uchar*)my_strdup(PSI_NOT_INSTRUMENTED, dictionary_name, MYF(0))))
3431 die(EX_MYSQLERR, "Couldn't allocate memory");
3432
3433 my_snprintf(query_buff, sizeof(query_buff), get_zip_dict_data_stmt,
3434 dictionary_name);
3435
3436 if (mysql_query_with_error_report(mysql, &result, query_buff))
3437 {
3438 DBUG_VOID_RETURN;
3439 }
3440
3441 row= mysql_fetch_row(result);
3442 if (row == 0)
3443 {
3444 mysql_free_result(result);
3445 maybe_die(EX_MYSQLERR,
3446 "Couldn't read data for compresion dictionary %s (%s)\n",
3447 dictionary_name, mysql_error(mysql));
3448 DBUG_VOID_RETURN;
3449 }
3450 lengths= mysql_fetch_lengths(result);
3451 assert(lengths != 0);
3452
3453 quoted_dictionary_name= quote_name(dictionary_name, quoted_buff, 0);
3454
3455 /*
3456 We print DROP COMPRESSION_DICTIONARY only if no --tab
3457 (file per table option) and no --skip-add-drop-compression-dictionary
3458 were specified
3459 */
3460 if (path == 0 && opt_drop_compression_dictionary)
3461 {
3462 fprintf(sql_file,
3463 "/*!" STRINGIFY_ARG(FIRST_SUPPORTED_COMPRESSED_COLUMNS_VERSION)
3464 " DROP COMPRESSION_DICTIONARY IF EXISTS %s */;\n",
3465 quoted_dictionary_name);
3466 check_io(sql_file);
3467 }
3468
3469 /*
3470 Whether IF NOT EXISTS is added to CREATE COMPRESSION_DICTIONARY
3471 depends on the --add-drop-compression-dictionary /
3472 --skip-add-drop-compression-dictionary options.
3473 */
3474 fprintf(sql_file,
3475 "/*!" STRINGIFY_ARG(FIRST_SUPPORTED_COMPRESSED_COLUMNS_VERSION)
3476 " CREATE COMPRESSION_DICTIONARY %s%s (",
3477 path != 0 ? "IF NOT EXISTS " : "",
3478 quoted_dictionary_name);
3479 check_io(sql_file);
3480
3481 unescape(sql_file, row[0], lengths[0]);
3482 fputs(") */;\n", sql_file);
3483 check_io(sql_file);
3484
3485 mysql_free_result(result);
3486 }
3487 DBUG_VOID_RETURN;
3488 }
3489
3490 /**
3491 Checks if --add-drop-table option is enabled and prints
3492 "DROP TABLE IF EXISTS ..." if the specified table is not a log table.
3493
3494 @param sq_file output file
3495 @param db db name
3496 @param table table name
3497 @param opt_quoted_table optionally quoted table name
3498 */
print_optional_drop_table(FILE * sql_file,const char * db,const char * table,const char * opt_quoted_table)3499 static void print_optional_drop_table(FILE *sql_file, const char* db,
3500 const char *table,
3501 const char *opt_quoted_table)
3502 {
3503 DBUG_ENTER("print_optional_drop_table");
3504 DBUG_PRINT("enter", ("db: %s table: %s", db, table));
3505 if (opt_drop)
3506 {
3507 if (!(general_log_or_slow_log_tables(db, table) ||
3508 replication_metadata_tables(db, table)))
3509 {
3510 fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", opt_quoted_table);
3511 check_io(sql_file);
3512 }
3513 }
3514 DBUG_VOID_RETURN;
3515 }
3516 /*
3517 get_table_structure -- retrievs database structure, prints out corresponding
3518 CREATE statement and fills out insert_pat if the table is the type we will
3519 be dumping.
3520
3521 ARGS
3522 table - table name
3523 db - db name
3524 table_type - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW"
3525 ignore_flag - what we must particularly ignore - see IGNORE_ defines above
3526 real_columns- Contains one byte per column, 0 means unused, 1 is used
3527 Generated columns are marked as unused
3528 RETURN
3529 number of fields in table, 0 if error
3530 */
3531
get_table_structure(char * table,char * db,char * table_type,char * ignore_flag,my_bool real_columns[])3532 static uint get_table_structure(char *table, char *db, char *table_type,
3533 char *ignore_flag, my_bool real_columns[])
3534 {
3535 my_bool init=0, write_data, complete_insert;
3536 my_ulonglong num_fields;
3537 char *result_table, *opt_quoted_table;
3538 const char *insert_option;
3539 char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
3540 char table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH];
3541 const char *show_fields_stmt= "SELECT `COLUMN_NAME` AS `Field`, "
3542 "`COLUMN_TYPE` AS `Type`, "
3543 "`IS_NULLABLE` AS `Null`, "
3544 "`COLUMN_KEY` AS `Key`, "
3545 "`COLUMN_DEFAULT` AS `Default`, "
3546 "`EXTRA` AS `Extra`, "
3547 "`COLUMN_COMMENT` AS `Comment` "
3548 "FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE "
3549 "TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'";
3550 FILE *sql_file= md_result_file;
3551 size_t len;
3552 my_bool is_log_table;
3553 my_bool is_replication_metadata_table;
3554 unsigned int colno;
3555 my_bool is_innodb_table;
3556 MYSQL_RES *result;
3557 MYSQL_ROW row;
3558 my_bool has_pk= FALSE;
3559 DBUG_ENTER("get_table_structure");
3560 DBUG_PRINT("enter", ("db: %s table: %s", db, table));
3561
3562 *ignore_flag= check_if_ignore_table(table, table_type);
3563
3564 complete_insert= 0;
3565 if ((write_data= !(*ignore_flag & IGNORE_DATA)))
3566 {
3567 complete_insert= opt_complete_insert;
3568 if (!insert_pat_inited)
3569 {
3570 insert_pat_inited= 1;
3571 init_dynamic_string_checked(&insert_pat, "", 1024, 1024);
3572 }
3573 else
3574 dynstr_set_checked(&insert_pat, "");
3575 }
3576
3577 insert_option= (opt_ignore ? " IGNORE " : "");
3578
3579 verbose_msg("-- Retrieving table structure for table %s...\n", table);
3580
3581 len= my_snprintf(query_buff, sizeof(query_buff),
3582 "SET SQL_QUOTE_SHOW_CREATE=%d",
3583 (opt_quoted || opt_keywords));
3584 if (!create_options)
3585 my_stpcpy(query_buff+len,
3586 "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
3587
3588 result_table= quote_name(table, table_buff, 1);
3589 opt_quoted_table= quote_name(table, table_buff2, 0);
3590
3591 if (opt_innodb_optimize_keys && !strcmp(table_type, "InnoDB"))
3592 has_pk= has_primary_key(table);
3593
3594 if (opt_order_by_primary || opt_order_by_primary_desc)
3595 order_by= primary_key_fields(result_table,
3596 opt_order_by_primary_desc ? TRUE : FALSE);
3597
3598 if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff))
3599 {
3600 /* using SHOW CREATE statement */
3601 if (!opt_no_create_info)
3602 {
3603 /* Make an sql-file, if path was given iow. option -T was given */
3604 char buff[20+FN_REFLEN];
3605 MYSQL_FIELD *field;
3606 my_bool freemem= FALSE;
3607 char const *text;
3608
3609 my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
3610
3611 if (switch_character_set_results(mysql, "binary") ||
3612 mysql_query_with_error_report(mysql, &result, buff) ||
3613 switch_character_set_results(mysql, default_charset))
3614 DBUG_RETURN(0);
3615
3616 if (path)
3617 {
3618 if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
3619 DBUG_RETURN(0);
3620
3621 write_header(sql_file, db);
3622 }
3623
3624 text= fix_identifier_with_newline(result_table, &freemem);
3625 if (strcmp (table_type, "VIEW") == 0) /* view */
3626 print_comment(sql_file, 0,
3627 "\n--\n-- Temporary table structure for view %s\n--\n\n",
3628 text);
3629 else
3630 print_comment(sql_file, 0,
3631 "\n--\n-- Table structure for table %s\n--\n\n", text);
3632
3633 if (freemem)
3634 my_free((void*)text);
3635
3636 field= mysql_fetch_field_direct(result, 0);
3637 if (strcmp(field->name, "View") == 0)
3638 {
3639 char *scv_buff= NULL;
3640 my_ulonglong n_cols;
3641
3642 /*
3643 Even if the "table" is a view, we do a DROP TABLE here. The
3644 view-specific code below fills in the DROP VIEW.
3645 We will skip the DROP TABLE for general_log and slow_log, since
3646 those stmts will fail, in case we apply dump by enabling logging.
3647 We will skip this for replication metadata tables as well.
3648 */
3649 print_optional_drop_table(sql_file, db, table, opt_quoted_table);
3650
3651 verbose_msg("-- It's a view, create dummy view\n");
3652
3653 /* save "show create" statement for later */
3654 if ((row= mysql_fetch_row(result)) && (scv_buff=row[1]))
3655 scv_buff= my_strdup(PSI_NOT_INSTRUMENTED,
3656 scv_buff, MYF(0));
3657
3658 mysql_free_result(result);
3659
3660 /*
3661 Create a table with the same name as the view and with columns of
3662 the same name in order to satisfy views that depend on this view.
3663 The table will be removed when the actual view is created.
3664
3665 The properties of each column, are not preserved in this temporary
3666 table, because they are not necessary.
3667
3668 This will not be necessary once we can determine dependencies
3669 between views and can simply dump them in the appropriate order.
3670 */
3671 my_snprintf(query_buff, sizeof(query_buff),
3672 "SHOW FIELDS FROM %s", result_table);
3673 if (switch_character_set_results(mysql, "binary") ||
3674 mysql_query_with_error_report(mysql, &result, query_buff) ||
3675 switch_character_set_results(mysql, default_charset))
3676 {
3677 /*
3678 View references invalid or privileged table/col/fun (err 1356),
3679 so we cannot create a stand-in table. Be defensive and dump
3680 a comment with the view's 'show create' statement. (Bug #17371)
3681 */
3682
3683 if (mysql_errno(mysql) == ER_VIEW_INVALID)
3684 fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : "");
3685
3686 my_free(scv_buff);
3687
3688 DBUG_RETURN(0);
3689 }
3690 else
3691 my_free(scv_buff);
3692
3693 n_cols= mysql_num_rows(result);
3694 if (0 != n_cols)
3695 {
3696
3697 /*
3698 The actual formula is based on the column names and how the .FRM
3699 files are stored and is too volatile to be repeated here.
3700 Thus we simply warn the user if the columns exceed a limit we
3701 know works most of the time.
3702 */
3703 if (n_cols >= 1000)
3704 fprintf(stderr,
3705 "-- Warning: Creating a stand-in table for view %s may"
3706 " fail when replaying the dump file produced because "
3707 "of the number of columns exceeding 1000. Exercise "
3708 "caution when replaying the produced dump file.\n",
3709 table);
3710 if (opt_drop)
3711 {
3712 /*
3713 We have already dropped any table of the same name above, so
3714 here we just drop the view.
3715 */
3716
3717 fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
3718 opt_quoted_table);
3719 check_io(sql_file);
3720 }
3721
3722 fprintf(sql_file,
3723 "SET @saved_cs_client = @@character_set_client;\n"
3724 "SET character_set_client = utf8;\n"
3725 "/*!50001 CREATE VIEW %s AS SELECT \n",
3726 result_table);
3727
3728 /*
3729 Get first row, following loop will prepend comma - keeps from
3730 having to know if the row being printed is last to determine if
3731 there should be a _trailing_ comma.
3732 */
3733
3734
3735 row= mysql_fetch_row(result);
3736
3737 /*
3738 A temporary view is created to resolve the view interdependencies.
3739 This temporary view is dropped when the actual view is created.
3740 */
3741
3742 fprintf(sql_file, " 1 AS %s",
3743 quote_name(row[0], name_buff, 0));
3744
3745 while((row= mysql_fetch_row(result)))
3746 {
3747 fprintf(sql_file, ",\n 1 AS %s",
3748 quote_name(row[0], name_buff, 0));
3749 }
3750
3751 fprintf(sql_file,"*/;\n"
3752 "SET character_set_client = @saved_cs_client;\n");
3753
3754 check_io(sql_file);
3755 }
3756
3757 mysql_free_result(result);
3758
3759 if (path)
3760 my_fclose(sql_file, MYF(MY_WME));
3761
3762 seen_views= 1;
3763 DBUG_RETURN(0);
3764 }
3765
3766 row= mysql_fetch_row(result);
3767
3768 is_innodb_table= (strcmp(table_type, "InnoDB") == 0);
3769 if (opt_innodb_optimize_keys && is_innodb_table)
3770 skip_secondary_keys(row[1], has_pk);
3771 if (is_innodb_table)
3772 {
3773 /*
3774 Search for compressed columns attributes and remove them if
3775 necessary.
3776 */
3777
3778 LIST *referenced_dictionaries= 0, *current_dictionary;
3779
3780 skip_compressed_columns(row[1], &referenced_dictionaries);
3781 referenced_dictionaries= list_reverse(referenced_dictionaries);
3782 for (current_dictionary= referenced_dictionaries;
3783 current_dictionary != 0;
3784 current_dictionary= list_rest(current_dictionary))
3785 {
3786 print_optional_create_compression_dictionary(
3787 sql_file, (const char*)current_dictionary->data);
3788 }
3789 list_free(referenced_dictionaries, TRUE);
3790 }
3791
3792 print_optional_drop_table(sql_file, db, table, opt_quoted_table);
3793
3794 is_log_table= general_log_or_slow_log_tables(db, table);
3795 is_replication_metadata_table= replication_metadata_tables(db, table);
3796 if (is_log_table || is_replication_metadata_table)
3797 row[1]+= 13; /* strlen("CREATE TABLE ")= 13 */
3798 if (opt_compatible_mode & 3)
3799 {
3800 fprintf(sql_file,
3801 (is_log_table || is_replication_metadata_table) ?
3802 "CREATE TABLE IF NOT EXISTS %s;\n" : "%s;\n", row[1]);
3803 }
3804 else
3805 {
3806 fprintf(sql_file,
3807 "/*!40101 SET @saved_cs_client = @@character_set_client */;\n"
3808 "/*!40101 SET character_set_client = utf8 */;\n"
3809 "%s%s;\n"
3810 "/*!40101 SET character_set_client = @saved_cs_client */;\n",
3811 (is_log_table || is_replication_metadata_table) ?
3812 "CREATE TABLE IF NOT EXISTS " : "", row[1]);
3813 }
3814
3815 check_io(sql_file);
3816 mysql_free_result(result);
3817 }
3818 my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
3819 result_table);
3820 if (mysql_query_with_error_report(mysql, &result, query_buff))
3821 {
3822 if (path)
3823 my_fclose(sql_file, MYF(MY_WME));
3824 DBUG_RETURN(0);
3825 }
3826
3827 if (write_data && !complete_insert)
3828 {
3829 /*
3830 If data contents of table are to be written and complete_insert
3831 is false (column list not required in INSERT statement), scan the
3832 column list for generated columns, as presence of any generated column
3833 will require that an explicit list of columns is printed.
3834 */
3835 while ((row= mysql_fetch_row(result)))
3836 {
3837 complete_insert|=
3838 strcmp(row[SHOW_EXTRA], "STORED GENERATED") == 0 ||
3839 strcmp(row[SHOW_EXTRA], "VIRTUAL GENERATED") == 0;
3840 }
3841 mysql_free_result(result);
3842
3843 if (mysql_query_with_error_report(mysql, &result, query_buff))
3844 {
3845 if (path)
3846 my_fclose(sql_file, MYF(MY_WME));
3847 DBUG_RETURN(0);
3848 }
3849 }
3850 /*
3851 If write_data is true, then we build up insert statements for
3852 the table's data. Note: in subsequent lines of code, this test
3853 will have to be performed each time we are appending to
3854 insert_pat.
3855 */
3856 if (write_data)
3857 {
3858 if (opt_replace_into)
3859 dynstr_append_checked(&insert_pat, "REPLACE ");
3860 else
3861 dynstr_append_checked(&insert_pat, "INSERT ");
3862 dynstr_append_checked(&insert_pat, insert_option);
3863 dynstr_append_checked(&insert_pat, "INTO ");
3864 dynstr_append_checked(&insert_pat, opt_quoted_table);
3865 if (complete_insert)
3866 {
3867 dynstr_append_checked(&insert_pat, " (");
3868 }
3869 else
3870 {
3871 dynstr_append_checked(&insert_pat, " VALUES ");
3872 if (!extended_insert)
3873 dynstr_append_checked(&insert_pat, "(");
3874 }
3875 }
3876
3877 colno= 0;
3878 while ((row= mysql_fetch_row(result)))
3879 {
3880 real_columns[colno]=
3881 strcmp(row[SHOW_EXTRA], "STORED GENERATED") != 0 &&
3882 strcmp(row[SHOW_EXTRA], "VIRTUAL GENERATED") != 0;
3883
3884 if (real_columns[colno++] && complete_insert)
3885 {
3886 if (init)
3887 {
3888 dynstr_append_checked(&insert_pat, ", ");
3889 }
3890 init=1;
3891 dynstr_append_checked(&insert_pat,
3892 quote_name(row[SHOW_FIELDNAME], name_buff, 0));
3893 }
3894 }
3895 num_fields= mysql_num_rows(result);
3896 mysql_free_result(result);
3897 }
3898 else
3899 {
3900 verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
3901 my_progname, mysql_error(mysql));
3902
3903 my_snprintf(query_buff, sizeof(query_buff), show_fields_stmt, db, table);
3904
3905 if (mysql_query_with_error_report(mysql, &result, query_buff))
3906 DBUG_RETURN(0);
3907
3908 if (write_data && !complete_insert)
3909 {
3910 /*
3911 If data contents of table are to be written and complete_insert
3912 is false (column list not required in INSERT statement), scan the
3913 column list for generated columns, as presence of any generated column
3914 will require that an explicit list of columns is printed.
3915 */
3916 while ((row= mysql_fetch_row(result)))
3917 {
3918 complete_insert|=
3919 strcmp(row[SHOW_EXTRA], "STORED GENERATED") == 0 ||
3920 strcmp(row[SHOW_EXTRA], "VIRTUAL GENERATED") == 0;
3921 }
3922 mysql_free_result(result);
3923
3924 if (mysql_query_with_error_report(mysql, &result, query_buff))
3925 {
3926 if (path)
3927 my_fclose(sql_file, MYF(MY_WME));
3928 DBUG_RETURN(0);
3929 }
3930 }
3931 /* Make an sql-file, if path was given iow. option -T was given */
3932 if (!opt_no_create_info)
3933 {
3934 my_bool freemem= FALSE;
3935 char const *text;
3936
3937 if (path)
3938 {
3939 if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
3940 DBUG_RETURN(0);
3941 write_header(sql_file, db);
3942 }
3943
3944 text= fix_identifier_with_newline(result_table, &freemem);
3945 print_comment(sql_file, 0,
3946 "\n--\n-- Table structure for table %s\n--\n\n",
3947 text);
3948 if (freemem)
3949 my_free((void*)text);
3950
3951 if (opt_drop)
3952 fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table);
3953 if (!opt_xml)
3954 fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
3955 else
3956 print_xml_tag(sql_file, "\t", "\n", "table_structure", "name=", table,
3957 NullS);
3958 check_io(sql_file);
3959 }
3960
3961 if (write_data)
3962 {
3963 if (opt_replace_into)
3964 dynstr_append_checked(&insert_pat, "REPLACE ");
3965 else
3966 dynstr_append_checked(&insert_pat, "INSERT ");
3967 dynstr_append_checked(&insert_pat, insert_option);
3968 dynstr_append_checked(&insert_pat, "INTO ");
3969 dynstr_append_checked(&insert_pat, result_table);
3970 if (complete_insert)
3971 dynstr_append_checked(&insert_pat, " (");
3972 else
3973 {
3974 dynstr_append_checked(&insert_pat, " VALUES ");
3975 if (!extended_insert)
3976 dynstr_append_checked(&insert_pat, "(");
3977 }
3978 }
3979
3980 colno= 0;
3981 while ((row= mysql_fetch_row(result)))
3982 {
3983 ulong *lengths= mysql_fetch_lengths(result);
3984
3985 real_columns[colno]=
3986 strcmp(row[SHOW_EXTRA], "STORED GENERATED") != 0 &&
3987 strcmp(row[SHOW_EXTRA], "VIRTUAL GENERATED") != 0;
3988
3989 if (!real_columns[colno++])
3990 continue;
3991
3992 if (init)
3993 {
3994 if (!opt_xml && !opt_no_create_info)
3995 {
3996 fputs(",\n",sql_file);
3997 check_io(sql_file);
3998 }
3999 if (complete_insert)
4000 dynstr_append_checked(&insert_pat, ", ");
4001 }
4002 init=1;
4003 if (complete_insert)
4004 dynstr_append_checked(&insert_pat,
4005 quote_name(row[SHOW_FIELDNAME], name_buff, 0));
4006 if (!opt_no_create_info)
4007 {
4008 if (opt_xml)
4009 {
4010 print_xml_row(sql_file, "field", result, &row, NullS);
4011 continue;
4012 }
4013
4014 if (opt_keywords)
4015 fprintf(sql_file, " %s.%s %s", result_table,
4016 quote_name(row[SHOW_FIELDNAME],name_buff, 0),
4017 row[SHOW_TYPE]);
4018 else
4019 fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],
4020 name_buff, 0),
4021 row[SHOW_TYPE]);
4022 if (row[SHOW_DEFAULT])
4023 {
4024 fputs(" DEFAULT ", sql_file);
4025 unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
4026 }
4027 if (!row[SHOW_NULL][0])
4028 fputs(" NOT NULL", sql_file);
4029 if (row[SHOW_EXTRA][0])
4030 fprintf(sql_file, " %s",row[SHOW_EXTRA]);
4031 check_io(sql_file);
4032 }
4033 }
4034 num_fields= mysql_num_rows(result);
4035 mysql_free_result(result);
4036 if (!opt_no_create_info)
4037 {
4038 /* Make an sql-file, if path was given iow. option -T was given */
4039 char buff[20+FN_REFLEN];
4040 uint keynr,primary_key;
4041 my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
4042 if (mysql_query_with_error_report(mysql, &result, buff))
4043 {
4044 if (mysql_errno(mysql) == ER_WRONG_OBJECT)
4045 {
4046 /* it is VIEW */
4047 fputs("\t\t<options Comment=\"view\" />\n", sql_file);
4048 goto continue_xml;
4049 }
4050 fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
4051 my_progname, result_table, mysql_error(mysql));
4052 if (path)
4053 my_fclose(sql_file, MYF(MY_WME));
4054 DBUG_RETURN(0);
4055 }
4056
4057 /* Find first which key is primary key */
4058 keynr=0;
4059 primary_key=INT_MAX;
4060 while ((row= mysql_fetch_row(result)))
4061 {
4062 if (atoi(row[3]) == 1)
4063 {
4064 keynr++;
4065 if (!strcmp(row[2],"PRIMARY"))
4066 {
4067 primary_key=keynr;
4068 break;
4069 }
4070 }
4071 }
4072 mysql_data_seek(result,0);
4073 keynr=0;
4074 while ((row= mysql_fetch_row(result)))
4075 {
4076 if (opt_xml)
4077 {
4078 print_xml_row(sql_file, "key", result, &row, NullS);
4079 continue;
4080 }
4081
4082 if (atoi(row[3]) == 1)
4083 {
4084 if (keynr++)
4085 putc(')', sql_file);
4086 if (atoi(row[1])) /* Test if duplicate key */
4087 /* Duplicate allowed */
4088 fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0));
4089 else if (keynr == primary_key)
4090 fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
4091 else
4092 fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff,
4093 0));
4094 }
4095 else
4096 putc(',', sql_file);
4097 fputs(quote_name(row[4], name_buff, 0), sql_file);
4098 if (row[7])
4099 fprintf(sql_file, " (%s)",row[7]); /* Sub key */
4100 check_io(sql_file);
4101 }
4102 mysql_free_result(result);
4103 if (!opt_xml)
4104 {
4105 if (keynr)
4106 putc(')', sql_file);
4107 fputs("\n)",sql_file);
4108 check_io(sql_file);
4109 }
4110
4111 /* Get MySQL specific create options */
4112 if (create_options)
4113 {
4114 char show_name_buff[NAME_LEN*2+2+24];
4115
4116 /* Check memory for quote_for_like() */
4117 my_snprintf(buff, sizeof(buff), "show table status like %s",
4118 quote_for_like(table, show_name_buff));
4119
4120 if (mysql_query_with_error_report(mysql, &result, buff))
4121 {
4122 if (mysql_errno(mysql) != ER_PARSE_ERROR)
4123 { /* If old MySQL version */
4124 verbose_msg("-- Warning: Couldn't get status information for " \
4125 "table %s (%s)\n", result_table,mysql_error(mysql));
4126 }
4127 }
4128 else if (!(row= mysql_fetch_row(result)))
4129 {
4130 fprintf(stderr,
4131 "Error: Couldn't read status information for table %s (%s)\n",
4132 result_table,mysql_error(mysql));
4133 }
4134 else
4135 {
4136 if (opt_xml)
4137 print_xml_row(sql_file, "options", result, &row, NullS);
4138 else
4139 {
4140 fputs("/*!",sql_file);
4141 print_value(sql_file,result,row,"engine=","Engine",0);
4142 print_value(sql_file,result,row,"","Create_options",0);
4143 print_value(sql_file,result,row,"comment=","Comment",1);
4144 fputs(" */",sql_file);
4145 check_io(sql_file);
4146 }
4147 }
4148 mysql_free_result(result); /* Is always safe to free */
4149 }
4150 continue_xml:
4151 if (!opt_xml)
4152 fputs(";\n", sql_file);
4153 else
4154 fputs("\t</table_structure>\n", sql_file);
4155 check_io(sql_file);
4156 }
4157 }
4158 if (complete_insert)
4159 {
4160 dynstr_append_checked(&insert_pat, ") VALUES ");
4161 if (!extended_insert)
4162 dynstr_append_checked(&insert_pat, "(");
4163 }
4164 if (sql_file != md_result_file)
4165 {
4166 fputs("\n", sql_file);
4167 write_footer(sql_file);
4168 my_fclose(sql_file, MYF(MY_WME));
4169 }
4170 DBUG_RETURN((uint) num_fields);
4171 } /* get_table_structure */
4172
dump_trigger_old(FILE * sql_file,MYSQL_RES * show_triggers_rs,MYSQL_ROW * show_trigger_row,const char * table_name)4173 static void dump_trigger_old(FILE *sql_file, MYSQL_RES *show_triggers_rs,
4174 MYSQL_ROW *show_trigger_row,
4175 const char *table_name)
4176 {
4177 char quoted_table_name_buf[NAME_LEN * 2 + 3];
4178 char *quoted_table_name= quote_name(table_name, quoted_table_name_buf, 1);
4179
4180 char name_buff[NAME_LEN * 4 + 3];
4181 const char *xml_msg= "\nWarning! mysqldump being run against old server "
4182 "that does not\nsupport 'SHOW CREATE TRIGGERS' "
4183 "statement. Skipping..\n";
4184
4185 DBUG_ENTER("dump_trigger_old");
4186
4187 if (opt_xml)
4188 {
4189 print_xml_comment(sql_file, strlen(xml_msg), xml_msg);
4190 check_io(sql_file);
4191 DBUG_VOID_RETURN;
4192 }
4193
4194 fprintf(sql_file,
4195 "--\n"
4196 "-- WARNING: old server version. "
4197 "The following dump may be incomplete.\n"
4198 "--\n");
4199
4200 if (opt_compact)
4201 fprintf(sql_file, "/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n");
4202
4203 if (opt_drop_trigger)
4204 fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", (*show_trigger_row)[0]);
4205
4206 fprintf(sql_file,
4207 "DELIMITER ;;\n"
4208 "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n"
4209 "/*!50003 CREATE */ ",
4210 (*show_trigger_row)[6]);
4211
4212 if (mysql_num_fields(show_triggers_rs) > 7)
4213 {
4214 /*
4215 mysqldump can be run against the server, that does not support
4216 definer in triggers (there is no DEFINER column in SHOW TRIGGERS
4217 output). So, we should check if we have this column before
4218 accessing it.
4219 */
4220
4221 size_t user_name_len;
4222 char user_name_str[USERNAME_LENGTH + 1];
4223 char quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
4224 size_t host_name_len;
4225 char host_name_str[HOSTNAME_LENGTH + 1];
4226 char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
4227
4228 parse_user((*show_trigger_row)[7],
4229 strlen((*show_trigger_row)[7]),
4230 user_name_str, &user_name_len,
4231 host_name_str, &host_name_len);
4232
4233 fprintf(sql_file,
4234 "/*!50017 DEFINER=%s@%s */ ",
4235 quote_name(user_name_str, quoted_user_name_str, FALSE),
4236 quote_name(host_name_str, quoted_host_name_str, FALSE));
4237 }
4238
4239 fprintf(sql_file,
4240 "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n"
4241 "DELIMITER ;\n",
4242 quote_name((*show_trigger_row)[0], name_buff, 0), /* Trigger */
4243 (*show_trigger_row)[4], /* Timing */
4244 (*show_trigger_row)[1], /* Event */
4245 quoted_table_name,
4246 (strchr(" \t\n\r", *((*show_trigger_row)[3]))) ? "" : " ",
4247 (*show_trigger_row)[3] /* Statement */);
4248
4249 if (opt_compact)
4250 fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n");
4251
4252 DBUG_VOID_RETURN;
4253 }
4254
dump_trigger(FILE * sql_file,MYSQL_RES * show_create_trigger_rs,const char * db_name,const char * db_cl_name)4255 static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
4256 const char *db_name,
4257 const char *db_cl_name)
4258 {
4259 MYSQL_ROW row;
4260 char *query_str;
4261 int db_cl_altered= FALSE;
4262
4263 DBUG_ENTER("dump_trigger");
4264
4265 while ((row= mysql_fetch_row(show_create_trigger_rs)))
4266 {
4267 if (opt_xml)
4268 {
4269 print_xml_row(sql_file, "trigger", show_create_trigger_rs, &row,
4270 "SQL Original Statement");
4271 check_io(sql_file);
4272 continue;
4273 }
4274
4275 query_str= cover_definer_clause(row[2], strlen(row[2]),
4276 C_STRING_WITH_LEN("50017"),
4277 C_STRING_WITH_LEN("50003"),
4278 C_STRING_WITH_LEN(" TRIGGER"));
4279 if (switch_db_collation(sql_file, db_name, ";",
4280 db_cl_name, row[5], &db_cl_altered))
4281 DBUG_RETURN(TRUE);
4282
4283 switch_cs_variables(sql_file, ";",
4284 row[3], /* character_set_client */
4285 row[3], /* character_set_results */
4286 row[4]); /* collation_connection */
4287
4288 remove_sql_mode(row[1], C_STRING_WITH_LEN("NO_AUTO_CREATE_USER"));
4289 switch_sql_mode(sql_file, ";", row[1]);
4290
4291 if (opt_drop_trigger)
4292 fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", row[0]);
4293
4294 fprintf(sql_file,
4295 "DELIMITER ;;\n"
4296 "/*!50003 %s */;;\n"
4297 "DELIMITER ;\n",
4298 (const char *) (query_str != NULL ? query_str : row[2]));
4299
4300 restore_sql_mode(sql_file, ";");
4301 restore_cs_variables(sql_file, ";");
4302
4303 if (db_cl_altered)
4304 {
4305 if (restore_db_collation(sql_file, db_name, ";", db_cl_name))
4306 DBUG_RETURN(TRUE);
4307 }
4308
4309 my_free(query_str);
4310 }
4311
4312 DBUG_RETURN(FALSE);
4313 }
4314
4315 /**
4316 Dump the triggers for a given table.
4317
4318 This should be called after the tables have been dumped in case a trigger
4319 depends on the existence of a table.
4320
4321 @param[in] table_name
4322 @param[in] db_name
4323
4324 @return Error status.
4325 @retval TRUE error has occurred.
4326 @retval FALSE operation succeed.
4327 */
4328
dump_triggers_for_table(char * table_name,char * db_name)4329 static int dump_triggers_for_table(char *table_name, char *db_name)
4330 {
4331 char name_buff[NAME_LEN*4+3];
4332 char query_buff[QUERY_LENGTH];
4333 uint old_opt_compatible_mode= opt_compatible_mode;
4334 MYSQL_RES *show_triggers_rs;
4335 MYSQL_ROW row;
4336 FILE *sql_file= md_result_file;
4337
4338 char db_cl_name[MY_CS_NAME_SIZE];
4339 int ret= TRUE;
4340
4341 DBUG_ENTER("dump_triggers_for_table");
4342 DBUG_PRINT("enter", ("db: %s, table_name: %s", db_name, table_name));
4343
4344 if (path && !(sql_file= open_sql_file_for_table(table_name,
4345 O_WRONLY | O_APPEND)))
4346 DBUG_RETURN(1);
4347
4348 /* Do not use ANSI_QUOTES on triggers in dump */
4349 opt_compatible_mode&= ~MASK_ANSI_QUOTES;
4350
4351 /* Get database collation. */
4352
4353 if (switch_character_set_results(mysql, "binary"))
4354 goto done;
4355
4356 if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name)))
4357 goto done;
4358
4359 /* Get list of triggers. */
4360
4361 my_snprintf(query_buff, sizeof(query_buff),
4362 "SHOW TRIGGERS LIKE %s",
4363 quote_for_like(table_name, name_buff));
4364
4365 if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff))
4366 goto done;
4367
4368 /* Dump triggers. */
4369
4370 if (! mysql_num_rows(show_triggers_rs))
4371 goto skip;
4372
4373 if (opt_xml)
4374 print_xml_tag(sql_file, "\t", "\n", "triggers", "name=",
4375 table_name, NullS);
4376
4377 while ((row= mysql_fetch_row(show_triggers_rs)))
4378 {
4379
4380 my_snprintf(query_buff, sizeof (query_buff),
4381 "SHOW CREATE TRIGGER %s",
4382 quote_name(row[0], name_buff, TRUE));
4383
4384 if (mysql_query(mysql, query_buff))
4385 {
4386 /*
4387 mysqldump is being run against old server, that does not support
4388 SHOW CREATE TRIGGER statement. We should use SHOW TRIGGERS output.
4389
4390 NOTE: the dump may be incorrect, as old SHOW TRIGGERS does not
4391 provide all the necessary information to restore trigger properly.
4392 */
4393
4394 dump_trigger_old(sql_file, show_triggers_rs, &row, table_name);
4395 }
4396 else
4397 {
4398 MYSQL_RES *show_create_trigger_rs= mysql_store_result(mysql);
4399
4400 if (!show_create_trigger_rs ||
4401 dump_trigger(sql_file, show_create_trigger_rs, db_name, db_cl_name))
4402 goto done;
4403
4404 mysql_free_result(show_create_trigger_rs);
4405 }
4406
4407 }
4408
4409 if (opt_xml)
4410 {
4411 fputs("\t</triggers>\n", sql_file);
4412 check_io(sql_file);
4413 }
4414
4415 skip:
4416 mysql_free_result(show_triggers_rs);
4417
4418 if (switch_character_set_results(mysql, default_charset))
4419 goto done;
4420
4421 /*
4422 make sure to set back opt_compatible mode to
4423 original value
4424 */
4425 opt_compatible_mode=old_opt_compatible_mode;
4426
4427 ret= FALSE;
4428
4429 done:
4430 if (path)
4431 my_fclose(sql_file, MYF(0));
4432
4433 DBUG_RETURN(ret);
4434 }
4435
add_load_option(DYNAMIC_STRING * str,const char * option,const char * option_value)4436 static void add_load_option(DYNAMIC_STRING *str, const char *option,
4437 const char *option_value)
4438 {
4439 if (!option_value)
4440 {
4441 /* Null value means we don't add this option. */
4442 return;
4443 }
4444
4445 dynstr_append_checked(str, option);
4446
4447 if (strncmp(option_value, "0x", sizeof("0x")-1) == 0)
4448 {
4449 /* It's a hex constant, don't escape */
4450 dynstr_append_checked(str, option_value);
4451 }
4452 else
4453 {
4454 /* char constant; escape */
4455 field_escape(str, option_value);
4456 }
4457 }
4458
4459
4460 /*
4461 Allow the user to specify field terminator strings like:
4462 "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
4463 This is done by doubling ' and add a end -\ if needed to avoid
4464 syntax errors from the SQL parser.
4465 */
4466
field_escape(DYNAMIC_STRING * in,const char * from)4467 static void field_escape(DYNAMIC_STRING* in, const char *from)
4468 {
4469 uint end_backslashes= 0;
4470
4471 dynstr_append_checked(in, "'");
4472
4473 while (*from)
4474 {
4475 dynstr_append_mem_checked(in, from, 1);
4476
4477 if (*from == '\\')
4478 end_backslashes^=1; /* find odd number of backslashes */
4479 else
4480 {
4481 if (*from == '\'' && !end_backslashes)
4482 {
4483 /* We want a duplicate of "'" for MySQL */
4484 dynstr_append_checked(in, "\'");
4485 }
4486 end_backslashes=0;
4487 }
4488 from++;
4489 }
4490 /* Add missing backslashes if user has specified odd number of backs.*/
4491 if (end_backslashes)
4492 dynstr_append_checked(in, "\\");
4493
4494 dynstr_append_checked(in, "'");
4495 }
4496
4497
4498
alloc_query_str(size_t size)4499 static char *alloc_query_str(size_t size)
4500 {
4501 char *query;
4502
4503 if (!(query= (char*) my_malloc(PSI_NOT_INSTRUMENTED,
4504 size, MYF(MY_WME))))
4505 die(EX_MYSQLERR, "Couldn't allocate a query string.");
4506
4507 return query;
4508 }
4509
4510
4511
4512 /*
4513 Dump delayed secondary index definitions when --innodb-optimize-keys is used.
4514 */
4515
dump_skipped_keys(const char * table)4516 static void dump_skipped_keys(const char *table)
4517 {
4518 uint keys;
4519
4520 if (!skipped_keys_list && !alter_constraints_list)
4521 return;
4522
4523 verbose_msg("-- Dumping delayed secondary index definitions for table %s\n",
4524 table);
4525
4526 if (skipped_keys_list)
4527 {
4528 uint sk_list_len= list_length(skipped_keys_list);
4529 skipped_keys_list= list_reverse(skipped_keys_list);
4530 fprintf(md_result_file, "ALTER TABLE %s%s", table,
4531 (sk_list_len > 1) ? "\n" : " ");
4532
4533 for (keys= sk_list_len; keys > 0; keys--)
4534 {
4535 LIST *node= skipped_keys_list;
4536 char *def= node->data;
4537
4538 fprintf(md_result_file, "%sADD %s%s", (sk_list_len > 1) ? " " : "",
4539 def, (keys > 1) ? ",\n" : ";\n");
4540
4541 skipped_keys_list= list_delete(skipped_keys_list, node);
4542 my_free(def);
4543 my_free(node);
4544 }
4545 }
4546
4547 if (alter_constraints_list)
4548 {
4549 uint ac_list_len= list_length(alter_constraints_list);
4550 alter_constraints_list= list_reverse(alter_constraints_list);
4551 fprintf(md_result_file, "ALTER TABLE %s%s", table,
4552 (ac_list_len > 1) ? "\n" : " ");
4553
4554 for (keys= ac_list_len; keys > 0; keys--)
4555 {
4556 LIST *node= alter_constraints_list;
4557 char *def= node->data;
4558
4559 fprintf(md_result_file, "%sADD %s%s", (ac_list_len > 1) ? " " : "",
4560 def, (keys > 1) ? ",\n" : ";\n");
4561
4562 alter_constraints_list= list_delete(alter_constraints_list, node);
4563 my_free(def);
4564 my_free(node);
4565 }
4566 }
4567
4568 assert(skipped_keys_list == NULL);
4569 assert(alter_constraints_list == NULL);
4570 }
4571
4572
4573 /*
4574
4575 SYNOPSIS
4576 dump_table()
4577
4578 dump_table saves database contents as a series of INSERT statements.
4579
4580 ARGS
4581 table - table name
4582 db - db name
4583
4584 RETURNS
4585 void
4586 */
4587
4588
dump_table(char * table,char * db)4589 static void dump_table(char *table, char *db)
4590 {
4591 char ignore_flag;
4592 char buf[200], table_buff[NAME_LEN+3];
4593 DYNAMIC_STRING query_string;
4594 DYNAMIC_STRING extended_row;
4595 char table_type[NAME_LEN];
4596 char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
4597 int error= 0;
4598 ulong rownr, row_break;
4599 size_t total_length, init_length;
4600 uint num_fields;
4601 MYSQL_RES *res;
4602 MYSQL_FIELD *field;
4603 MYSQL_ROW row;
4604 my_bool real_columns[MAX_FIELDS];
4605 DBUG_ENTER("dump_table");
4606
4607 /*
4608 Make sure you get the create table info before the following check for
4609 --no-data flag below. Otherwise, the create table info won't be printed.
4610 */
4611 num_fields= get_table_structure(table, db, table_type, &ignore_flag,
4612 real_columns);
4613
4614 /*
4615 The "table" could be a view. If so, we don't do anything here.
4616 */
4617 if (strcmp(table_type, "VIEW") == 0)
4618 DBUG_VOID_RETURN;
4619
4620 /*
4621 We don't dump data fo`r replication metadata tables.
4622 */
4623 if (replication_metadata_tables(db, table))
4624 DBUG_VOID_RETURN;
4625
4626 result_table= quote_name(table,table_buff, 1);
4627 opt_quoted_table= quote_name(table, table_buff2, 0);
4628
4629 /* Check --no-data flag */
4630 if (opt_no_data)
4631 {
4632 dump_skipped_keys(opt_quoted_table);
4633
4634 verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n",
4635 table);
4636 DBUG_VOID_RETURN;
4637 }
4638
4639 DBUG_PRINT("info",
4640 ("ignore_flag: %x num_fields: %d", (int) ignore_flag,
4641 num_fields));
4642 /*
4643 If the table type is a merge table or any type that has to be
4644 _completely_ ignored and no data dumped
4645 */
4646 if (ignore_flag & IGNORE_DATA)
4647 {
4648 verbose_msg("-- Warning: Skipping data for table '%s' because " \
4649 "it's of type %s\n", table, table_type);
4650 DBUG_VOID_RETURN;
4651 }
4652 /* Check that there are any fields in the table */
4653 if (num_fields == 0)
4654 {
4655 verbose_msg("-- Skipping dump data for table '%s', it has no fields\n",
4656 table);
4657 DBUG_VOID_RETURN;
4658 }
4659
4660 verbose_msg("-- Sending SELECT query...\n");
4661
4662 init_dynamic_string_checked(&query_string, "", 1024, 1024);
4663 if (extended_insert)
4664 init_dynamic_string_checked(&extended_row, "", 1024, 1024);
4665
4666 if (path)
4667 {
4668 char filename[FN_REFLEN], tmp_path[FN_REFLEN];
4669
4670 /*
4671 Convert the path to native os format
4672 and resolve to the full filepath.
4673 */
4674 convert_dirname(tmp_path,path,NullS);
4675 my_load_path(tmp_path, tmp_path, NULL);
4676 fn_format(filename, table, tmp_path, ".txt", MYF(MY_UNPACK_FILENAME));
4677
4678 /* Must delete the file that 'INTO OUTFILE' will write to */
4679 my_delete(filename, MYF(0));
4680
4681 /* convert to a unix path name to stick into the query */
4682 to_unix_path(filename);
4683
4684 /* now build the query string */
4685
4686 dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '");
4687 dynstr_append_checked(&query_string, filename);
4688 dynstr_append_checked(&query_string, "'");
4689
4690 dynstr_append_checked(&query_string, " /*!50138 CHARACTER SET ");
4691 dynstr_append_checked(&query_string, default_charset == mysql_universal_client_charset ?
4692 my_charset_bin.name : /* backward compatibility */
4693 default_charset);
4694 dynstr_append_checked(&query_string, " */");
4695
4696 if (fields_terminated || enclosed || opt_enclosed || escaped)
4697 dynstr_append_checked(&query_string, " FIELDS");
4698
4699 add_load_option(&query_string, " TERMINATED BY ", fields_terminated);
4700 add_load_option(&query_string, " ENCLOSED BY ", enclosed);
4701 add_load_option(&query_string, " OPTIONALLY ENCLOSED BY ", opt_enclosed);
4702 add_load_option(&query_string, " ESCAPED BY ", escaped);
4703 add_load_option(&query_string, " LINES TERMINATED BY ", lines_terminated);
4704
4705 dynstr_append_checked(&query_string, " FROM ");
4706 dynstr_append_checked(&query_string, result_table);
4707
4708 if (where)
4709 {
4710 dynstr_append_checked(&query_string, " WHERE ");
4711 dynstr_append_checked(&query_string, where);
4712 }
4713 else if ((!my_strcasecmp(charset_info, db, "mysql")) &&
4714 (!my_strcasecmp(charset_info, table, "proc")) &&
4715 opt_alldbs)
4716 {
4717 dynstr_append_checked(&query_string, " WHERE db != 'sys'");
4718 }
4719
4720 if (order_by)
4721 {
4722 dynstr_append_checked(&query_string, " ORDER BY ");
4723 dynstr_append_checked(&query_string, order_by);
4724 }
4725
4726 if (mysql_real_query(mysql, query_string.str, (ulong)query_string.length))
4727 {
4728 DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
4729 dynstr_free(&query_string);
4730 DBUG_VOID_RETURN;
4731 }
4732 }
4733 else
4734 {
4735 my_bool freemem= FALSE;
4736 char const* text= fix_identifier_with_newline(result_table, &freemem);
4737 print_comment(md_result_file, 0, "\n--\n-- Dumping data for table %s\n--\n",
4738 text);
4739 if (freemem)
4740 my_free((void*)text);
4741
4742 dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * FROM ");
4743 dynstr_append_checked(&query_string, result_table);
4744
4745 if (where)
4746 {
4747 freemem= FALSE;
4748 text= fix_identifier_with_newline(where, &freemem);
4749 print_comment(md_result_file, 0, "-- WHERE: %s\n", text);
4750 if (freemem)
4751 my_free((void*)text);
4752
4753 dynstr_append_checked(&query_string, " WHERE ");
4754 dynstr_append_checked(&query_string, where);
4755 }
4756 /*
4757 If table is mysql.proc then do not dump routines which belong
4758 to sys schema
4759 */
4760 else if ((!my_strcasecmp(charset_info, db, "mysql")) &&
4761 (!my_strcasecmp(charset_info, table, "proc")) &&
4762 opt_alldbs)
4763 {
4764 dynstr_append_checked(&query_string, " WHERE db != 'sys'");
4765 }
4766 if (order_by)
4767 {
4768 freemem= FALSE;
4769 text= fix_identifier_with_newline(order_by, &freemem);
4770 print_comment(md_result_file, 0, "-- ORDER BY: %s\n", text);
4771 if (freemem)
4772 my_free((void*)text);
4773
4774 dynstr_append_checked(&query_string, " ORDER BY ");
4775 dynstr_append_checked(&query_string, order_by);
4776 }
4777
4778 if (!opt_xml && !opt_compact)
4779 {
4780 fputs("\n", md_result_file);
4781 check_io(md_result_file);
4782 }
4783 if (mysql_query_with_error_report(mysql, 0, query_string.str))
4784 {
4785 DB_error(mysql, "when retrieving data from server");
4786 goto err;
4787 }
4788 if (quick)
4789 res=mysql_use_result(mysql);
4790 else
4791 res=mysql_store_result(mysql);
4792 if (!res)
4793 {
4794 DB_error(mysql, "when retrieving data from server");
4795 goto err;
4796 }
4797
4798 verbose_msg("-- Retrieving rows...\n");
4799 if (mysql_num_fields(res) != num_fields)
4800 {
4801 fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n",
4802 my_progname, result_table);
4803 error= EX_CONSCHECK;
4804 goto err;
4805 }
4806
4807 if (opt_lock)
4808 {
4809 fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
4810 check_io(md_result_file);
4811 }
4812 /* Moved disable keys to after lock per bug 15977 */
4813 if (opt_disable_keys)
4814 {
4815 fprintf(md_result_file, "/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
4816 opt_quoted_table);
4817 check_io(md_result_file);
4818 }
4819
4820 total_length= opt_net_buffer_length; /* Force row break */
4821 row_break=0;
4822 rownr=0;
4823 init_length=(uint) insert_pat.length+4;
4824 if (opt_xml)
4825 print_xml_tag(md_result_file, "\t", "\n", "table_data", "name=", table,
4826 NullS);
4827 if (opt_autocommit)
4828 {
4829 fprintf(md_result_file, "set autocommit=0;\n");
4830 check_io(md_result_file);
4831 }
4832
4833 while ((row= mysql_fetch_row(res)))
4834 {
4835 uint i;
4836 ulong *lengths= mysql_fetch_lengths(res);
4837 rownr++;
4838 if (!extended_insert && !opt_xml)
4839 {
4840 fputs(insert_pat.str,md_result_file);
4841 check_io(md_result_file);
4842 }
4843 mysql_field_seek(res,0);
4844
4845 if (opt_xml)
4846 {
4847 fputs("\t<row>\n", md_result_file);
4848 check_io(md_result_file);
4849 }
4850
4851 for (i= 0; i < mysql_num_fields(res); i++)
4852 {
4853 int is_blob;
4854 ulong length= lengths[i];
4855
4856 if (!(field= mysql_fetch_field(res)))
4857 die(EX_CONSCHECK,
4858 "Not enough fields from table %s! Aborting.\n",
4859 result_table);
4860
4861 if (!real_columns[i])
4862 continue;
4863 /*
4864 63 is my_charset_bin. If charsetnr is not 63,
4865 we have not a BLOB but a TEXT column.
4866 */
4867 is_blob= (field->charsetnr == 63 &&
4868 (field->type == MYSQL_TYPE_BIT ||
4869 field->type == MYSQL_TYPE_STRING ||
4870 field->type == MYSQL_TYPE_VAR_STRING ||
4871 field->type == MYSQL_TYPE_VARCHAR ||
4872 field->type == MYSQL_TYPE_BLOB ||
4873 field->type == MYSQL_TYPE_LONG_BLOB ||
4874 field->type == MYSQL_TYPE_MEDIUM_BLOB ||
4875 field->type == MYSQL_TYPE_TINY_BLOB ||
4876 field->type == MYSQL_TYPE_GEOMETRY)) ? 1 : 0;
4877 if (extended_insert && !opt_xml)
4878 {
4879 if (i == 0)
4880 dynstr_set_checked(&extended_row,"(");
4881 else
4882 dynstr_append_checked(&extended_row,",");
4883
4884 if (row[i])
4885 {
4886 if (length)
4887 {
4888 if (!(field->flags & NUM_FLAG))
4889 {
4890 /*
4891 "length * 2 + 2" is OK for HEX mode:
4892 - In HEX mode we need exactly 2 bytes per character
4893 plus 2 bytes for '0x' prefix.
4894 - In non-HEX mode we need up to 2 bytes per character,
4895 plus 2 bytes for leading and trailing '\'' characters
4896 and reserve 1 byte for terminating '\0'.
4897 In addition to this, for the blob type, we need to
4898 reserve for the "_binary " string that gets added in
4899 front of the string in the dump.
4900 */
4901 if (opt_hex_blob && is_blob)
4902 {
4903 dynstr_realloc_checked(&extended_row,length * 2 + 2 + 1);
4904 dynstr_append_checked(&extended_row, "0x");
4905 extended_row.length+= mysql_hex_string(extended_row.str +
4906 extended_row.length,
4907 row[i], length);
4908 assert(extended_row.length+1 <= extended_row.max_length);
4909 /* mysql_hex_string() already terminated string by '\0' */
4910 assert(extended_row.str[extended_row.length] == '\0');
4911 }
4912 else
4913 {
4914 dynstr_realloc_checked(&extended_row,length * 2 + 2 + 1 +
4915 (is_blob? strlen("_binary ") : 0));
4916 if (is_blob)
4917 {
4918 /*
4919 inform SQL parser that this string isn't in
4920 character_set_connection, so it doesn't emit a warning.
4921 */
4922 dynstr_append_checked(&extended_row, "_binary ");
4923 }
4924 dynstr_append_checked(&extended_row,"'");
4925 extended_row.length +=
4926 mysql_real_escape_string_quote(&mysql_connection,
4927 &extended_row.str[extended_row.length],
4928 row[i],length,
4929 '\'');
4930 extended_row.str[extended_row.length]='\0';
4931 dynstr_append_checked(&extended_row,"'");
4932 }
4933 }
4934 else
4935 {
4936 /* change any strings ("inf", "-inf", "nan") into NULL */
4937 char *ptr= row[i];
4938 if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
4939 my_isalpha(charset_info, ptr[1])))
4940 dynstr_append_checked(&extended_row, "NULL");
4941 else
4942 {
4943 if (field->type == MYSQL_TYPE_DECIMAL)
4944 {
4945 /* add " signs around */
4946 dynstr_append_checked(&extended_row, "'");
4947 dynstr_append_checked(&extended_row, ptr);
4948 dynstr_append_checked(&extended_row, "'");
4949 }
4950 else
4951 dynstr_append_checked(&extended_row, ptr);
4952 }
4953 }
4954 }
4955 else
4956 dynstr_append_checked(&extended_row,"''");
4957 }
4958 else
4959 dynstr_append_checked(&extended_row,"NULL");
4960 }
4961 else
4962 {
4963 if (i && !opt_xml)
4964 {
4965 fputc(',', md_result_file);
4966 check_io(md_result_file);
4967 }
4968 if (row[i])
4969 {
4970 if (!(field->flags & NUM_FLAG))
4971 {
4972 if (opt_xml)
4973 {
4974 if (opt_hex_blob && is_blob && length)
4975 {
4976 /* Define xsi:type="xs:hexBinary" for hex encoded data */
4977 print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
4978 field->name, "xsi:type=", "xs:hexBinary", NullS);
4979 print_blob_as_hex(md_result_file, row[i], length);
4980 }
4981 else
4982 {
4983 print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
4984 field->name, NullS);
4985 print_quoted_xml(md_result_file, row[i], length, 0);
4986 }
4987 fputs("</field>\n", md_result_file);
4988 }
4989 else if (opt_hex_blob && is_blob && length)
4990 {
4991 fputs("0x", md_result_file);
4992 print_blob_as_hex(md_result_file, row[i], length);
4993 }
4994 else
4995 {
4996 if (is_blob)
4997 {
4998 fputs("_binary ", md_result_file);
4999 check_io(md_result_file);
5000 }
5001 unescape(md_result_file, row[i], length);
5002 }
5003 }
5004 else
5005 {
5006 /* change any strings ("inf", "-inf", "nan") into NULL */
5007 char *ptr= row[i];
5008 if (opt_xml)
5009 {
5010 print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
5011 field->name, NullS);
5012 fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
5013 md_result_file);
5014 fputs("</field>\n", md_result_file);
5015 }
5016 else if (my_isalpha(charset_info, *ptr) ||
5017 (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
5018 fputs("NULL", md_result_file);
5019 else if (field->type == MYSQL_TYPE_DECIMAL)
5020 {
5021 /* add " signs around */
5022 fputc('\'', md_result_file);
5023 fputs(ptr, md_result_file);
5024 fputc('\'', md_result_file);
5025 }
5026 else
5027 fputs(ptr, md_result_file);
5028 }
5029 }
5030 else
5031 {
5032 /* The field value is NULL */
5033 if (!opt_xml)
5034 fputs("NULL", md_result_file);
5035 else
5036 print_xml_null_tag(md_result_file, "\t\t", "field name=",
5037 field->name, "\n");
5038 }
5039 check_io(md_result_file);
5040 }
5041 }
5042
5043 if (opt_xml)
5044 {
5045 fputs("\t</row>\n", md_result_file);
5046 check_io(md_result_file);
5047 }
5048
5049 if (extended_insert)
5050 {
5051 size_t row_length;
5052 dynstr_append_checked(&extended_row,")");
5053 row_length= 2 + extended_row.length;
5054 if (total_length + row_length < opt_net_buffer_length)
5055 {
5056 total_length+= row_length;
5057 fputc(',',md_result_file); /* Always row break */
5058 fputs(extended_row.str,md_result_file);
5059 }
5060 else
5061 {
5062 if (row_break)
5063 fputs(";\n", md_result_file);
5064 row_break=1; /* This is first row */
5065
5066 fputs(insert_pat.str,md_result_file);
5067 fputs(extended_row.str,md_result_file);
5068 total_length= row_length+init_length;
5069 }
5070 check_io(md_result_file);
5071 }
5072 else if (!opt_xml)
5073 {
5074 fputs(");\n", md_result_file);
5075 check_io(md_result_file);
5076 }
5077 }
5078
5079 /* XML - close table tag and supress regular output */
5080 if (opt_xml)
5081 fputs("\t</table_data>\n", md_result_file);
5082 else if (extended_insert && row_break)
5083 fputs(";\n", md_result_file); /* If not empty table */
5084 fflush(md_result_file);
5085 check_io(md_result_file);
5086 if (mysql_errno(mysql))
5087 {
5088 my_snprintf(buf, sizeof(buf),
5089 "%s: Error %d: %s when dumping table %s at row: %ld\n",
5090 my_progname,
5091 mysql_errno(mysql),
5092 mysql_error(mysql),
5093 result_table,
5094 rownr);
5095 fputs(buf,stderr);
5096 error= EX_CONSCHECK;
5097 goto err;
5098 }
5099
5100 dump_skipped_keys(opt_quoted_table);
5101
5102 /* Moved enable keys to before unlock per bug 15977 */
5103 if (opt_disable_keys)
5104 {
5105 fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
5106 opt_quoted_table);
5107 check_io(md_result_file);
5108 }
5109 if (opt_lock)
5110 {
5111 fputs("UNLOCK TABLES;\n", md_result_file);
5112 check_io(md_result_file);
5113 }
5114 if (opt_autocommit)
5115 {
5116 fprintf(md_result_file, "commit;\n");
5117 check_io(md_result_file);
5118 }
5119 mysql_free_result(res);
5120 }
5121 dynstr_free(&query_string);
5122 if (extended_insert)
5123 dynstr_free(&extended_row);
5124 DBUG_VOID_RETURN;
5125
5126 err:
5127 dynstr_free(&query_string);
5128 if (extended_insert)
5129 dynstr_free(&extended_row);
5130 maybe_exit(error);
5131 DBUG_VOID_RETURN;
5132 } /* dump_table */
5133
5134
getTableName(int reset)5135 static char *getTableName(int reset)
5136 {
5137 static MYSQL_RES *res= NULL;
5138 MYSQL_ROW row;
5139
5140 if (!res)
5141 {
5142 if (!(res= mysql_list_tables(mysql,NullS)))
5143 return(NULL);
5144 }
5145 if ((row= mysql_fetch_row(res)))
5146 return((char*) row[0]);
5147
5148 if (reset)
5149 mysql_data_seek(res,0); /* We want to read again */
5150 else
5151 {
5152 mysql_free_result(res);
5153 res= NULL;
5154 }
5155 return(NULL);
5156 } /* getTableName */
5157
5158
5159 /*
5160 dump all logfile groups and tablespaces
5161 */
5162
dump_all_tablespaces()5163 static int dump_all_tablespaces()
5164 {
5165 return dump_tablespaces(NULL);
5166 }
5167
dump_tablespaces_for_tables(char * db,char ** table_names,int tables)5168 static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
5169 {
5170 DYNAMIC_STRING where;
5171 int r;
5172 int i;
5173 char name_buff[NAME_LEN*2+3];
5174
5175 mysql_real_escape_string_quote(mysql, name_buff, db, (ulong)strlen(db), '\'');
5176
5177 init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
5178 "SELECT DISTINCT TABLESPACE_NAME FROM"
5179 " INFORMATION_SCHEMA.PARTITIONS"
5180 " WHERE"
5181 " TABLE_SCHEMA='", 256, 1024);
5182 dynstr_append_checked(&where, name_buff);
5183 dynstr_append_checked(&where, "' AND TABLE_NAME IN (");
5184
5185 for (i=0 ; i<tables ; i++)
5186 {
5187 mysql_real_escape_string_quote(mysql, name_buff,
5188 table_names[i], (ulong)strlen(table_names[i]), '\'');
5189
5190 dynstr_append_checked(&where, "'");
5191 dynstr_append_checked(&where, name_buff);
5192 dynstr_append_checked(&where, "',");
5193 }
5194 dynstr_trunc(&where, 1);
5195 dynstr_append_checked(&where,"))");
5196
5197 DBUG_PRINT("info",("Dump TS for Tables where: %s",where.str));
5198 r= dump_tablespaces(where.str);
5199 dynstr_free(&where);
5200 return r;
5201 }
5202
dump_tablespaces_for_databases(char ** databases)5203 static int dump_tablespaces_for_databases(char** databases)
5204 {
5205 DYNAMIC_STRING where;
5206 int r;
5207 int i;
5208
5209 init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
5210 "SELECT DISTINCT TABLESPACE_NAME FROM"
5211 " INFORMATION_SCHEMA.PARTITIONS"
5212 " WHERE"
5213 " TABLE_SCHEMA IN (", 256, 1024);
5214
5215 for (i=0 ; databases[i]!=NULL ; i++)
5216 {
5217 char db_name_buff[NAME_LEN*2+3];
5218 mysql_real_escape_string_quote(mysql, db_name_buff,
5219 databases[i], (ulong)strlen(databases[i]), '\'');
5220 dynstr_append_checked(&where, "'");
5221 dynstr_append_checked(&where, db_name_buff);
5222 dynstr_append_checked(&where, "',");
5223 }
5224 dynstr_trunc(&where, 1);
5225 dynstr_append_checked(&where,"))");
5226
5227 DBUG_PRINT("info",("Dump TS for DBs where: %s",where.str));
5228 r= dump_tablespaces(where.str);
5229 dynstr_free(&where);
5230 return r;
5231 }
5232
dump_tablespaces(char * ts_where)5233 static int dump_tablespaces(char* ts_where)
5234 {
5235 MYSQL_ROW row;
5236 MYSQL_RES *tableres;
5237 char buf[FN_REFLEN];
5238 DYNAMIC_STRING sqlbuf;
5239 int first= 0;
5240 /*
5241 The following are used for parsing the EXTRA field
5242 */
5243 char extra_format[]= "UNDO_BUFFER_SIZE=";
5244 char *ubs;
5245 char *endsemi;
5246 DBUG_ENTER("dump_tablespaces");
5247
5248 init_dynamic_string_checked(&sqlbuf,
5249 "SELECT LOGFILE_GROUP_NAME,"
5250 " FILE_NAME,"
5251 " TOTAL_EXTENTS,"
5252 " INITIAL_SIZE,"
5253 " ENGINE,"
5254 " EXTRA"
5255 " FROM INFORMATION_SCHEMA.FILES"
5256 " WHERE FILE_TYPE = 'UNDO LOG'"
5257 " AND FILE_NAME IS NOT NULL"
5258 " AND LOGFILE_GROUP_NAME IS NOT NULL",
5259 256, 1024);
5260 if(ts_where)
5261 {
5262 dynstr_append_checked(&sqlbuf,
5263 " AND LOGFILE_GROUP_NAME IN ("
5264 "SELECT DISTINCT LOGFILE_GROUP_NAME"
5265 " FROM INFORMATION_SCHEMA.FILES"
5266 " WHERE FILE_TYPE = 'DATAFILE'"
5267 );
5268 dynstr_append_checked(&sqlbuf, ts_where);
5269 dynstr_append_checked(&sqlbuf, ")");
5270 }
5271 dynstr_append_checked(&sqlbuf,
5272 " GROUP BY LOGFILE_GROUP_NAME, FILE_NAME"
5273 ", ENGINE, TOTAL_EXTENTS, INITIAL_SIZE"
5274 " ORDER BY LOGFILE_GROUP_NAME");
5275
5276 if (mysql_query(mysql, sqlbuf.str) ||
5277 !(tableres = mysql_store_result(mysql)))
5278 {
5279 dynstr_free(&sqlbuf);
5280 if (mysql_errno(mysql) == ER_BAD_TABLE_ERROR ||
5281 mysql_errno(mysql) == ER_BAD_DB_ERROR ||
5282 mysql_errno(mysql) == ER_UNKNOWN_TABLE)
5283 {
5284 fprintf(md_result_file,
5285 "\n--\n-- Not dumping tablespaces as no INFORMATION_SCHEMA.FILES"
5286 " table on this server\n--\n");
5287 check_io(md_result_file);
5288 DBUG_RETURN(0);
5289 }
5290
5291 my_printf_error(0, "Error: '%s' when trying to dump tablespaces",
5292 MYF(0), mysql_error(mysql));
5293 DBUG_RETURN(1);
5294 }
5295
5296 buf[0]= 0;
5297 while ((row= mysql_fetch_row(tableres)))
5298 {
5299 if (strcmp(buf, row[0]) != 0)
5300 first= 1;
5301 if (first)
5302 {
5303 print_comment(md_result_file, 0, "\n--\n-- Logfile group: %s\n--\n",
5304 row[0]);
5305
5306 fprintf(md_result_file, "\nCREATE");
5307 }
5308 else
5309 {
5310 fprintf(md_result_file, "\nALTER");
5311 }
5312 fprintf(md_result_file,
5313 " LOGFILE GROUP %s\n"
5314 " ADD UNDOFILE '%s'\n",
5315 row[0],
5316 row[1]);
5317 if (first)
5318 {
5319 ubs= strstr(row[5],extra_format);
5320 if(!ubs)
5321 break;
5322 ubs+= strlen(extra_format);
5323 endsemi= strstr(ubs,";");
5324 if(endsemi)
5325 endsemi[0]= '\0';
5326 fprintf(md_result_file,
5327 " UNDO_BUFFER_SIZE %s\n",
5328 ubs);
5329 }
5330 fprintf(md_result_file,
5331 " INITIAL_SIZE %s\n"
5332 " ENGINE=%s;\n",
5333 row[3],
5334 row[4]);
5335 check_io(md_result_file);
5336 if (first)
5337 {
5338 first= 0;
5339 strxmov(buf, row[0], NullS);
5340 }
5341 }
5342 dynstr_free(&sqlbuf);
5343 mysql_free_result(tableres);
5344 init_dynamic_string_checked(&sqlbuf,
5345 "SELECT DISTINCT TABLESPACE_NAME,"
5346 " FILE_NAME,"
5347 " LOGFILE_GROUP_NAME,"
5348 " EXTENT_SIZE,"
5349 " INITIAL_SIZE,"
5350 " ENGINE"
5351 " FROM INFORMATION_SCHEMA.FILES"
5352 " WHERE FILE_TYPE = 'DATAFILE'",
5353 256, 1024);
5354
5355 if(ts_where)
5356 dynstr_append_checked(&sqlbuf, ts_where);
5357
5358 dynstr_append_checked(&sqlbuf, " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME");
5359
5360 if (mysql_query_with_error_report(mysql, &tableres, sqlbuf.str))
5361 {
5362 dynstr_free(&sqlbuf);
5363 DBUG_RETURN(1);
5364 }
5365
5366 buf[0]= 0;
5367 while ((row= mysql_fetch_row(tableres)))
5368 {
5369 if (strcmp(buf, row[0]) != 0)
5370 first= 1;
5371 if (first)
5372 {
5373 print_comment(md_result_file, 0, "\n--\n-- Tablespace: %s\n--\n", row[0]);
5374 fprintf(md_result_file, "\nCREATE");
5375 }
5376 else
5377 {
5378 fprintf(md_result_file, "\nALTER");
5379 }
5380 fprintf(md_result_file,
5381 " TABLESPACE %s\n"
5382 " ADD DATAFILE '%s'\n",
5383 row[0],
5384 row[1]);
5385 if (first)
5386 {
5387 fprintf(md_result_file,
5388 " USE LOGFILE GROUP %s\n"
5389 " EXTENT_SIZE %s\n",
5390 row[2],
5391 row[3]);
5392 }
5393 fprintf(md_result_file,
5394 " INITIAL_SIZE %s\n"
5395 " ENGINE=%s;\n",
5396 row[4],
5397 row[5]);
5398 check_io(md_result_file);
5399 if (first)
5400 {
5401 first= 0;
5402 strxmov(buf, row[0], NullS);
5403 }
5404 }
5405
5406 mysql_free_result(tableres);
5407 dynstr_free(&sqlbuf);
5408 DBUG_RETURN(0);
5409 }
5410
5411
5412 static int
is_ndbinfo(MYSQL * mysql,const char * dbname)5413 is_ndbinfo(MYSQL* mysql, const char* dbname)
5414 {
5415 static int checked_ndbinfo= 0;
5416 static int have_ndbinfo= 0;
5417
5418 if (!checked_ndbinfo)
5419 {
5420 MYSQL_RES *res;
5421 MYSQL_ROW row;
5422 char buf[32], query[64];
5423
5424 my_snprintf(query, sizeof(query),
5425 "SHOW VARIABLES LIKE %s",
5426 quote_for_like("ndbinfo_version", buf));
5427
5428 checked_ndbinfo= 1;
5429
5430 if (mysql_query_with_error_report(mysql, &res, query))
5431 return 0;
5432
5433 if (!(row= mysql_fetch_row(res)))
5434 {
5435 mysql_free_result(res);
5436 return 0;
5437 }
5438
5439 have_ndbinfo= 1;
5440 mysql_free_result(res);
5441 }
5442
5443 if (!have_ndbinfo)
5444 return 0;
5445
5446 if (my_strcasecmp(&my_charset_latin1, dbname, "ndbinfo") == 0)
5447 return 1;
5448
5449 return 0;
5450 }
5451
5452
dump_all_databases()5453 static int dump_all_databases()
5454 {
5455 MYSQL_ROW row;
5456 MYSQL_RES *tableres;
5457 int result=0;
5458
5459 my_ulonglong total_databases= 0;
5460 char **database_list;
5461 uint db_cnt = 0, cnt = 0;
5462 uint mysql_db_found = 0;
5463
5464 if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES"))
5465 return 1;
5466
5467 total_databases= mysql_num_rows(tableres);
5468 database_list = (char **) my_malloc(PSI_NOT_INSTRUMENTED,
5469 (sizeof(char *) * total_databases), MYF(MY_WME));
5470
5471 while ((row= mysql_fetch_row(tableres)))
5472 {
5473 if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION &&
5474 !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME))
5475 continue;
5476
5477 if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
5478 !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME))
5479 continue;
5480
5481 if (mysql_get_server_version(mysql) >= FIRST_SYS_SCHEMA_VERSION &&
5482 !my_strcasecmp(&my_charset_latin1, row[0], SYS_SCHEMA_DB_NAME))
5483 continue;
5484
5485 if (is_ndbinfo(mysql, row[0]))
5486 continue;
5487
5488 if (mysql_db_found || (!my_strcasecmp(charset_info, row[0], "mysql")))
5489 {
5490 if (dump_all_tables_in_db(row[0]))
5491 result=1;
5492 mysql_db_found = 1;
5493 /*
5494 once mysql database is found dump all dbs saved as part
5495 of database_list
5496 */
5497 for (; cnt < db_cnt; cnt++)
5498 {
5499 if (dump_all_tables_in_db(database_list[cnt]))
5500 result=1;
5501 my_free(database_list[cnt]);
5502 }
5503 }
5504 else
5505 {
5506 /*
5507 till mysql database is not found save database names to
5508 database_list
5509 */
5510 database_list[db_cnt] = my_strdup(PSI_NOT_INSTRUMENTED, row[0],
5511 MYF(MY_WME | MY_ZEROFILL));
5512 db_cnt++;
5513 }
5514 }
5515 assert(mysql_db_found);
5516 memset(database_list, 0, sizeof(*database_list));
5517 my_free(database_list);
5518
5519 mysql_free_result(tableres);
5520 if (seen_views)
5521 {
5522 if (mysql_query(mysql, "SHOW DATABASES") ||
5523 !(tableres= mysql_store_result(mysql)))
5524 {
5525 my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
5526 MYF(0), mysql_error(mysql));
5527 return 1;
5528 }
5529 while ((row= mysql_fetch_row(tableres)))
5530 {
5531 if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION &&
5532 !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME))
5533 continue;
5534
5535 if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
5536 !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME))
5537 continue;
5538
5539 if (mysql_get_server_version(mysql) >= FIRST_SYS_SCHEMA_VERSION &&
5540 !my_strcasecmp(&my_charset_latin1, row[0], SYS_SCHEMA_DB_NAME))
5541 continue;
5542
5543 if (is_ndbinfo(mysql, row[0]))
5544 continue;
5545
5546 if (dump_all_views_in_db(row[0]))
5547 result=1;
5548 }
5549 mysql_free_result(tableres);
5550 }
5551 return result;
5552 }
5553 /* dump_all_databases */
5554
5555
dump_databases(char ** db_names)5556 static int dump_databases(char **db_names)
5557 {
5558 int result=0;
5559 char **db;
5560 DBUG_ENTER("dump_databases");
5561
5562 for (db= db_names ; *db ; db++)
5563 {
5564 if (dump_all_tables_in_db(*db))
5565 result=1;
5566 }
5567 if (!result && seen_views)
5568 {
5569 for (db= db_names ; *db ; db++)
5570 {
5571 if (dump_all_views_in_db(*db))
5572 result=1;
5573 }
5574 }
5575 DBUG_RETURN(result);
5576 } /* dump_databases */
5577
5578
5579 /*
5580 View Specific database initalization.
5581
5582 SYNOPSIS
5583 init_dumping_views
5584 qdatabase quoted name of the database
5585 is_mysql_db TRUE if the db is mysql, else FALSE
5586
5587 RETURN VALUES
5588 0 Success.
5589 1 Failure.
5590 */
init_dumping_views(char * qdatabase MY_ATTRIBUTE ((unused)),my_bool is_mysql_db MY_ATTRIBUTE ((unused)))5591 int init_dumping_views(char *qdatabase MY_ATTRIBUTE((unused)),
5592 my_bool is_mysql_db MY_ATTRIBUTE((unused)))
5593 {
5594 return 0;
5595 } /* init_dumping_views */
5596
5597
5598 /*
5599 Table Specific database initalization.
5600
5601 SYNOPSIS
5602 init_dumping_tables
5603 qdatabase quoted name of the database
5604 is_mysql_db TRUE if the db is mysql, else FALSE
5605
5606 RETURN VALUES
5607 0 Success.
5608 1 Failure.
5609 */
5610
init_dumping_tables(char * qdatabase,my_bool is_mysql_db)5611 int init_dumping_tables(char *qdatabase, my_bool is_mysql_db)
5612 {
5613 DBUG_ENTER("init_dumping_tables");
5614
5615 if (!opt_create_db)
5616 {
5617 char qbuf[256];
5618 MYSQL_ROW row;
5619 MYSQL_RES *dbinfo;
5620
5621 my_snprintf(qbuf, sizeof(qbuf),
5622 "SHOW CREATE DATABASE IF NOT EXISTS %s",
5623 qdatabase);
5624
5625 if (mysql_query(mysql, qbuf) || !(dbinfo = mysql_store_result(mysql)))
5626 {
5627 /* Old server version, dump generic CREATE DATABASE */
5628 if (opt_drop_database && (!opt_skip_mysql_schema || !is_mysql_db))
5629 fprintf(md_result_file,
5630 "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
5631 qdatabase);
5632 fprintf(md_result_file,
5633 "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
5634 qdatabase);
5635 }
5636 else
5637 {
5638 if (opt_drop_database && (!opt_skip_mysql_schema || !is_mysql_db))
5639 fprintf(md_result_file,
5640 "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
5641 qdatabase);
5642 row = mysql_fetch_row(dbinfo);
5643 if (row[1])
5644 {
5645 fprintf(md_result_file,"\n%s;\n",row[1]);
5646 }
5647 mysql_free_result(dbinfo);
5648 }
5649 }
5650 DBUG_RETURN(0);
5651 } /* init_dumping_tables */
5652
5653
init_dumping(char * database,int init_func (char *,my_bool))5654 static int init_dumping(char *database, int init_func(char*, my_bool))
5655 {
5656 if (is_ndbinfo(mysql, database))
5657 {
5658 verbose_msg("-- Skipping dump of ndbinfo database\n");
5659 return 0;
5660 }
5661
5662 if (mysql_select_db(mysql, database))
5663 {
5664 DB_error(mysql, "when selecting the database");
5665 return 1; /* If --force */
5666 }
5667 if (!path && !opt_xml)
5668 {
5669 if (opt_databases || opt_alldbs)
5670 {
5671 /*
5672 length of table name * 2 (if name contains quotes), 2 quotes and 0
5673 */
5674 char quoted_database_buf[NAME_LEN*2+3];
5675 char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
5676 my_bool freemem= FALSE;
5677 char const* text= fix_identifier_with_newline(qdatabase, &freemem);
5678 my_bool is_mysql_db= !my_strcasecmp(charset_info, database, "mysql");
5679
5680 print_comment(md_result_file, 0, "\n--\n-- Current Database: %s\n--\n",
5681 text);
5682 if (freemem)
5683 my_free((void*)text);
5684
5685 /* Call the view or table specific function */
5686 init_func(qdatabase, is_mysql_db);
5687
5688 fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
5689 check_io(md_result_file);
5690 }
5691 }
5692 return 0;
5693 } /* init_dumping */
5694
5695
5696 /* Return 1 if we should copy the table */
5697
include_table(const uchar * hash_key,size_t len)5698 my_bool include_table(const uchar *hash_key, size_t len)
5699 {
5700 return ! my_hash_search(&ignore_table, hash_key, len);
5701 }
5702
5703
dump_all_tables_in_db(char * database)5704 static int dump_all_tables_in_db(char *database)
5705 {
5706 char *table;
5707 uint numrows;
5708 char table_buff[NAME_LEN*2+3];
5709 char hash_key[2*NAME_LEN+2]; /* "db.tablename" */
5710 char *afterdot;
5711 my_bool general_log_table_exists= 0, slow_log_table_exists=0;
5712 int using_mysql_db= !my_strcasecmp(charset_info, database, "mysql");
5713 my_bool real_columns[MAX_FIELDS];
5714
5715 DBUG_ENTER("dump_all_tables_in_db");
5716
5717 afterdot= my_stpcpy(hash_key, database);
5718 *afterdot++= '.';
5719
5720 if (init_dumping(database, init_dumping_tables))
5721 DBUG_RETURN(1);
5722 if (opt_xml)
5723 print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
5724
5725 if (lock_tables)
5726 {
5727 DYNAMIC_STRING query;
5728 init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
5729 for (numrows= 0 ; (table= getTableName(1)) ; )
5730 {
5731 char *end= my_stpcpy(afterdot, table);
5732 if (include_table((uchar*) hash_key,end - hash_key))
5733 {
5734 numrows++;
5735 dynstr_append_checked(&query, quote_name(table, table_buff, 1));
5736 dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
5737 }
5738 }
5739 if (numrows && mysql_real_query(mysql, query.str, (ulong)(query.length-1)))
5740 DB_error(mysql, "when using LOCK TABLES");
5741 /* We shall continue here, if --force was given */
5742 dynstr_free(&query);
5743 }
5744 if (flush_logs)
5745 {
5746 if (mysql_refresh(mysql, REFRESH_LOG))
5747 DB_error(mysql, "when doing refresh");
5748 /* We shall continue here, if --force was given */
5749 else
5750 verbose_msg("-- dump_all_tables_in_db : logs flushed successfully!\n");
5751 }
5752 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
5753 {
5754 verbose_msg("-- Setting savepoint...\n");
5755 if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp"))
5756 DBUG_RETURN(1);
5757 }
5758 while ((table= getTableName(0)))
5759 {
5760 char *end= my_stpcpy(afterdot, table);
5761 if (include_table((uchar*) hash_key, end - hash_key))
5762 {
5763 dump_table(table,database);
5764 my_free(order_by);
5765 order_by= 0;
5766 if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009)
5767 {
5768 if (dump_triggers_for_table(table, database))
5769 {
5770 if (path)
5771 my_fclose(md_result_file, MYF(MY_WME));
5772 maybe_exit(EX_MYSQLERR);
5773 }
5774 }
5775
5776 /**
5777 ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata
5778 lock on table which was already dumped. This allows to avoid blocking
5779 concurrent DDL on this table without sacrificing correctness, as we
5780 won't access table second time and dumps created by --single-transaction
5781 mode have validity point at the start of transaction anyway.
5782 Note that this doesn't make --single-transaction mode with concurrent
5783 DDL safe in general case. It just improves situation for people for whom
5784 it might be working.
5785 */
5786 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
5787 {
5788 verbose_msg("-- Rolling back to savepoint sp...\n");
5789 if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp"))
5790 maybe_exit(EX_MYSQLERR);
5791 }
5792 }
5793 else
5794 {
5795 /*
5796 If general_log and slow_log exists in the 'mysql' database,
5797 we should dump the table structure. But we cannot
5798 call get_table_structure() here as 'LOCK TABLES' query got executed
5799 above on the session and that 'LOCK TABLES' query does not contain
5800 'general_log' and 'slow_log' tables. (you cannot acquire lock
5801 on log tables). Hence mark the existence of these log tables here and
5802 after 'UNLOCK TABLES' query is executed on the session, get the table
5803 structure from server and dump it in the file.
5804 */
5805 if (using_mysql_db)
5806 {
5807 if (!my_strcasecmp(charset_info, table, "general_log"))
5808 general_log_table_exists= 1;
5809 else if (!my_strcasecmp(charset_info, table, "slow_log"))
5810 slow_log_table_exists= 1;
5811 }
5812 }
5813 }
5814
5815 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
5816 {
5817 verbose_msg("-- Releasing savepoint...\n");
5818 if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp"))
5819 DBUG_RETURN(1);
5820 }
5821
5822 if (opt_events && mysql_get_server_version(mysql) >= 50106)
5823 {
5824 DBUG_PRINT("info", ("Dumping events for database %s", database));
5825 dump_events_for_db(database);
5826 }
5827 if (opt_routines && mysql_get_server_version(mysql) >= 50009)
5828 {
5829 DBUG_PRINT("info", ("Dumping routines for database %s", database));
5830 dump_routines_for_db(database);
5831 }
5832 if (opt_xml)
5833 {
5834 fputs("</database>\n", md_result_file);
5835 check_io(md_result_file);
5836 }
5837 if (lock_tables)
5838 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
5839 if (using_mysql_db)
5840 {
5841 char table_type[NAME_LEN];
5842 char ignore_flag;
5843 if (general_log_table_exists)
5844 {
5845 if (!get_table_structure((char *) "general_log",
5846 database, table_type, &ignore_flag,
5847 real_columns))
5848 verbose_msg("-- Warning: get_table_structure() failed with some internal "
5849 "error for 'general_log' table\n");
5850 }
5851 if (slow_log_table_exists)
5852 {
5853 if (!get_table_structure((char *) "slow_log",
5854 database, table_type, &ignore_flag,
5855 real_columns))
5856 verbose_msg("-- Warning: get_table_structure() failed with some internal "
5857 "error for 'slow_log' table\n");
5858 }
5859 }
5860 if (flush_privileges && using_mysql_db)
5861 {
5862 fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n");
5863 fprintf(md_result_file,"\n/*! FLUSH PRIVILEGES */;\n");
5864 }
5865 DBUG_RETURN(0);
5866 } /* dump_all_tables_in_db */
5867
5868
5869 /*
5870 dump structure of views of database
5871
5872 SYNOPSIS
5873 dump_all_views_in_db()
5874 database database name
5875
5876 RETURN
5877 0 OK
5878 1 ERROR
5879 */
5880
dump_all_views_in_db(char * database)5881 static my_bool dump_all_views_in_db(char *database)
5882 {
5883 char *table;
5884 uint numrows;
5885 char table_buff[NAME_LEN*2+3];
5886 char hash_key[2*NAME_LEN+2]; /* "db.tablename" */
5887 char *afterdot;
5888
5889 afterdot= my_stpcpy(hash_key, database);
5890 *afterdot++= '.';
5891
5892 if (init_dumping(database, init_dumping_views))
5893 return 1;
5894 if (opt_xml)
5895 print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
5896 if (lock_tables)
5897 {
5898 DYNAMIC_STRING query;
5899 init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
5900 for (numrows= 0 ; (table= getTableName(1)); )
5901 {
5902 char *end= my_stpcpy(afterdot, table);
5903 if (include_table((uchar*) hash_key,end - hash_key))
5904 {
5905 numrows++;
5906 dynstr_append_checked(&query, quote_name(table, table_buff, 1));
5907 dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
5908 }
5909 }
5910 if (numrows && mysql_real_query(mysql, query.str, (ulong)(query.length-1)))
5911 DB_error(mysql, "when using LOCK TABLES");
5912 /* We shall continue here, if --force was given */
5913 dynstr_free(&query);
5914 }
5915 if (flush_logs)
5916 {
5917 if (mysql_refresh(mysql, REFRESH_LOG))
5918 DB_error(mysql, "when doing refresh");
5919 /* We shall continue here, if --force was given */
5920 else
5921 verbose_msg("-- dump_all_views_in_db : logs flushed successfully!\n");
5922 }
5923 while ((table= getTableName(0)))
5924 {
5925 char *end= my_stpcpy(afterdot, table);
5926 if (include_table((uchar*) hash_key, end - hash_key))
5927 get_view_structure(table, database);
5928 }
5929 if (opt_xml)
5930 {
5931 fputs("</database>\n", md_result_file);
5932 check_io(md_result_file);
5933 }
5934 if (lock_tables)
5935 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
5936 return 0;
5937 } /* dump_all_tables_in_db */
5938
5939
5940 /*
5941 get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
5942 table name from the server for the table name given on the command line.
5943 we do this because the table name given on the command line may be a
5944 different case (e.g. T1 vs t1)
5945
5946 RETURN
5947 pointer to the table name
5948 0 if error
5949 */
5950
get_actual_table_name(const char * old_table_name,MEM_ROOT * root)5951 static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
5952 {
5953 char *name= 0;
5954 MYSQL_RES *table_res;
5955 MYSQL_ROW row;
5956 char query[50 + 2*NAME_LEN];
5957 char show_name_buff[FN_REFLEN];
5958 DBUG_ENTER("get_actual_table_name");
5959
5960 /* Check memory for quote_for_like() */
5961 assert(2*sizeof(old_table_name) < sizeof(show_name_buff));
5962 my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
5963 quote_for_like(old_table_name, show_name_buff));
5964
5965 if (mysql_query_with_error_report(mysql, 0, query))
5966 DBUG_RETURN(NullS);
5967
5968 if ((table_res= mysql_store_result(mysql)))
5969 {
5970 my_ulonglong num_rows= mysql_num_rows(table_res);
5971 if (num_rows > 0)
5972 {
5973 ulong *lengths;
5974 /*
5975 Return first row
5976 TODO: Return all matching rows
5977 */
5978 row= mysql_fetch_row(table_res);
5979 lengths= mysql_fetch_lengths(table_res);
5980 name= strmake_root(root, row[0], lengths[0]);
5981 }
5982 mysql_free_result(table_res);
5983 }
5984 DBUG_PRINT("exit", ("new_table_name: %s", name));
5985 DBUG_RETURN(name);
5986 }
5987
5988
dump_selected_tables(char * db,char ** table_names,int tables)5989 static int dump_selected_tables(char *db, char **table_names, int tables)
5990 {
5991 char table_buff[NAME_LEN*2+3];
5992 DYNAMIC_STRING lock_tables_query;
5993 MEM_ROOT root;
5994 char **dump_tables, **pos, **end;
5995 DBUG_ENTER("dump_selected_tables");
5996
5997 if (init_dumping(db, init_dumping_tables))
5998 DBUG_RETURN(1);
5999
6000 init_alloc_root(PSI_NOT_INSTRUMENTED, &root, 8192, 0);
6001 if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
6002 die(EX_EOM, "alloc_root failure.");
6003
6004 init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
6005 for (; tables > 0 ; tables-- , table_names++)
6006 {
6007 /* the table name passed on commandline may be wrong case */
6008 if ((*pos= get_actual_table_name(*table_names, &root)))
6009 {
6010 /* Add found table name to lock_tables_query */
6011 if (lock_tables)
6012 {
6013 dynstr_append_checked(&lock_tables_query, quote_name(*pos, table_buff, 1));
6014 dynstr_append_checked(&lock_tables_query, " READ /*!32311 LOCAL */,");
6015 }
6016 pos++;
6017 }
6018 else
6019 {
6020 if (!opt_force)
6021 {
6022 dynstr_free(&lock_tables_query);
6023 free_root(&root, MYF(0));
6024 }
6025 maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names);
6026 /* We shall countinue here, if --force was given */
6027 }
6028 }
6029 end= pos;
6030
6031 /* Can't LOCK TABLES in I_S / P_S, so don't try. */
6032 if (lock_tables &&
6033 !(mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION &&
6034 !my_strcasecmp(&my_charset_latin1, db, INFORMATION_SCHEMA_DB_NAME)) &&
6035 !(mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
6036 !my_strcasecmp(&my_charset_latin1, db, PERFORMANCE_SCHEMA_DB_NAME)))
6037 {
6038 if (mysql_real_query(mysql, lock_tables_query.str,
6039 (ulong)(lock_tables_query.length-1)))
6040 {
6041 if (!opt_force)
6042 {
6043 dynstr_free(&lock_tables_query);
6044 free_root(&root, MYF(0));
6045 }
6046 DB_error(mysql, "when doing LOCK TABLES");
6047 /* We shall countinue here, if --force was given */
6048 }
6049 }
6050 dynstr_free(&lock_tables_query);
6051 if (flush_logs)
6052 {
6053 if (mysql_refresh(mysql, REFRESH_LOG))
6054 {
6055 if (!opt_force)
6056 free_root(&root, MYF(0));
6057 DB_error(mysql, "when doing refresh");
6058 }
6059 /* We shall countinue here, if --force was given */
6060 else
6061 verbose_msg("-- dump_selected_tables : logs flushed successfully!\n");
6062 }
6063 if (opt_xml)
6064 print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
6065
6066 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
6067 {
6068 verbose_msg("-- Setting savepoint...\n");
6069 if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp"))
6070 DBUG_RETURN(1);
6071 }
6072
6073 /* Dump each selected table */
6074 for (pos= dump_tables; pos < end; pos++)
6075 {
6076 DBUG_PRINT("info",("Dumping table %s", *pos));
6077 dump_table(*pos, db);
6078 if (opt_dump_triggers &&
6079 mysql_get_server_version(mysql) >= 50009)
6080 {
6081 if (dump_triggers_for_table(*pos, db))
6082 {
6083 if (path)
6084 my_fclose(md_result_file, MYF(MY_WME));
6085 maybe_exit(EX_MYSQLERR);
6086 }
6087 }
6088
6089 /**
6090 ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata
6091 lock on table which was already dumped. This allows to avoid blocking
6092 concurrent DDL on this table without sacrificing correctness, as we
6093 won't access table second time and dumps created by --single-transaction
6094 mode have validity point at the start of transaction anyway.
6095 Note that this doesn't make --single-transaction mode with concurrent
6096 DDL safe in general case. It just improves situation for people for whom
6097 it might be working.
6098 */
6099 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
6100 {
6101 verbose_msg("-- Rolling back to savepoint sp...\n");
6102 if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp"))
6103 maybe_exit(EX_MYSQLERR);
6104 }
6105 }
6106
6107 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
6108 {
6109 verbose_msg("-- Releasing savepoint...\n");
6110 if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp"))
6111 DBUG_RETURN(1);
6112
6113 }
6114
6115 /* Dump each selected view */
6116 if (seen_views)
6117 {
6118 for (pos= dump_tables; pos < end; pos++)
6119 get_view_structure(*pos, db);
6120 }
6121 if (opt_events && mysql_get_server_version(mysql) >= 50106)
6122 {
6123 DBUG_PRINT("info", ("Dumping events for database %s", db));
6124 dump_events_for_db(db);
6125 }
6126 /* obtain dump of routines (procs/functions) */
6127 if (opt_routines && mysql_get_server_version(mysql) >= 50009)
6128 {
6129 DBUG_PRINT("info", ("Dumping routines for database %s", db));
6130 dump_routines_for_db(db);
6131 }
6132 free_root(&root, MYF(0));
6133 my_free(order_by);
6134 order_by= 0;
6135 if (opt_xml)
6136 {
6137 fputs("</database>\n", md_result_file);
6138 check_io(md_result_file);
6139 }
6140 if (lock_tables)
6141 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
6142 DBUG_RETURN(0);
6143 } /* dump_selected_tables */
6144
6145
do_show_master_status(MYSQL * mysql_con,int consistent_binlog_pos)6146 static int do_show_master_status(MYSQL *mysql_con, int consistent_binlog_pos)
6147 {
6148 MYSQL_ROW row;
6149 MYSQL_RES *master;
6150 char binlog_pos_file[FN_REFLEN];
6151 char binlog_pos_offset[LONGLONG_LEN+1];
6152 char *file, *offset;
6153 const char *comment_prefix=
6154 (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
6155
6156 if (consistent_binlog_pos)
6157 {
6158 if (!check_consistent_binlog_pos(binlog_pos_file, binlog_pos_offset))
6159 return 1;
6160
6161 file= binlog_pos_file;
6162 offset= binlog_pos_offset;
6163 }
6164 else
6165 {
6166 if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
6167 return 1;
6168
6169 row= mysql_fetch_row(master);
6170 if (row && row[0] && row[1])
6171 {
6172 file= row[0];
6173 offset= row[1];
6174 }
6175 else
6176 {
6177 mysql_free_result(master);
6178 if (!opt_force)
6179 {
6180 /* SHOW MASTER STATUS reports nothing and --force is not enabled */
6181 my_printf_error(0, "Error: Binlogging on server not active", MYF(0));
6182 maybe_exit(EX_MYSQLERR);
6183 return 1;
6184 }
6185 else
6186 {
6187 return 0;
6188 }
6189 }
6190 }
6191
6192 /* SHOW MASTER STATUS reports file and position */
6193 print_comment(md_result_file, 0,
6194 "\n--\n-- Position to start replication or point-in-time "
6195 "recovery from\n--\n\n");
6196 fprintf(md_result_file,
6197 "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
6198 comment_prefix, file, offset);
6199 check_io(md_result_file);
6200
6201 if (!consistent_binlog_pos)
6202 mysql_free_result(master);
6203
6204 return 0;
6205 }
6206
do_stop_slave_sql(MYSQL * mysql_con)6207 static int do_stop_slave_sql(MYSQL *mysql_con)
6208 {
6209 MYSQL_RES *slave;
6210 /* We need to check if the slave sql is running in the first place */
6211 if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
6212 return(1);
6213 else
6214 {
6215 MYSQL_ROW row= mysql_fetch_row(slave);
6216 if (row && row[11])
6217 {
6218 /* if SLAVE SQL is not running, we don't stop it */
6219 if (!strcmp(row[11],"No"))
6220 {
6221 mysql_free_result(slave);
6222 /* Silently assume that they don't have the slave running */
6223 return(0);
6224 }
6225 }
6226 }
6227 mysql_free_result(slave);
6228
6229 /* now, stop slave if running */
6230 if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
6231 return(1);
6232
6233 return(0);
6234 }
6235
add_stop_slave(void)6236 static int add_stop_slave(void)
6237 {
6238 if (opt_comments)
6239 fprintf(md_result_file,
6240 "\n--\n-- stop slave statement to make a recovery dump)\n--\n\n");
6241 fprintf(md_result_file, "STOP SLAVE;\n");
6242 return(0);
6243 }
6244
add_slave_statements(void)6245 static int add_slave_statements(void)
6246 {
6247 if (opt_comments)
6248 fprintf(md_result_file,
6249 "\n--\n-- start slave statement to make a recovery dump)\n--\n\n");
6250 fprintf(md_result_file, "START SLAVE;\n");
6251 return(0);
6252 }
6253
do_show_slave_status(MYSQL * mysql_con)6254 static int do_show_slave_status(MYSQL *mysql_con)
6255 {
6256 MYSQL_RES *slave= NULL;
6257 const char *comment_prefix=
6258 (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "";
6259 if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
6260 {
6261 if (!opt_force)
6262 {
6263 /* SHOW SLAVE STATUS reports nothing and --force is not enabled */
6264 my_printf_error(0, "Error: Slave not set up", MYF(0));
6265 }
6266 mysql_free_result(slave);
6267 return 1;
6268 }
6269 else
6270 {
6271 const int n_master_host= 1;
6272 const int n_master_port= 3;
6273 const int n_master_log_file= 9;
6274 const int n_master_log_pos= 21;
6275 const int n_channel_name= 55;
6276 MYSQL_ROW row= mysql_fetch_row(slave);
6277 /* Since 5.7 is is possible that SSS returns multiple channels */
6278 while (row)
6279 {
6280 if (row[n_master_log_file] && row[n_master_log_pos])
6281 {
6282 /* SHOW MASTER STATUS reports file and position */
6283 if (opt_comments)
6284 fprintf(md_result_file,
6285 "\n--\n-- Position to start replication or point-in-time "
6286 "recovery from (the master of this slave)\n--\n\n");
6287
6288 fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix);
6289
6290 if (opt_include_master_host_port)
6291 {
6292 if (row[n_master_host])
6293 fprintf(md_result_file, "MASTER_HOST='%s', ", row[n_master_host]);
6294 if (row[n_master_port])
6295 fprintf(md_result_file, "MASTER_PORT=%s, ", row[n_master_port]);
6296 }
6297 fprintf(md_result_file,
6298 "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s",
6299 row[n_master_log_file], row[n_master_log_pos]);
6300
6301 /* Only print the FOR CHANNEL if there is more than one channel */
6302 if (slave->row_count > 1)
6303 fprintf(md_result_file, " FOR CHANNEL '%s'", row[n_channel_name]);
6304
6305 fprintf(md_result_file, ";\n");
6306 }
6307 row= mysql_fetch_row(slave);
6308 }
6309 check_io(md_result_file);
6310 mysql_free_result(slave);
6311 }
6312 return 0;
6313 }
6314
do_start_slave_sql(MYSQL * mysql_con)6315 static int do_start_slave_sql(MYSQL *mysql_con)
6316 {
6317 MYSQL_RES *slave;
6318 /* We need to check if the slave sql is stopped in the first place */
6319 if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
6320 return(1);
6321 else
6322 {
6323 MYSQL_ROW row= mysql_fetch_row(slave);
6324 if (row && row[11])
6325 {
6326 /* if SLAVE SQL is not running, we don't start it */
6327 if (!strcmp(row[11],"Yes"))
6328 {
6329 mysql_free_result(slave);
6330 /* Silently assume that they don't have the slave running */
6331 return(0);
6332 }
6333 }
6334 }
6335 mysql_free_result(slave);
6336
6337 /* now, start slave if stopped */
6338 if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE"))
6339 {
6340 my_printf_error(0, "Error: Unable to start slave", MYF(0));
6341 return 1;
6342 }
6343 return(0);
6344 }
6345
6346
6347
do_flush_tables_read_lock(MYSQL * mysql_con)6348 static int do_flush_tables_read_lock(MYSQL *mysql_con)
6349 {
6350 /*
6351 We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
6352 will wait but will not stall the whole mysqld, and when the long update is
6353 done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
6354 FLUSH TABLES is to lower the probability of a stage where both mysqldump
6355 and most client connections are stalled. Of course, if a second long
6356 update starts between the two FLUSHes, we have that bad stall.
6357 */
6358 return
6359 ( mysql_query_with_error_report(mysql_con, 0,
6360 ((opt_master_data != 0) ?
6361 "FLUSH /*!40101 LOCAL */ TABLES" :
6362 "FLUSH TABLES")) ||
6363 mysql_query_with_error_report(mysql_con, 0,
6364 "FLUSH TABLES WITH READ LOCK") );
6365 }
6366
6367 /**
6368 Execute LOCK TABLES FOR BACKUP if supported by the server.
6369
6370 @note If LOCK TABLES FOR BACKUP is not supported by the server, then nothing
6371 is done and no error condition is returned.
6372
6373 @returns whether there was an error or not
6374 */
6375
do_lock_tables_for_backup(MYSQL * mysql_con)6376 static int do_lock_tables_for_backup(MYSQL *mysql_con)
6377 {
6378 return mysql_query_with_error_report(mysql_con, 0,
6379 "LOCK TABLES FOR BACKUP");
6380 }
6381
do_unlock_tables(MYSQL * mysql_con)6382 static int do_unlock_tables(MYSQL *mysql_con)
6383 {
6384 return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES");
6385 }
6386
get_bin_log_name(MYSQL * mysql_con,char * buff_log_name,uint buff_len)6387 static int get_bin_log_name(MYSQL *mysql_con,
6388 char* buff_log_name, uint buff_len)
6389 {
6390 MYSQL_RES *res;
6391 MYSQL_ROW row;
6392
6393 if (mysql_query(mysql_con, "SHOW MASTER STATUS") ||
6394 !(res= mysql_store_result(mysql)))
6395 return 1;
6396
6397 if (!(row= mysql_fetch_row(res)))
6398 {
6399 mysql_free_result(res);
6400 return 1;
6401 }
6402 /*
6403 Only one row is returned, and the first column is the name of the
6404 active log.
6405 */
6406 strmake(buff_log_name, row[0], buff_len - 1);
6407
6408 mysql_free_result(res);
6409 return 0;
6410 }
6411
purge_bin_logs_to(MYSQL * mysql_con,char * log_name)6412 static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name)
6413 {
6414 DYNAMIC_STRING str;
6415 int err;
6416 init_dynamic_string_checked(&str, "PURGE BINARY LOGS TO '", 1024, 1024);
6417 dynstr_append_checked(&str, log_name);
6418 dynstr_append_checked(&str, "'");
6419 err = mysql_query_with_error_report(mysql_con, 0, str.str);
6420 dynstr_free(&str);
6421 return err;
6422 }
6423
6424
start_transaction(MYSQL * mysql_con)6425 static int start_transaction(MYSQL *mysql_con)
6426 {
6427 verbose_msg("-- Starting transaction...\n");
6428 /*
6429 We use BEGIN for old servers. --single-transaction --master-data will fail
6430 on old servers, but that's ok as it was already silently broken (it didn't
6431 do a consistent read, so better tell people frankly, with the error).
6432
6433 We want the first consistent read to be used for all tables to dump so we
6434 need the REPEATABLE READ level (not anything lower, for example READ
6435 COMMITTED would give one new consistent read per dumped table).
6436 */
6437 if ((mysql_get_server_version(mysql_con) < 40100) && opt_master_data)
6438 {
6439 fprintf(stderr, "-- %s: the combination of --single-transaction and "
6440 "--master-data requires a MySQL server version of at least 4.1 "
6441 "(current server's version is %s). %s\n",
6442 opt_force ? "Warning" : "Error",
6443 mysql_con->server_version ? mysql_con->server_version : "unknown",
6444 opt_force ? "Continuing due to --force, backup may not be "
6445 "consistent across all tables!" : "Aborting.");
6446 if (!opt_force)
6447 exit(EX_MYSQLERR);
6448 }
6449
6450 return (mysql_query_with_error_report(mysql_con, 0,
6451 "SET SESSION TRANSACTION ISOLATION "
6452 "LEVEL REPEATABLE READ") ||
6453 mysql_query_with_error_report(mysql_con, 0,
6454 "START TRANSACTION "
6455 "/*!40100 WITH CONSISTENT SNAPSHOT */"));
6456 }
6457
6458
find_set(TYPELIB * lib,const char * x,size_t length,char ** err_pos,uint * err_len)6459 static ulong find_set(TYPELIB *lib, const char *x, size_t length,
6460 char **err_pos, uint *err_len)
6461 {
6462 const char *end= x + length;
6463 ulong found= 0;
6464 uint find;
6465 char buff[255];
6466
6467 *err_pos= 0; /* No error yet */
6468 while (end > x && my_isspace(charset_info, end[-1]))
6469 end--;
6470
6471 *err_len= 0;
6472 if (x != end)
6473 {
6474 const char *start= x;
6475 for (;;)
6476 {
6477 const char *pos= start;
6478 uint var_len;
6479
6480 for (; pos != end && *pos != ','; pos++) ;
6481 var_len= (uint) (pos - start);
6482 strmake(buff, start, MY_MIN(sizeof(buff) - 1, var_len));
6483 find= find_type(buff, lib, FIND_TYPE_BASIC);
6484 if (!find)
6485 {
6486 *err_pos= (char*) start;
6487 *err_len= var_len;
6488 }
6489 else
6490 found|= ((longlong) 1 << (find - 1));
6491 if (pos == end)
6492 break;
6493 start= pos + 1;
6494 }
6495 }
6496 return found;
6497 }
6498
6499
6500 /* Print a value with a prefix on file */
print_value(FILE * file,MYSQL_RES * result,MYSQL_ROW row,const char * prefix,const char * name,int string_value)6501 static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
6502 const char *prefix, const char *name,
6503 int string_value)
6504 {
6505 MYSQL_FIELD *field;
6506 mysql_field_seek(result, 0);
6507
6508 for ( ; (field= mysql_fetch_field(result)) ; row++)
6509 {
6510 if (!strcmp(field->name,name))
6511 {
6512 if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
6513 {
6514 fputc(' ',file);
6515 fputs(prefix, file);
6516 if (string_value)
6517 unescape(file,row[0], strlen(row[0]));
6518 else
6519 fputs(row[0], file);
6520 check_io(file);
6521 return;
6522 }
6523 }
6524 }
6525 return; /* This shouldn't happen */
6526 } /* print_value */
6527
6528
6529 /*
6530 SYNOPSIS
6531
6532 Check if the table is one of the table types that should be ignored:
6533 MRG_ISAM, MRG_MYISAM.
6534
6535 If the table should be altogether ignored, it returns a TRUE, FALSE if it
6536 should not be ignored.
6537
6538 ARGS
6539
6540 check_if_ignore_table()
6541 table_name Table name to check
6542 table_type Type of table
6543
6544 GLOBAL VARIABLES
6545 mysql MySQL connection
6546 verbose Write warning messages
6547
6548 RETURN
6549 char (bit value) See IGNORE_ values at top
6550 */
6551
check_if_ignore_table(const char * table_name,char * table_type)6552 char check_if_ignore_table(const char *table_name, char *table_type)
6553 {
6554 char result= IGNORE_NONE;
6555 char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
6556 MYSQL_RES *res= NULL;
6557 MYSQL_ROW row;
6558 DBUG_ENTER("check_if_ignore_table");
6559
6560 /* Check memory for quote_for_like() */
6561 assert(2*sizeof(table_name) < sizeof(show_name_buff));
6562 my_snprintf(buff, sizeof(buff), "show table status like %s",
6563 quote_for_like(table_name, show_name_buff));
6564 if (mysql_query_with_error_report(mysql, &res, buff))
6565 {
6566 if (mysql_errno(mysql) != ER_PARSE_ERROR)
6567 { /* If old MySQL version */
6568 verbose_msg("-- Warning: Couldn't get status information for "
6569 "table %s (%s)\n", table_name, mysql_error(mysql));
6570 DBUG_RETURN(result); /* assume table is ok */
6571 }
6572 }
6573 if (!(row= mysql_fetch_row(res)))
6574 {
6575 fprintf(stderr,
6576 "Error: Couldn't read status information for table %s (%s)\n",
6577 table_name, mysql_error(mysql));
6578 mysql_free_result(res);
6579 DBUG_RETURN(result); /* assume table is ok */
6580 }
6581 if (!(row[1]))
6582 strmake(table_type, "VIEW", NAME_LEN-1);
6583 else
6584 {
6585 strmake(table_type, row[1], NAME_LEN-1);
6586
6587 /* If these two types, we want to skip dumping the table. */
6588 if (!opt_no_data &&
6589 (!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") ||
6590 !strcmp(table_type,"MRG_ISAM") ||
6591 !strcmp(table_type,"FEDERATED")))
6592 result= IGNORE_DATA;
6593 }
6594 mysql_free_result(res);
6595 DBUG_RETURN(result);
6596 }
6597
6598
6599 /*
6600 Get string of comma-separated primary key field names
6601
6602 SYNOPSIS
6603 char *primary_key_fields(const char *table_name)
6604 RETURNS pointer to allocated buffer (must be freed by caller)
6605 table_name quoted table name
6606
6607 DESCRIPTION
6608 Use SHOW KEYS FROM table_name, allocate a buffer to hold the
6609 field names, and then build that string and return the pointer
6610 to that buffer.
6611
6612 Returns NULL if there is no PRIMARY or UNIQUE key on the table,
6613 or if there is some failure. It is better to continue to dump
6614 the table unsorted, rather than exit without dumping the data.
6615 */
6616
primary_key_fields(const char * table_name,const my_bool desc)6617 static char *primary_key_fields(const char *table_name, const my_bool desc)
6618 {
6619 MYSQL_RES *res= NULL;
6620 MYSQL_ROW row;
6621 /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
6622 char show_keys_buff[15 + NAME_LEN * 2 + 3];
6623 size_t result_length= 0;
6624 char *result= 0;
6625 char buff[NAME_LEN * 2 + 3];
6626 char *quoted_field;
6627 static const char *desc_index= " DESC";
6628
6629 my_snprintf(show_keys_buff, sizeof(show_keys_buff),
6630 "SHOW KEYS FROM %s", table_name);
6631 if (mysql_query(mysql, show_keys_buff) ||
6632 !(res= mysql_store_result(mysql)))
6633 {
6634 fprintf(stderr, "Warning: Couldn't read keys from table %s;"
6635 " records are NOT sorted (%s)\n",
6636 table_name, mysql_error(mysql));
6637 /* Don't exit, because it's better to print out unsorted records */
6638 goto cleanup;
6639 }
6640
6641 /*
6642 * Figure out the length of the ORDER BY clause result.
6643 * Note that SHOW KEYS is ordered: a PRIMARY key is always the first
6644 * row, and UNIQUE keys come before others. So we only need to check
6645 * the first key, not all keys.
6646 */
6647 if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0)
6648 {
6649 /* Key is unique */
6650 do
6651 {
6652 quoted_field= quote_name(row[4], buff, 0);
6653 result_length+= strlen(quoted_field) + 1; /* + 1 for ',' or \0 */
6654 if (desc)
6655 {
6656 result_length+= strlen(desc_index);
6657 }
6658 } while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1);
6659 }
6660
6661 /* Build the ORDER BY clause result */
6662 if (result_length)
6663 {
6664 char *end;
6665 /* result (terminating \0 is already in result_length) */
6666 result= my_malloc(PSI_NOT_INSTRUMENTED,
6667 result_length + 10, MYF(MY_WME));
6668 if (!result)
6669 {
6670 fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
6671 goto cleanup;
6672 }
6673 mysql_data_seek(res, 0);
6674 row= mysql_fetch_row(res);
6675 quoted_field= quote_name(row[4], buff, 0);
6676 end= my_stpcpy(result, quoted_field);
6677 while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1)
6678 {
6679 quoted_field= quote_name(row[4], buff, 0);
6680 end= strxmov(end, desc ? " DESC," : ",", quoted_field, NullS);
6681 }
6682 if (desc)
6683 {
6684 end= my_stpmov(end, " DESC");
6685 }
6686 }
6687
6688 cleanup:
6689 if (res)
6690 mysql_free_result(res);
6691
6692 return result;
6693 }
6694
6695
6696 /*
6697 Replace a substring
6698
6699 SYNOPSIS
6700 replace
6701 ds_str The string to search and perform the replace in
6702 search_str The string to search for
6703 search_len Length of the string to search for
6704 replace_str The string to replace with
6705 replace_len Length of the string to replace with
6706
6707 RETURN
6708 0 String replaced
6709 1 Could not find search_str in str
6710 */
6711
replace(DYNAMIC_STRING * ds_str,const char * search_str,size_t search_len,const char * replace_str,size_t replace_len)6712 static int replace(DYNAMIC_STRING *ds_str,
6713 const char *search_str, size_t search_len,
6714 const char *replace_str, size_t replace_len)
6715 {
6716 DYNAMIC_STRING ds_tmp;
6717 const char *start= strstr(ds_str->str, search_str);
6718 if (!start)
6719 return 1;
6720 init_dynamic_string_checked(&ds_tmp, "",
6721 ds_str->length + replace_len, 256);
6722 dynstr_append_mem_checked(&ds_tmp, ds_str->str, start - ds_str->str);
6723 dynstr_append_mem_checked(&ds_tmp, replace_str, replace_len);
6724 dynstr_append_checked(&ds_tmp, start + search_len);
6725 dynstr_set_checked(ds_str, ds_tmp.str);
6726 dynstr_free(&ds_tmp);
6727 return 0;
6728 }
6729
6730
6731 /**
6732 This function sets the session binlog in the dump file.
6733 When --set-gtid-purged is used, this function is called to
6734 disable the session binlog and at the end of the dump, to restore
6735 the session binlog.
6736
6737 @note: md_result_file should have been opened, before
6738 this function is called.
6739 */
6740
set_session_binlog()6741 static void set_session_binlog()
6742 {
6743 static my_bool is_binlog_disabled= FALSE;
6744
6745 if (!is_binlog_disabled)
6746 {
6747 fprintf(md_result_file,
6748 "SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;\n");
6749 fprintf(md_result_file, "SET @@SESSION.SQL_LOG_BIN= 0;\n");
6750 is_binlog_disabled= 1;
6751 }
6752 else
6753 {
6754 fprintf(md_result_file,
6755 "SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;\n");
6756 is_binlog_disabled= 0;
6757 }
6758 }
6759
6760
6761 /**
6762 This function gets the GTID_EXECUTED sets from the
6763 server and assigns those sets to GTID_PURGED in the
6764 dump file.
6765
6766 @param[in] mysql_con connection to the server
6767 @param[in] ftwrl_done FLUSH TABLES WITH READ LOCK query was issued
6768
6769 @retval FALSE succesfully printed GTID_PURGED sets
6770 in the dump file.
6771 @retval TRUE failed.
6772
6773 */
6774
add_set_gtid_purged(MYSQL * mysql_con,my_bool ftwrl_done)6775 static my_bool add_set_gtid_purged(MYSQL *mysql_con, my_bool ftwrl_done)
6776 {
6777 MYSQL_RES *gtid_purged_res;
6778 MYSQL_ROW gtid_set;
6779 ulonglong num_sets, idx;
6780 int value_idx= 1;
6781 int capture_raw_gtid_executed= TRUE;
6782 char gtid_buffer[128];
6783 /*
6784 Check if we didn't already acquire FTWRL
6785 and we are in transaction with consistent snapshot.
6786 If we are, and snapshot of gtid_executed is supported by server - use it.
6787 */
6788 if (!ftwrl_done && opt_single_transaction)
6789 {
6790 if (!consistent_gtid_executed_supported(mysql_con) ||
6791 mysql_query_with_error_report(
6792 mysql_con, >id_purged_res,
6793 "SHOW STATUS LIKE 'Binlog_snapshot_gtid_executed'"))
6794 {
6795 fprintf(stderr,
6796 "\nWARNING: Server does not support consistent snapshot of "
6797 "GTID_EXECUTED."
6798 "\nThe value provided for GTID_PURGED may be inaccurate!"
6799 "\nTo overcome this issue, start mysqldump with "
6800 "--lock-all-tables.\n");
6801
6802 fprintf(md_result_file,
6803 "\n\n--"
6804 "\n-- WARNING: Server does not support consistent snapshot of "
6805 "GTID_EXECUTED."
6806 "\n-- The value provided for GTID_PURGED may be inaccurate!"
6807 "\n-- To overcome this issue, start mysqldump with "
6808 "--lock-all-tables."
6809 "\n--\n");
6810 }
6811 else
6812 {
6813 capture_raw_gtid_executed= FALSE;
6814 }
6815 }
6816
6817 if (capture_raw_gtid_executed)
6818 {
6819 /* query to get the GTID_EXECUTED */
6820 value_idx= 0;
6821 if (mysql_query_with_error_report(mysql_con, >id_purged_res,
6822 "SELECT @@GLOBAL.GTID_EXECUTED"))
6823 {
6824 return TRUE;
6825 }
6826 }
6827
6828 /* Proceed only if gtid_purged_res is non empty */
6829 if ((num_sets= mysql_num_rows(gtid_purged_res)) > 0)
6830 {
6831 gtid_executed_buffer_inited= 1;
6832 init_dynamic_string_checked(>id_executed_buffer, "", 1024, 1024);
6833 if (opt_comments)
6834 {
6835 my_snprintf(gtid_buffer, 128,
6836 "\n--\n-- GTID state at the end of the backup"
6837 "\n-- (origin: %s)"
6838 "\n--\n\n",
6839 capture_raw_gtid_executed ? "@@global.gtid_executed"
6840 : "Binlog_snapshot_gtid_executed");
6841 dynstr_append_checked(>id_executed_buffer, gtid_buffer);
6842 }
6843
6844 dynstr_append_checked(>id_executed_buffer, "SET @@GLOBAL.GTID_PURGED='");
6845
6846 /* formatting is not required, even for multiple gtid sets */
6847 for (idx= 0; idx< num_sets; idx++)
6848 {
6849 gtid_set= mysql_fetch_row(gtid_purged_res);
6850 dynstr_append_checked(>id_executed_buffer, (char *)gtid_set[value_idx]);
6851 }
6852 /* for the last set close the SET expression */
6853 dynstr_append_checked(>id_executed_buffer, "';\n");
6854 }
6855 mysql_free_result(gtid_purged_res);
6856
6857 return FALSE; /*success */
6858 }
6859
6860
6861 /**
6862 This function processes the opt_set_gtid_purged option.
6863 This function when called with the flag as FALSE, just
6864 disables the binlog by calling set_session_binlog().
6865 Later when this function is called with the flag as TRUE,
6866 SET @@GLOBAL.GTID_PURGED is written in the output and the
6867 session binlog is restored if disabled previously.
6868
6869 @param[in] mysql_con the connection to the server
6870 @param[in] ftwrl_done FLUSH TABLES WITH READ LOCK query was issued
6871 @param[in] flag If FALSE, just disable binlog and not
6872 set the gtid purged as it will be set
6873 at a later point of time.
6874 If TRUE, set the gtid purged and
6875 restore the session binlog if disabled
6876 previously.
6877
6878 @retval FALSE successful according to the value
6879 of opt_set_gtid_purged.
6880 @retval TRUE fail.
6881 */
6882
process_set_gtid_purged(MYSQL * mysql_con,my_bool ftwrl_done,my_bool flag)6883 static my_bool process_set_gtid_purged(MYSQL* mysql_con, my_bool ftwrl_done,
6884 my_bool flag)
6885 {
6886 MYSQL_RES *gtid_mode_res;
6887 MYSQL_ROW gtid_mode_row;
6888 char *gtid_mode_val= 0;
6889 static int gtid_mode= -1;
6890 char buf[32], query[64];
6891
6892 if (opt_set_gtid_purged_mode == SET_GTID_PURGED_OFF)
6893 return FALSE; /* nothing to be done */
6894
6895 /*
6896 Set gtid_mode, by fetching gtid_mode from server, if its not
6897 yet populated. gtid_mode is set to -1 if gtid_mode is not yet
6898 fetched from the server.
6899 */
6900 if (gtid_mode < 0)
6901 {
6902 /*
6903 Check if the server has the knowledge of GTIDs(pre mysql-5.6)
6904 or if the gtid_mode is ON or OFF.
6905 */
6906 my_snprintf(query, sizeof(query), "SHOW VARIABLES LIKE %s",
6907 quote_for_like("gtid_mode", buf));
6908
6909 if (mysql_query_with_error_report(mysql_con, >id_mode_res, query))
6910 return TRUE;
6911
6912 gtid_mode_row = mysql_fetch_row(gtid_mode_res);
6913
6914 /*
6915 gtid_mode_row is NULL for pre 5.6 versions. For versions >= 5.6,
6916 get the gtid_mode value from the second column.
6917 */
6918 gtid_mode_val = gtid_mode_row ? (char*)gtid_mode_row[1] : NULL;
6919 gtid_mode= (gtid_mode_val && strcmp(gtid_mode_val, "OFF")) ? 1 : 0;
6920 mysql_free_result(gtid_mode_res);
6921 }
6922
6923 if (gtid_mode)
6924 {
6925 /*
6926 For any gtid_mode !=OFF and irrespective of --set-gtid-purged
6927 being AUTO or ON, add GTID_PURGED in the output.
6928 */
6929 if (!flag)
6930 {
6931 set_session_binlog();
6932 if (add_set_gtid_purged(mysql_con, ftwrl_done))
6933 return TRUE;
6934 }
6935
6936 else
6937 {
6938 if (flag && (opt_databases || !opt_alldbs || !opt_dump_triggers
6939 || !opt_routines || !opt_events))
6940 {
6941 fprintf(stderr,"Warning: A partial dump from a server that has GTIDs will "
6942 "by default include the GTIDs of all transactions, even "
6943 "those that changed suppressed parts of the database. If "
6944 "you don't want to restore GTIDs, pass "
6945 "--set-gtid-purged=OFF. To make a complete dump, pass "
6946 "--all-databases --triggers --routines --events. \n");
6947 }
6948
6949 fputs(gtid_executed_buffer.str, md_result_file);
6950 }
6951 }
6952 else /* gtid_mode is off */
6953 {
6954 if (flag && opt_set_gtid_purged_mode == SET_GTID_PURGED_ON)
6955 {
6956 fprintf(stderr, "Error: Server has GTIDs disabled.\n");
6957 return TRUE;
6958 }
6959 }
6960
6961 return FALSE;
6962 }
6963
6964
6965 /*
6966 Getting VIEW structure
6967
6968 SYNOPSIS
6969 get_view_structure()
6970 table view name
6971 db db name
6972
6973 RETURN
6974 0 OK
6975 1 ERROR
6976 */
6977
get_view_structure(char * table,char * db)6978 static my_bool get_view_structure(char *table, char* db)
6979 {
6980 MYSQL_RES *table_res;
6981 MYSQL_ROW row;
6982 MYSQL_FIELD *field;
6983 char *result_table, *opt_quoted_table;
6984 char table_buff[NAME_LEN*2+3];
6985 char table_buff2[NAME_LEN*2+3];
6986 char query[QUERY_LENGTH];
6987 FILE *sql_file= md_result_file;
6988 my_bool freemem= FALSE;
6989 char const *text;
6990 DBUG_ENTER("get_view_structure");
6991
6992 if (opt_no_create_info) /* Don't write table creation info */
6993 DBUG_RETURN(0);
6994
6995 verbose_msg("-- Retrieving view structure for table %s...\n", table);
6996
6997 result_table= quote_name(table, table_buff, 1);
6998 opt_quoted_table= quote_name(table, table_buff2, 0);
6999
7000 if (switch_character_set_results(mysql, "binary"))
7001 DBUG_RETURN(1);
7002
7003 my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table);
7004
7005 if (mysql_query_with_error_report(mysql, &table_res, query))
7006 {
7007 switch_character_set_results(mysql, default_charset);
7008 DBUG_RETURN(0);
7009 }
7010
7011 /* Check if this is a view */
7012 field= mysql_fetch_field_direct(table_res, 0);
7013 if (strcmp(field->name, "View") != 0)
7014 {
7015 switch_character_set_results(mysql, default_charset);
7016 verbose_msg("-- It's base table, skipped\n");
7017 mysql_free_result(table_res);
7018 DBUG_RETURN(0);
7019 }
7020
7021 /* If requested, open separate .sql file for this view */
7022 if (path)
7023 {
7024 if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
7025 {
7026 mysql_free_result(table_res);
7027 DBUG_RETURN(1);
7028 }
7029
7030 write_header(sql_file, db);
7031 }
7032
7033 text= fix_identifier_with_newline(result_table, &freemem);
7034 print_comment(sql_file, 0,
7035 "\n--\n-- Final view structure for view %s\n--\n\n", text);
7036 if (freemem)
7037 my_free((void*)text);
7038
7039 verbose_msg("-- Dropping the temporary view structure created\n");
7040 fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", opt_quoted_table);
7041
7042 my_snprintf(query, sizeof(query),
7043 "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, "
7044 " CHARACTER_SET_CLIENT, COLLATION_CONNECTION "
7045 "FROM information_schema.views "
7046 "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db);
7047
7048 if (mysql_query(mysql, query))
7049 {
7050 /*
7051 Use the raw output from SHOW CREATE TABLE if
7052 information_schema query fails.
7053 */
7054 row= mysql_fetch_row(table_res);
7055 fprintf(sql_file, "/*!50001 %s */;\n", row[1]);
7056 check_io(sql_file);
7057 mysql_free_result(table_res);
7058 }
7059 else
7060 {
7061 char *ptr;
7062 ulong *lengths;
7063 char search_buf[256], replace_buf[256];
7064 ulong search_len, replace_len;
7065 DYNAMIC_STRING ds_view;
7066
7067 /* Save the result of SHOW CREATE TABLE in ds_view */
7068 row= mysql_fetch_row(table_res);
7069 lengths= mysql_fetch_lengths(table_res);
7070 init_dynamic_string_checked(&ds_view, row[1], lengths[1] + 1, 1024);
7071 mysql_free_result(table_res);
7072
7073 /* Get the result from "select ... information_schema" */
7074 if (!(table_res= mysql_store_result(mysql)) ||
7075 !(row= mysql_fetch_row(table_res)))
7076 {
7077 if (table_res)
7078 mysql_free_result(table_res);
7079 dynstr_free(&ds_view);
7080 DB_error(mysql, "when trying to save the result of SHOW CREATE TABLE in ds_view.");
7081 DBUG_RETURN(1);
7082 }
7083
7084 lengths= mysql_fetch_lengths(table_res);
7085
7086 /*
7087 "WITH %s CHECK OPTION" is available from 5.0.2
7088 Surround it with !50002 comments
7089 */
7090 if (strcmp(row[0], "NONE"))
7091 {
7092
7093 ptr= search_buf;
7094 search_len= (ulong)(strxmov(ptr, "WITH ", row[0],
7095 " CHECK OPTION", NullS) - ptr);
7096 ptr= replace_buf;
7097 replace_len=(ulong)(strxmov(ptr, "*/\n/*!50002 WITH ", row[0],
7098 " CHECK OPTION", NullS) - ptr);
7099 replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
7100 }
7101
7102 /*
7103 "DEFINER=%s SQL SECURITY %s" is available from 5.0.13
7104 Surround it with !50013 comments
7105 */
7106 {
7107 size_t user_name_len;
7108 char user_name_str[USERNAME_LENGTH + 1];
7109 char quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
7110 size_t host_name_len;
7111 char host_name_str[HOSTNAME_LENGTH + 1];
7112 char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
7113
7114 parse_user(row[1], lengths[1], user_name_str, &user_name_len,
7115 host_name_str, &host_name_len);
7116
7117 ptr= search_buf;
7118 search_len=
7119 (ulong)(strxmov(ptr, "DEFINER=",
7120 quote_name(user_name_str, quoted_user_name_str, FALSE),
7121 "@",
7122 quote_name(host_name_str, quoted_host_name_str, FALSE),
7123 " SQL SECURITY ", row[2], NullS) - ptr);
7124 ptr= replace_buf;
7125 replace_len=
7126 (ulong)(strxmov(ptr, "*/\n/*!50013 DEFINER=",
7127 quote_name(user_name_str, quoted_user_name_str, FALSE),
7128 "@",
7129 quote_name(host_name_str, quoted_host_name_str, FALSE),
7130 " SQL SECURITY ", row[2],
7131 " */\n/*!50001", NullS) - ptr);
7132 replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
7133 }
7134
7135 /* Dump view structure to file */
7136
7137 fprintf(sql_file,
7138 "/*!50001 SET @saved_cs_client = @@character_set_client */;\n"
7139 "/*!50001 SET @saved_cs_results = @@character_set_results */;\n"
7140 "/*!50001 SET @saved_col_connection = @@collation_connection */;\n"
7141 "/*!50001 SET character_set_client = %s */;\n"
7142 "/*!50001 SET character_set_results = %s */;\n"
7143 "/*!50001 SET collation_connection = %s */;\n"
7144 "/*!50001 %s */;\n"
7145 "/*!50001 SET character_set_client = @saved_cs_client */;\n"
7146 "/*!50001 SET character_set_results = @saved_cs_results */;\n"
7147 "/*!50001 SET collation_connection = @saved_col_connection */;\n",
7148 (const char *) row[3],
7149 (const char *) row[3],
7150 (const char *) row[4],
7151 (const char *) ds_view.str);
7152
7153 check_io(sql_file);
7154 mysql_free_result(table_res);
7155 dynstr_free(&ds_view);
7156 }
7157
7158 if (switch_character_set_results(mysql, default_charset))
7159 DBUG_RETURN(1);
7160
7161 /* If a separate .sql file was opened, close it now */
7162 if (sql_file != md_result_file)
7163 {
7164 fputs("\n", sql_file);
7165 write_footer(sql_file);
7166 my_fclose(sql_file, MYF(MY_WME));
7167 }
7168 DBUG_RETURN(0);
7169 }
7170
7171 /*
7172 The following functions are wrappers for the dynamic string functions
7173 and if they fail, the wrappers will terminate the current process.
7174 */
7175
7176 #define DYNAMIC_STR_ERROR_MSG "Couldn't perform DYNAMIC_STRING operation"
7177
init_dynamic_string_checked(DYNAMIC_STRING * str,const char * init_str,size_t init_alloc,size_t alloc_increment)7178 static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
7179 size_t init_alloc, size_t alloc_increment)
7180 {
7181 if (init_dynamic_string(str, init_str, init_alloc, alloc_increment))
7182 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
7183 }
7184
dynstr_append_checked(DYNAMIC_STRING * dest,const char * src)7185 static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src)
7186 {
7187 if (dynstr_append(dest, src))
7188 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
7189 }
7190
dynstr_set_checked(DYNAMIC_STRING * str,const char * init_str)7191 static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str)
7192 {
7193 if (dynstr_set(str, init_str))
7194 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
7195 }
7196
dynstr_append_mem_checked(DYNAMIC_STRING * str,const char * append,size_t length)7197 static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
7198 size_t length)
7199 {
7200 if (dynstr_append_mem(str, append, length))
7201 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
7202 }
7203
dynstr_realloc_checked(DYNAMIC_STRING * str,size_t additional_size)7204 static void dynstr_realloc_checked(DYNAMIC_STRING *str, size_t additional_size)
7205 {
7206 if (dynstr_realloc(str, additional_size))
7207 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
7208 }
7209
has_session_variables_like(MYSQL * mysql_con,const char * var_name)7210 static my_bool has_session_variables_like(MYSQL *mysql_con, const char *var_name)
7211 {
7212 MYSQL_RES *res;
7213 MYSQL_ROW row;
7214 char *val= 0;
7215 char buf[32], query[256];
7216 my_bool has_var= FALSE;
7217 my_bool has_table= FALSE;
7218
7219 my_snprintf(query, sizeof(query), "SELECT COUNT(*) FROM"
7220 " INFORMATION_SCHEMA.TABLES WHERE table_schema ="
7221 " 'performance_schema' AND table_name = 'session_variables'");
7222 if (mysql_query_with_error_report(mysql_con, &res, query))
7223 return FALSE;
7224
7225 row = mysql_fetch_row(res);
7226 val = row ? (char*)row[0] : NULL;
7227 has_table = val && strcmp(val, "0") != 0;
7228 mysql_free_result(res);
7229
7230 if (has_table)
7231 {
7232 my_snprintf(query, sizeof(query), "SELECT COUNT(*) FROM"
7233 " performance_schema.session_variables WHERE VARIABLE_NAME LIKE"
7234 " %s", quote_for_like(var_name, buf));
7235 if (mysql_query_with_error_report(mysql_con, &res, query))
7236 return FALSE;
7237
7238 row = mysql_fetch_row(res);
7239 val = row ? (char*)row[0] : NULL;
7240 has_var = val && strcmp(val, "0") != 0;
7241 mysql_free_result(res);
7242 }
7243
7244 return has_var;
7245 }
7246
7247 /**
7248 Check if the server supports LOCK TABLES FOR BACKUP.
7249
7250 @returns TRUE if there is support, FALSE otherwise.
7251 */
7252
server_supports_backup_locks(void)7253 static my_bool server_supports_backup_locks(void)
7254 {
7255 MYSQL_RES *res;
7256 MYSQL_ROW row;
7257 my_bool rc;
7258
7259 if (mysql_query_with_error_report(mysql, &res,
7260 "SHOW VARIABLES LIKE 'have_backup_locks'"))
7261 return FALSE;
7262
7263 if ((row= mysql_fetch_row(res)) == NULL)
7264 {
7265 mysql_free_result(res);
7266 return FALSE;
7267 }
7268
7269 rc= mysql_num_fields(res) > 1 && !strcmp(row[1], "YES");
7270
7271 mysql_free_result(res);
7272
7273 return rc;
7274 }
7275
7276 /*
7277 This function executes all sql statements from the given file.
7278 Each statement lenght is limited to 1023 characters including
7279 trailing semicolon.
7280 Each statement has to be in its own line.
7281
7282 @param[in] sql_file File name containing sql statements to be
7283 executed.
7284 @retval 1 failure
7285 0 success
7286 */
7287 #ifndef NDEBUG
7288 #define SQL_STATEMENT_MAX_LEN 1024 // 1023 chars for statement + trailing 0
execute_sql_file(const char * sql_file)7289 static int execute_sql_file(const char *sql_file)
7290 {
7291 static const char *win_eol= "\r\n";
7292 static const char *linux_eol= "\n";
7293 static const char *win_semicolon= ";\r\n";
7294 static const char *linux_semicolon= ";\n";
7295 static const char *semicolon= ";";
7296 static const char *comment= "#";
7297
7298 FILE *file;
7299 char buf[SQL_STATEMENT_MAX_LEN];
7300
7301 if (!sql_file)
7302 return 0;
7303
7304 if (!(file= fopen(sql_file, "r")))
7305 {
7306 fprintf(stderr, "Cannot open file %s\n", sql_file);
7307 return 1;
7308 }
7309
7310 while (fgets(buf, SQL_STATEMENT_MAX_LEN, file))
7311 {
7312 // simple validation
7313 size_t query_len= strlen(buf);
7314
7315 // empty file
7316 if (query_len == 0)
7317 {
7318 fclose(file);
7319 return 1;
7320 }
7321
7322 // If this is empty or comment line, skip it
7323 if (strcmp(buf, linux_eol) == 0 || strcmp(buf, win_eol) == 0 ||
7324 strstr(buf, comment) == buf)
7325 {
7326 continue;
7327 }
7328
7329 // we need line ending with semicolon and optionally a new line
7330 // which differs on Windows and Linux
7331 if (strstr(buf, linux_semicolon) == 0 &&
7332 strstr(buf, win_semicolon) == 0 && strstr(buf, semicolon) == 0)
7333 {
7334 fclose(file);
7335 return 1;
7336 }
7337
7338 if (mysql_query_with_error_report(mysql, 0, buf))
7339 {
7340 fclose(file);
7341 return 1;
7342 }
7343 }
7344
7345 fclose(file);
7346 return 0;
7347 }
7348 #endif // NDEBUG
7349
main(int argc,char ** argv)7350 int main(int argc, char **argv)
7351 {
7352 char bin_log_name[FN_REFLEN];
7353 int exit_code, md_result_fd;
7354 int has_consistent_binlog_pos= 0;
7355 int has_consistent_gtid_executed= 0;
7356 my_bool ftwrl_done= FALSE;
7357
7358 MY_INIT("mysqldump");
7359
7360 compatible_mode_normal_str[0]= 0;
7361 default_charset= (char *)mysql_universal_client_charset;
7362 memset(&ignore_table, 0, sizeof(ignore_table));
7363
7364 exit_code= get_options(&argc, &argv);
7365 if (exit_code)
7366 {
7367 free_resources();
7368 exit(exit_code);
7369 }
7370
7371 /*
7372 Disable comments in xml mode if 'comments' option is not explicitly used.
7373 */
7374 if (opt_xml && !opt_comments_used)
7375 opt_comments= 0;
7376
7377 if (log_error_file)
7378 {
7379 if(!(stderror_file= freopen(log_error_file, "a+", stderr)))
7380 {
7381 free_resources();
7382 exit(EX_MYSQLERR);
7383 }
7384 }
7385
7386 if (connect_to_db(current_host, current_user, opt_password))
7387 {
7388 free_resources();
7389 exit(EX_MYSQLERR);
7390 }
7391
7392 #ifndef NDEBUG
7393 if (execute_sql_file(start_sql_file))
7394 goto err;
7395 #endif
7396
7397 if (!path)
7398 write_header(md_result_file, *argv);
7399
7400 if (opt_lock_for_backup && !server_supports_backup_locks())
7401 {
7402 fprintf(stderr, "%s: Error: --lock-for-backup was specified with "
7403 "--single-transaction, but the server does not support "
7404 "LOCK TABLES FOR BACKUP.\n",
7405 my_progname);
7406 goto err;
7407 }
7408
7409 if (opt_slave_data && do_stop_slave_sql(mysql))
7410 goto err;
7411
7412 if (opt_single_transaction && opt_master_data)
7413 {
7414 /*
7415 See if we can avoid FLUSH TABLES WITH READ LOCK with Binlog_snapshot_*
7416 variables.
7417 */
7418 has_consistent_binlog_pos= check_consistent_binlog_pos(NULL, NULL);
7419 }
7420
7421 has_consistent_gtid_executed= consistent_gtid_executed_supported(mysql);
7422
7423 /*
7424 NOTE:
7425 1. --lock-all-tables and --single-transaction are mutually exclusive
7426 2. has_consistent_binlog_pos == true => opt_single_transaction == true
7427 3. --master-data => implicitly adds --lock-all-tables
7428 4. --master-data + --single-transaction => does not add implicit --lock-all-tables
7429
7430 We require FTWRL if any of the following:
7431 1. explicitly requested by --lock-all-tables
7432 2. --master-data requested, but server does not provide consistent
7433 binlog position (or does not support consistent gtid_executed)
7434 Having consistent gtid_executed condition is here to be compatible with upstream
7435 behavior on servers which support consistent binlog position, but do not
7436 support consistent gtid_executed. In such case we need FTWRL.
7437 3. --single-transaction and --flush-logs
7438 */
7439 if (opt_lock_all_tables ||
7440 (opt_master_data &&
7441 (!has_consistent_binlog_pos || !has_consistent_gtid_executed)) ||
7442 (opt_single_transaction && flush_logs))
7443 {
7444 if (do_flush_tables_read_lock(mysql))
7445 goto err;
7446 ftwrl_done = TRUE;
7447 }
7448 else if (opt_lock_for_backup && do_lock_tables_for_backup(mysql))
7449 goto err;
7450
7451 /*
7452 Flush logs before starting transaction since
7453 this causes implicit commit starting mysql-5.5.
7454 */
7455 if (opt_lock_all_tables || opt_master_data ||
7456 (opt_single_transaction && flush_logs) ||
7457 opt_delete_master_logs)
7458 {
7459 if (flush_logs || opt_delete_master_logs)
7460 {
7461 if (mysql_refresh(mysql, REFRESH_LOG))
7462 {
7463 DB_error(mysql, "when doing refresh");
7464 goto err;
7465 }
7466 verbose_msg("-- main : logs flushed successfully!\n");
7467 }
7468
7469 /* Not anymore! That would not be sensible. */
7470 flush_logs= 0;
7471 }
7472
7473 if (opt_delete_master_logs)
7474 {
7475 if (get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name)))
7476 goto err;
7477 }
7478
7479 if (has_session_variables_like(mysql, "rocksdb_skip_fill_cache"))
7480 mysql_query_with_error_report(mysql, 0,
7481 "SET SESSION rocksdb_skip_fill_cache=1");
7482
7483 if (opt_single_transaction && start_transaction(mysql))
7484 goto err;
7485
7486 /* Add 'STOP SLAVE to beginning of dump */
7487 if (opt_slave_apply && add_stop_slave())
7488 goto err;
7489
7490 /* Process opt_set_gtid_purged and add SET disable binlog if required. */
7491 if (process_set_gtid_purged(mysql, ftwrl_done, FALSE))
7492 goto err;
7493
7494
7495 if (opt_master_data && do_show_master_status(mysql, has_consistent_binlog_pos))
7496 goto err;
7497 if (opt_slave_data && do_show_slave_status(mysql))
7498 goto err;
7499
7500 /**
7501 Note:
7502 opt_single_transaction == true => opt_lock_all_tables == false and vice versa
7503
7504 We acquired the lock (FTWRL or LTFB) if
7505 1. --lock-all-tables => FTWRL + opt_single_transaction == false
7506 2. --lock-for-backup => LTFB + opt_single_transaction == true
7507 3. --master-data => (--lock-all-tables) FTWRL + opt_single_transaction == false
7508 4. --master-data + --single-transaction =>
7509 FTWRL if consistent snapshot not supported + opt_single_transaction == true
7510 5. --single-transaction + --flush-logs => FTWRL + opt_single_transaction == true
7511
7512 We have to unlock in cases: 4, 5
7513
7514 We need to keep the lock up to the end of backup if:
7515 1. we have --lock-for-backup
7516 2. we have --lock-all-tables (so opt_single_transaction == false)
7517 We unlock if none of above.
7518
7519 If not locked previously, unlocking will not do any harm.
7520 */
7521 if (!(opt_lock_all_tables || opt_lock_for_backup))
7522 {
7523 if (do_unlock_tables(mysql)) /* unlock but no commit! */
7524 goto err;
7525 }
7526
7527 if (opt_alltspcs)
7528 dump_all_tablespaces();
7529
7530 if (opt_alldbs)
7531 {
7532 if (!opt_alltspcs && !opt_notspcs)
7533 dump_all_tablespaces();
7534 dump_all_databases();
7535 }
7536 else
7537 {
7538 // Check all arguments meet length condition. Currently database and table
7539 // names are limited to NAME_LEN bytes and stack-based buffers assumes
7540 // that escaped name will be not longer than NAME_LEN*2 + 2 bytes long.
7541 int argument;
7542 for (argument= 0; argument < argc; argument++)
7543 {
7544 size_t argument_length= strlen(argv[argument]);
7545 if (argument_length > NAME_LEN)
7546 {
7547 die(EX_CONSCHECK, "[ERROR] Argument '%s' is too long, it cannot be "
7548 "name for any table or database.\n", argv[argument]);
7549 }
7550 }
7551
7552 if (argc > 1 && !opt_databases)
7553 {
7554 /* Only one database and selected table(s) */
7555 if (!opt_alltspcs && !opt_notspcs)
7556 dump_tablespaces_for_tables(*argv, (argv + 1), (argc - 1));
7557 dump_selected_tables(*argv, (argv + 1), (argc - 1));
7558 }
7559 else
7560 {
7561 /* One or more databases, all tables */
7562 if (!opt_alltspcs && !opt_notspcs)
7563 dump_tablespaces_for_databases(argv);
7564 dump_databases(argv);
7565 }
7566 }
7567
7568 /* if --dump-slave , start the slave sql thread */
7569 if (opt_slave_data && do_start_slave_sql(mysql))
7570 goto err;
7571
7572 /* Process opt_set_gtid_purged and add SET @@GLOBAL.GTID_PURGED if required. */
7573 if (process_set_gtid_purged(mysql, ftwrl_done, TRUE))
7574 goto err;
7575
7576 /* add 'START SLAVE' to end of dump */
7577 if (opt_slave_apply && add_slave_statements())
7578 goto err;
7579
7580 if (md_result_file)
7581 md_result_fd= my_fileno(md_result_file);
7582
7583 /*
7584 Ensure dumped data flushed.
7585 First we will flush the file stream data to kernel buffers with fflush().
7586 Second we will flush the kernel buffers data to physical disk file with
7587 my_sync(), this will make sure the data succeessfully dumped to disk file.
7588 fsync() fails with EINVAL if stdout is not redirected to any file, hence
7589 MY_IGNORE_BADFD is passed to ingnore that error.
7590 */
7591 if (md_result_file &&
7592 (fflush(md_result_file) || my_sync(md_result_fd, MYF(MY_IGNORE_BADFD))))
7593 {
7594 if (!first_error)
7595 first_error= EX_MYSQLERR;
7596 goto err;
7597 }
7598 /* everything successful, purge the old logs files */
7599 if (opt_delete_master_logs && purge_bin_logs_to(mysql, bin_log_name))
7600 goto err;
7601
7602 #if defined (_WIN32) && !defined (EMBEDDED_LIBRARY)
7603 my_free(shared_memory_base_name);
7604 #endif
7605 /*
7606 No reason to explicitely COMMIT the transaction, neither to explicitely
7607 UNLOCK TABLES: these will be automatically be done by the server when we
7608 disconnect now. Saves some code here, some network trips, adds nothing to
7609 server.
7610 */
7611 err:
7612 #ifndef NDEBUG
7613 execute_sql_file(finish_sql_file);
7614 #endif
7615
7616 dbDisconnect(current_host);
7617 if (!path)
7618 write_footer(md_result_file);
7619 free_resources();
7620
7621 if (stderror_file)
7622 fclose(stderror_file);
7623
7624 return(first_error);
7625 } /* main */
7626