· 10 years ago · Jul 21, 2016, 01:54 PM
1/*
2 Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
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 as published by
6 the Free Software Foundation; version 2 of the License.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
16*/
17
18/* mysqldump.c - Dump a tables contents and format to an ASCII file
19**
20** The author's original notes follow :-
21**
22** AUTHOR: Igor Romanenko (igor@frog.kiev.ua)
23** DATE: December 3, 1994
24** WARRANTY: None, expressed, impressed, implied
25** or other
26** STATUS: Public domain
27** Adapted and optimized for MySQL by
28** Michael Widenius, Sinisa Milivojevic, Jani Tolonen
29** -w --where added 9/10/98 by Jim Faucette
30** slave code by David Saez Padros <david@ols.es>
31** master/autocommit code by Brian Aker <brian@tangent.org>
32** SSL by
33** Andrei Errapart <andreie@no.spam.ee>
34** Tõnu Samuel <tonu@please.do.not.remove.this.spam.ee>
35** XML by Gary Huntress <ghuntress@mediaone.net> 10/10/01, cleaned up
36** and adapted to mysqldump 05/11/01 by Jani Tolonen
37** Added --single-transaction option 06/06/2002 by Peter Zaitsev
38** 10 Jun 2003: SET NAMES and --no-set-names by Alexander Barkov
39*/
40
41#define DUMP_VERSION "10.13"
42
43#include <my_global.h>
44#include <my_sys.h>
45#include <my_user.h>
46#include <m_string.h>
47#include <m_ctype.h>
48#include <hash.h>
49#include <stdarg.h>
50
51#include "client_priv.h"
52#include "my_default.h"
53#include "mysql.h"
54#include "mysql_version.h"
55#include "mysqld_error.h"
56
57#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
58
59/* Exit codes */
60
61#define EX_USAGE 1
62#define EX_MYSQLERR 2
63#define EX_CONSCHECK 3
64#define EX_EOM 4
65#define EX_EOF 5 /* ferror for output file was got */
66#define EX_ILLEGAL_TABLE 6
67
68/* index into 'show fields from table' */
69
70#define SHOW_FIELDNAME 0
71#define SHOW_TYPE 1
72#define SHOW_NULL 2
73#define SHOW_DEFAULT 4
74#define SHOW_EXTRA 5
75
76/* Size of buffer for dump's select query */
77#define QUERY_LENGTH 1536
78
79/* Size of comment buffer. */
80#define COMMENT_LENGTH 2048
81
82/* ignore table flags */
83#define IGNORE_NONE 0x00 /* no ignore */
84#define IGNORE_DATA 0x01 /* don't dump data for this table */
85#define IGNORE_INSERT_DELAYED 0x02 /* table doesn't support INSERT DELAYED */
86
87
88static void add_load_option(DYNAMIC_STRING *str, const char *option,
89 const char *option_value);
90static ulong find_set(TYPELIB *lib, const char *x, uint length,
91 char **err_pos, uint *err_len);
92static char *alloc_query_str(ulong size);
93
94static void field_escape(DYNAMIC_STRING* in, const char *from);
95static my_bool verbose= 0, opt_no_create_info= 0, opt_no_data= 0,
96 quick= 1, extended_insert= 1,
97 lock_tables=1,ignore_errors=0,flush_logs=0,flush_privileges=0,
98 opt_drop=1,opt_keywords=0,opt_lock=1,opt_compress=0,
99 opt_delayed=0,create_options=1,opt_quoted=0,opt_databases=0,
100 opt_alldbs=0,opt_create_db=0,opt_lock_all_tables=0,
101 opt_set_charset=0, opt_dump_date=1,
102 opt_autocommit=0,opt_disable_keys=1,opt_xml=0,
103 opt_delete_master_logs=0, tty_password=0,
104 opt_single_transaction=0, opt_comments= 0, opt_compact= 0,
105 opt_hex_blob=0, opt_order_by_primary=0, opt_ignore=0,
106 opt_complete_insert= 0, opt_drop_database= 0,
107 opt_replace_into= 0,
108 opt_dump_triggers= 0, opt_routines=0, opt_tz_utc=1,
109 opt_slave_apply= 0,
110 opt_include_master_host_port= 0,
111 opt_events= 0, opt_comments_used= 0,
112 opt_alltspcs=0, opt_notspcs= 0, opt_drop_trigger= 0,
113 opt_secure_auth= 1;
114static my_bool insert_pat_inited= 0, debug_info_flag= 0, debug_check_flag= 0;
115static ulong opt_max_allowed_packet, opt_net_buffer_length;
116static MYSQL mysql_connection,*mysql=0;
117static DYNAMIC_STRING insert_pat;
118static char *opt_password=0,*current_user=0,
119 *current_host=0,*path=0,*fields_terminated=0,
120 *lines_terminated=0, *enclosed=0, *opt_enclosed=0, *escaped=0,
121 *where=0, *order_by=0,
122 *opt_compatible_mode_str= 0,
123 *err_ptr= 0,
124 *log_error_file= NULL;
125static char **defaults_argv= 0;
126static char compatible_mode_normal_str[255];
127/* Server supports character_set_results session variable? */
128static my_bool server_supports_switching_charsets= TRUE;
129static ulong opt_compatible_mode= 0;
130#define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1
131#define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2
132#define MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL 1
133#define MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL 2
134static uint opt_mysql_port= 0, opt_master_data;
135static uint opt_slave_data;
136static uint my_end_arg;
137static char * opt_mysql_unix_port=0;
138static char *opt_bind_addr = NULL;
139static int first_error=0;
140static DYNAMIC_STRING extended_row;
141#include <sslopt-vars.h>
142FILE *md_result_file= 0;
143FILE *stderror_file=0;
144
145const char *set_gtid_purged_mode_names[]=
146{"OFF", "AUTO", "ON", NullS};
147static TYPELIB set_gtid_purged_mode_typelib=
148 {array_elements(set_gtid_purged_mode_names) -1, "",
149 set_gtid_purged_mode_names, NULL};
150static enum enum_set_gtid_purged_mode {
151 SET_GTID_PURGED_OFF= 0,
152 SET_GTID_PURGED_AUTO =1,
153 SET_GTID_PURGED_ON=2
154} opt_set_gtid_purged_mode= SET_GTID_PURGED_AUTO;
155
156#ifdef HAVE_SMEM
157static char *shared_memory_base_name=0;
158#endif
159static uint opt_protocol= 0;
160static char *opt_plugin_dir= 0, *opt_default_auth= 0;
161
162/*
163Dynamic_string wrapper functions. In this file use these
164wrappers, they will terminate the process if there is
165an allocation failure.
166*/
167static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
168 uint init_alloc, uint alloc_increment);
169static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src);
170static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str);
171static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
172 uint length);
173static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size);
174/*
175 Constant for detection of default value of default_charset.
176 If default_charset is equal to mysql_universal_client_charset, then
177 it is the default value which assigned at the very beginning of main().
178*/
179static const char *mysql_universal_client_charset=
180 MYSQL_UNIVERSAL_CLIENT_CHARSET;
181static char *default_charset;
182static CHARSET_INFO *charset_info= &my_charset_latin1;
183const char *default_dbug_option="d:t:o,/tmp/mysqldump.trace";
184/* have we seen any VIEWs during table scanning? */
185my_bool seen_views= 0;
186const char *compatible_mode_names[]=
187{
188 "MYSQL323", "MYSQL40", "POSTGRESQL", "ORACLE", "MSSQL", "DB2",
189 "MAXDB", "NO_KEY_OPTIONS", "NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS",
190 "ANSI",
191 NullS
192};
193#define MASK_ANSI_QUOTES \
194(\
195 (1<<2) | /* POSTGRESQL */\
196 (1<<3) | /* ORACLE */\
197 (1<<4) | /* MSSQL */\
198 (1<<5) | /* DB2 */\
199 (1<<6) | /* MAXDB */\
200 (1<<10) /* ANSI */\
201)
202TYPELIB compatible_mode_typelib= {array_elements(compatible_mode_names) - 1,
203 "", compatible_mode_names, NULL};
204
205HASH ignore_table;
206
207static struct my_option my_long_options[] =
208{
209 {"all-databases", 'A',
210 "Dump all the databases. This will be same as --databases with all databases selected.",
211 &opt_alldbs, &opt_alldbs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
212 0, 0},
213 {"all-tablespaces", 'Y',
214 "Dump all the tablespaces.",
215 &opt_alltspcs, &opt_alltspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
216 0, 0},
217 {"no-tablespaces", 'y',
218 "Do not dump any tablespace information.",
219 &opt_notspcs, &opt_notspcs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
220 0, 0},
221 {"add-drop-database", OPT_DROP_DATABASE, "Add a DROP DATABASE before each create.",
222 &opt_drop_database, &opt_drop_database, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
223 0},
224 {"add-drop-table", OPT_DROP, "Add a DROP TABLE before each create.",
225 &opt_drop, &opt_drop, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
226 0},
227 {"add-drop-trigger", 0, "Add a DROP TRIGGER before each create.",
228 &opt_drop_trigger, &opt_drop_trigger, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0,
229 0},
230 {"add-locks", OPT_LOCKS, "Add locks around INSERT statements.",
231 &opt_lock, &opt_lock, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
232 0},
233 {"allow-keywords", OPT_KEYWORDS,
234 "Allow creation of column names that are keywords.", &opt_keywords,
235 &opt_keywords, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
236 {"apply-slave-statements", OPT_MYSQLDUMP_SLAVE_APPLY,
237 "Adds 'STOP SLAVE' prior to 'CHANGE MASTER' and 'START SLAVE' to bottom of dump.",
238 &opt_slave_apply, &opt_slave_apply, 0, GET_BOOL, NO_ARG,
239 0, 0, 0, 0, 0, 0},
240 {"bind-address", 0, "IP address to bind to.",
241 (uchar**) &opt_bind_addr, (uchar**) &opt_bind_addr, 0, GET_STR,
242 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
243 {"character-sets-dir", OPT_CHARSETS_DIR,
244 "Directory for character set files.", &charsets_dir,
245 &charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
246 {"comments", 'i', "Write additional information.",
247 &opt_comments, &opt_comments, 0, GET_BOOL, NO_ARG,
248 1, 0, 0, 0, 0, 0},
249 {"compatible", OPT_COMPATIBLE,
250 "Change the dump to be compatible with a given mode. By default tables "
251 "are dumped in a format optimized for MySQL. Legal modes are: ansi, "
252 "mysql323, mysql40, postgresql, oracle, mssql, db2, maxdb, no_key_options, "
253 "no_table_options, no_field_options. One can use several modes separated "
254 "by commas. Note: Requires MySQL server version 4.1.0 or higher. "
255 "This option is ignored with earlier server versions.",
256 &opt_compatible_mode_str, &opt_compatible_mode_str, 0,
257 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
258 {"compact", OPT_COMPACT,
259 "Give less verbose output (useful for debugging). Disables structure "
260 "comments and header/footer constructs. Enables options --skip-add-"
261 "drop-table --skip-add-locks --skip-comments --skip-disable-keys "
262 "--skip-set-charset.",
263 &opt_compact, &opt_compact, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
264 {"complete-insert", 'c', "Use complete insert statements.",
265 &opt_complete_insert, &opt_complete_insert, 0, GET_BOOL,
266 NO_ARG, 0, 0, 0, 0, 0, 0},
267 {"compress", 'C', "Use compression in server/client protocol.",
268 &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
269 0, 0, 0},
270 {"create-options", 'a',
271 "Include all MySQL specific create options.",
272 &create_options, &create_options, 0, GET_BOOL, NO_ARG, 1,
273 0, 0, 0, 0, 0},
274 {"databases", 'B',
275 "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.",
276 &opt_databases, &opt_databases, 0, GET_BOOL, NO_ARG, 0, 0,
277 0, 0, 0, 0},
278#ifdef DBUG_OFF
279 {"debug", '#', "This is a non-debug version. Catch this and exit.",
280 0,0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
281#else
282 {"debug", '#', "Output debug log.", &default_dbug_option,
283 &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
284#endif
285 {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
286 &debug_check_flag, &debug_check_flag, 0,
287 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
288 {"debug-info", OPT_DEBUG_INFO, "Print some debug info at exit.",
289 &debug_info_flag, &debug_info_flag,
290 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
291 {"default-character-set", OPT_DEFAULT_CHARSET,
292 "Set the default character set.", &default_charset,
293 &default_charset, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
294 {"delayed-insert", OPT_DELAYED, "Insert rows with INSERT DELAYED.",
295 &opt_delayed, &opt_delayed, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
296 0, 0},
297 {"delete-master-logs", OPT_DELETE_MASTER_LOGS,
298 "Delete logs on master after backup. This automatically enables --master-data.",
299 &opt_delete_master_logs, &opt_delete_master_logs, 0,
300 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
301 {"disable-keys", 'K',
302 "'/*!40000 ALTER TABLE tb_name DISABLE KEYS */; and '/*!40000 ALTER "
303 "TABLE tb_name ENABLE KEYS */; will be put in the output.", &opt_disable_keys,
304 &opt_disable_keys, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
305 {"dump-slave", OPT_MYSQLDUMP_SLAVE_DATA,
306 "This causes the binary log position and filename of the master to be "
307 "appended to the dumped data output. Setting the value to 1, will print"
308 "it as a CHANGE MASTER command in the dumped data output; if equal"
309 " to 2, that command will be prefixed with a comment symbol. "
310 "This option will turn --lock-all-tables on, unless "
311 "--single-transaction is specified too (in which case a "
312 "global read lock is only taken a short time at the beginning of the dump "
313 "- don't forget to read about --single-transaction below). In all cases "
314 "any action on logs will happen at the exact moment of the dump."
315 "Option automatically turns --lock-tables off.",
316 &opt_slave_data, &opt_slave_data, 0,
317 GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL, 0, 0, 0},
318 {"events", 'E', "Dump events.",
319 &opt_events, &opt_events, 0, GET_BOOL,
320 NO_ARG, 0, 0, 0, 0, 0, 0},
321 {"extended-insert", 'e',
322 "Use multiple-row INSERT syntax that include several VALUES lists.",
323 &extended_insert, &extended_insert, 0, GET_BOOL, NO_ARG,
324 1, 0, 0, 0, 0, 0},
325 {"fields-terminated-by", OPT_FTB,
326 "Fields in the output file are terminated by the given string.",
327 &fields_terminated, &fields_terminated, 0,
328 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
329 {"fields-enclosed-by", OPT_ENC,
330 "Fields in the output file are enclosed by the given character.",
331 &enclosed, &enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
332 {"fields-optionally-enclosed-by", OPT_O_ENC,
333 "Fields in the output file are optionally enclosed by the given character.",
334 &opt_enclosed, &opt_enclosed, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0 ,0, 0},
335 {"fields-escaped-by", OPT_ESC,
336 "Fields in the output file are escaped by the given character.",
337 &escaped, &escaped, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
338 {"flush-logs", 'F', "Flush logs file in server before starting dump. "
339 "Note that if you dump many databases at once (using the option "
340 "--databases= or --all-databases), the logs will be flushed for "
341 "each database dumped. The exception is when using --lock-all-tables "
342 "or --master-data: "
343 "in this case the logs will be flushed only once, corresponding "
344 "to the moment all tables are locked. So if you want your dump and "
345 "the log flush to happen at the same exact moment you should use "
346 "--lock-all-tables or --master-data with --flush-logs.",
347 &flush_logs, &flush_logs, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
348 0, 0},
349 {"flush-privileges", OPT_ESC, "Emit a FLUSH PRIVILEGES statement "
350 "after dumping the mysql database. This option should be used any "
351 "time the dump contains the mysql database and any other database "
352 "that depends on the data in the mysql database for proper restore. ",
353 &flush_privileges, &flush_privileges, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
354 0, 0},
355 {"force", 'f', "Continue even if we get an SQL error.",
356 &ignore_errors, &ignore_errors, 0, GET_BOOL, NO_ARG,
357 0, 0, 0, 0, 0, 0},
358 {"help", '?', "Display this help message and exit.", 0, 0, 0, GET_NO_ARG,
359 NO_ARG, 0, 0, 0, 0, 0, 0},
360 {"hex-blob", OPT_HEXBLOB, "Dump binary strings (BINARY, "
361 "VARBINARY, BLOB) in hexadecimal format.",
362 &opt_hex_blob, &opt_hex_blob, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
363 {"host", 'h', "Connect to host.", ¤t_host,
364 ¤t_host, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
365 {"ignore-table", OPT_IGNORE_TABLE,
366 "Do not dump the specified table. To specify more than one table to ignore, "
367 "use the directive multiple times, once for each table. Each table must "
368 "be specified with both database and table names, e.g., "
369 "--ignore-table=database.table.",
370 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
371 {"include-master-host-port", OPT_MYSQLDUMP_INCLUDE_MASTER_HOST_PORT,
372 "Adds 'MASTER_HOST=<host>, MASTER_PORT=<port>' to 'CHANGE MASTER TO..' "
373 "in dump produced with --dump-slave.", &opt_include_master_host_port,
374 &opt_include_master_host_port, 0, GET_BOOL, NO_ARG,
375 0, 0, 0, 0, 0, 0},
376 {"insert-ignore", OPT_INSERT_IGNORE, "Insert rows with INSERT IGNORE.",
377 &opt_ignore, &opt_ignore, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
378 0, 0},
379 {"lines-terminated-by", OPT_LTB,
380 "Lines in the output file are terminated by the given string.",
381 &lines_terminated, &lines_terminated, 0, GET_STR,
382 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
383 {"lock-all-tables", 'x', "Locks all tables across all databases. This "
384 "is achieved by taking a global read lock for the duration of the whole "
385 "dump. Automatically turns --single-transaction and --lock-tables off.",
386 &opt_lock_all_tables, &opt_lock_all_tables, 0, GET_BOOL, NO_ARG,
387 0, 0, 0, 0, 0, 0},
388 {"lock-tables", 'l', "Lock all tables for read.", &lock_tables,
389 &lock_tables, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
390 {"log-error", OPT_ERROR_LOG_FILE, "Append warnings and errors to given file.",
391 &log_error_file, &log_error_file, 0, GET_STR,
392 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
393 {"master-data", OPT_MASTER_DATA,
394 "This causes the binary log position and filename to be appended to the "
395 "output. If equal to 1, will print it as a CHANGE MASTER command; if equal"
396 " to 2, that command will be prefixed with a comment symbol. "
397 "This option will turn --lock-all-tables on, unless "
398 "--single-transaction is specified too (in which case a "
399 "global read lock is only taken a short time at the beginning of the dump; "
400 "don't forget to read about --single-transaction below). In all cases, "
401 "any action on logs will happen at the exact moment of the dump. "
402 "Option automatically turns --lock-tables off.",
403 &opt_master_data, &opt_master_data, 0,
404 GET_UINT, OPT_ARG, 0, 0, MYSQL_OPT_MASTER_DATA_COMMENTED_SQL, 0, 0, 0},
405 {"max_allowed_packet", OPT_MAX_ALLOWED_PACKET,
406 "The maximum packet length to send to or receive from server.",
407 &opt_max_allowed_packet, &opt_max_allowed_packet, 0,
408 GET_ULONG, REQUIRED_ARG, 24*1024*1024, 4096,
409 (longlong) 2L*1024L*1024L*1024L, MALLOC_OVERHEAD, 1024, 0},
410 {"net_buffer_length", OPT_NET_BUFFER_LENGTH,
411 "The buffer size for TCP/IP and socket communication.",
412 &opt_net_buffer_length, &opt_net_buffer_length, 0,
413 GET_ULONG, REQUIRED_ARG, 1024*1024L-1025, 4096, 16*1024L*1024L,
414 MALLOC_OVERHEAD-1024, 1024, 0},
415 {"no-autocommit", OPT_AUTOCOMMIT,
416 "Wrap tables with autocommit/commit statements.",
417 &opt_autocommit, &opt_autocommit, 0, GET_BOOL, NO_ARG,
418 0, 0, 0, 0, 0, 0},
419 {"no-create-db", 'n',
420 "Suppress the CREATE DATABASE ... IF EXISTS statement that normally is "
421 "output for each dumped database if --all-databases or --databases is "
422 "given.",
423 &opt_create_db, &opt_create_db, 0,
424 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
425 {"no-create-info", 't', "Don't write table creation info.",
426 &opt_no_create_info, &opt_no_create_info, 0, GET_BOOL,
427 NO_ARG, 0, 0, 0, 0, 0, 0},
428 {"no-data", 'd', "No row information.", &opt_no_data,
429 &opt_no_data, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
430 {"no-set-names", 'N', "Same as --skip-set-charset.",
431 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
432 {"opt", OPT_OPTIMIZE,
433 "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.",
434 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
435 {"order-by-primary", OPT_ORDER_BY_PRIMARY,
436 "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.",
437 &opt_order_by_primary, &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
438 {"password", 'p',
439 "Password to use when connecting to server. If password is not given it's solicited on the tty.",
440 0, 0, 0, GET_PASSWORD, OPT_ARG, 0, 0, 0, 0, 0, 0},
441#ifdef __WIN__
442 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
443 NO_ARG, 0, 0, 0, 0, 0, 0},
444#endif
445 {"port", 'P', "Port number to use for connection.", &opt_mysql_port,
446 &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0,
447 0},
448 {"protocol", OPT_MYSQL_PROTOCOL,
449 "The protocol to use for connection (tcp, socket, pipe, memory).",
450 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
451 {"quick", 'q', "Don't buffer query, dump directly to stdout.",
452 &quick, &quick, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
453 {"quote-names",'Q', "Quote table and column names with backticks (`).",
454 &opt_quoted, &opt_quoted, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0,
455 0, 0},
456 {"replace", OPT_MYSQL_REPLACE_INTO, "Use REPLACE INTO instead of INSERT INTO.",
457 &opt_replace_into, &opt_replace_into, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
458 0, 0},
459 {"result-file", 'r',
460 "Direct output to a given file. This option should be used in systems "
461 "(e.g., DOS, Windows) that use carriage-return linefeed pairs (\\r\\n) "
462 "to separate text lines. This option ensures that only a single newline "
463 "is used.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
464 {"routines", 'R', "Dump stored routines (functions and procedures).",
465 &opt_routines, &opt_routines, 0, GET_BOOL,
466 NO_ARG, 0, 0, 0, 0, 0, 0},
467 {"set-charset", OPT_SET_CHARSET,
468 "Add 'SET NAMES default_character_set' to the output.",
469 &opt_set_charset, &opt_set_charset, 0, GET_BOOL, NO_ARG, 1,
470 0, 0, 0, 0, 0},
471 {"set-gtid-purged", OPT_SET_GTID_PURGED,
472 "Add 'SET @@GLOBAL.GTID_PURGED' to the output. Possible values for "
473 "this option are ON, OFF and AUTO. If ON is used and GTIDs "
474 "are not enabled on the server, an error is generated. If OFF is "
475 "used, this option does nothing. If AUTO is used and GTIDs are enabled "
476 "on the server, 'SET @@GLOBAL.GTID_PURGED' is added to the output. "
477 "If GTIDs are disabled, AUTO does nothing. If no value is supplied "
478 "then the default (AUTO) value will be considered.",
479 0, 0, 0, GET_STR, OPT_ARG,
480 0, 0, 0, 0, 0, 0},
481#ifdef HAVE_SMEM
482 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
483 "Base name of shared memory.", &shared_memory_base_name, &shared_memory_base_name,
484 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
485#endif
486 /*
487 Note that the combination --single-transaction --master-data
488 will give bullet-proof binlog position only if server >=4.1.3. That's the
489 old "FLUSH TABLES WITH READ LOCK does not block commit" fixed bug.
490 */
491 {"single-transaction", OPT_TRANSACTION,
492 "Creates a consistent snapshot by dumping all tables in a single "
493 "transaction. Works ONLY for tables stored in storage engines which "
494 "support multiversioning (currently only InnoDB does); the dump is NOT "
495 "guaranteed to be consistent for other storage engines. "
496 "While a --single-transaction dump is in process, to ensure a valid "
497 "dump file (correct table contents and binary log position), no other "
498 "connection should use the following statements: ALTER TABLE, DROP "
499 "TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not "
500 "isolated from them. Option automatically turns off --lock-tables.",
501 &opt_single_transaction, &opt_single_transaction, 0,
502 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
503 {"dump-date", OPT_DUMP_DATE, "Put a dump date to the end of the output.",
504 &opt_dump_date, &opt_dump_date, 0,
505 GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
506 {"skip-opt", OPT_SKIP_OPTIMIZATION,
507 "Disable --opt. Disables --add-drop-table, --add-locks, --create-options, --quick, --extended-insert, --lock-tables, --set-charset, and --disable-keys.",
508 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
509 {"socket", 'S', "The socket file to use for connection.",
510 &opt_mysql_unix_port, &opt_mysql_unix_port, 0,
511 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
512 {"secure-auth", OPT_SECURE_AUTH, "Refuse client connecting to server if it"
513 " uses old (pre-4.1.1) protocol.", &opt_secure_auth,
514 &opt_secure_auth, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
515#include <sslopt-longopts.h>
516 {"tab",'T',
517 "Create tab-separated textfile for each table to given path. (Create .sql "
518 "and .txt files.) NOTE: This only works if mysqldump is run on the same "
519 "machine as the mysqld server.",
520 &path, &path, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
521 {"tables", OPT_TABLES, "Overrides option --databases (-B).",
522 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
523 {"triggers", OPT_TRIGGERS, "Dump triggers for each dumped table.",
524 &opt_dump_triggers, &opt_dump_triggers, 0, GET_BOOL,
525 NO_ARG, 1, 0, 0, 0, 0, 0},
526 {"tz-utc", OPT_TZ_UTC,
527 "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.",
528 &opt_tz_utc, &opt_tz_utc, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
529#ifndef DONT_ALLOW_USER_CHANGE
530 {"user", 'u', "User for login if not current user.",
531 ¤t_user, ¤t_user, 0, GET_STR, REQUIRED_ARG,
532 0, 0, 0, 0, 0, 0},
533#endif
534 {"verbose", 'v', "Print info about the various stages.",
535 &verbose, &verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
536 {"version",'V', "Output version information and exit.", 0, 0, 0,
537 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
538 {"where", 'w', "Dump only selected records. Quotes are mandatory.",
539 &where, &where, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
540 {"xml", 'X', "Dump a database as well formed XML.", 0, 0, 0, GET_NO_ARG,
541 NO_ARG, 0, 0, 0, 0, 0, 0},
542 {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
543 &opt_plugin_dir, &opt_plugin_dir, 0,
544 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
545 {"default_auth", OPT_DEFAULT_AUTH,
546 "Default authentication client-side plugin to use.",
547 &opt_default_auth, &opt_default_auth, 0,
548 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
549 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
550};
551
552static const char *load_default_groups[]= { "mysqldump","client",0 };
553
554static void maybe_exit(int error);
555static void die(int error, const char* reason, ...);
556static void maybe_die(int error, const char* reason, ...);
557static void write_header(FILE *sql_file, char *db_name);
558static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
559 const char *prefix,const char *name,
560 int string_value);
561static int dump_selected_tables(char *db, char **table_names, int tables);
562static int dump_all_tables_in_db(char *db);
563static int init_dumping_views(char *);
564static int init_dumping_tables(char *);
565static int init_dumping(char *, int init_func(char*));
566static int dump_databases(char **);
567static int dump_all_databases();
568static char *quote_name(const char *name, char *buff, my_bool force);
569char check_if_ignore_table(const char *table_name, char *table_type);
570static char *primary_key_fields(const char *table_name);
571static my_bool get_view_structure(char *table, char* db);
572static my_bool dump_all_views_in_db(char *database);
573static int dump_all_tablespaces();
574static int dump_tablespaces_for_tables(char *db, char **table_names, int tables);
575static int dump_tablespaces_for_databases(char** databases);
576static int dump_tablespaces(char* ts_where);
577static void print_comment(FILE *sql_file, my_bool is_error, const char *format,
578 ...);
579
580
581/*
582 Print the supplied message if in verbose mode
583
584 SYNOPSIS
585 verbose_msg()
586 fmt format specifier
587 ... variable number of parameters
588*/
589
590static void verbose_msg(const char *fmt, ...)
591{
592 va_list args;
593 DBUG_ENTER("verbose_msg");
594
595 if (!verbose)
596 DBUG_VOID_RETURN;
597
598 va_start(args, fmt);
599 vfprintf(stderr, fmt, args);
600 va_end(args);
601
602 fflush(stderr);
603
604 DBUG_VOID_RETURN;
605}
606
607/*
608 exit with message if ferror(file)
609
610 SYNOPSIS
611 check_io()
612 file - checked file
613*/
614
615void check_io(FILE *file)
616{
617 if (ferror(file) || errno == 5)
618 die(EX_EOF, "Got errno %d on write", errno);
619}
620
621static void print_version(void)
622{
623 printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,DUMP_VERSION,
624 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
625} /* print_version */
626
627
628static void short_usage_sub(void)
629{
630 printf("Usage: %s [OPTIONS] database [tables]\n", my_progname);
631 printf("OR %s [OPTIONS] --databases [OPTIONS] DB1 [DB2 DB3...]\n",
632 my_progname);
633 printf("OR %s [OPTIONS] --all-databases [OPTIONS]\n", my_progname);
634}
635
636
637static void usage(void)
638{
639 print_version();
640 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"));
641 puts("Dumping structure and contents of MySQL databases and tables.");
642 short_usage_sub();
643 print_defaults("my",load_default_groups);
644 my_print_help(my_long_options);
645 my_print_variables(my_long_options);
646} /* usage */
647
648
649static void short_usage(void)
650{
651 short_usage_sub();
652 printf("For more options, use %s --help\n", my_progname);
653}
654
655
656static void write_header(FILE *sql_file, char *db_name)
657{
658 if (opt_xml)
659 {
660 fputs("<?xml version=\"1.0\"?>\n", sql_file);
661 /*
662 Schema reference. Allows use of xsi:nil for NULL values and
663 xsi:type to define an element's data type.
664 */
665 fputs("<mysqldump ", sql_file);
666 fputs("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"",
667 sql_file);
668 fputs(">\n", sql_file);
669 check_io(sql_file);
670 }
671 else if (!opt_compact)
672 {
673 print_comment(sql_file, 0,
674 "-- MySQL dump %s Distrib %s, for %s (%s)\n--\n",
675 DUMP_VERSION, MYSQL_SERVER_VERSION, SYSTEM_TYPE,
676 MACHINE_TYPE);
677 print_comment(sql_file, 0, "-- Host: %s Database: %s\n",
678 current_host ? current_host : "localhost",
679 db_name ? db_name : "");
680 print_comment(sql_file, 0,
681 "-- ------------------------------------------------------\n"
682 );
683 print_comment(sql_file, 0, "-- Server version\t%s\n",
684 mysql_get_server_info(&mysql_connection));
685
686 if (opt_set_charset)
687 fprintf(sql_file,
688"\n/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;"
689"\n/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;"
690"\n/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;"
691"\n/*!40101 SET NAMES %s */;\n",default_charset);
692
693 if (opt_tz_utc)
694 {
695 fprintf(sql_file, "/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;\n");
696 fprintf(sql_file, "/*!40103 SET TIME_ZONE='+00:00' */;\n");
697 }
698
699 if (!path)
700 {
701 fprintf(md_result_file,"\
702/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;\n\
703/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n\
704");
705 }
706 fprintf(sql_file,
707 "/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='%s%s%s' */;\n"
708 "/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;\n",
709 path?"":"NO_AUTO_VALUE_ON_ZERO",compatible_mode_normal_str[0]==0?"":",",
710 compatible_mode_normal_str);
711 check_io(sql_file);
712 }
713} /* write_header */
714
715
716static void write_footer(FILE *sql_file)
717{
718 if (opt_xml)
719 {
720 fputs("</mysqldump>\n", sql_file);
721 check_io(sql_file);
722 }
723 else if (!opt_compact)
724 {
725 if (opt_tz_utc)
726 fprintf(sql_file,"/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;\n");
727
728 fprintf(sql_file,"\n/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;\n");
729 if (!path)
730 {
731 fprintf(md_result_file,"\
732/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;\n\
733/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;\n");
734 }
735 if (opt_set_charset)
736 fprintf(sql_file,
737"/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;\n"
738"/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;\n"
739"/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;\n");
740 fprintf(sql_file,
741 "/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;\n");
742 fputs("\n", sql_file);
743
744 if (opt_dump_date)
745 {
746 char time_str[20];
747 get_date(time_str, GETDATE_DATE_TIME, 0);
748 print_comment(sql_file, 0, "-- Dump completed on %s\n", time_str);
749 }
750 else
751 print_comment(sql_file, 0, "-- Dump completed\n");
752
753 check_io(sql_file);
754 }
755} /* write_footer */
756
757
758uchar* get_table_key(const char *entry, size_t *length,
759 my_bool not_used __attribute__((unused)))
760{
761 *length= strlen(entry);
762 return (uchar*) entry;
763}
764
765
766static my_bool
767get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
768 char *argument)
769{
770 switch (optid) {
771 case 'p':
772 if (argument == disabled_my_option)
773 argument= (char*) ""; /* Don't require password */
774 if (argument)
775 {
776 char *start=argument;
777 my_free(opt_password);
778 opt_password=my_strdup(argument,MYF(MY_FAE));
779 while (*argument) *argument++= 'x'; /* Destroy argument */
780 if (*start)
781 start[1]=0; /* Cut length of argument */
782 tty_password= 0;
783 }
784 else
785 tty_password=1;
786 break;
787 case 'r':
788 if (!(md_result_file= my_fopen(argument, O_WRONLY | FILE_BINARY,
789 MYF(MY_WME))))
790 exit(1);
791 break;
792 case 'W':
793#ifdef __WIN__
794 opt_protocol= MYSQL_PROTOCOL_PIPE;
795#endif
796 break;
797 case 'N':
798 opt_set_charset= 0;
799 break;
800 case 'T':
801 opt_disable_keys=0;
802
803 if (strlen(argument) >= FN_REFLEN)
804 {
805 /*
806 This check is made because the some the file functions below
807 have FN_REFLEN sized stack allocated buffers and will cause
808 a crash even if the input destination buffer is large enough
809 to hold the output.
810 */
811 die(EX_USAGE, "Input filename too long: %s", argument);
812 }
813
814 break;
815 case '#':
816 DBUG_PUSH(argument ? argument : default_dbug_option);
817 debug_check_flag= 1;
818 break;
819#include <sslopt-case.h>
820 case 'V': print_version(); exit(0);
821 case 'X':
822 opt_xml= 1;
823 extended_insert= opt_drop= opt_lock=
824 opt_disable_keys= opt_autocommit= opt_create_db= 0;
825 break;
826 case 'i':
827 opt_comments_used= 1;
828 break;
829 case 'I':
830 case '?':
831 usage();
832 exit(0);
833 case (int) OPT_MASTER_DATA:
834 if (!argument) /* work like in old versions */
835 opt_master_data= MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL;
836 break;
837 case (int) OPT_MYSQLDUMP_SLAVE_DATA:
838 if (!argument) /* work like in old versions */
839 opt_slave_data= MYSQL_OPT_SLAVE_DATA_EFFECTIVE_SQL;
840 break;
841 case (int) OPT_OPTIMIZE:
842 extended_insert= opt_drop= opt_lock= quick= create_options=
843 opt_disable_keys= lock_tables= opt_set_charset= 1;
844 break;
845 case (int) OPT_SKIP_OPTIMIZATION:
846 extended_insert= opt_drop= opt_lock= quick= create_options=
847 opt_disable_keys= lock_tables= opt_set_charset= 0;
848 break;
849 case (int) OPT_COMPACT:
850 if (opt_compact)
851 {
852 opt_comments= opt_drop= opt_disable_keys= opt_lock= 0;
853 opt_set_charset= 0;
854 }
855 break;
856 case (int) OPT_TABLES:
857 opt_databases=0;
858 break;
859 case (int) OPT_IGNORE_TABLE:
860 {
861 if (!strchr(argument, '.'))
862 {
863 fprintf(stderr, "Illegal use of option --ignore-table=<database>.<table>\n");
864 exit(1);
865 }
866 if (my_hash_insert(&ignore_table, (uchar*)my_strdup(argument, MYF(0))))
867 exit(EX_EOM);
868 break;
869 }
870 case (int) OPT_COMPATIBLE:
871 {
872 char buff[255];
873 char *end= compatible_mode_normal_str;
874 int i;
875 ulong mode;
876 uint err_len;
877
878 opt_quoted= 1;
879 opt_set_charset= 0;
880 opt_compatible_mode_str= argument;
881 opt_compatible_mode= find_set(&compatible_mode_typelib,
882 argument, (uint) strlen(argument),
883 &err_ptr, &err_len);
884 if (err_len)
885 {
886 strmake(buff, err_ptr, MY_MIN(sizeof(buff) - 1, err_len));
887 fprintf(stderr, "Invalid mode to --compatible: %s\n", buff);
888 exit(1);
889 }
890#if !defined(DBUG_OFF)
891 {
892 uint size_for_sql_mode= 0;
893 const char **ptr;
894 for (ptr= compatible_mode_names; *ptr; ptr++)
895 size_for_sql_mode+= strlen(*ptr);
896 size_for_sql_mode+= sizeof(compatible_mode_names)-1;
897 DBUG_ASSERT(sizeof(compatible_mode_normal_str)>=size_for_sql_mode);
898 }
899#endif
900 mode= opt_compatible_mode;
901 for (i= 0, mode= opt_compatible_mode; mode; mode>>= 1, i++)
902 {
903 if (mode & 1)
904 {
905 end= strmov(end, compatible_mode_names[i]);
906 end= strmov(end, ",");
907 }
908 }
909 if (end!=compatible_mode_normal_str)
910 end[-1]= 0;
911 /*
912 Set charset to the default compiled value if it hasn't
913 been reset yet by --default-character-set=xxx.
914 */
915 if (default_charset == mysql_universal_client_charset)
916 default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
917 break;
918 }
919 case (int) OPT_MYSQL_PROTOCOL:
920 opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
921 opt->name);
922 break;
923 case (int) OPT_SET_GTID_PURGED:
924 {
925 if (argument)
926 opt_set_gtid_purged_mode= find_type_or_exit(argument,
927 &set_gtid_purged_mode_typelib,
928 opt->name)-1;
929 break;
930 }
931 }
932 return 0;
933}
934
935static int get_options(int *argc, char ***argv)
936{
937 int ho_error;
938 MYSQL_PARAMETERS *mysql_params= mysql_get_parameters();
939
940 opt_max_allowed_packet= *mysql_params->p_max_allowed_packet;
941 opt_net_buffer_length= *mysql_params->p_net_buffer_length;
942
943 md_result_file= stdout;
944 my_getopt_use_args_separator= TRUE;
945 if (load_defaults("my",load_default_groups,argc,argv))
946 return 1;
947 my_getopt_use_args_separator= FALSE;
948
949 defaults_argv= *argv;
950
951 if (my_hash_init(&ignore_table, charset_info, 16, 0, 0,
952 (my_hash_get_key) get_table_key, my_free, 0))
953 return(EX_EOM);
954 /* Don't copy internal log tables */
955 if (my_hash_insert(&ignore_table,
956 (uchar*) my_strdup("mysql.apply_status", MYF(MY_WME))) ||
957 my_hash_insert(&ignore_table,
958 (uchar*) my_strdup("mysql.schema", MYF(MY_WME))) ||
959 my_hash_insert(&ignore_table,
960 (uchar*) my_strdup("mysql.general_log", MYF(MY_WME))) ||
961 my_hash_insert(&ignore_table,
962 (uchar*) my_strdup("mysql.slow_log", MYF(MY_WME))))
963 return(EX_EOM);
964
965 if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
966 return(ho_error);
967
968 *mysql_params->p_max_allowed_packet= opt_max_allowed_packet;
969 *mysql_params->p_net_buffer_length= opt_net_buffer_length;
970 if (debug_info_flag)
971 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
972 if (debug_check_flag)
973 my_end_arg= MY_CHECK_ERROR;
974
975 if (opt_delayed)
976 opt_lock=0; /* Can't have lock with delayed */
977 if (!path && (enclosed || opt_enclosed || escaped || lines_terminated ||
978 fields_terminated))
979 {
980 fprintf(stderr,
981 "%s: You must use option --tab with --fields-...\n", my_progname);
982 return(EX_USAGE);
983 }
984
985 /* We don't delete master logs if slave data option */
986 if (opt_slave_data)
987 {
988 opt_lock_all_tables= !opt_single_transaction;
989 opt_master_data= 0;
990 opt_delete_master_logs= 0;
991 }
992
993 /* Ensure consistency of the set of binlog & locking options */
994 if (opt_delete_master_logs && !opt_master_data)
995 opt_master_data= MYSQL_OPT_MASTER_DATA_COMMENTED_SQL;
996 if (opt_single_transaction && opt_lock_all_tables)
997 {
998 fprintf(stderr, "%s: You can't use --single-transaction and "
999 "--lock-all-tables at the same time.\n", my_progname);
1000 return(EX_USAGE);
1001 }
1002 if (opt_master_data)
1003 {
1004 opt_lock_all_tables= !opt_single_transaction;
1005 opt_slave_data= 0;
1006 }
1007 if (opt_single_transaction || opt_lock_all_tables)
1008 lock_tables= 0;
1009 if (enclosed && opt_enclosed)
1010 {
1011 fprintf(stderr, "%s: You can't use ..enclosed.. and ..optionally-enclosed.. at the same time.\n", my_progname);
1012 return(EX_USAGE);
1013 }
1014 if ((opt_databases || opt_alldbs) && path)
1015 {
1016 fprintf(stderr,
1017 "%s: --databases or --all-databases can't be used with --tab.\n",
1018 my_progname);
1019 return(EX_USAGE);
1020 }
1021 if (strcmp(default_charset, charset_info->csname) &&
1022 !(charset_info= get_charset_by_csname(default_charset,
1023 MY_CS_PRIMARY, MYF(MY_WME))))
1024 exit(1);
1025 if ((*argc < 1 && !opt_alldbs) || (*argc > 0 && opt_alldbs))
1026 {
1027 short_usage();
1028 return EX_USAGE;
1029 }
1030 if (tty_password)
1031 opt_password=get_tty_password(NullS);
1032 return(0);
1033} /* get_options */
1034
1035
1036/*
1037** DB_error -- prints mysql error message and exits the program.
1038*/
1039static void DB_error(MYSQL *mysql_arg, const char *when)
1040{
1041 DBUG_ENTER("DB_error");
1042 maybe_die(EX_MYSQLERR, "Got error: %d: %s %s",
1043 mysql_errno(mysql_arg), mysql_error(mysql_arg), when);
1044 DBUG_VOID_RETURN;
1045}
1046
1047
1048
1049/*
1050 Prints out an error message and kills the process.
1051
1052 SYNOPSIS
1053 die()
1054 error_num - process return value
1055 fmt_reason - a format string for use by my_vsnprintf.
1056 ... - variable arguments for above fmt_reason string
1057
1058 DESCRIPTION
1059 This call prints out the formatted error message to stderr and then
1060 terminates the process.
1061*/
1062static void die(int error_num, const char* fmt_reason, ...)
1063{
1064 char buffer[1000];
1065 va_list args;
1066 va_start(args,fmt_reason);
1067 my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
1068 va_end(args);
1069
1070 fprintf(stderr, "%s: %s\n", my_progname, buffer);
1071 fflush(stderr);
1072
1073 ignore_errors= 0; /* force the exit */
1074 maybe_exit(error_num);
1075}
1076
1077
1078/*
1079 Prints out an error message and maybe kills the process.
1080
1081 SYNOPSIS
1082 maybe_die()
1083 error_num - process return value
1084 fmt_reason - a format string for use by my_vsnprintf.
1085 ... - variable arguments for above fmt_reason string
1086
1087 DESCRIPTION
1088 This call prints out the formatted error message to stderr and then
1089 terminates the process, unless the --force command line option is used.
1090
1091 This call should be used for non-fatal errors (such as database
1092 errors) that the code may still be able to continue to the next unit
1093 of work.
1094
1095*/
1096static void maybe_die(int error_num, const char* fmt_reason, ...)
1097{
1098 char buffer[1000];
1099 va_list args;
1100 va_start(args,fmt_reason);
1101 my_vsnprintf(buffer, sizeof(buffer), fmt_reason, args);
1102 va_end(args);
1103
1104 fprintf(stderr, "%s: %s\n", my_progname, buffer);
1105 fflush(stderr);
1106
1107 maybe_exit(error_num);
1108}
1109
1110
1111
1112/*
1113 Sends a query to server, optionally reads result, prints error message if
1114 some.
1115
1116 SYNOPSIS
1117 mysql_query_with_error_report()
1118 mysql_con connection to use
1119 res if non zero, result will be put there with
1120 mysql_store_result()
1121 query query to send to server
1122
1123 RETURN VALUES
1124 0 query sending and (if res!=0) result reading went ok
1125 1 error
1126*/
1127
1128static int mysql_query_with_error_report(MYSQL *mysql_con, MYSQL_RES **res,
1129 const char *query)
1130{
1131 if (mysql_query(mysql_con, query) ||
1132 (res && !((*res)= mysql_store_result(mysql_con))))
1133 {
1134 maybe_die(EX_MYSQLERR, "Couldn't execute '%s': %s (%d)",
1135 query, mysql_error(mysql_con), mysql_errno(mysql_con));
1136 return 1;
1137 }
1138 return 0;
1139}
1140
1141
1142static int fetch_db_collation(const char *db_name,
1143 char *db_cl_name,
1144 int db_cl_size)
1145{
1146 my_bool err_status= FALSE;
1147 char query[QUERY_LENGTH];
1148 MYSQL_RES *db_cl_res;
1149 MYSQL_ROW db_cl_row;
1150 char quoted_database_buf[NAME_LEN*2+3];
1151 char *qdatabase= quote_name(db_name, quoted_database_buf, 1);
1152
1153 my_snprintf(query, sizeof (query), "use %s", qdatabase);
1154
1155 if (mysql_query_with_error_report(mysql, NULL, query))
1156 return 1;
1157
1158 if (mysql_query_with_error_report(mysql, &db_cl_res,
1159 "select @@collation_database"))
1160 return 1;
1161
1162 do
1163 {
1164 if (mysql_num_rows(db_cl_res) != 1)
1165 {
1166 err_status= TRUE;
1167 break;
1168 }
1169
1170 if (!(db_cl_row= mysql_fetch_row(db_cl_res)))
1171 {
1172 err_status= TRUE;
1173 break;
1174 }
1175
1176 strncpy(db_cl_name, db_cl_row[0], db_cl_size);
1177 db_cl_name[db_cl_size - 1]= 0; /* just in case. */
1178
1179 } while (FALSE);
1180
1181 mysql_free_result(db_cl_res);
1182
1183 return err_status ? 1 : 0;
1184}
1185
1186
1187static char *my_case_str(const char *str,
1188 uint str_len,
1189 const char *token,
1190 uint token_len)
1191{
1192 my_match_t match;
1193
1194 uint status= my_charset_latin1.coll->instr(&my_charset_latin1,
1195 str, str_len,
1196 token, token_len,
1197 &match, 1);
1198
1199 return status ? (char *) str + match.end : NULL;
1200}
1201
1202
1203static int switch_db_collation(FILE *sql_file,
1204 const char *db_name,
1205 const char *delimiter,
1206 const char *current_db_cl_name,
1207 const char *required_db_cl_name,
1208 int *db_cl_altered)
1209{
1210 if (strcmp(current_db_cl_name, required_db_cl_name) != 0)
1211 {
1212 char quoted_db_buf[NAME_LEN * 2 + 3];
1213 char *quoted_db_name= quote_name(db_name, quoted_db_buf, FALSE);
1214
1215 CHARSET_INFO *db_cl= get_charset_by_name(required_db_cl_name, MYF(0));
1216
1217 if (!db_cl)
1218 return 1;
1219
1220 fprintf(sql_file,
1221 "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n",
1222 (const char *) quoted_db_name,
1223 (const char *) db_cl->csname,
1224 (const char *) db_cl->name,
1225 (const char *) delimiter);
1226
1227 *db_cl_altered= 1;
1228
1229 return 0;
1230 }
1231
1232 *db_cl_altered= 0;
1233
1234 return 0;
1235}
1236
1237
1238static int restore_db_collation(FILE *sql_file,
1239 const char *db_name,
1240 const char *delimiter,
1241 const char *db_cl_name)
1242{
1243 char quoted_db_buf[NAME_LEN * 2 + 3];
1244 char *quoted_db_name= quote_name(db_name, quoted_db_buf, FALSE);
1245
1246 CHARSET_INFO *db_cl= get_charset_by_name(db_cl_name, MYF(0));
1247
1248 if (!db_cl)
1249 return 1;
1250
1251 fprintf(sql_file,
1252 "ALTER DATABASE %s CHARACTER SET %s COLLATE %s %s\n",
1253 (const char *) quoted_db_name,
1254 (const char *) db_cl->csname,
1255 (const char *) db_cl->name,
1256 (const char *) delimiter);
1257
1258 return 0;
1259}
1260
1261
1262static void switch_cs_variables(FILE *sql_file,
1263 const char *delimiter,
1264 const char *character_set_client,
1265 const char *character_set_results,
1266 const char *collation_connection)
1267{
1268 fprintf(sql_file,
1269 "/*!50003 SET @saved_cs_client = @@character_set_client */ %s\n"
1270 "/*!50003 SET @saved_cs_results = @@character_set_results */ %s\n"
1271 "/*!50003 SET @saved_col_connection = @@collation_connection */ %s\n"
1272 "/*!50003 SET character_set_client = %s */ %s\n"
1273 "/*!50003 SET character_set_results = %s */ %s\n"
1274 "/*!50003 SET collation_connection = %s */ %s\n",
1275 (const char *) delimiter,
1276 (const char *) delimiter,
1277 (const char *) delimiter,
1278
1279 (const char *) character_set_client,
1280 (const char *) delimiter,
1281
1282 (const char *) character_set_results,
1283 (const char *) delimiter,
1284
1285 (const char *) collation_connection,
1286 (const char *) delimiter);
1287}
1288
1289
1290static void restore_cs_variables(FILE *sql_file,
1291 const char *delimiter)
1292{
1293 fprintf(sql_file,
1294 "/*!50003 SET character_set_client = @saved_cs_client */ %s\n"
1295 "/*!50003 SET character_set_results = @saved_cs_results */ %s\n"
1296 "/*!50003 SET collation_connection = @saved_col_connection */ %s\n",
1297 (const char *) delimiter,
1298 (const char *) delimiter,
1299 (const char *) delimiter);
1300}
1301
1302
1303static void switch_sql_mode(FILE *sql_file,
1304 const char *delimiter,
1305 const char *sql_mode)
1306{
1307 fprintf(sql_file,
1308 "/*!50003 SET @saved_sql_mode = @@sql_mode */ %s\n"
1309 "/*!50003 SET sql_mode = '%s' */ %s\n",
1310 (const char *) delimiter,
1311
1312 (const char *) sql_mode,
1313 (const char *) delimiter);
1314}
1315
1316
1317static void restore_sql_mode(FILE *sql_file,
1318 const char *delimiter)
1319{
1320 fprintf(sql_file,
1321 "/*!50003 SET sql_mode = @saved_sql_mode */ %s\n",
1322 (const char *) delimiter);
1323}
1324
1325
1326static void switch_time_zone(FILE *sql_file,
1327 const char *delimiter,
1328 const char *time_zone)
1329{
1330 fprintf(sql_file,
1331 "/*!50003 SET @saved_time_zone = @@time_zone */ %s\n"
1332 "/*!50003 SET time_zone = '%s' */ %s\n",
1333 (const char *) delimiter,
1334
1335 (const char *) time_zone,
1336 (const char *) delimiter);
1337}
1338
1339
1340static void restore_time_zone(FILE *sql_file,
1341 const char *delimiter)
1342{
1343 fprintf(sql_file,
1344 "/*!50003 SET time_zone = @saved_time_zone */ %s\n",
1345 (const char *) delimiter);
1346}
1347
1348
1349/**
1350 Switch charset for results to some specified charset. If the server does not
1351 support character_set_results variable, nothing can be done here. As for
1352 whether something should be done here, future new callers of this function
1353 should be aware that the server lacking the facility of switching charsets is
1354 treated as success.
1355
1356 @note If the server lacks support, then nothing is changed and no error
1357 condition is returned.
1358
1359 @returns whether there was an error or not
1360*/
1361static int switch_character_set_results(MYSQL *mysql, const char *cs_name)
1362{
1363 char query_buffer[QUERY_LENGTH];
1364 size_t query_length;
1365
1366 /* Server lacks facility. This is not an error, by arbitrary decision . */
1367 if (!server_supports_switching_charsets)
1368 return FALSE;
1369
1370 query_length= my_snprintf(query_buffer,
1371 sizeof (query_buffer),
1372 "SET SESSION character_set_results = '%s'",
1373 (const char *) cs_name);
1374
1375 return mysql_real_query(mysql, query_buffer, query_length);
1376}
1377
1378/**
1379 Rewrite statement, enclosing DEFINER clause in version-specific comment.
1380
1381 This function parses any CREATE statement and encloses DEFINER-clause in
1382 version-specific comment:
1383 input query: CREATE DEFINER=a@b FUNCTION ...
1384 rewritten query: CREATE * / / *!50020 DEFINER=a@b * / / *!50003 FUNCTION ...
1385
1386 @note This function will go away when WL#3995 is implemented.
1387
1388 @param[in] stmt_str CREATE statement string.
1389 @param[in] stmt_length Length of the stmt_str.
1390 @param[in] definer_version_str Minimal MySQL version number when
1391 DEFINER clause is supported in the
1392 given statement.
1393 @param[in] definer_version_length Length of definer_version_str.
1394 @param[in] stmt_version_str Minimal MySQL version number when the
1395 given statement is supported.
1396 @param[in] stmt_version_length Length of stmt_version_str.
1397 @param[in] keyword_str Keyword to look for after CREATE.
1398 @param[in] keyword_length Length of keyword_str.
1399
1400 @return pointer to the new allocated query string.
1401*/
1402
1403static char *cover_definer_clause(const char *stmt_str,
1404 uint stmt_length,
1405 const char *definer_version_str,
1406 uint definer_version_length,
1407 const char *stmt_version_str,
1408 uint stmt_version_length,
1409 const char *keyword_str,
1410 uint keyword_length)
1411{
1412 char *definer_begin= my_case_str(stmt_str, stmt_length,
1413 C_STRING_WITH_LEN(" DEFINER"));
1414 char *definer_end= NULL;
1415
1416 char *query_str= NULL;
1417 char *query_ptr;
1418
1419 if (!definer_begin)
1420 return NULL;
1421
1422 definer_end= my_case_str(definer_begin, strlen(definer_begin),
1423 keyword_str, keyword_length);
1424
1425 if (!definer_end)
1426 return NULL;
1427
1428 /*
1429 Allocate memory for new query string: original string
1430 from SHOW statement and version-specific comments.
1431 */
1432 query_str= alloc_query_str(stmt_length + 23);
1433
1434 query_ptr= strnmov(query_str, stmt_str, definer_begin - stmt_str);
1435 query_ptr= strnmov(query_ptr, C_STRING_WITH_LEN("*/ /*!"));
1436 query_ptr= strnmov(query_ptr, definer_version_str, definer_version_length);
1437 query_ptr= strnmov(query_ptr, definer_begin, definer_end - definer_begin);
1438 query_ptr= strnmov(query_ptr, C_STRING_WITH_LEN("*/ /*!"));
1439 query_ptr= strnmov(query_ptr, stmt_version_str, stmt_version_length);
1440 query_ptr= strxmov(query_ptr, definer_end, NullS);
1441
1442 return query_str;
1443}
1444
1445/*
1446 Open a new .sql file to dump the table or view into
1447
1448 SYNOPSIS
1449 open_sql_file_for_table
1450 name name of the table or view
1451 flags flags (as per "man 2 open")
1452
1453 RETURN VALUES
1454 0 Failed to open file
1455 > 0 Handle of the open file
1456*/
1457static FILE* open_sql_file_for_table(const char* table, int flags)
1458{
1459 FILE* res;
1460 char filename[FN_REFLEN], tmp_path[FN_REFLEN];
1461 convert_dirname(tmp_path,path,NullS);
1462 res= my_fopen(fn_format(filename, table, tmp_path, ".sql", 4),
1463 flags, MYF(MY_WME));
1464 return res;
1465}
1466
1467
1468static void free_resources()
1469{
1470 if (md_result_file && md_result_file != stdout)
1471 my_fclose(md_result_file, MYF(0));
1472 my_free(opt_password);
1473 if (my_hash_inited(&ignore_table))
1474 my_hash_free(&ignore_table);
1475 if (extended_insert)
1476 dynstr_free(&extended_row);
1477 if (insert_pat_inited)
1478 dynstr_free(&insert_pat);
1479 if (defaults_argv)
1480 free_defaults(defaults_argv);
1481 my_end(my_end_arg);
1482}
1483
1484
1485static void maybe_exit(int error)
1486{
1487 if (!first_error)
1488 first_error= error;
1489 if (ignore_errors)
1490 return;
1491 if (mysql)
1492 mysql_close(mysql);
1493 free_resources();
1494 exit(error);
1495}
1496
1497
1498/*
1499 db_connect -- connects to the host and selects DB.
1500*/
1501
1502static int connect_to_db(char *host, char *user,char *passwd)
1503{
1504 char buff[20+FN_REFLEN];
1505 DBUG_ENTER("connect_to_db");
1506
1507 verbose_msg("-- Connecting to %s...\n", host ? host : "localhost");
1508 mysql_init(&mysql_connection);
1509 if (opt_compress)
1510 mysql_options(&mysql_connection,MYSQL_OPT_COMPRESS,NullS);
1511#ifdef HAVE_OPENSSL
1512 if (opt_use_ssl)
1513 {
1514 mysql_ssl_set(&mysql_connection, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
1515 opt_ssl_capath, opt_ssl_cipher);
1516 mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
1517 mysql_options(&mysql_connection, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
1518 }
1519 mysql_options(&mysql_connection,MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
1520 (char*)&opt_ssl_verify_server_cert);
1521#endif
1522 if (opt_protocol)
1523 mysql_options(&mysql_connection,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
1524 if (opt_bind_addr)
1525 mysql_options(&mysql_connection,MYSQL_OPT_BIND,opt_bind_addr);
1526 if (!opt_secure_auth)
1527 mysql_options(&mysql_connection,MYSQL_SECURE_AUTH,(char*)&opt_secure_auth);
1528#ifdef HAVE_SMEM
1529 if (shared_memory_base_name)
1530 mysql_options(&mysql_connection,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
1531#endif
1532 mysql_options(&mysql_connection, MYSQL_SET_CHARSET_NAME, default_charset);
1533
1534 if (opt_plugin_dir && *opt_plugin_dir)
1535 mysql_options(&mysql_connection, MYSQL_PLUGIN_DIR, opt_plugin_dir);
1536
1537 if (opt_default_auth && *opt_default_auth)
1538 mysql_options(&mysql_connection, MYSQL_DEFAULT_AUTH, opt_default_auth);
1539
1540 mysql_options(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
1541 mysql_options4(&mysql_connection, MYSQL_OPT_CONNECT_ATTR_ADD,
1542 "program_name", "mysqldump");
1543 if (!(mysql= mysql_real_connect(&mysql_connection,host,user,passwd,
1544 NULL,opt_mysql_port,opt_mysql_unix_port,
1545 0)))
1546 {
1547 DB_error(&mysql_connection, "when trying to connect");
1548 DBUG_RETURN(1);
1549 }
1550 if ((mysql_get_server_version(&mysql_connection) < 40100) ||
1551 (opt_compatible_mode & 3))
1552 {
1553 /* Don't dump SET NAMES with a pre-4.1 server (bug#7997). */
1554 opt_set_charset= 0;
1555
1556 /* Don't switch charsets for 4.1 and earlier. (bug#34192). */
1557 server_supports_switching_charsets= FALSE;
1558 }
1559 /*
1560 As we're going to set SQL_MODE, it would be lost on reconnect, so we
1561 cannot reconnect.
1562 */
1563 mysql->reconnect= 0;
1564 my_snprintf(buff, sizeof(buff), "/*!40100 SET @@SQL_MODE='%s' */",
1565 compatible_mode_normal_str);
1566 if (mysql_query_with_error_report(mysql, 0, buff))
1567 DBUG_RETURN(1);
1568 /*
1569 set time_zone to UTC to allow dumping date types between servers with
1570 different time zone settings
1571 */
1572 if (opt_tz_utc)
1573 {
1574 my_snprintf(buff, sizeof(buff), "/*!40103 SET TIME_ZONE='+00:00' */");
1575 if (mysql_query_with_error_report(mysql, 0, buff))
1576 DBUG_RETURN(1);
1577 }
1578 DBUG_RETURN(0);
1579} /* connect_to_db */
1580
1581
1582/*
1583** dbDisconnect -- disconnects from the host.
1584*/
1585static void dbDisconnect(char *host)
1586{
1587 verbose_msg("-- Disconnecting from %s...\n", host ? host : "localhost");
1588 mysql_close(mysql);
1589} /* dbDisconnect */
1590
1591
1592static void unescape(FILE *file,char *pos,uint length)
1593{
1594 char *tmp;
1595 DBUG_ENTER("unescape");
1596 if (!(tmp=(char*) my_malloc(length*2+1, MYF(MY_WME))))
1597 die(EX_MYSQLERR, "Couldn't allocate memory");
1598
1599 mysql_real_escape_string(&mysql_connection, tmp, pos, length);
1600 fputc('\'', file);
1601 fputs(tmp, file);
1602 fputc('\'', file);
1603 check_io(file);
1604 my_free(tmp);
1605 DBUG_VOID_RETURN;
1606} /* unescape */
1607
1608
1609static my_bool test_if_special_chars(const char *str)
1610{
1611#if MYSQL_VERSION_ID >= 32300
1612 for ( ; *str ; str++)
1613 if (!my_isvar(charset_info,*str) && *str != '$')
1614 return 1;
1615#endif
1616 return 0;
1617} /* test_if_special_chars */
1618
1619
1620
1621/*
1622 quote_name(name, buff, force)
1623
1624 Quotes char string, taking into account compatible mode
1625
1626 Args
1627
1628 name Unquoted string containing that which will be quoted
1629 buff The buffer that contains the quoted value, also returned
1630 force Flag to make it ignore 'test_if_special_chars'
1631
1632 Returns
1633
1634 buff quoted string
1635
1636*/
1637static char *quote_name(const char *name, char *buff, my_bool force)
1638{
1639 char *to= buff;
1640 char qtype= (opt_compatible_mode & MASK_ANSI_QUOTES) ? '\"' : '`';
1641
1642 if (!force && !opt_quoted && !test_if_special_chars(name))
1643 return (char*) name;
1644 *to++= qtype;
1645 while (*name)
1646 {
1647 if (*name == qtype)
1648 *to++= qtype;
1649 *to++= *name++;
1650 }
1651 to[0]= qtype;
1652 to[1]= 0;
1653 return buff;
1654} /* quote_name */
1655
1656
1657/*
1658 Quote a table name so it can be used in "SHOW TABLES LIKE <tabname>"
1659
1660 SYNOPSIS
1661 quote_for_like()
1662 name name of the table
1663 buff quoted name of the table
1664
1665 DESCRIPTION
1666 Quote \, _, ' and % characters
1667
1668 Note: Because MySQL uses the C escape syntax in strings
1669 (for example, '\n' to represent newline), you must double
1670 any '\' that you use in your LIKE strings. For example, to
1671 search for '\n', specify it as '\\n'. To search for '\', specify
1672 it as '\\\\' (the backslashes are stripped once by the parser
1673 and another time when the pattern match is done, leaving a
1674 single backslash to be matched).
1675
1676 Example: "t\1" => "t\\\\1"
1677
1678*/
1679static char *quote_for_like(const char *name, char *buff)
1680{
1681 char *to= buff;
1682 *to++= '\'';
1683 while (*name)
1684 {
1685 if (*name == '\\')
1686 {
1687 *to++='\\';
1688 *to++='\\';
1689 *to++='\\';
1690 }
1691 else if (*name == '\'' || *name == '_' || *name == '%')
1692 *to++= '\\';
1693 *to++= *name++;
1694 }
1695 to[0]= '\'';
1696 to[1]= 0;
1697 return buff;
1698}
1699
1700
1701/**
1702 Quote and print a string.
1703
1704 @param xml_file - Output file.
1705 @param str - String to print.
1706 @param len - Its length.
1707 @param is_attribute_name - A check for attribute name or value.
1708
1709 @description
1710 Quote '<' '>' '&' '\"' chars and print a string to the xml_file.
1711*/
1712
1713static void print_quoted_xml(FILE *xml_file, const char *str, ulong len,
1714 my_bool is_attribute_name)
1715{
1716 const char *end;
1717
1718 for (end= str + len; str != end; str++)
1719 {
1720 switch (*str) {
1721 case '<':
1722 fputs("<", xml_file);
1723 break;
1724 case '>':
1725 fputs(">", xml_file);
1726 break;
1727 case '&':
1728 fputs("&", xml_file);
1729 break;
1730 case '\"':
1731 fputs(""", xml_file);
1732 break;
1733 case ' ':
1734 /* Attribute names cannot contain spaces. */
1735 if (is_attribute_name)
1736 {
1737 fputs("_", xml_file);
1738 break;
1739 }
1740 /* fall through */
1741 default:
1742 fputc(*str, xml_file);
1743 break;
1744 }
1745 }
1746 check_io(xml_file);
1747}
1748
1749
1750/*
1751 Print xml tag. Optionally add attribute(s).
1752
1753 SYNOPSIS
1754 print_xml_tag(xml_file, sbeg, send, tag_name, first_attribute_name,
1755 ..., attribute_name_n, attribute_value_n, NullS)
1756 xml_file - output file
1757 sbeg - line beginning
1758 line_end - line ending
1759 tag_name - XML tag name.
1760 first_attribute_name - tag and first attribute
1761 first_attribute_value - (Implied) value of first attribute
1762 attribute_name_n - attribute n
1763 attribute_value_n - value of attribute n
1764
1765 DESCRIPTION
1766 Print XML tag with any number of attribute="value" pairs to the xml_file.
1767
1768 Format is:
1769 sbeg<tag_name first_attribute_name="first_attribute_value" ...
1770 attribute_name_n="attribute_value_n">send
1771 NOTE
1772 Additional arguments must be present in attribute/value pairs.
1773 The last argument should be the null character pointer.
1774 All attribute_value arguments MUST be NULL terminated strings.
1775 All attribute_value arguments will be quoted before output.
1776*/
1777
1778static void print_xml_tag(FILE * xml_file, const char* sbeg,
1779 const char* line_end,
1780 const char* tag_name,
1781 const char* first_attribute_name, ...)
1782{
1783 va_list arg_list;
1784 const char *attribute_name, *attribute_value;
1785
1786 fputs(sbeg, xml_file);
1787 fputc('<', xml_file);
1788 fputs(tag_name, xml_file);
1789
1790 va_start(arg_list, first_attribute_name);
1791 attribute_name= first_attribute_name;
1792 while (attribute_name != NullS)
1793 {
1794 attribute_value= va_arg(arg_list, char *);
1795 DBUG_ASSERT(attribute_value != NullS);
1796
1797 fputc(' ', xml_file);
1798 fputs(attribute_name, xml_file);
1799 fputc('\"', xml_file);
1800
1801 print_quoted_xml(xml_file, attribute_value, strlen(attribute_value), 0);
1802 fputc('\"', xml_file);
1803
1804 attribute_name= va_arg(arg_list, char *);
1805 }
1806 va_end(arg_list);
1807
1808 fputc('>', xml_file);
1809 fputs(line_end, xml_file);
1810 check_io(xml_file);
1811}
1812
1813
1814/*
1815 Print xml tag with for a field that is null
1816
1817 SYNOPSIS
1818 print_xml_null_tag()
1819 xml_file - output file
1820 sbeg - line beginning
1821 stag_atr - tag and attribute
1822 sval - value of attribute
1823 line_end - line ending
1824
1825 DESCRIPTION
1826 Print tag with one attribute to the xml_file. Format is:
1827 <stag_atr="sval" xsi:nil="true"/>
1828 NOTE
1829 sval MUST be a NULL terminated string.
1830 sval string will be qouted before output.
1831*/
1832
1833static void print_xml_null_tag(FILE * xml_file, const char* sbeg,
1834 const char* stag_atr, const char* sval,
1835 const char* line_end)
1836{
1837 fputs(sbeg, xml_file);
1838 fputs("<", xml_file);
1839 fputs(stag_atr, xml_file);
1840 fputs("\"", xml_file);
1841 print_quoted_xml(xml_file, sval, strlen(sval), 0);
1842 fputs("\" xsi:nil=\"true\" />", xml_file);
1843 fputs(line_end, xml_file);
1844 check_io(xml_file);
1845}
1846
1847
1848/**
1849 Print xml CDATA section.
1850
1851 @param xml_file - output file
1852 @param str - string to print
1853 @param len - length of the string
1854
1855 @note
1856 This function also takes care of the presence of '[[>'
1857 string in the str. If found, the CDATA section is broken
1858 into two CDATA sections, <![CDATA[]]]]> and <![CDATA[>]].
1859*/
1860
1861static void print_xml_cdata(FILE *xml_file, const char *str, ulong len)
1862{
1863 const char *end;
1864
1865 fputs("<![CDATA[\n", xml_file);
1866 for (end= str + len; str != end; str++)
1867 {
1868 switch(*str) {
1869 case ']':
1870 if ((*(str + 1) == ']') && (*(str + 2) =='>'))
1871 {
1872 fputs("]]]]><![CDATA[>", xml_file);
1873 str += 2;
1874 continue;
1875 }
1876 /* fall through */
1877 default:
1878 fputc(*str, xml_file);
1879 break;
1880 }
1881 }
1882 fputs("\n]]>\n", xml_file);
1883 check_io(xml_file);
1884}
1885
1886
1887/*
1888 Print xml tag with many attributes.
1889
1890 SYNOPSIS
1891 print_xml_row()
1892 xml_file - output file
1893 row_name - xml tag name
1894 tableRes - query result
1895 row - result row
1896 str_create - create statement header string
1897
1898 DESCRIPTION
1899 Print tag with many attribute to the xml_file. Format is:
1900 \t\t<row_name Atr1="Val1" Atr2="Val2"... />
1901 NOTE
1902 All atributes and values will be quoted before output.
1903*/
1904
1905static void print_xml_row(FILE *xml_file, const char *row_name,
1906 MYSQL_RES *tableRes, MYSQL_ROW *row,
1907 const char *str_create)
1908{
1909 uint i;
1910 my_bool body_found __attribute__((unused)) = 0;
1911 char *create_stmt_ptr= NULL;
1912 ulong create_stmt_len= 0;
1913 MYSQL_FIELD *field;
1914 ulong *lengths= mysql_fetch_lengths(tableRes);
1915
1916 fprintf(xml_file, "\t\t<%s", row_name);
1917 check_io(xml_file);
1918 mysql_field_seek(tableRes, 0);
1919 for (i= 0; (field= mysql_fetch_field(tableRes)); i++)
1920 {
1921 if ((*row)[i])
1922 {
1923 /* For 'create' statements, dump using CDATA. */
1924 if ((str_create) && (strcmp(str_create, field->name) == 0))
1925 {
1926 create_stmt_ptr= (*row)[i];
1927 create_stmt_len= lengths[i];
1928 body_found= 1;
1929 }
1930 else
1931 {
1932 fputc(' ', xml_file);
1933 print_quoted_xml(xml_file, field->name, field->name_length, 1);
1934 fputs("=\"", xml_file);
1935 print_quoted_xml(xml_file, (*row)[i], lengths[i], 0);
1936 fputc('"', xml_file);
1937 check_io(xml_file);
1938 }
1939 }
1940 }
1941
1942 if (create_stmt_len)
1943 {
1944 DBUG_ASSERT(body_found);
1945 fputs(">\n", xml_file);
1946 print_xml_cdata(xml_file, create_stmt_ptr, create_stmt_len);
1947 fprintf(xml_file, "\t\t</%s>\n", row_name);
1948 }
1949 else
1950 fputs(" />\n", xml_file);
1951
1952 check_io(xml_file);
1953}
1954
1955
1956/**
1957 Print xml comments.
1958
1959 @param xml_file - output file
1960 @param len - length of comment message
1961 @param comment_string - comment message
1962
1963 @description
1964 Print the comment message in the format:
1965 "<!-- \n comment string \n -->\n"
1966
1967 @note
1968 Any occurrence of continuous hyphens will be
1969 squeezed to a single hyphen.
1970*/
1971
1972static void print_xml_comment(FILE *xml_file, ulong len,
1973 const char *comment_string)
1974{
1975 const char* end;
1976
1977 fputs("<!-- ", xml_file);
1978
1979 for (end= comment_string + len; comment_string != end; comment_string++)
1980 {
1981 /*
1982 The string "--" (double-hyphen) MUST NOT occur within xml comments.
1983 */
1984 switch (*comment_string) {
1985 case '-':
1986 if (*(comment_string + 1) == '-') /* Only one hyphen allowed. */
1987 break;
1988 default:
1989 fputc(*comment_string, xml_file);
1990 break;
1991 }
1992 }
1993 fputs(" -->\n", xml_file);
1994 check_io(xml_file);
1995}
1996
1997
1998
1999/* A common printing function for xml and non-xml modes. */
2000
2001static void print_comment(FILE *sql_file, my_bool is_error, const char *format,
2002 ...)
2003{
2004 static char comment_buff[COMMENT_LENGTH];
2005 va_list args;
2006
2007 /* If its an error message, print it ignoring opt_comments. */
2008 if (!is_error && !opt_comments)
2009 return;
2010
2011 va_start(args, format);
2012 my_vsnprintf(comment_buff, COMMENT_LENGTH, format, args);
2013 va_end(args);
2014
2015 if (!opt_xml)
2016 {
2017 fputs(comment_buff, sql_file);
2018 check_io(sql_file);
2019 return;
2020 }
2021
2022 print_xml_comment(sql_file, strlen(comment_buff), comment_buff);
2023}
2024
2025
2026/*
2027 create_delimiter
2028 Generate a new (null-terminated) string that does not exist in query
2029 and is therefore suitable for use as a query delimiter. Store this
2030 delimiter in delimiter_buff .
2031
2032 This is quite simple in that it doesn't even try to parse statements as an
2033 interpreter would. It merely returns a string that is not in the query, which
2034 is much more than adequate for constructing a delimiter.
2035
2036 RETURN
2037 ptr to the delimiter on Success
2038 NULL on Failure
2039*/
2040static char *create_delimiter(char *query, char *delimiter_buff,
2041 int delimiter_max_size)
2042{
2043 int proposed_length;
2044 char *presence;
2045
2046 delimiter_buff[0]= ';'; /* start with one semicolon, and */
2047
2048 for (proposed_length= 2; proposed_length < delimiter_max_size;
2049 delimiter_max_size++) {
2050
2051 delimiter_buff[proposed_length-1]= ';'; /* add semicolons, until */
2052 delimiter_buff[proposed_length]= '\0';
2053
2054 presence = strstr(query, delimiter_buff);
2055 if (presence == NULL) { /* the proposed delimiter is not in the query. */
2056 return delimiter_buff;
2057 }
2058
2059 }
2060 return NULL; /* but if we run out of space, return nothing at all. */
2061}
2062
2063
2064/*
2065 dump_events_for_db
2066 -- retrieves list of events for a given db, and prints out
2067 the CREATE EVENT statement into the output (the dump).
2068
2069 RETURN
2070 0 Success
2071 1 Error
2072*/
2073static uint dump_events_for_db(char *db)
2074{
2075 char query_buff[QUERY_LENGTH];
2076 char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
2077 char *event_name;
2078 char delimiter[QUERY_LENGTH];
2079 FILE *sql_file= md_result_file;
2080 MYSQL_RES *event_res, *event_list_res;
2081 MYSQL_ROW row, event_list_row;
2082
2083 char db_cl_name[MY_CS_NAME_SIZE];
2084 int db_cl_altered= FALSE;
2085
2086 DBUG_ENTER("dump_events_for_db");
2087 DBUG_PRINT("enter", ("db: '%s'", db));
2088
2089 mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
2090
2091 /* nice comments */
2092 print_comment(sql_file, 0,
2093 "\n--\n-- Dumping events for database '%s'\n--\n", db);
2094
2095 /*
2096 not using "mysql_query_with_error_report" because we may have not
2097 enough privileges to lock mysql.events.
2098 */
2099 if (lock_tables)
2100 mysql_query(mysql, "LOCK TABLES mysql.event READ");
2101
2102 if (mysql_query_with_error_report(mysql, &event_list_res, "show events"))
2103 DBUG_RETURN(0);
2104
2105 strcpy(delimiter, ";");
2106 if (mysql_num_rows(event_list_res) > 0)
2107 {
2108 if (opt_xml)
2109 fputs("\t<events>\n", sql_file);
2110 else
2111 {
2112 fprintf(sql_file, "/*!50106 SET @save_time_zone= @@TIME_ZONE */ ;\n");
2113
2114 /* Get database collation. */
2115
2116 if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
2117 DBUG_RETURN(1);
2118 }
2119
2120 if (switch_character_set_results(mysql, "binary"))
2121 DBUG_RETURN(1);
2122
2123 while ((event_list_row= mysql_fetch_row(event_list_res)) != NULL)
2124 {
2125 event_name= quote_name(event_list_row[1], name_buff, 0);
2126 DBUG_PRINT("info", ("retrieving CREATE EVENT for %s", name_buff));
2127 my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE EVENT %s",
2128 event_name);
2129
2130 if (mysql_query_with_error_report(mysql, &event_res, query_buff))
2131 DBUG_RETURN(1);
2132
2133 while ((row= mysql_fetch_row(event_res)) != NULL)
2134 {
2135 if (opt_xml)
2136 {
2137 print_xml_row(sql_file, "event", event_res, &row,
2138 "Create Event");
2139 continue;
2140 }
2141
2142 /*
2143 if the user has EXECUTE privilege he can see event names, but not the
2144 event body!
2145 */
2146 if (strlen(row[3]) != 0)
2147 {
2148 char *query_str;
2149
2150 if (opt_drop)
2151 fprintf(sql_file, "/*!50106 DROP EVENT IF EXISTS %s */%s\n",
2152 event_name, delimiter);
2153
2154 if (create_delimiter(row[3], delimiter, sizeof(delimiter)) == NULL)
2155 {
2156 fprintf(stderr, "%s: Warning: Can't create delimiter for event '%s'\n",
2157 my_progname, event_name);
2158 DBUG_RETURN(1);
2159 }
2160
2161 fprintf(sql_file, "DELIMITER %s\n", delimiter);
2162
2163 if (mysql_num_fields(event_res) >= 7)
2164 {
2165 if (switch_db_collation(sql_file, db_name_buff, delimiter,
2166 db_cl_name, row[6], &db_cl_altered))
2167 {
2168 DBUG_RETURN(1);
2169 }
2170
2171 switch_cs_variables(sql_file, delimiter,
2172 row[4], /* character_set_client */
2173 row[4], /* character_set_results */
2174 row[5]); /* collation_connection */
2175 }
2176 else
2177 {
2178 /*
2179 mysqldump is being run against the server, that does not
2180 provide character set information in SHOW CREATE
2181 statements.
2182
2183 NOTE: the dump may be incorrect, since character set
2184 information is required in order to restore event properly.
2185 */
2186
2187 fprintf(sql_file,
2188 "--\n"
2189 "-- WARNING: old server version. "
2190 "The following dump may be incomplete.\n"
2191 "--\n");
2192 }
2193
2194 switch_sql_mode(sql_file, delimiter, row[1]);
2195
2196 switch_time_zone(sql_file, delimiter, row[2]);
2197
2198 query_str= cover_definer_clause(row[3], strlen(row[3]),
2199 C_STRING_WITH_LEN("50117"),
2200 C_STRING_WITH_LEN("50106"),
2201 C_STRING_WITH_LEN(" EVENT"));
2202
2203 fprintf(sql_file,
2204 "/*!50106 %s */ %s\n",
2205 (const char *) (query_str != NULL ? query_str : row[3]),
2206 (const char *) delimiter);
2207
2208 restore_time_zone(sql_file, delimiter);
2209 restore_sql_mode(sql_file, delimiter);
2210
2211 if (mysql_num_fields(event_res) >= 7)
2212 {
2213 restore_cs_variables(sql_file, delimiter);
2214
2215 if (db_cl_altered)
2216 {
2217 if (restore_db_collation(sql_file, db_name_buff, delimiter,
2218 db_cl_name))
2219 DBUG_RETURN(1);
2220 }
2221 }
2222 }
2223 } /* end of event printing */
2224 mysql_free_result(event_res);
2225
2226 } /* end of list of events */
2227 if (opt_xml)
2228 {
2229 fputs("\t</events>\n", sql_file);
2230 check_io(sql_file);
2231 }
2232 else
2233 {
2234 fprintf(sql_file, "DELIMITER ;\n");
2235 fprintf(sql_file, "/*!50106 SET TIME_ZONE= @save_time_zone */ ;\n");
2236 }
2237
2238 if (switch_character_set_results(mysql, default_charset))
2239 DBUG_RETURN(1);
2240 }
2241 mysql_free_result(event_list_res);
2242
2243 if (lock_tables)
2244 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
2245 DBUG_RETURN(0);
2246}
2247
2248
2249/*
2250 Print hex value for blob data.
2251
2252 SYNOPSIS
2253 print_blob_as_hex()
2254 output_file - output file
2255 str - string to print
2256 len - its length
2257
2258 DESCRIPTION
2259 Print hex value for blob data.
2260*/
2261
2262static void print_blob_as_hex(FILE *output_file, const char *str, ulong len)
2263{
2264 /* sakaik got the idea to to provide blob's in hex notation. */
2265 const char *ptr= str, *end= ptr + len;
2266 for (; ptr < end ; ptr++)
2267 fprintf(output_file, "%02X", *((uchar *)ptr));
2268 check_io(output_file);
2269}
2270
2271/*
2272 dump_routines_for_db
2273 -- retrieves list of routines for a given db, and prints out
2274 the CREATE PROCEDURE definition into the output (the dump).
2275
2276 This function has logic to print the appropriate syntax depending on whether
2277 this is a procedure or functions
2278
2279 RETURN
2280 0 Success
2281 1 Error
2282*/
2283
2284static uint dump_routines_for_db(char *db)
2285{
2286 char query_buff[QUERY_LENGTH];
2287 const char *routine_type[]= {"FUNCTION", "PROCEDURE"};
2288 char db_name_buff[NAME_LEN*2+3], name_buff[NAME_LEN*2+3];
2289 char *routine_name;
2290 int i;
2291 FILE *sql_file= md_result_file;
2292 MYSQL_RES *routine_res, *routine_list_res;
2293 MYSQL_ROW row, routine_list_row;
2294
2295 char db_cl_name[MY_CS_NAME_SIZE];
2296 int db_cl_altered= FALSE;
2297
2298 DBUG_ENTER("dump_routines_for_db");
2299 DBUG_PRINT("enter", ("db: '%s'", db));
2300
2301 mysql_real_escape_string(mysql, db_name_buff, db, strlen(db));
2302
2303 /* nice comments */
2304 print_comment(sql_file, 0,
2305 "\n--\n-- Dumping routines for database '%s'\n--\n", db);
2306
2307 /*
2308 not using "mysql_query_with_error_report" because we may have not
2309 enough privileges to lock mysql.proc.
2310 */
2311 if (lock_tables)
2312 mysql_query(mysql, "LOCK TABLES mysql.proc READ");
2313
2314 /* Get database collation. */
2315
2316 if (fetch_db_collation(db_name_buff, db_cl_name, sizeof (db_cl_name)))
2317 DBUG_RETURN(1);
2318
2319 if (switch_character_set_results(mysql, "binary"))
2320 DBUG_RETURN(1);
2321
2322 if (opt_xml)
2323 fputs("\t<routines>\n", sql_file);
2324
2325 /* 0, retrieve and dump functions, 1, procedures */
2326 for (i= 0; i <= 1; i++)
2327 {
2328 my_snprintf(query_buff, sizeof(query_buff),
2329 "SHOW %s STATUS WHERE Db = '%s'",
2330 routine_type[i], db_name_buff);
2331
2332 if (mysql_query_with_error_report(mysql, &routine_list_res, query_buff))
2333 DBUG_RETURN(1);
2334
2335 if (mysql_num_rows(routine_list_res))
2336 {
2337
2338 while ((routine_list_row= mysql_fetch_row(routine_list_res)))
2339 {
2340 routine_name= quote_name(routine_list_row[1], name_buff, 0);
2341 DBUG_PRINT("info", ("retrieving CREATE %s for %s", routine_type[i],
2342 name_buff));
2343 my_snprintf(query_buff, sizeof(query_buff), "SHOW CREATE %s %s",
2344 routine_type[i], routine_name);
2345
2346 if (mysql_query_with_error_report(mysql, &routine_res, query_buff))
2347 DBUG_RETURN(1);
2348
2349 while ((row= mysql_fetch_row(routine_res)))
2350 {
2351 /*
2352 if the user has EXECUTE privilege he see routine names, but NOT the
2353 routine body of other routines that are not the creator of!
2354 */
2355 DBUG_PRINT("info",("length of body for %s row[2] '%s' is %d",
2356 routine_name, row[2] ? row[2] : "(null)",
2357 row[2] ? (int) strlen(row[2]) : 0));
2358 if (row[2] == NULL)
2359 {
2360 print_comment(sql_file, 1, "\n-- insufficient privileges to %s\n",
2361 query_buff);
2362 print_comment(sql_file, 1,
2363 "-- does %s have permissions on mysql.proc?\n\n",
2364 current_user);
2365 maybe_die(EX_MYSQLERR,"%s has insufficent privileges to %s!", current_user, query_buff);
2366 }
2367 else if (strlen(row[2]))
2368 {
2369 if (opt_xml)
2370 {
2371 if (i) // Procedures.
2372 print_xml_row(sql_file, "routine", routine_res, &row,
2373 "Create Procedure");
2374 else // Functions.
2375 print_xml_row(sql_file, "routine", routine_res, &row,
2376 "Create Function");
2377 continue;
2378 }
2379 if (opt_drop)
2380 fprintf(sql_file, "/*!50003 DROP %s IF EXISTS %s */;\n",
2381 routine_type[i], routine_name);
2382
2383 if (mysql_num_fields(routine_res) >= 6)
2384 {
2385 if (switch_db_collation(sql_file, db_name_buff, ";",
2386 db_cl_name, row[5], &db_cl_altered))
2387 {
2388 DBUG_RETURN(1);
2389 }
2390
2391 switch_cs_variables(sql_file, ";",
2392 row[3], /* character_set_client */
2393 row[3], /* character_set_results */
2394 row[4]); /* collation_connection */
2395 }
2396 else
2397 {
2398 /*
2399 mysqldump is being run against the server, that does not
2400 provide character set information in SHOW CREATE
2401 statements.
2402
2403 NOTE: the dump may be incorrect, since character set
2404 information is required in order to restore stored
2405 procedure/function properly.
2406 */
2407
2408 fprintf(sql_file,
2409 "--\n"
2410 "-- WARNING: old server version. "
2411 "The following dump may be incomplete.\n"
2412 "--\n");
2413 }
2414
2415
2416 switch_sql_mode(sql_file, ";", row[1]);
2417
2418 fprintf(sql_file,
2419 "DELIMITER ;;\n"
2420 "%s ;;\n"
2421 "DELIMITER ;\n",
2422 (const char *) row[2]);
2423
2424 restore_sql_mode(sql_file, ";");
2425
2426 if (mysql_num_fields(routine_res) >= 6)
2427 {
2428 restore_cs_variables(sql_file, ";");
2429
2430 if (db_cl_altered)
2431 {
2432 if (restore_db_collation(sql_file, db_name_buff, ";", db_cl_name))
2433 DBUG_RETURN(1);
2434 }
2435 }
2436
2437 }
2438 } /* end of routine printing */
2439 mysql_free_result(routine_res);
2440
2441 } /* end of list of routines */
2442 }
2443 mysql_free_result(routine_list_res);
2444 } /* end of for i (0 .. 1) */
2445
2446 if (opt_xml)
2447 {
2448 fputs("\t</routines>\n", sql_file);
2449 check_io(sql_file);
2450 }
2451
2452 if (switch_character_set_results(mysql, default_charset))
2453 DBUG_RETURN(1);
2454
2455 if (lock_tables)
2456 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
2457 DBUG_RETURN(0);
2458}
2459
2460/* general_log or slow_log tables under mysql database */
2461static inline my_bool general_log_or_slow_log_tables(const char *db,
2462 const char *table)
2463{
2464 return (!my_strcasecmp(charset_info, db, "mysql")) &&
2465 (!my_strcasecmp(charset_info, table, "general_log") ||
2466 !my_strcasecmp(charset_info, table, "slow_log"));
2467}
2468
2469/*
2470 get_table_structure -- retrievs database structure, prints out corresponding
2471 CREATE statement and fills out insert_pat if the table is the type we will
2472 be dumping.
2473
2474 ARGS
2475 table - table name
2476 db - db name
2477 table_type - table type, e.g. "MyISAM" or "InnoDB", but also "VIEW"
2478 ignore_flag - what we must particularly ignore - see IGNORE_ defines above
2479
2480 RETURN
2481 number of fields in table, 0 if error
2482*/
2483
2484static uint get_table_structure(char *table, char *db, char *table_type,
2485 char *ignore_flag)
2486{
2487 my_bool init=0, delayed, write_data, complete_insert;
2488 my_ulonglong num_fields;
2489 char *result_table, *opt_quoted_table;
2490 const char *insert_option;
2491 char name_buff[NAME_LEN+3],table_buff[NAME_LEN*2+3];
2492 char table_buff2[NAME_LEN*2+3], query_buff[QUERY_LENGTH];
2493 const char *show_fields_stmt= "SELECT `COLUMN_NAME` AS `Field`, "
2494 "`COLUMN_TYPE` AS `Type`, "
2495 "`IS_NULLABLE` AS `Null`, "
2496 "`COLUMN_KEY` AS `Key`, "
2497 "`COLUMN_DEFAULT` AS `Default`, "
2498 "`EXTRA` AS `Extra`, "
2499 "`COLUMN_COMMENT` AS `Comment` "
2500 "FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE "
2501 "TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'";
2502 FILE *sql_file= md_result_file;
2503 int len;
2504 my_bool is_log_table;
2505 MYSQL_RES *result;
2506 MYSQL_ROW row;
2507 DBUG_ENTER("get_table_structure");
2508 DBUG_PRINT("enter", ("db: %s table: %s", db, table));
2509
2510 *ignore_flag= check_if_ignore_table(table, table_type);
2511
2512 delayed= opt_delayed;
2513 if (delayed && (*ignore_flag & IGNORE_INSERT_DELAYED))
2514 {
2515 delayed= 0;
2516 verbose_msg("-- Warning: Unable to use delayed inserts for table '%s' "
2517 "because it's of type %s\n", table, table_type);
2518 }
2519
2520 complete_insert= 0;
2521 if ((write_data= !(*ignore_flag & IGNORE_DATA)))
2522 {
2523 complete_insert= opt_complete_insert;
2524 if (!insert_pat_inited)
2525 {
2526 insert_pat_inited= 1;
2527 init_dynamic_string_checked(&insert_pat, "", 1024, 1024);
2528 }
2529 else
2530 dynstr_set_checked(&insert_pat, "");
2531 }
2532
2533 insert_option= ((delayed && opt_ignore) ? " DELAYED IGNORE " :
2534 delayed ? " DELAYED " : opt_ignore ? " IGNORE " : "");
2535
2536 verbose_msg("-- Retrieving table structure for table %s...\n", table);
2537
2538 len= my_snprintf(query_buff, sizeof(query_buff),
2539 "SET SQL_QUOTE_SHOW_CREATE=%d",
2540 (opt_quoted || opt_keywords));
2541 if (!create_options)
2542 strmov(query_buff+len,
2543 "/*!40102 ,SQL_MODE=concat(@@sql_mode, _utf8 ',NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS') */");
2544
2545 result_table= quote_name(table, table_buff, 1);
2546 opt_quoted_table= quote_name(table, table_buff2, 0);
2547
2548 if (opt_order_by_primary)
2549 order_by= primary_key_fields(result_table);
2550
2551 if (!opt_xml && !mysql_query_with_error_report(mysql, 0, query_buff))
2552 {
2553 /* using SHOW CREATE statement */
2554 if (!opt_no_create_info)
2555 {
2556 /* Make an sql-file, if path was given iow. option -T was given */
2557 char buff[20+FN_REFLEN];
2558 MYSQL_FIELD *field;
2559
2560 my_snprintf(buff, sizeof(buff), "show create table %s", result_table);
2561
2562 if (switch_character_set_results(mysql, "binary") ||
2563 mysql_query_with_error_report(mysql, &result, buff) ||
2564 switch_character_set_results(mysql, default_charset))
2565 DBUG_RETURN(0);
2566
2567 if (path)
2568 {
2569 if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
2570 DBUG_RETURN(0);
2571
2572 write_header(sql_file, db);
2573 }
2574
2575 if (strcmp (table_type, "VIEW") == 0) /* view */
2576 print_comment(sql_file, 0,
2577 "\n--\n-- Temporary view structure for view %s\n--\n\n",
2578 result_table);
2579 else
2580 print_comment(sql_file, 0,
2581 "\n--\n-- Table structure for table %s\n--\n\n",
2582 result_table);
2583
2584 if (opt_drop)
2585 {
2586 /*
2587 Even if the "table" is a view, we do a DROP TABLE here. The
2588 view-specific code below fills in the DROP VIEW.
2589 We will skip the DROP TABLE for general_log and slow_log, since
2590 those stmts will fail, in case we apply dump by enabling logging.
2591 */
2592 if (!general_log_or_slow_log_tables(db, table))
2593 fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",
2594 opt_quoted_table);
2595 check_io(sql_file);
2596 }
2597
2598 field= mysql_fetch_field_direct(result, 0);
2599 if (strcmp(field->name, "View") == 0)
2600 {
2601 char *scv_buff= NULL;
2602 my_ulonglong n_cols;
2603
2604 verbose_msg("-- It's a view, create dummy view\n");
2605
2606 /* save "show create" statement for later */
2607 if ((row= mysql_fetch_row(result)) && (scv_buff=row[1]))
2608 scv_buff= my_strdup(scv_buff, MYF(0));
2609
2610 mysql_free_result(result);
2611
2612 /*
2613 Create a table with the same name as the view and with columns of
2614 the same name in order to satisfy views that depend on this view.
2615 The table will be removed when the actual view is created.
2616
2617 The properties of each column, are not preserved in this temporary
2618 table, because they are not necessary.
2619
2620 This will not be necessary once we can determine dependencies
2621 between views and can simply dump them in the appropriate order.
2622 */
2623 my_snprintf(query_buff, sizeof(query_buff),
2624 "SHOW FIELDS FROM %s", result_table);
2625 if (switch_character_set_results(mysql, "binary") ||
2626 mysql_query_with_error_report(mysql, &result, query_buff) ||
2627 switch_character_set_results(mysql, default_charset))
2628 {
2629 /*
2630 View references invalid or privileged table/col/fun (err 1356),
2631 so we cannot create a stand-in table. Be defensive and dump
2632 a comment with the view's 'show create' statement. (Bug #17371)
2633 */
2634
2635 if (mysql_errno(mysql) == ER_VIEW_INVALID)
2636 fprintf(sql_file, "\n-- failed on view %s: %s\n\n", result_table, scv_buff ? scv_buff : "");
2637
2638 my_free(scv_buff);
2639
2640 DBUG_RETURN(0);
2641 }
2642 else
2643 my_free(scv_buff);
2644
2645 n_cols= mysql_num_rows(result);
2646 if (0 != n_cols)
2647 {
2648
2649 /*
2650 The actual formula is based on the column names and how the .FRM
2651 files are stored and is too volatile to be repeated here.
2652 Thus we simply warn the user if the columns exceed a limit we
2653 know works most of the time.
2654 */
2655 if (n_cols >= 1000)
2656 fprintf(stderr,
2657 "-- Warning: Creating a stand-in table for view %s may"
2658 " fail when replaying the dump file produced because "
2659 "of the number of columns exceeding 1000. Exercise "
2660 "caution when replaying the produced dump file.\n",
2661 table);
2662 if (opt_drop)
2663 {
2664 /*
2665 We have already dropped any table of the same name above, so
2666 here we just drop the view.
2667 */
2668
2669 fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n",
2670 opt_quoted_table);
2671 check_io(sql_file);
2672 }
2673
2674 fprintf(sql_file,
2675 "SET @saved_cs_client = @@character_set_client;\n"
2676 "SET character_set_client = utf8;\n"
2677 "/*!50001 CREATE VIEW %s AS SELECT \n",
2678 result_table);
2679
2680 /*
2681 Get first row, following loop will prepend comma - keeps from
2682 having to know if the row being printed is last to determine if
2683 there should be a _trailing_ comma.
2684 */
2685
2686
2687 row= mysql_fetch_row(result);
2688
2689 /*
2690 A temporary view is created to resolve the view interdependencies.
2691 This temporary view is dropped when the actual view is created.
2692 */
2693
2694 fprintf(sql_file, " 1 AS %s",
2695 quote_name(row[0], name_buff, 0));
2696
2697 while((row= mysql_fetch_row(result)))
2698 {
2699 fprintf(sql_file, ",\n 1 AS %s",
2700 quote_name(row[0], name_buff, 0));
2701 }
2702
2703 fprintf(sql_file,"*/;\n"
2704 "SET character_set_client = @saved_cs_client;\n");
2705
2706 check_io(sql_file);
2707 }
2708
2709 mysql_free_result(result);
2710
2711 if (path)
2712 my_fclose(sql_file, MYF(MY_WME));
2713
2714 seen_views= 1;
2715 DBUG_RETURN(0);
2716 }
2717
2718 row= mysql_fetch_row(result);
2719
2720 is_log_table= general_log_or_slow_log_tables(db, table);
2721 if (is_log_table)
2722 row[1]+= 13; /* strlen("CREATE TABLE ")= 13 */
2723 if (opt_compatible_mode & 3)
2724 {
2725 fprintf(sql_file,
2726 is_log_table ? "CREATE TABLE IF NOT EXISTS %s;\n" : "%s;\n",
2727 row[1]);
2728 }
2729 else
2730 {
2731 fprintf(sql_file,
2732 "/*!40101 SET @saved_cs_client = @@character_set_client */;\n"
2733 "/*!40101 SET character_set_client = utf8 */;\n"
2734 "%s%s;\n"
2735 "/*!40101 SET character_set_client = @saved_cs_client */;\n",
2736 is_log_table ? "CREATE TABLE IF NOT EXISTS " : "",
2737 row[1]);
2738 }
2739
2740 check_io(sql_file);
2741 mysql_free_result(result);
2742 }
2743 my_snprintf(query_buff, sizeof(query_buff), "show fields from %s",
2744 result_table);
2745 if (mysql_query_with_error_report(mysql, &result, query_buff))
2746 {
2747 if (path)
2748 my_fclose(sql_file, MYF(MY_WME));
2749 DBUG_RETURN(0);
2750 }
2751
2752 /*
2753 If write_data is true, then we build up insert statements for
2754 the table's data. Note: in subsequent lines of code, this test
2755 will have to be performed each time we are appending to
2756 insert_pat.
2757 */
2758 if (write_data)
2759 {
2760 if (opt_replace_into)
2761 dynstr_append_checked(&insert_pat, "REPLACE ");
2762 else
2763 dynstr_append_checked(&insert_pat, "INSERT ");
2764 dynstr_append_checked(&insert_pat, insert_option);
2765 dynstr_append_checked(&insert_pat, "INTO ");
2766 dynstr_append_checked(&insert_pat, opt_quoted_table);
2767 if (complete_insert)
2768 {
2769 dynstr_append_checked(&insert_pat, " (");
2770 }
2771 else
2772 {
2773 dynstr_append_checked(&insert_pat, " VALUES ");
2774 if (!extended_insert)
2775 dynstr_append_checked(&insert_pat, "(");
2776 }
2777 }
2778
2779 while ((row= mysql_fetch_row(result)))
2780 {
2781 if (complete_insert)
2782 {
2783 if (init)
2784 {
2785 dynstr_append_checked(&insert_pat, ", ");
2786 }
2787 init=1;
2788 dynstr_append_checked(&insert_pat,
2789 quote_name(row[SHOW_FIELDNAME], name_buff, 0));
2790 }
2791 }
2792 num_fields= mysql_num_rows(result);
2793 mysql_free_result(result);
2794 }
2795 else
2796 {
2797 verbose_msg("%s: Warning: Can't set SQL_QUOTE_SHOW_CREATE option (%s)\n",
2798 my_progname, mysql_error(mysql));
2799
2800 my_snprintf(query_buff, sizeof(query_buff), show_fields_stmt, db, table);
2801
2802 if (mysql_query_with_error_report(mysql, &result, query_buff))
2803 DBUG_RETURN(0);
2804
2805 /* Make an sql-file, if path was given iow. option -T was given */
2806 if (!opt_no_create_info)
2807 {
2808 if (path)
2809 {
2810 if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
2811 DBUG_RETURN(0);
2812 write_header(sql_file, db);
2813 }
2814
2815 print_comment(sql_file, 0,
2816 "\n--\n-- Table structure for table %s\n--\n\n",
2817 result_table);
2818 if (opt_drop)
2819 fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n", result_table);
2820 if (!opt_xml)
2821 fprintf(sql_file, "CREATE TABLE %s (\n", result_table);
2822 else
2823 print_xml_tag(sql_file, "\t", "\n", "table_structure", "name=", table,
2824 NullS);
2825 check_io(sql_file);
2826 }
2827
2828 if (write_data)
2829 {
2830 if (opt_replace_into)
2831 dynstr_append_checked(&insert_pat, "REPLACE ");
2832 else
2833 dynstr_append_checked(&insert_pat, "INSERT ");
2834 dynstr_append_checked(&insert_pat, insert_option);
2835 dynstr_append_checked(&insert_pat, "INTO ");
2836 dynstr_append_checked(&insert_pat, result_table);
2837 if (complete_insert)
2838 dynstr_append_checked(&insert_pat, " (");
2839 else
2840 {
2841 dynstr_append_checked(&insert_pat, " VALUES ");
2842 if (!extended_insert)
2843 dynstr_append_checked(&insert_pat, "(");
2844 }
2845 }
2846
2847 while ((row= mysql_fetch_row(result)))
2848 {
2849 ulong *lengths= mysql_fetch_lengths(result);
2850 if (init)
2851 {
2852 if (!opt_xml && !opt_no_create_info)
2853 {
2854 fputs(",\n",sql_file);
2855 check_io(sql_file);
2856 }
2857 if (complete_insert)
2858 dynstr_append_checked(&insert_pat, ", ");
2859 }
2860 init=1;
2861 if (complete_insert)
2862 dynstr_append_checked(&insert_pat,
2863 quote_name(row[SHOW_FIELDNAME], name_buff, 0));
2864 if (!opt_no_create_info)
2865 {
2866 if (opt_xml)
2867 {
2868 print_xml_row(sql_file, "field", result, &row, NullS);
2869 continue;
2870 }
2871
2872 if (opt_keywords)
2873 fprintf(sql_file, " %s.%s %s", result_table,
2874 quote_name(row[SHOW_FIELDNAME],name_buff, 0),
2875 row[SHOW_TYPE]);
2876 else
2877 fprintf(sql_file, " %s %s", quote_name(row[SHOW_FIELDNAME],
2878 name_buff, 0),
2879 row[SHOW_TYPE]);
2880 if (row[SHOW_DEFAULT])
2881 {
2882 fputs(" DEFAULT ", sql_file);
2883 unescape(sql_file, row[SHOW_DEFAULT], lengths[SHOW_DEFAULT]);
2884 }
2885 if (!row[SHOW_NULL][0])
2886 fputs(" NOT NULL", sql_file);
2887 if (row[SHOW_EXTRA][0])
2888 fprintf(sql_file, " %s",row[SHOW_EXTRA]);
2889 check_io(sql_file);
2890 }
2891 }
2892 num_fields= mysql_num_rows(result);
2893 mysql_free_result(result);
2894 if (!opt_no_create_info)
2895 {
2896 /* Make an sql-file, if path was given iow. option -T was given */
2897 char buff[20+FN_REFLEN];
2898 uint keynr,primary_key;
2899 my_snprintf(buff, sizeof(buff), "show keys from %s", result_table);
2900 if (mysql_query_with_error_report(mysql, &result, buff))
2901 {
2902 if (mysql_errno(mysql) == ER_WRONG_OBJECT)
2903 {
2904 /* it is VIEW */
2905 fputs("\t\t<options Comment=\"view\" />\n", sql_file);
2906 goto continue_xml;
2907 }
2908 fprintf(stderr, "%s: Can't get keys for table %s (%s)\n",
2909 my_progname, result_table, mysql_error(mysql));
2910 if (path)
2911 my_fclose(sql_file, MYF(MY_WME));
2912 DBUG_RETURN(0);
2913 }
2914
2915 /* Find first which key is primary key */
2916 keynr=0;
2917 primary_key=INT_MAX;
2918 while ((row= mysql_fetch_row(result)))
2919 {
2920 if (atoi(row[3]) == 1)
2921 {
2922 keynr++;
2923#ifdef FORCE_PRIMARY_KEY
2924 if (atoi(row[1]) == 0 && primary_key == INT_MAX)
2925 primary_key=keynr;
2926#endif
2927 if (!strcmp(row[2],"PRIMARY"))
2928 {
2929 primary_key=keynr;
2930 break;
2931 }
2932 }
2933 }
2934 mysql_data_seek(result,0);
2935 keynr=0;
2936 while ((row= mysql_fetch_row(result)))
2937 {
2938 if (opt_xml)
2939 {
2940 print_xml_row(sql_file, "key", result, &row, NullS);
2941 continue;
2942 }
2943
2944 if (atoi(row[3]) == 1)
2945 {
2946 if (keynr++)
2947 putc(')', sql_file);
2948 if (atoi(row[1])) /* Test if duplicate key */
2949 /* Duplicate allowed */
2950 fprintf(sql_file, ",\n KEY %s (",quote_name(row[2],name_buff,0));
2951 else if (keynr == primary_key)
2952 fputs(",\n PRIMARY KEY (",sql_file); /* First UNIQUE is primary */
2953 else
2954 fprintf(sql_file, ",\n UNIQUE %s (",quote_name(row[2],name_buff,
2955 0));
2956 }
2957 else
2958 putc(',', sql_file);
2959 fputs(quote_name(row[4], name_buff, 0), sql_file);
2960 if (row[7])
2961 fprintf(sql_file, " (%s)",row[7]); /* Sub key */
2962 check_io(sql_file);
2963 }
2964 mysql_free_result(result);
2965 if (!opt_xml)
2966 {
2967 if (keynr)
2968 putc(')', sql_file);
2969 fputs("\n)",sql_file);
2970 check_io(sql_file);
2971 }
2972
2973 /* Get MySQL specific create options */
2974 if (create_options)
2975 {
2976 char show_name_buff[NAME_LEN*2+2+24];
2977
2978 /* Check memory for quote_for_like() */
2979 my_snprintf(buff, sizeof(buff), "show table status like %s",
2980 quote_for_like(table, show_name_buff));
2981
2982 if (mysql_query_with_error_report(mysql, &result, buff))
2983 {
2984 if (mysql_errno(mysql) != ER_PARSE_ERROR)
2985 { /* If old MySQL version */
2986 verbose_msg("-- Warning: Couldn't get status information for " \
2987 "table %s (%s)\n", result_table,mysql_error(mysql));
2988 }
2989 }
2990 else if (!(row= mysql_fetch_row(result)))
2991 {
2992 fprintf(stderr,
2993 "Error: Couldn't read status information for table %s (%s)\n",
2994 result_table,mysql_error(mysql));
2995 }
2996 else
2997 {
2998 if (opt_xml)
2999 print_xml_row(sql_file, "options", result, &row, NullS);
3000 else
3001 {
3002 fputs("/*!",sql_file);
3003 print_value(sql_file,result,row,"engine=","Engine",0);
3004 print_value(sql_file,result,row,"","Create_options",0);
3005 print_value(sql_file,result,row,"comment=","Comment",1);
3006 fputs(" */",sql_file);
3007 check_io(sql_file);
3008 }
3009 }
3010 mysql_free_result(result); /* Is always safe to free */
3011 }
3012continue_xml:
3013 if (!opt_xml)
3014 fputs(";\n", sql_file);
3015 else
3016 fputs("\t</table_structure>\n", sql_file);
3017 check_io(sql_file);
3018 }
3019 }
3020 if (complete_insert)
3021 {
3022 dynstr_append_checked(&insert_pat, ") VALUES ");
3023 if (!extended_insert)
3024 dynstr_append_checked(&insert_pat, "(");
3025 }
3026 if (sql_file != md_result_file)
3027 {
3028 fputs("\n", sql_file);
3029 write_footer(sql_file);
3030 my_fclose(sql_file, MYF(MY_WME));
3031 }
3032 DBUG_RETURN((uint) num_fields);
3033} /* get_table_structure */
3034
3035static void dump_trigger_old(FILE *sql_file, MYSQL_RES *show_triggers_rs,
3036 MYSQL_ROW *show_trigger_row,
3037 const char *table_name)
3038{
3039 char quoted_table_name_buf[NAME_LEN * 2 + 3];
3040 char *quoted_table_name= quote_name(table_name, quoted_table_name_buf, 1);
3041
3042 char name_buff[NAME_LEN * 4 + 3];
3043 const char *xml_msg= "\nWarning! mysqldump being run against old server "
3044 "that does not\nsupport 'SHOW CREATE TRIGGERS' "
3045 "statement. Skipping..\n";
3046
3047 DBUG_ENTER("dump_trigger_old");
3048
3049 if (opt_xml)
3050 {
3051 print_xml_comment(sql_file, strlen(xml_msg), xml_msg);
3052 check_io(sql_file);
3053 DBUG_VOID_RETURN;
3054 }
3055
3056 fprintf(sql_file,
3057 "--\n"
3058 "-- WARNING: old server version. "
3059 "The following dump may be incomplete.\n"
3060 "--\n");
3061
3062 if (opt_compact)
3063 fprintf(sql_file, "/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n");
3064
3065 if (opt_drop_trigger)
3066 fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", (*show_trigger_row)[0]);
3067
3068 fprintf(sql_file,
3069 "DELIMITER ;;\n"
3070 "/*!50003 SET SESSION SQL_MODE=\"%s\" */;;\n"
3071 "/*!50003 CREATE */ ",
3072 (*show_trigger_row)[6]);
3073
3074 if (mysql_num_fields(show_triggers_rs) > 7)
3075 {
3076 /*
3077 mysqldump can be run against the server, that does not support
3078 definer in triggers (there is no DEFINER column in SHOW TRIGGERS
3079 output). So, we should check if we have this column before
3080 accessing it.
3081 */
3082
3083 size_t user_name_len;
3084 char user_name_str[USERNAME_LENGTH + 1];
3085 char quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
3086 size_t host_name_len;
3087 char host_name_str[HOSTNAME_LENGTH + 1];
3088 char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
3089
3090 parse_user((*show_trigger_row)[7],
3091 strlen((*show_trigger_row)[7]),
3092 user_name_str, &user_name_len,
3093 host_name_str, &host_name_len);
3094
3095 fprintf(sql_file,
3096 "/*!50017 DEFINER=%s@%s */ ",
3097 quote_name(user_name_str, quoted_user_name_str, FALSE),
3098 quote_name(host_name_str, quoted_host_name_str, FALSE));
3099 }
3100
3101 fprintf(sql_file,
3102 "/*!50003 TRIGGER %s %s %s ON %s FOR EACH ROW%s%s */;;\n"
3103 "DELIMITER ;\n",
3104 quote_name((*show_trigger_row)[0], name_buff, 0), /* Trigger */
3105 (*show_trigger_row)[4], /* Timing */
3106 (*show_trigger_row)[1], /* Event */
3107 quoted_table_name,
3108 (strchr(" \t\n\r", *((*show_trigger_row)[3]))) ? "" : " ",
3109 (*show_trigger_row)[3] /* Statement */);
3110
3111 if (opt_compact)
3112 fprintf(sql_file, "/*!50003 SET SESSION SQL_MODE=@OLD_SQL_MODE */;\n");
3113
3114 DBUG_VOID_RETURN;
3115}
3116
3117static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
3118 const char *db_name,
3119 const char *db_cl_name)
3120{
3121 MYSQL_ROW row;
3122 char *query_str;
3123 int db_cl_altered= FALSE;
3124
3125 DBUG_ENTER("dump_trigger");
3126
3127 while ((row= mysql_fetch_row(show_create_trigger_rs)))
3128 {
3129 if (opt_xml)
3130 {
3131 print_xml_row(sql_file, "trigger", show_create_trigger_rs, &row,
3132 "SQL Original Statement");
3133 check_io(sql_file);
3134 continue;
3135 }
3136
3137 query_str= cover_definer_clause(row[2], strlen(row[2]),
3138 C_STRING_WITH_LEN("50017"),
3139 C_STRING_WITH_LEN("50003"),
3140 C_STRING_WITH_LEN(" TRIGGER"));
3141 if (switch_db_collation(sql_file, db_name, ";",
3142 db_cl_name, row[5], &db_cl_altered))
3143 DBUG_RETURN(TRUE);
3144
3145 switch_cs_variables(sql_file, ";",
3146 row[3], /* character_set_client */
3147 row[3], /* character_set_results */
3148 row[4]); /* collation_connection */
3149
3150 switch_sql_mode(sql_file, ";", row[1]);
3151
3152 if (opt_drop_trigger)
3153 fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", row[0]);
3154
3155 fprintf(sql_file,
3156 "DELIMITER ;;\n"
3157 "/*!50003 %s */;;\n"
3158 "DELIMITER ;\n",
3159 (const char *) (query_str != NULL ? query_str : row[2]));
3160
3161 restore_sql_mode(sql_file, ";");
3162 restore_cs_variables(sql_file, ";");
3163
3164 if (db_cl_altered)
3165 {
3166 if (restore_db_collation(sql_file, db_name, ";", db_cl_name))
3167 DBUG_RETURN(TRUE);
3168 }
3169
3170 my_free(query_str);
3171 }
3172
3173 DBUG_RETURN(FALSE);
3174}
3175
3176/**
3177 Dump the triggers for a given table.
3178
3179 This should be called after the tables have been dumped in case a trigger
3180 depends on the existence of a table.
3181
3182 @param[in] table_name
3183 @param[in] db_name
3184
3185 @return Error status.
3186 @retval TRUE error has occurred.
3187 @retval FALSE operation succeed.
3188*/
3189
3190static int dump_triggers_for_table(char *table_name, char *db_name)
3191{
3192 char name_buff[NAME_LEN*4+3];
3193 char query_buff[QUERY_LENGTH];
3194 uint old_opt_compatible_mode= opt_compatible_mode;
3195 MYSQL_RES *show_triggers_rs;
3196 MYSQL_ROW row;
3197 FILE *sql_file= md_result_file;
3198
3199 char db_cl_name[MY_CS_NAME_SIZE];
3200 int ret= TRUE;
3201
3202 DBUG_ENTER("dump_triggers_for_table");
3203 DBUG_PRINT("enter", ("db: %s, table_name: %s", db_name, table_name));
3204
3205 if (path && !(sql_file= open_sql_file_for_table(table_name,
3206 O_WRONLY | O_APPEND)))
3207 DBUG_RETURN(1);
3208
3209 /* Do not use ANSI_QUOTES on triggers in dump */
3210 opt_compatible_mode&= ~MASK_ANSI_QUOTES;
3211
3212 /* Get database collation. */
3213
3214 if (switch_character_set_results(mysql, "binary"))
3215 goto done;
3216
3217 if (fetch_db_collation(db_name, db_cl_name, sizeof (db_cl_name)))
3218 goto done;
3219
3220 /* Get list of triggers. */
3221
3222 my_snprintf(query_buff, sizeof(query_buff),
3223 "SHOW TRIGGERS LIKE %s",
3224 quote_for_like(table_name, name_buff));
3225
3226 if (mysql_query_with_error_report(mysql, &show_triggers_rs, query_buff))
3227 goto done;
3228
3229 /* Dump triggers. */
3230
3231 if (! mysql_num_rows(show_triggers_rs))
3232 goto skip;
3233
3234 if (opt_xml)
3235 print_xml_tag(sql_file, "\t", "\n", "triggers", "name=",
3236 table_name, NullS);
3237
3238 while ((row= mysql_fetch_row(show_triggers_rs)))
3239 {
3240
3241 my_snprintf(query_buff, sizeof (query_buff),
3242 "SHOW CREATE TRIGGER %s",
3243 quote_name(row[0], name_buff, TRUE));
3244
3245 if (mysql_query(mysql, query_buff))
3246 {
3247 /*
3248 mysqldump is being run against old server, that does not support
3249 SHOW CREATE TRIGGER statement. We should use SHOW TRIGGERS output.
3250
3251 NOTE: the dump may be incorrect, as old SHOW TRIGGERS does not
3252 provide all the necessary information to restore trigger properly.
3253 */
3254
3255 dump_trigger_old(sql_file, show_triggers_rs, &row, table_name);
3256 }
3257 else
3258 {
3259 MYSQL_RES *show_create_trigger_rs= mysql_store_result(mysql);
3260
3261 if (!show_create_trigger_rs ||
3262 dump_trigger(sql_file, show_create_trigger_rs, db_name, db_cl_name))
3263 goto done;
3264
3265 mysql_free_result(show_create_trigger_rs);
3266 }
3267
3268 }
3269
3270 if (opt_xml)
3271 {
3272 fputs("\t</triggers>\n", sql_file);
3273 check_io(sql_file);
3274 }
3275
3276skip:
3277 mysql_free_result(show_triggers_rs);
3278
3279 if (switch_character_set_results(mysql, default_charset))
3280 goto done;
3281
3282 /*
3283 make sure to set back opt_compatible mode to
3284 original value
3285 */
3286 opt_compatible_mode=old_opt_compatible_mode;
3287
3288 ret= FALSE;
3289
3290done:
3291 if (path)
3292 my_fclose(sql_file, MYF(0));
3293
3294 DBUG_RETURN(ret);
3295}
3296
3297static void add_load_option(DYNAMIC_STRING *str, const char *option,
3298 const char *option_value)
3299{
3300 if (!option_value)
3301 {
3302 /* Null value means we don't add this option. */
3303 return;
3304 }
3305
3306 dynstr_append_checked(str, option);
3307
3308 if (strncmp(option_value, "0x", sizeof("0x")-1) == 0)
3309 {
3310 /* It's a hex constant, don't escape */
3311 dynstr_append_checked(str, option_value);
3312 }
3313 else
3314 {
3315 /* char constant; escape */
3316 field_escape(str, option_value);
3317 }
3318}
3319
3320
3321/*
3322 Allow the user to specify field terminator strings like:
3323 "'", "\", "\\" (escaped backslash), "\t" (tab), "\n" (newline)
3324 This is done by doubling ' and add a end -\ if needed to avoid
3325 syntax errors from the SQL parser.
3326*/
3327
3328static void field_escape(DYNAMIC_STRING* in, const char *from)
3329{
3330 uint end_backslashes= 0;
3331
3332 dynstr_append_checked(in, "'");
3333
3334 while (*from)
3335 {
3336 dynstr_append_mem_checked(in, from, 1);
3337
3338 if (*from == '\\')
3339 end_backslashes^=1; /* find odd number of backslashes */
3340 else
3341 {
3342 if (*from == '\'' && !end_backslashes)
3343 {
3344 /* We want a duplicate of "'" for MySQL */
3345 dynstr_append_checked(in, "\'");
3346 }
3347 end_backslashes=0;
3348 }
3349 from++;
3350 }
3351 /* Add missing backslashes if user has specified odd number of backs.*/
3352 if (end_backslashes)
3353 dynstr_append_checked(in, "\\");
3354
3355 dynstr_append_checked(in, "'");
3356}
3357
3358
3359
3360static char *alloc_query_str(ulong size)
3361{
3362 char *query;
3363
3364 if (!(query= (char*) my_malloc(size, MYF(MY_WME))))
3365 die(EX_MYSQLERR, "Couldn't allocate a query string.");
3366
3367 return query;
3368}
3369
3370
3371/*
3372
3373 SYNOPSIS
3374 dump_table()
3375
3376 dump_table saves database contents as a series of INSERT statements.
3377
3378 ARGS
3379 table - table name
3380 db - db name
3381
3382 RETURNS
3383 void
3384*/
3385
3386
3387static void dump_table(char *table, char *db)
3388{
3389 char ignore_flag;
3390 char buf[200], table_buff[NAME_LEN+3];
3391 DYNAMIC_STRING query_string;
3392 char table_type[NAME_LEN];
3393 char *result_table, table_buff2[NAME_LEN*2+3], *opt_quoted_table;
3394 int error= 0;
3395 ulong rownr, row_break, total_length, init_length;
3396 uint num_fields;
3397 MYSQL_RES *res;
3398 MYSQL_FIELD *field;
3399 MYSQL_ROW row;
3400 DBUG_ENTER("dump_table");
3401
3402 /*
3403 Make sure you get the create table info before the following check for
3404 --no-data flag below. Otherwise, the create table info won't be printed.
3405 */
3406 num_fields= get_table_structure(table, db, table_type, &ignore_flag);
3407
3408 /*
3409 The "table" could be a view. If so, we don't do anything here.
3410 */
3411 if (strcmp(table_type, "VIEW") == 0)
3412 DBUG_VOID_RETURN;
3413
3414 /* Check --no-data flag */
3415 if (opt_no_data)
3416 {
3417 verbose_msg("-- Skipping dump data for table '%s', --no-data was used\n",
3418 table);
3419 DBUG_VOID_RETURN;
3420 }
3421
3422 DBUG_PRINT("info",
3423 ("ignore_flag: %x num_fields: %d", (int) ignore_flag,
3424 num_fields));
3425 /*
3426 If the table type is a merge table or any type that has to be
3427 _completely_ ignored and no data dumped
3428 */
3429 if (ignore_flag & IGNORE_DATA)
3430 {
3431 verbose_msg("-- Warning: Skipping data for table '%s' because " \
3432 "it's of type %s\n", table, table_type);
3433 DBUG_VOID_RETURN;
3434 }
3435 /* Check that there are any fields in the table */
3436 if (num_fields == 0)
3437 {
3438 verbose_msg("-- Skipping dump data for table '%s', it has no fields\n",
3439 table);
3440 DBUG_VOID_RETURN;
3441 }
3442
3443 result_table= quote_name(table,table_buff, 1);
3444 opt_quoted_table= quote_name(table, table_buff2, 0);
3445
3446 verbose_msg("-- Sending SELECT query...\n");
3447
3448 init_dynamic_string_checked(&query_string, "", 1024, 1024);
3449
3450 if (path)
3451 {
3452 char filename[FN_REFLEN], tmp_path[FN_REFLEN];
3453
3454 /*
3455 Convert the path to native os format
3456 and resolve to the full filepath.
3457 */
3458 convert_dirname(tmp_path,path,NullS);
3459 my_load_path(tmp_path, tmp_path, NULL);
3460 fn_format(filename, table, tmp_path, ".txt", MYF(MY_UNPACK_FILENAME));
3461
3462 /* Must delete the file that 'INTO OUTFILE' will write to */
3463 my_delete(filename, MYF(0));
3464
3465 /* convert to a unix path name to stick into the query */
3466 to_unix_path(filename);
3467
3468 /* now build the query string */
3469
3470 dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * INTO OUTFILE '");
3471 dynstr_append_checked(&query_string, filename);
3472 dynstr_append_checked(&query_string, "'");
3473
3474 dynstr_append_checked(&query_string, " /*!50138 CHARACTER SET ");
3475 dynstr_append_checked(&query_string, default_charset == mysql_universal_client_charset ?
3476 my_charset_bin.name : /* backward compatibility */
3477 default_charset);
3478 dynstr_append_checked(&query_string, " */");
3479
3480 if (fields_terminated || enclosed || opt_enclosed || escaped)
3481 dynstr_append_checked(&query_string, " FIELDS");
3482
3483 add_load_option(&query_string, " TERMINATED BY ", fields_terminated);
3484 add_load_option(&query_string, " ENCLOSED BY ", enclosed);
3485 add_load_option(&query_string, " OPTIONALLY ENCLOSED BY ", opt_enclosed);
3486 add_load_option(&query_string, " ESCAPED BY ", escaped);
3487 add_load_option(&query_string, " LINES TERMINATED BY ", lines_terminated);
3488
3489 dynstr_append_checked(&query_string, " FROM ");
3490 dynstr_append_checked(&query_string, result_table);
3491
3492 if (where)
3493 {
3494 dynstr_append_checked(&query_string, " WHERE ");
3495 dynstr_append_checked(&query_string, where);
3496 }
3497
3498 if (order_by)
3499 {
3500 dynstr_append_checked(&query_string, " ORDER BY ");
3501 dynstr_append_checked(&query_string, order_by);
3502 }
3503
3504 if (mysql_real_query(mysql, query_string.str, query_string.length))
3505 {
3506 DB_error(mysql, "when executing 'SELECT INTO OUTFILE'");
3507 dynstr_free(&query_string);
3508 DBUG_VOID_RETURN;
3509 }
3510 }
3511 else
3512 {
3513 print_comment(md_result_file, 0,
3514 "\n--\n-- Dumping data for table %s\n--\n",
3515 result_table);
3516
3517 dynstr_append_checked(&query_string, "SELECT /*!40001 SQL_NO_CACHE */ * FROM ");
3518 dynstr_append_checked(&query_string, result_table);
3519
3520 if (where)
3521 {
3522 print_comment(md_result_file, 0, "-- WHERE: %s\n", where);
3523
3524 dynstr_append_checked(&query_string, " WHERE ");
3525 dynstr_append_checked(&query_string, where);
3526 }
3527 if (order_by)
3528 {
3529 print_comment(md_result_file, 0, "-- ORDER BY: %s\n", order_by);
3530
3531 dynstr_append_checked(&query_string, " ORDER BY ");
3532 dynstr_append_checked(&query_string, order_by);
3533 }
3534
3535 if (!opt_xml && !opt_compact)
3536 {
3537 fputs("\n", md_result_file);
3538 check_io(md_result_file);
3539 }
3540 if (mysql_query_with_error_report(mysql, 0, query_string.str))
3541 {
3542 DB_error(mysql, "when retrieving data from server");
3543 goto err;
3544 }
3545 if (quick)
3546 res=mysql_use_result(mysql);
3547 else
3548 res=mysql_store_result(mysql);
3549 if (!res)
3550 {
3551 DB_error(mysql, "when retrieving data from server");
3552 goto err;
3553 }
3554
3555 verbose_msg("-- Retrieving rows...\n");
3556 if (mysql_num_fields(res) != num_fields)
3557 {
3558 fprintf(stderr,"%s: Error in field count for table: %s ! Aborting.\n",
3559 my_progname, result_table);
3560 error= EX_CONSCHECK;
3561 goto err;
3562 }
3563
3564 if (opt_lock)
3565 {
3566 fprintf(md_result_file,"LOCK TABLES %s WRITE;\n", opt_quoted_table);
3567 check_io(md_result_file);
3568 }
3569 /* Moved disable keys to after lock per bug 15977 */
3570 if (opt_disable_keys)
3571 {
3572 fprintf(md_result_file, "/*!40000 ALTER TABLE %s DISABLE KEYS */;\n",
3573 opt_quoted_table);
3574 check_io(md_result_file);
3575 }
3576
3577 total_length= opt_net_buffer_length; /* Force row break */
3578 row_break=0;
3579 rownr=0;
3580 init_length=(uint) insert_pat.length+4;
3581 if (opt_xml)
3582 print_xml_tag(md_result_file, "\t", "\n", "table_data", "name=", table,
3583 NullS);
3584 if (opt_autocommit)
3585 {
3586 fprintf(md_result_file, "set autocommit=0;\n");
3587 check_io(md_result_file);
3588 }
3589
3590 while ((row= mysql_fetch_row(res)))
3591 {
3592 uint i;
3593 ulong *lengths= mysql_fetch_lengths(res);
3594 rownr++;
3595 if (!extended_insert && !opt_xml)
3596 {
3597 fputs(insert_pat.str,md_result_file);
3598 check_io(md_result_file);
3599 }
3600 mysql_field_seek(res,0);
3601
3602 if (opt_xml)
3603 {
3604 fputs("\t<row>\n", md_result_file);
3605 check_io(md_result_file);
3606 }
3607
3608 for (i= 0; i < mysql_num_fields(res); i++)
3609 {
3610 int is_blob;
3611 ulong length= lengths[i];
3612
3613 if (!(field= mysql_fetch_field(res)))
3614 die(EX_CONSCHECK,
3615 "Not enough fields from table %s! Aborting.\n",
3616 result_table);
3617
3618 /*
3619 63 is my_charset_bin. If charsetnr is not 63,
3620 we have not a BLOB but a TEXT column.
3621 we'll dump in hex only BLOB columns.
3622 */
3623 is_blob= (opt_hex_blob && field->charsetnr == 63 &&
3624 (field->type == MYSQL_TYPE_BIT ||
3625 field->type == MYSQL_TYPE_STRING ||
3626 field->type == MYSQL_TYPE_VAR_STRING ||
3627 field->type == MYSQL_TYPE_VARCHAR ||
3628 field->type == MYSQL_TYPE_BLOB ||
3629 field->type == MYSQL_TYPE_LONG_BLOB ||
3630 field->type == MYSQL_TYPE_MEDIUM_BLOB ||
3631 field->type == MYSQL_TYPE_TINY_BLOB ||
3632 field->type == MYSQL_TYPE_GEOMETRY)) ? 1 : 0;
3633 if (extended_insert && !opt_xml)
3634 {
3635 if (i == 0)
3636 dynstr_set_checked(&extended_row,"(");
3637 else
3638 dynstr_append_checked(&extended_row,",");
3639
3640 if (row[i])
3641 {
3642 if (length)
3643 {
3644 if (!(field->flags & NUM_FLAG))
3645 {
3646 /*
3647 "length * 2 + 2" is OK for both HEX and non-HEX modes:
3648 - In HEX mode we need exactly 2 bytes per character
3649 plus 2 bytes for '0x' prefix.
3650 - In non-HEX mode we need up to 2 bytes per character,
3651 plus 2 bytes for leading and trailing '\'' characters.
3652 Also we need to reserve 1 byte for terminating '\0'.
3653 */
3654 dynstr_realloc_checked(&extended_row,length * 2 + 2 + 1);
3655 if (opt_hex_blob && is_blob)
3656 {
3657 dynstr_append_checked(&extended_row, "0x");
3658 extended_row.length+= mysql_hex_string(extended_row.str +
3659 extended_row.length,
3660 row[i], length);
3661 DBUG_ASSERT(extended_row.length+1 <= extended_row.max_length);
3662 /* mysql_hex_string() already terminated string by '\0' */
3663 DBUG_ASSERT(extended_row.str[extended_row.length] == '\0');
3664 }
3665 else
3666 {
3667 dynstr_append_checked(&extended_row,"'");
3668 extended_row.length +=
3669 mysql_real_escape_string(&mysql_connection,
3670 &extended_row.str[extended_row.length],
3671 row[i],length);
3672 extended_row.str[extended_row.length]='\0';
3673 dynstr_append_checked(&extended_row,"'");
3674 }
3675 }
3676 else
3677 {
3678 /* change any strings ("inf", "-inf", "nan") into NULL */
3679 char *ptr= row[i];
3680 if (my_isalpha(charset_info, *ptr) || (*ptr == '-' &&
3681 my_isalpha(charset_info, ptr[1])))
3682 dynstr_append_checked(&extended_row, "NULL");
3683 else
3684 {
3685 if (field->type == MYSQL_TYPE_DECIMAL)
3686 {
3687 /* add " signs around */
3688 dynstr_append_checked(&extended_row, "'");
3689 dynstr_append_checked(&extended_row, ptr);
3690 dynstr_append_checked(&extended_row, "'");
3691 }
3692 else
3693 dynstr_append_checked(&extended_row, ptr);
3694 }
3695 }
3696 }
3697 else
3698 dynstr_append_checked(&extended_row,"''");
3699 }
3700 else
3701 dynstr_append_checked(&extended_row,"NULL");
3702 }
3703 else
3704 {
3705 if (i && !opt_xml)
3706 {
3707 fputc(',', md_result_file);
3708 check_io(md_result_file);
3709 }
3710 if (row[i])
3711 {
3712 if (!(field->flags & NUM_FLAG))
3713 {
3714 if (opt_xml)
3715 {
3716 if (opt_hex_blob && is_blob && length)
3717 {
3718 /* Define xsi:type="xs:hexBinary" for hex encoded data */
3719 print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
3720 field->name, "xsi:type=", "xs:hexBinary", NullS);
3721 print_blob_as_hex(md_result_file, row[i], length);
3722 }
3723 else
3724 {
3725 print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
3726 field->name, NullS);
3727 print_quoted_xml(md_result_file, row[i], length, 0);
3728 }
3729 fputs("</field>\n", md_result_file);
3730 }
3731 else if (opt_hex_blob && is_blob && length)
3732 {
3733 fputs("0x", md_result_file);
3734 print_blob_as_hex(md_result_file, row[i], length);
3735 }
3736 else
3737 unescape(md_result_file, row[i], length);
3738 }
3739 else
3740 {
3741 /* change any strings ("inf", "-inf", "nan") into NULL */
3742 char *ptr= row[i];
3743 if (opt_xml)
3744 {
3745 print_xml_tag(md_result_file, "\t\t", "", "field", "name=",
3746 field->name, NullS);
3747 fputs(!my_isalpha(charset_info, *ptr) ? ptr: "NULL",
3748 md_result_file);
3749 fputs("</field>\n", md_result_file);
3750 }
3751 else if (my_isalpha(charset_info, *ptr) ||
3752 (*ptr == '-' && my_isalpha(charset_info, ptr[1])))
3753 fputs("NULL", md_result_file);
3754 else if (field->type == MYSQL_TYPE_DECIMAL)
3755 {
3756 /* add " signs around */
3757 fputc('\'', md_result_file);
3758 fputs(ptr, md_result_file);
3759 fputc('\'', md_result_file);
3760 }
3761 else
3762 fputs(ptr, md_result_file);
3763 }
3764 }
3765 else
3766 {
3767 /* The field value is NULL */
3768 if (!opt_xml)
3769 fputs("NULL", md_result_file);
3770 else
3771 print_xml_null_tag(md_result_file, "\t\t", "field name=",
3772 field->name, "\n");
3773 }
3774 check_io(md_result_file);
3775 }
3776 }
3777
3778 if (opt_xml)
3779 {
3780 fputs("\t</row>\n", md_result_file);
3781 check_io(md_result_file);
3782 }
3783
3784 if (extended_insert)
3785 {
3786 ulong row_length;
3787 dynstr_append_checked(&extended_row,")");
3788 row_length= 2 + extended_row.length;
3789 if (total_length + row_length < opt_net_buffer_length)
3790 {
3791 total_length+= row_length;
3792 fputc(',',md_result_file); /* Always row break */
3793 fputs(extended_row.str,md_result_file);
3794 }
3795 else
3796 {
3797 if (row_break)
3798 fputs(";\n", md_result_file);
3799 row_break=1; /* This is first row */
3800
3801 fputs(insert_pat.str,md_result_file);
3802 fputs(extended_row.str,md_result_file);
3803 total_length= row_length+init_length;
3804 }
3805 check_io(md_result_file);
3806 }
3807 else if (!opt_xml)
3808 {
3809 fputs(");\n", md_result_file);
3810 check_io(md_result_file);
3811 }
3812 }
3813
3814 /* XML - close table tag and supress regular output */
3815 if (opt_xml)
3816 fputs("\t</table_data>\n", md_result_file);
3817 else if (extended_insert && row_break)
3818 fputs(";\n", md_result_file); /* If not empty table */
3819 fflush(md_result_file);
3820 check_io(md_result_file);
3821 if (mysql_errno(mysql))
3822 {
3823 my_snprintf(buf, sizeof(buf),
3824 "%s: Error %d: %s when dumping table %s at row: %ld\n",
3825 my_progname,
3826 mysql_errno(mysql),
3827 mysql_error(mysql),
3828 result_table,
3829 rownr);
3830 fputs(buf,stderr);
3831 error= EX_CONSCHECK;
3832 goto err;
3833 }
3834
3835 /* Moved enable keys to before unlock per bug 15977 */
3836 if (opt_disable_keys)
3837 {
3838 fprintf(md_result_file,"/*!40000 ALTER TABLE %s ENABLE KEYS */;\n",
3839 opt_quoted_table);
3840 check_io(md_result_file);
3841 }
3842 if (opt_lock)
3843 {
3844 fputs("UNLOCK TABLES;\n", md_result_file);
3845 check_io(md_result_file);
3846 }
3847 if (opt_autocommit)
3848 {
3849 fprintf(md_result_file, "commit;\n");
3850 check_io(md_result_file);
3851 }
3852 mysql_free_result(res);
3853 }
3854 dynstr_free(&query_string);
3855 DBUG_VOID_RETURN;
3856
3857err:
3858 dynstr_free(&query_string);
3859 maybe_exit(error);
3860 DBUG_VOID_RETURN;
3861} /* dump_table */
3862
3863
3864static char *getTableName(int reset)
3865{
3866 static MYSQL_RES *res= NULL;
3867 MYSQL_ROW row;
3868
3869 if (!res)
3870 {
3871 if (!(res= mysql_list_tables(mysql,NullS)))
3872 return(NULL);
3873 }
3874 if ((row= mysql_fetch_row(res)))
3875 return((char*) row[0]);
3876
3877 if (reset)
3878 mysql_data_seek(res,0); /* We want to read again */
3879 else
3880 {
3881 mysql_free_result(res);
3882 res= NULL;
3883 }
3884 return(NULL);
3885} /* getTableName */
3886
3887
3888/*
3889 dump all logfile groups and tablespaces
3890*/
3891
3892static int dump_all_tablespaces()
3893{
3894 return dump_tablespaces(NULL);
3895}
3896
3897static int dump_tablespaces_for_tables(char *db, char **table_names, int tables)
3898{
3899 DYNAMIC_STRING where;
3900 int r;
3901 int i;
3902 char name_buff[NAME_LEN*2+3];
3903
3904 mysql_real_escape_string(mysql, name_buff, db, strlen(db));
3905
3906 init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
3907 "SELECT DISTINCT TABLESPACE_NAME FROM"
3908 " INFORMATION_SCHEMA.PARTITIONS"
3909 " WHERE"
3910 " TABLE_SCHEMA='", 256, 1024);
3911 dynstr_append_checked(&where, name_buff);
3912 dynstr_append_checked(&where, "' AND TABLE_NAME IN (");
3913
3914 for (i=0 ; i<tables ; i++)
3915 {
3916 mysql_real_escape_string(mysql, name_buff,
3917 table_names[i], strlen(table_names[i]));
3918
3919 dynstr_append_checked(&where, "'");
3920 dynstr_append_checked(&where, name_buff);
3921 dynstr_append_checked(&where, "',");
3922 }
3923 dynstr_trunc(&where, 1);
3924 dynstr_append_checked(&where,"))");
3925
3926 DBUG_PRINT("info",("Dump TS for Tables where: %s",where.str));
3927 r= dump_tablespaces(where.str);
3928 dynstr_free(&where);
3929 return r;
3930}
3931
3932static int dump_tablespaces_for_databases(char** databases)
3933{
3934 DYNAMIC_STRING where;
3935 int r;
3936 int i;
3937
3938 init_dynamic_string_checked(&where, " AND TABLESPACE_NAME IN ("
3939 "SELECT DISTINCT TABLESPACE_NAME FROM"
3940 " INFORMATION_SCHEMA.PARTITIONS"
3941 " WHERE"
3942 " TABLE_SCHEMA IN (", 256, 1024);
3943
3944 for (i=0 ; databases[i]!=NULL ; i++)
3945 {
3946 char db_name_buff[NAME_LEN*2+3];
3947 mysql_real_escape_string(mysql, db_name_buff,
3948 databases[i], strlen(databases[i]));
3949 dynstr_append_checked(&where, "'");
3950 dynstr_append_checked(&where, db_name_buff);
3951 dynstr_append_checked(&where, "',");
3952 }
3953 dynstr_trunc(&where, 1);
3954 dynstr_append_checked(&where,"))");
3955
3956 DBUG_PRINT("info",("Dump TS for DBs where: %s",where.str));
3957 r= dump_tablespaces(where.str);
3958 dynstr_free(&where);
3959 return r;
3960}
3961
3962static int dump_tablespaces(char* ts_where)
3963{
3964 MYSQL_ROW row;
3965 MYSQL_RES *tableres;
3966 char buf[FN_REFLEN];
3967 DYNAMIC_STRING sqlbuf;
3968 int first= 0;
3969 /*
3970 The following are used for parsing the EXTRA field
3971 */
3972 char extra_format[]= "UNDO_BUFFER_SIZE=";
3973 char *ubs;
3974 char *endsemi;
3975 DBUG_ENTER("dump_tablespaces");
3976
3977 init_dynamic_string_checked(&sqlbuf,
3978 "SELECT LOGFILE_GROUP_NAME,"
3979 " FILE_NAME,"
3980 " TOTAL_EXTENTS,"
3981 " INITIAL_SIZE,"
3982 " ENGINE,"
3983 " EXTRA"
3984 " FROM INFORMATION_SCHEMA.FILES"
3985 " WHERE FILE_TYPE = 'UNDO LOG'"
3986 " AND FILE_NAME IS NOT NULL",
3987 256, 1024);
3988 if(ts_where)
3989 {
3990 dynstr_append_checked(&sqlbuf,
3991 " AND LOGFILE_GROUP_NAME IN ("
3992 "SELECT DISTINCT LOGFILE_GROUP_NAME"
3993 " FROM INFORMATION_SCHEMA.FILES"
3994 " WHERE FILE_TYPE = 'DATAFILE'"
3995 );
3996 dynstr_append_checked(&sqlbuf, ts_where);
3997 dynstr_append_checked(&sqlbuf, ")");
3998 }
3999 dynstr_append_checked(&sqlbuf,
4000 " GROUP BY LOGFILE_GROUP_NAME, FILE_NAME"
4001 ", ENGINE"
4002 " ORDER BY LOGFILE_GROUP_NAME");
4003
4004 if (mysql_query(mysql, sqlbuf.str) ||
4005 !(tableres = mysql_store_result(mysql)))
4006 {
4007 dynstr_free(&sqlbuf);
4008 if (mysql_errno(mysql) == ER_BAD_TABLE_ERROR ||
4009 mysql_errno(mysql) == ER_BAD_DB_ERROR ||
4010 mysql_errno(mysql) == ER_UNKNOWN_TABLE)
4011 {
4012 fprintf(md_result_file,
4013 "\n--\n-- Not dumping tablespaces as no INFORMATION_SCHEMA.FILES"
4014 " table on this server\n--\n");
4015 check_io(md_result_file);
4016 DBUG_RETURN(0);
4017 }
4018
4019 my_printf_error(0, "Error: '%s' when trying to dump tablespaces",
4020 MYF(0), mysql_error(mysql));
4021 DBUG_RETURN(1);
4022 }
4023
4024 buf[0]= 0;
4025 while ((row= mysql_fetch_row(tableres)))
4026 {
4027 if (strcmp(buf, row[0]) != 0)
4028 first= 1;
4029 if (first)
4030 {
4031 print_comment(md_result_file, 0, "\n--\n-- Logfile group: %s\n--\n",
4032 row[0]);
4033
4034 fprintf(md_result_file, "\nCREATE");
4035 }
4036 else
4037 {
4038 fprintf(md_result_file, "\nALTER");
4039 }
4040 fprintf(md_result_file,
4041 " LOGFILE GROUP %s\n"
4042 " ADD UNDOFILE '%s'\n",
4043 row[0],
4044 row[1]);
4045 if (first)
4046 {
4047 ubs= strstr(row[5],extra_format);
4048 if(!ubs)
4049 break;
4050 ubs+= strlen(extra_format);
4051 endsemi= strstr(ubs,";");
4052 if(endsemi)
4053 endsemi[0]= '\0';
4054 fprintf(md_result_file,
4055 " UNDO_BUFFER_SIZE %s\n",
4056 ubs);
4057 }
4058 fprintf(md_result_file,
4059 " INITIAL_SIZE %s\n"
4060 " ENGINE=%s;\n",
4061 row[3],
4062 row[4]);
4063 check_io(md_result_file);
4064 if (first)
4065 {
4066 first= 0;
4067 strxmov(buf, row[0], NullS);
4068 }
4069 }
4070 dynstr_free(&sqlbuf);
4071 mysql_free_result(tableres);
4072 init_dynamic_string_checked(&sqlbuf,
4073 "SELECT DISTINCT TABLESPACE_NAME,"
4074 " FILE_NAME,"
4075 " LOGFILE_GROUP_NAME,"
4076 " EXTENT_SIZE,"
4077 " INITIAL_SIZE,"
4078 " ENGINE"
4079 " FROM INFORMATION_SCHEMA.FILES"
4080 " WHERE FILE_TYPE = 'DATAFILE'",
4081 256, 1024);
4082
4083 if(ts_where)
4084 dynstr_append_checked(&sqlbuf, ts_where);
4085
4086 dynstr_append_checked(&sqlbuf, " ORDER BY TABLESPACE_NAME, LOGFILE_GROUP_NAME");
4087
4088 if (mysql_query_with_error_report(mysql, &tableres, sqlbuf.str))
4089 {
4090 dynstr_free(&sqlbuf);
4091 DBUG_RETURN(1);
4092 }
4093
4094 buf[0]= 0;
4095 while ((row= mysql_fetch_row(tableres)))
4096 {
4097 if (strcmp(buf, row[0]) != 0)
4098 first= 1;
4099 if (first)
4100 {
4101 print_comment(md_result_file, 0, "\n--\n-- Tablespace: %s\n--\n", row[0]);
4102 fprintf(md_result_file, "\nCREATE");
4103 }
4104 else
4105 {
4106 fprintf(md_result_file, "\nALTER");
4107 }
4108 fprintf(md_result_file,
4109 " TABLESPACE %s\n"
4110 " ADD DATAFILE '%s'\n",
4111 row[0],
4112 row[1]);
4113 if (first)
4114 {
4115 fprintf(md_result_file,
4116 " USE LOGFILE GROUP %s\n"
4117 " EXTENT_SIZE %s\n",
4118 row[2],
4119 row[3]);
4120 }
4121 fprintf(md_result_file,
4122 " INITIAL_SIZE %s\n"
4123 " ENGINE=%s;\n",
4124 row[4],
4125 row[5]);
4126 check_io(md_result_file);
4127 if (first)
4128 {
4129 first= 0;
4130 strxmov(buf, row[0], NullS);
4131 }
4132 }
4133
4134 mysql_free_result(tableres);
4135 dynstr_free(&sqlbuf);
4136 DBUG_RETURN(0);
4137}
4138
4139
4140static int
4141is_ndbinfo(MYSQL* mysql, const char* dbname)
4142{
4143 static int checked_ndbinfo= 0;
4144 static int have_ndbinfo= 0;
4145
4146 if (!checked_ndbinfo)
4147 {
4148 MYSQL_RES *res;
4149 MYSQL_ROW row;
4150 char buf[32], query[64];
4151
4152 my_snprintf(query, sizeof(query),
4153 "SHOW VARIABLES LIKE %s",
4154 quote_for_like("ndbinfo_version", buf));
4155
4156 checked_ndbinfo= 1;
4157
4158 if (mysql_query_with_error_report(mysql, &res, query))
4159 return 0;
4160
4161 if (!(row= mysql_fetch_row(res)))
4162 {
4163 mysql_free_result(res);
4164 return 0;
4165 }
4166
4167 have_ndbinfo= 1;
4168 mysql_free_result(res);
4169 }
4170
4171 if (!have_ndbinfo)
4172 return 0;
4173
4174 if (my_strcasecmp(&my_charset_latin1, dbname, "ndbinfo") == 0)
4175 return 1;
4176
4177 return 0;
4178}
4179
4180
4181static int dump_all_databases()
4182{
4183 MYSQL_ROW row;
4184 MYSQL_RES *tableres;
4185 int result=0;
4186
4187 if (mysql_query_with_error_report(mysql, &tableres, "SHOW DATABASES"))
4188 return 1;
4189 while ((row= mysql_fetch_row(tableres)))
4190 {
4191 if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION &&
4192 !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME))
4193 continue;
4194
4195 if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
4196 !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME))
4197 continue;
4198
4199 if (is_ndbinfo(mysql, row[0]))
4200 continue;
4201
4202 if (dump_all_tables_in_db(row[0]))
4203 result=1;
4204 }
4205 if (seen_views)
4206 {
4207 if (mysql_query(mysql, "SHOW DATABASES") ||
4208 !(tableres= mysql_store_result(mysql)))
4209 {
4210 my_printf_error(0, "Error: Couldn't execute 'SHOW DATABASES': %s",
4211 MYF(0), mysql_error(mysql));
4212 return 1;
4213 }
4214 while ((row= mysql_fetch_row(tableres)))
4215 {
4216 if (mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION &&
4217 !my_strcasecmp(&my_charset_latin1, row[0], INFORMATION_SCHEMA_DB_NAME))
4218 continue;
4219
4220 if (mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
4221 !my_strcasecmp(&my_charset_latin1, row[0], PERFORMANCE_SCHEMA_DB_NAME))
4222 continue;
4223
4224 if (is_ndbinfo(mysql, row[0]))
4225 continue;
4226
4227 if (dump_all_views_in_db(row[0]))
4228 result=1;
4229 }
4230 }
4231 return result;
4232}
4233/* dump_all_databases */
4234
4235
4236static int dump_databases(char **db_names)
4237{
4238 int result=0;
4239 char **db;
4240 DBUG_ENTER("dump_databases");
4241
4242 for (db= db_names ; *db ; db++)
4243 {
4244 if (dump_all_tables_in_db(*db))
4245 result=1;
4246 }
4247 if (!result && seen_views)
4248 {
4249 for (db= db_names ; *db ; db++)
4250 {
4251 if (dump_all_views_in_db(*db))
4252 result=1;
4253 }
4254 }
4255 DBUG_RETURN(result);
4256} /* dump_databases */
4257
4258
4259/*
4260View Specific database initalization.
4261
4262SYNOPSIS
4263 init_dumping_views
4264 qdatabase quoted name of the database
4265
4266RETURN VALUES
4267 0 Success.
4268 1 Failure.
4269*/
4270int init_dumping_views(char *qdatabase __attribute__((unused)))
4271{
4272 return 0;
4273} /* init_dumping_views */
4274
4275
4276/*
4277Table Specific database initalization.
4278
4279SYNOPSIS
4280 init_dumping_tables
4281 qdatabase quoted name of the database
4282
4283RETURN VALUES
4284 0 Success.
4285 1 Failure.
4286*/
4287
4288int init_dumping_tables(char *qdatabase)
4289{
4290 DBUG_ENTER("init_dumping_tables");
4291
4292 if (!opt_create_db)
4293 {
4294 char qbuf[256];
4295 MYSQL_ROW row;
4296 MYSQL_RES *dbinfo;
4297
4298 my_snprintf(qbuf, sizeof(qbuf),
4299 "SHOW CREATE DATABASE IF NOT EXISTS %s",
4300 qdatabase);
4301
4302 if (mysql_query(mysql, qbuf) || !(dbinfo = mysql_store_result(mysql)))
4303 {
4304 /* Old server version, dump generic CREATE DATABASE */
4305 if (opt_drop_database)
4306 fprintf(md_result_file,
4307 "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
4308 qdatabase);
4309 fprintf(md_result_file,
4310 "\nCREATE DATABASE /*!32312 IF NOT EXISTS*/ %s;\n",
4311 qdatabase);
4312 }
4313 else
4314 {
4315 if (opt_drop_database)
4316 fprintf(md_result_file,
4317 "\n/*!40000 DROP DATABASE IF EXISTS %s*/;\n",
4318 qdatabase);
4319 row = mysql_fetch_row(dbinfo);
4320 if (row[1])
4321 {
4322 fprintf(md_result_file,"\n%s;\n",row[1]);
4323 }
4324 mysql_free_result(dbinfo);
4325 }
4326 }
4327 DBUG_RETURN(0);
4328} /* init_dumping_tables */
4329
4330
4331static int init_dumping(char *database, int init_func(char*))
4332{
4333 if (is_ndbinfo(mysql, database))
4334 {
4335 verbose_msg("-- Skipping dump of ndbinfo database\n");
4336 return 0;
4337 }
4338
4339 if (mysql_select_db(mysql, database))
4340 {
4341 DB_error(mysql, "when selecting the database");
4342 return 1; /* If --force */
4343 }
4344 if (!path && !opt_xml)
4345 {
4346 if (opt_databases || opt_alldbs)
4347 {
4348 /*
4349 length of table name * 2 (if name contains quotes), 2 quotes and 0
4350 */
4351 char quoted_database_buf[NAME_LEN*2+3];
4352 char *qdatabase= quote_name(database,quoted_database_buf,opt_quoted);
4353
4354 print_comment(md_result_file, 0,
4355 "\n--\n-- Current Database: %s\n--\n", qdatabase);
4356
4357 /* Call the view or table specific function */
4358 init_func(qdatabase);
4359
4360 fprintf(md_result_file,"\nUSE %s;\n", qdatabase);
4361 check_io(md_result_file);
4362 }
4363 }
4364 if (extended_insert)
4365 init_dynamic_string_checked(&extended_row, "", 1024, 1024);
4366 return 0;
4367} /* init_dumping */
4368
4369
4370/* Return 1 if we should copy the table */
4371
4372my_bool include_table(const uchar *hash_key, size_t len)
4373{
4374 return ! my_hash_search(&ignore_table, hash_key, len);
4375}
4376
4377
4378static int dump_all_tables_in_db(char *database)
4379{
4380 char *table;
4381 uint numrows;
4382 char table_buff[NAME_LEN*2+3];
4383 char hash_key[2*NAME_LEN+2]; /* "db.tablename" */
4384 char *afterdot;
4385 my_bool general_log_table_exists= 0, slow_log_table_exists=0;
4386 int using_mysql_db= !my_strcasecmp(charset_info, database, "mysql");
4387 DBUG_ENTER("dump_all_tables_in_db");
4388
4389 afterdot= strmov(hash_key, database);
4390 *afterdot++= '.';
4391
4392 if (init_dumping(database, init_dumping_tables))
4393 DBUG_RETURN(1);
4394 if (opt_xml)
4395 print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
4396
4397 if (lock_tables)
4398 {
4399 DYNAMIC_STRING query;
4400 init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
4401 for (numrows= 0 ; (table= getTableName(1)) ; )
4402 {
4403 char *end= strmov(afterdot, table);
4404 if (include_table((uchar*) hash_key,end - hash_key))
4405 {
4406 numrows++;
4407 dynstr_append_checked(&query, quote_name(table, table_buff, 1));
4408 dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
4409 }
4410 }
4411 if (numrows && mysql_real_query(mysql, query.str, query.length-1))
4412 DB_error(mysql, "when using LOCK TABLES");
4413 /* We shall continue here, if --force was given */
4414 dynstr_free(&query);
4415 }
4416 if (flush_logs)
4417 {
4418 if (mysql_refresh(mysql, REFRESH_LOG))
4419 DB_error(mysql, "when doing refresh");
4420 /* We shall continue here, if --force was given */
4421 else
4422 verbose_msg("-- dump_all_tables_in_db : logs flushed successfully!\n");
4423 }
4424 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
4425 {
4426 verbose_msg("-- Setting savepoint...\n");
4427 if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp"))
4428 DBUG_RETURN(1);
4429 }
4430 while ((table= getTableName(0)))
4431 {
4432 char *end= strmov(afterdot, table);
4433 if (include_table((uchar*) hash_key, end - hash_key))
4434 {
4435 dump_table(table,database);
4436 my_free(order_by);
4437 order_by= 0;
4438 if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009)
4439 {
4440 if (dump_triggers_for_table(table, database))
4441 {
4442 if (path)
4443 my_fclose(md_result_file, MYF(MY_WME));
4444 maybe_exit(EX_MYSQLERR);
4445 }
4446 }
4447
4448 /**
4449 ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata
4450 lock on table which was already dumped. This allows to avoid blocking
4451 concurrent DDL on this table without sacrificing correctness, as we
4452 won't access table second time and dumps created by --single-transaction
4453 mode have validity point at the start of transaction anyway.
4454 Note that this doesn't make --single-transaction mode with concurrent
4455 DDL safe in general case. It just improves situation for people for whom
4456 it might be working.
4457 */
4458 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
4459 {
4460 verbose_msg("-- Rolling back to savepoint sp...\n");
4461 if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp"))
4462 maybe_exit(EX_MYSQLERR);
4463 }
4464 }
4465 else
4466 {
4467 /*
4468 If general_log and slow_log exists in the 'mysql' database,
4469 we should dump the table structure. But we cannot
4470 call get_table_structure() here as 'LOCK TABLES' query got executed
4471 above on the session and that 'LOCK TABLES' query does not contain
4472 'general_log' and 'slow_log' tables. (you cannot acquire lock
4473 on log tables). Hence mark the existence of these log tables here and
4474 after 'UNLOCK TABLES' query is executed on the session, get the table
4475 structure from server and dump it in the file.
4476 */
4477 if (using_mysql_db)
4478 {
4479 if (!my_strcasecmp(charset_info, table, "general_log"))
4480 general_log_table_exists= 1;
4481 else if (!my_strcasecmp(charset_info, table, "slow_log"))
4482 slow_log_table_exists= 1;
4483 }
4484 }
4485 }
4486
4487 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
4488 {
4489 verbose_msg("-- Releasing savepoint...\n");
4490 if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp"))
4491 DBUG_RETURN(1);
4492 }
4493
4494 if (opt_events && mysql_get_server_version(mysql) >= 50106)
4495 {
4496 DBUG_PRINT("info", ("Dumping events for database %s", database));
4497 dump_events_for_db(database);
4498 }
4499 if (opt_routines && mysql_get_server_version(mysql) >= 50009)
4500 {
4501 DBUG_PRINT("info", ("Dumping routines for database %s", database));
4502 dump_routines_for_db(database);
4503 }
4504 if (opt_xml)
4505 {
4506 fputs("</database>\n", md_result_file);
4507 check_io(md_result_file);
4508 }
4509 if (lock_tables)
4510 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
4511 if (using_mysql_db)
4512 {
4513 char table_type[NAME_LEN];
4514 char ignore_flag;
4515 if (general_log_table_exists)
4516 {
4517 if (!get_table_structure((char *) "general_log",
4518 database, table_type, &ignore_flag) )
4519 verbose_msg("-- Warning: get_table_structure() failed with some internal "
4520 "error for 'general_log' table\n");
4521 }
4522 if (slow_log_table_exists)
4523 {
4524 if (!get_table_structure((char *) "slow_log",
4525 database, table_type, &ignore_flag) )
4526 verbose_msg("-- Warning: get_table_structure() failed with some internal "
4527 "error for 'slow_log' table\n");
4528 }
4529 }
4530 if (flush_privileges && using_mysql_db)
4531 {
4532 fprintf(md_result_file,"\n--\n-- Flush Grant Tables \n--\n");
4533 fprintf(md_result_file,"\n/*! FLUSH PRIVILEGES */;\n");
4534 }
4535 DBUG_RETURN(0);
4536} /* dump_all_tables_in_db */
4537
4538
4539/*
4540 dump structure of views of database
4541
4542 SYNOPSIS
4543 dump_all_views_in_db()
4544 database database name
4545
4546 RETURN
4547 0 OK
4548 1 ERROR
4549*/
4550
4551static my_bool dump_all_views_in_db(char *database)
4552{
4553 char *table;
4554 uint numrows;
4555 char table_buff[NAME_LEN*2+3];
4556 char hash_key[2*NAME_LEN+2]; /* "db.tablename" */
4557 char *afterdot;
4558
4559 afterdot= strmov(hash_key, database);
4560 *afterdot++= '.';
4561
4562 if (init_dumping(database, init_dumping_views))
4563 return 1;
4564 if (opt_xml)
4565 print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
4566 if (lock_tables)
4567 {
4568 DYNAMIC_STRING query;
4569 init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
4570 for (numrows= 0 ; (table= getTableName(1)); )
4571 {
4572 char *end= strmov(afterdot, table);
4573 if (include_table((uchar*) hash_key,end - hash_key))
4574 {
4575 numrows++;
4576 dynstr_append_checked(&query, quote_name(table, table_buff, 1));
4577 dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
4578 }
4579 }
4580 if (numrows && mysql_real_query(mysql, query.str, query.length-1))
4581 DB_error(mysql, "when using LOCK TABLES");
4582 /* We shall continue here, if --force was given */
4583 dynstr_free(&query);
4584 }
4585 if (flush_logs)
4586 {
4587 if (mysql_refresh(mysql, REFRESH_LOG))
4588 DB_error(mysql, "when doing refresh");
4589 /* We shall continue here, if --force was given */
4590 else
4591 verbose_msg("-- dump_all_views_in_db : logs flushed successfully!\n");
4592 }
4593 while ((table= getTableName(0)))
4594 {
4595 char *end= strmov(afterdot, table);
4596 if (include_table((uchar*) hash_key, end - hash_key))
4597 get_view_structure(table, database);
4598 }
4599 if (opt_xml)
4600 {
4601 fputs("</database>\n", md_result_file);
4602 check_io(md_result_file);
4603 }
4604 if (lock_tables)
4605 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
4606 return 0;
4607} /* dump_all_tables_in_db */
4608
4609
4610/*
4611 get_actual_table_name -- executes a SHOW TABLES LIKE '%s' to get the actual
4612 table name from the server for the table name given on the command line.
4613 we do this because the table name given on the command line may be a
4614 different case (e.g. T1 vs t1)
4615
4616 RETURN
4617 pointer to the table name
4618 0 if error
4619*/
4620
4621static char *get_actual_table_name(const char *old_table_name, MEM_ROOT *root)
4622{
4623 char *name= 0;
4624 MYSQL_RES *table_res;
4625 MYSQL_ROW row;
4626 char query[50 + 2*NAME_LEN];
4627 char show_name_buff[FN_REFLEN];
4628 DBUG_ENTER("get_actual_table_name");
4629
4630 /* Check memory for quote_for_like() */
4631 DBUG_ASSERT(2*sizeof(old_table_name) < sizeof(show_name_buff));
4632 my_snprintf(query, sizeof(query), "SHOW TABLES LIKE %s",
4633 quote_for_like(old_table_name, show_name_buff));
4634
4635 if (mysql_query_with_error_report(mysql, 0, query))
4636 return NullS;
4637
4638 if ((table_res= mysql_store_result(mysql)))
4639 {
4640 my_ulonglong num_rows= mysql_num_rows(table_res);
4641 if (num_rows > 0)
4642 {
4643 ulong *lengths;
4644 /*
4645 Return first row
4646 TODO: Return all matching rows
4647 */
4648 row= mysql_fetch_row(table_res);
4649 lengths= mysql_fetch_lengths(table_res);
4650 name= strmake_root(root, row[0], lengths[0]);
4651 }
4652 mysql_free_result(table_res);
4653 }
4654 DBUG_PRINT("exit", ("new_table_name: %s", name));
4655 DBUG_RETURN(name);
4656}
4657
4658
4659static int dump_selected_tables(char *db, char **table_names, int tables)
4660{
4661 char table_buff[NAME_LEN*2+3];
4662 DYNAMIC_STRING lock_tables_query;
4663 MEM_ROOT root;
4664 char **dump_tables, **pos, **end;
4665 DBUG_ENTER("dump_selected_tables");
4666
4667 if (init_dumping(db, init_dumping_tables))
4668 DBUG_RETURN(1);
4669
4670 init_alloc_root(&root, 8192, 0);
4671 if (!(dump_tables= pos= (char**) alloc_root(&root, tables * sizeof(char *))))
4672 die(EX_EOM, "alloc_root failure.");
4673
4674 init_dynamic_string_checked(&lock_tables_query, "LOCK TABLES ", 256, 1024);
4675 for (; tables > 0 ; tables-- , table_names++)
4676 {
4677 /* the table name passed on commandline may be wrong case */
4678 if ((*pos= get_actual_table_name(*table_names, &root)))
4679 {
4680 /* Add found table name to lock_tables_query */
4681 if (lock_tables)
4682 {
4683 dynstr_append_checked(&lock_tables_query, quote_name(*pos, table_buff, 1));
4684 dynstr_append_checked(&lock_tables_query, " READ /*!32311 LOCAL */,");
4685 }
4686 pos++;
4687 }
4688 else
4689 {
4690 if (!ignore_errors)
4691 {
4692 dynstr_free(&lock_tables_query);
4693 free_root(&root, MYF(0));
4694 }
4695 maybe_die(EX_ILLEGAL_TABLE, "Couldn't find table: \"%s\"", *table_names);
4696 /* We shall countinue here, if --force was given */
4697 }
4698 }
4699 end= pos;
4700
4701 /* Can't LOCK TABLES in I_S / P_S, so don't try. */
4702 if (lock_tables &&
4703 !(mysql_get_server_version(mysql) >= FIRST_INFORMATION_SCHEMA_VERSION &&
4704 !my_strcasecmp(&my_charset_latin1, db, INFORMATION_SCHEMA_DB_NAME)) &&
4705 !(mysql_get_server_version(mysql) >= FIRST_PERFORMANCE_SCHEMA_VERSION &&
4706 !my_strcasecmp(&my_charset_latin1, db, PERFORMANCE_SCHEMA_DB_NAME)))
4707 {
4708 if (mysql_real_query(mysql, lock_tables_query.str,
4709 lock_tables_query.length-1))
4710 {
4711 if (!ignore_errors)
4712 {
4713 dynstr_free(&lock_tables_query);
4714 free_root(&root, MYF(0));
4715 }
4716 DB_error(mysql, "when doing LOCK TABLES");
4717 /* We shall countinue here, if --force was given */
4718 }
4719 }
4720 dynstr_free(&lock_tables_query);
4721 if (flush_logs)
4722 {
4723 if (mysql_refresh(mysql, REFRESH_LOG))
4724 {
4725 if (!ignore_errors)
4726 free_root(&root, MYF(0));
4727 DB_error(mysql, "when doing refresh");
4728 }
4729 /* We shall countinue here, if --force was given */
4730 else
4731 verbose_msg("-- dump_selected_tables : logs flushed successfully!\n");
4732 }
4733 if (opt_xml)
4734 print_xml_tag(md_result_file, "", "\n", "database", "name=", db, NullS);
4735
4736 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
4737 {
4738 verbose_msg("-- Setting savepoint...\n");
4739 if (mysql_query_with_error_report(mysql, 0, "SAVEPOINT sp"))
4740 DBUG_RETURN(1);
4741 }
4742
4743 /* Dump each selected table */
4744 for (pos= dump_tables; pos < end; pos++)
4745 {
4746 DBUG_PRINT("info",("Dumping table %s", *pos));
4747 dump_table(*pos, db);
4748 if (opt_dump_triggers &&
4749 mysql_get_server_version(mysql) >= 50009)
4750 {
4751 if (dump_triggers_for_table(*pos, db))
4752 {
4753 if (path)
4754 my_fclose(md_result_file, MYF(MY_WME));
4755 maybe_exit(EX_MYSQLERR);
4756 }
4757 }
4758
4759 /**
4760 ROLLBACK TO SAVEPOINT in --single-transaction mode to release metadata
4761 lock on table which was already dumped. This allows to avoid blocking
4762 concurrent DDL on this table without sacrificing correctness, as we
4763 won't access table second time and dumps created by --single-transaction
4764 mode have validity point at the start of transaction anyway.
4765 Note that this doesn't make --single-transaction mode with concurrent
4766 DDL safe in general case. It just improves situation for people for whom
4767 it might be working.
4768 */
4769 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
4770 {
4771 verbose_msg("-- Rolling back to savepoint sp...\n");
4772 if (mysql_query_with_error_report(mysql, 0, "ROLLBACK TO SAVEPOINT sp"))
4773 maybe_exit(EX_MYSQLERR);
4774 }
4775 }
4776
4777 if (opt_single_transaction && mysql_get_server_version(mysql) >= 50500)
4778 {
4779 verbose_msg("-- Releasing savepoint...\n");
4780 if (mysql_query_with_error_report(mysql, 0, "RELEASE SAVEPOINT sp"))
4781 DBUG_RETURN(1);
4782
4783 }
4784
4785 /* Dump each selected view */
4786 if (seen_views)
4787 {
4788 for (pos= dump_tables; pos < end; pos++)
4789 get_view_structure(*pos, db);
4790 }
4791 if (opt_events && mysql_get_server_version(mysql) >= 50106)
4792 {
4793 DBUG_PRINT("info", ("Dumping events for database %s", db));
4794 dump_events_for_db(db);
4795 }
4796 /* obtain dump of routines (procs/functions) */
4797 if (opt_routines && mysql_get_server_version(mysql) >= 50009)
4798 {
4799 DBUG_PRINT("info", ("Dumping routines for database %s", db));
4800 dump_routines_for_db(db);
4801 }
4802 free_root(&root, MYF(0));
4803 my_free(order_by);
4804 order_by= 0;
4805 if (opt_xml)
4806 {
4807 fputs("</database>\n", md_result_file);
4808 check_io(md_result_file);
4809 }
4810 if (lock_tables)
4811 (void) mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES");
4812 DBUG_RETURN(0);
4813} /* dump_selected_tables */
4814
4815
4816static int do_show_master_status(MYSQL *mysql_con)
4817{
4818 MYSQL_ROW row;
4819 MYSQL_RES *master;
4820 const char *comment_prefix=
4821 (opt_master_data == MYSQL_OPT_MASTER_DATA_COMMENTED_SQL) ? "-- " : "";
4822 if (mysql_query_with_error_report(mysql_con, &master, "SHOW MASTER STATUS"))
4823 {
4824 return 1;
4825 }
4826 else
4827 {
4828 row= mysql_fetch_row(master);
4829 if (row && row[0] && row[1])
4830 {
4831 /* SHOW MASTER STATUS reports file and position */
4832 print_comment(md_result_file, 0,
4833 "\n--\n-- Position to start replication or point-in-time "
4834 "recovery from\n--\n\n");
4835 fprintf(md_result_file,
4836 "%sCHANGE MASTER TO MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n",
4837 comment_prefix, row[0], row[1]);
4838 check_io(md_result_file);
4839 }
4840 else if (!ignore_errors)
4841 {
4842 /* SHOW MASTER STATUS reports nothing and --force is not enabled */
4843 my_printf_error(0, "Error: Binlogging on server not active",
4844 MYF(0));
4845 mysql_free_result(master);
4846 maybe_exit(EX_MYSQLERR);
4847 return 1;
4848 }
4849 mysql_free_result(master);
4850 }
4851 return 0;
4852}
4853
4854static int do_stop_slave_sql(MYSQL *mysql_con)
4855{
4856 MYSQL_RES *slave;
4857 /* We need to check if the slave sql is running in the first place */
4858 if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
4859 return(1);
4860 else
4861 {
4862 MYSQL_ROW row= mysql_fetch_row(slave);
4863 if (row && row[11])
4864 {
4865 /* if SLAVE SQL is not running, we don't stop it */
4866 if (!strcmp(row[11],"No"))
4867 {
4868 mysql_free_result(slave);
4869 /* Silently assume that they don't have the slave running */
4870 return(0);
4871 }
4872 }
4873 }
4874 mysql_free_result(slave);
4875
4876 /* now, stop slave if running */
4877 if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
4878 return(1);
4879
4880 return(0);
4881}
4882
4883static int add_stop_slave(void)
4884{
4885 if (opt_comments)
4886 fprintf(md_result_file,
4887 "\n--\n-- stop slave statement to make a recovery dump)\n--\n\n");
4888 fprintf(md_result_file, "STOP SLAVE;\n");
4889 return(0);
4890}
4891
4892static int add_slave_statements(void)
4893{
4894 if (opt_comments)
4895 fprintf(md_result_file,
4896 "\n--\n-- start slave statement to make a recovery dump)\n--\n\n");
4897 fprintf(md_result_file, "START SLAVE;\n");
4898 return(0);
4899}
4900
4901static int do_show_slave_status(MYSQL *mysql_con)
4902{
4903 MYSQL_RES *slave= NULL;
4904 const char *comment_prefix=
4905 (opt_slave_data == MYSQL_OPT_SLAVE_DATA_COMMENTED_SQL) ? "-- " : "";
4906 if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
4907 {
4908 if (!ignore_errors)
4909 {
4910 /* SHOW SLAVE STATUS reports nothing and --force is not enabled */
4911 my_printf_error(0, "Error: Slave not set up", MYF(0));
4912 }
4913 mysql_free_result(slave);
4914 return 1;
4915 }
4916 else
4917 {
4918 MYSQL_ROW row= mysql_fetch_row(slave);
4919 if (row && row[9] && row[21])
4920 {
4921 /* SHOW MASTER STATUS reports file and position */
4922 if (opt_comments)
4923 fprintf(md_result_file,
4924 "\n--\n-- Position to start replication or point-in-time "
4925 "recovery from (the master of this slave)\n--\n\n");
4926
4927 fprintf(md_result_file, "%sCHANGE MASTER TO ", comment_prefix);
4928
4929 if (opt_include_master_host_port)
4930 {
4931 if (row[1])
4932 fprintf(md_result_file, "MASTER_HOST='%s', ", row[1]);
4933 if (row[3])
4934 fprintf(md_result_file, "MASTER_PORT=%s, ", row[3]);
4935 }
4936 fprintf(md_result_file,
4937 "MASTER_LOG_FILE='%s', MASTER_LOG_POS=%s;\n", row[9], row[21]);
4938
4939 check_io(md_result_file);
4940 }
4941 mysql_free_result(slave);
4942 }
4943 return 0;
4944}
4945
4946static int do_start_slave_sql(MYSQL *mysql_con)
4947{
4948 MYSQL_RES *slave;
4949 /* We need to check if the slave sql is stopped in the first place */
4950 if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
4951 return(1);
4952 else
4953 {
4954 MYSQL_ROW row= mysql_fetch_row(slave);
4955 if (row && row[11])
4956 {
4957 /* if SLAVE SQL is not running, we don't start it */
4958 if (!strcmp(row[11],"Yes"))
4959 {
4960 mysql_free_result(slave);
4961 /* Silently assume that they don't have the slave running */
4962 return(0);
4963 }
4964 }
4965 }
4966 mysql_free_result(slave);
4967
4968 /* now, start slave if stopped */
4969 if (mysql_query_with_error_report(mysql_con, 0, "START SLAVE"))
4970 {
4971 my_printf_error(0, "Error: Unable to start slave", MYF(0));
4972 return 1;
4973 }
4974 return(0);
4975}
4976
4977
4978
4979static int do_flush_tables_read_lock(MYSQL *mysql_con)
4980{
4981 /*
4982 We do first a FLUSH TABLES. If a long update is running, the FLUSH TABLES
4983 will wait but will not stall the whole mysqld, and when the long update is
4984 done the FLUSH TABLES WITH READ LOCK will start and succeed quickly. So,
4985 FLUSH TABLES is to lower the probability of a stage where both mysqldump
4986 and most client connections are stalled. Of course, if a second long
4987 update starts between the two FLUSHes, we have that bad stall.
4988 */
4989 return
4990 ( mysql_query_with_error_report(mysql_con, 0,
4991 ((opt_master_data != 0) ?
4992 "FLUSH /*!40101 LOCAL */ TABLES" :
4993 "FLUSH TABLES")) ||
4994 mysql_query_with_error_report(mysql_con, 0,
4995 "FLUSH TABLES WITH READ LOCK") );
4996}
4997
4998
4999static int do_unlock_tables(MYSQL *mysql_con)
5000{
5001 return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES");
5002}
5003
5004static int get_bin_log_name(MYSQL *mysql_con,
5005 char* buff_log_name, uint buff_len)
5006{
5007 MYSQL_RES *res;
5008 MYSQL_ROW row;
5009
5010 if (mysql_query(mysql_con, "SHOW MASTER STATUS") ||
5011 !(res= mysql_store_result(mysql)))
5012 return 1;
5013
5014 if (!(row= mysql_fetch_row(res)))
5015 {
5016 mysql_free_result(res);
5017 return 1;
5018 }
5019 /*
5020 Only one row is returned, and the first column is the name of the
5021 active log.
5022 */
5023 strmake(buff_log_name, row[0], buff_len - 1);
5024
5025 mysql_free_result(res);
5026 return 0;
5027}
5028
5029static int purge_bin_logs_to(MYSQL *mysql_con, char* log_name)
5030{
5031 DYNAMIC_STRING str;
5032 int err;
5033 init_dynamic_string_checked(&str, "PURGE BINARY LOGS TO '", 1024, 1024);
5034 dynstr_append_checked(&str, log_name);
5035 dynstr_append_checked(&str, "'");
5036 err = mysql_query_with_error_report(mysql_con, 0, str.str);
5037 dynstr_free(&str);
5038 return err;
5039}
5040
5041
5042static int start_transaction(MYSQL *mysql_con)
5043{
5044 verbose_msg("-- Starting transaction...\n");
5045 /*
5046 We use BEGIN for old servers. --single-transaction --master-data will fail
5047 on old servers, but that's ok as it was already silently broken (it didn't
5048 do a consistent read, so better tell people frankly, with the error).
5049
5050 We want the first consistent read to be used for all tables to dump so we
5051 need the REPEATABLE READ level (not anything lower, for example READ
5052 COMMITTED would give one new consistent read per dumped table).
5053 */
5054 if ((mysql_get_server_version(mysql_con) < 40100) && opt_master_data)
5055 {
5056 fprintf(stderr, "-- %s: the combination of --single-transaction and "
5057 "--master-data requires a MySQL server version of at least 4.1 "
5058 "(current server's version is %s). %s\n",
5059 ignore_errors ? "Warning" : "Error",
5060 mysql_con->server_version ? mysql_con->server_version : "unknown",
5061 ignore_errors ? "Continuing due to --force, backup may not be consistent across all tables!" : "Aborting.");
5062 if (!ignore_errors)
5063 exit(EX_MYSQLERR);
5064 }
5065
5066 return (mysql_query_with_error_report(mysql_con, 0,
5067 "SET SESSION TRANSACTION ISOLATION "
5068 "LEVEL REPEATABLE READ") ||
5069 mysql_query_with_error_report(mysql_con, 0,
5070 "START TRANSACTION "
5071 "/*!40100 WITH CONSISTENT SNAPSHOT */"));
5072}
5073
5074
5075static ulong find_set(TYPELIB *lib, const char *x, uint length,
5076 char **err_pos, uint *err_len)
5077{
5078 const char *end= x + length;
5079 ulong found= 0;
5080 uint find;
5081 char buff[255];
5082
5083 *err_pos= 0; /* No error yet */
5084 while (end > x && my_isspace(charset_info, end[-1]))
5085 end--;
5086
5087 *err_len= 0;
5088 if (x != end)
5089 {
5090 const char *start= x;
5091 for (;;)
5092 {
5093 const char *pos= start;
5094 uint var_len;
5095
5096 for (; pos != end && *pos != ','; pos++) ;
5097 var_len= (uint) (pos - start);
5098 strmake(buff, start, MY_MIN(sizeof(buff) - 1, var_len));
5099 find= find_type(buff, lib, FIND_TYPE_BASIC);
5100 if (!find)
5101 {
5102 *err_pos= (char*) start;
5103 *err_len= var_len;
5104 }
5105 else
5106 found|= ((longlong) 1 << (find - 1));
5107 if (pos == end)
5108 break;
5109 start= pos + 1;
5110 }
5111 }
5112 return found;
5113}
5114
5115
5116/* Print a value with a prefix on file */
5117static void print_value(FILE *file, MYSQL_RES *result, MYSQL_ROW row,
5118 const char *prefix, const char *name,
5119 int string_value)
5120{
5121 MYSQL_FIELD *field;
5122 mysql_field_seek(result, 0);
5123
5124 for ( ; (field= mysql_fetch_field(result)) ; row++)
5125 {
5126 if (!strcmp(field->name,name))
5127 {
5128 if (row[0] && row[0][0] && strcmp(row[0],"0")) /* Skip default */
5129 {
5130 fputc(' ',file);
5131 fputs(prefix, file);
5132 if (string_value)
5133 unescape(file,row[0],(uint) strlen(row[0]));
5134 else
5135 fputs(row[0], file);
5136 check_io(file);
5137 return;
5138 }
5139 }
5140 }
5141 return; /* This shouldn't happen */
5142} /* print_value */
5143
5144
5145/*
5146 SYNOPSIS
5147
5148 Check if we the table is one of the table types that should be ignored:
5149 MRG_ISAM, MRG_MYISAM, if opt_delayed, if that table supports delayed inserts.
5150 If the table should be altogether ignored, it returns a TRUE, FALSE if it
5151 should not be ignored. If the user has selected to use INSERT DELAYED, it
5152 sets the value of the bool pointer supports_delayed_inserts to 0 if not
5153 supported, 1 if it is supported.
5154
5155 ARGS
5156
5157 check_if_ignore_table()
5158 table_name Table name to check
5159 table_type Type of table
5160
5161 GLOBAL VARIABLES
5162 mysql MySQL connection
5163 verbose Write warning messages
5164
5165 RETURN
5166 char (bit value) See IGNORE_ values at top
5167*/
5168
5169char check_if_ignore_table(const char *table_name, char *table_type)
5170{
5171 char result= IGNORE_NONE;
5172 char buff[FN_REFLEN+80], show_name_buff[FN_REFLEN];
5173 MYSQL_RES *res= NULL;
5174 MYSQL_ROW row;
5175 DBUG_ENTER("check_if_ignore_table");
5176
5177 /* Check memory for quote_for_like() */
5178 DBUG_ASSERT(2*sizeof(table_name) < sizeof(show_name_buff));
5179 my_snprintf(buff, sizeof(buff), "show table status like %s",
5180 quote_for_like(table_name, show_name_buff));
5181 if (mysql_query_with_error_report(mysql, &res, buff))
5182 {
5183 if (mysql_errno(mysql) != ER_PARSE_ERROR)
5184 { /* If old MySQL version */
5185 verbose_msg("-- Warning: Couldn't get status information for "
5186 "table %s (%s)\n", table_name, mysql_error(mysql));
5187 DBUG_RETURN(result); /* assume table is ok */
5188 }
5189 }
5190 if (!(row= mysql_fetch_row(res)))
5191 {
5192 fprintf(stderr,
5193 "Error: Couldn't read status information for table %s (%s)\n",
5194 table_name, mysql_error(mysql));
5195 mysql_free_result(res);
5196 DBUG_RETURN(result); /* assume table is ok */
5197 }
5198 if (!(row[1]))
5199 strmake(table_type, "VIEW", NAME_LEN-1);
5200 else
5201 {
5202 /*
5203 If the table type matches any of these, we do support delayed inserts.
5204 Note: we do not want to skip dumping this table if if is not one of
5205 these types, but we do want to use delayed inserts in the dump if
5206 the table type is _NOT_ one of these types
5207 */
5208 strmake(table_type, row[1], NAME_LEN-1);
5209 if (opt_delayed)
5210 {
5211 if (strcmp(table_type,"MyISAM") &&
5212 strcmp(table_type,"ISAM") &&
5213 strcmp(table_type,"ARCHIVE") &&
5214 strcmp(table_type,"HEAP") &&
5215 strcmp(table_type,"MEMORY"))
5216 result= IGNORE_INSERT_DELAYED;
5217 }
5218
5219 /*
5220 If these two types, we do want to skip dumping the table
5221 */
5222 if (!opt_no_data &&
5223 (!my_strcasecmp(&my_charset_latin1, table_type, "MRG_MyISAM") ||
5224 !strcmp(table_type,"MRG_ISAM") ||
5225 !strcmp(table_type,"FEDERATED")))
5226 result= IGNORE_DATA;
5227 }
5228 mysql_free_result(res);
5229 DBUG_RETURN(result);
5230}
5231
5232
5233/*
5234 Get string of comma-separated primary key field names
5235
5236 SYNOPSIS
5237 char *primary_key_fields(const char *table_name)
5238 RETURNS pointer to allocated buffer (must be freed by caller)
5239 table_name quoted table name
5240
5241 DESCRIPTION
5242 Use SHOW KEYS FROM table_name, allocate a buffer to hold the
5243 field names, and then build that string and return the pointer
5244 to that buffer.
5245
5246 Returns NULL if there is no PRIMARY or UNIQUE key on the table,
5247 or if there is some failure. It is better to continue to dump
5248 the table unsorted, rather than exit without dumping the data.
5249*/
5250
5251static char *primary_key_fields(const char *table_name)
5252{
5253 MYSQL_RES *res= NULL;
5254 MYSQL_ROW row;
5255 /* SHOW KEYS FROM + table name * 2 (escaped) + 2 quotes + \0 */
5256 char show_keys_buff[15 + NAME_LEN * 2 + 3];
5257 uint result_length= 0;
5258 char *result= 0;
5259 char buff[NAME_LEN * 2 + 3];
5260 char *quoted_field;
5261
5262 my_snprintf(show_keys_buff, sizeof(show_keys_buff),
5263 "SHOW KEYS FROM %s", table_name);
5264 if (mysql_query(mysql, show_keys_buff) ||
5265 !(res= mysql_store_result(mysql)))
5266 {
5267 fprintf(stderr, "Warning: Couldn't read keys from table %s;"
5268 " records are NOT sorted (%s)\n",
5269 table_name, mysql_error(mysql));
5270 /* Don't exit, because it's better to print out unsorted records */
5271 goto cleanup;
5272 }
5273
5274 /*
5275 * Figure out the length of the ORDER BY clause result.
5276 * Note that SHOW KEYS is ordered: a PRIMARY key is always the first
5277 * row, and UNIQUE keys come before others. So we only need to check
5278 * the first key, not all keys.
5279 */
5280 if ((row= mysql_fetch_row(res)) && atoi(row[1]) == 0)
5281 {
5282 /* Key is unique */
5283 do
5284 {
5285 quoted_field= quote_name(row[4], buff, 0);
5286 result_length+= strlen(quoted_field) + 1; /* + 1 for ',' or \0 */
5287 } while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1);
5288 }
5289
5290 /* Build the ORDER BY clause result */
5291 if (result_length)
5292 {
5293 char *end;
5294 /* result (terminating \0 is already in result_length) */
5295 result= my_malloc(result_length + 10, MYF(MY_WME));
5296 if (!result)
5297 {
5298 fprintf(stderr, "Error: Not enough memory to store ORDER BY clause\n");
5299 goto cleanup;
5300 }
5301 mysql_data_seek(res, 0);
5302 row= mysql_fetch_row(res);
5303 quoted_field= quote_name(row[4], buff, 0);
5304 end= strmov(result, quoted_field);
5305 while ((row= mysql_fetch_row(res)) && atoi(row[3]) > 1)
5306 {
5307 quoted_field= quote_name(row[4], buff, 0);
5308 end= strxmov(end, ",", quoted_field, NullS);
5309 }
5310 }
5311
5312cleanup:
5313 if (res)
5314 mysql_free_result(res);
5315
5316 return result;
5317}
5318
5319
5320/*
5321 Replace a substring
5322
5323 SYNOPSIS
5324 replace
5325 ds_str The string to search and perform the replace in
5326 search_str The string to search for
5327 search_len Length of the string to search for
5328 replace_str The string to replace with
5329 replace_len Length of the string to replace with
5330
5331 RETURN
5332 0 String replaced
5333 1 Could not find search_str in str
5334*/
5335
5336static int replace(DYNAMIC_STRING *ds_str,
5337 const char *search_str, ulong search_len,
5338 const char *replace_str, ulong replace_len)
5339{
5340 DYNAMIC_STRING ds_tmp;
5341 const char *start= strstr(ds_str->str, search_str);
5342 if (!start)
5343 return 1;
5344 init_dynamic_string_checked(&ds_tmp, "",
5345 ds_str->length + replace_len, 256);
5346 dynstr_append_mem_checked(&ds_tmp, ds_str->str, start - ds_str->str);
5347 dynstr_append_mem_checked(&ds_tmp, replace_str, replace_len);
5348 dynstr_append_checked(&ds_tmp, start + search_len);
5349 dynstr_set_checked(ds_str, ds_tmp.str);
5350 dynstr_free(&ds_tmp);
5351 return 0;
5352}
5353
5354
5355/**
5356 This function sets the session binlog in the dump file.
5357 When --set-gtid-purged is used, this function is called to
5358 disable the session binlog and at the end of the dump, to restore
5359 the session binlog.
5360
5361 @note: md_result_file should have been opened, before
5362 this function is called.
5363
5364 @param[in] flag If FALSE, disable binlog.
5365 If TRUE and binlog disabled previously,
5366 restore the session binlog.
5367*/
5368
5369static void set_session_binlog(my_bool flag)
5370{
5371 static my_bool is_binlog_disabled= FALSE;
5372
5373 if (!flag && !is_binlog_disabled)
5374 {
5375 fprintf(md_result_file,
5376 "SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;\n");
5377 fprintf(md_result_file, "SET @@SESSION.SQL_LOG_BIN= 0;\n");
5378 is_binlog_disabled= 1;
5379 }
5380 else if (flag && is_binlog_disabled)
5381 {
5382 fprintf(md_result_file,
5383 "SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;\n");
5384 is_binlog_disabled= 0;
5385 }
5386}
5387
5388
5389/**
5390 This function gets the GTID_EXECUTED sets from the
5391 server and assigns those sets to GTID_PURGED in the
5392 dump file.
5393
5394 @param[in] mysql_con connection to the server
5395
5396 @retval FALSE succesfully printed GTID_PURGED sets
5397 in the dump file.
5398 @retval TRUE failed.
5399
5400*/
5401
5402static my_bool add_set_gtid_purged(MYSQL *mysql_con)
5403{
5404 MYSQL_RES *gtid_purged_res;
5405 MYSQL_ROW gtid_set;
5406 ulong num_sets, idx;
5407
5408 /* query to get the GTID_EXECUTED */
5409 if (mysql_query_with_error_report(mysql_con, >id_purged_res,
5410 "SELECT @@GLOBAL.GTID_EXECUTED"))
5411 return TRUE;
5412
5413 /* Proceed only if gtid_purged_res is non empty */
5414 if ((num_sets= mysql_num_rows(gtid_purged_res)) > 0)
5415 {
5416 if (opt_comments)
5417 fprintf(md_result_file,
5418 "\n--\n-- GTID state at the beginning of the backup \n--\n\n");
5419
5420 fprintf(md_result_file,"SET @@GLOBAL.GTID_PURGED='");
5421
5422 /* formatting is not required, even for multiple gtid sets */
5423 for (idx= 0; idx< num_sets-1; idx++)
5424 {
5425 gtid_set= mysql_fetch_row(gtid_purged_res);
5426 fprintf(md_result_file,"%s,", (char*)gtid_set[0]);
5427 }
5428 /* for the last set */
5429 gtid_set= mysql_fetch_row(gtid_purged_res);
5430 /* close the SET expression */
5431 fprintf(md_result_file,"%s';\n", (char*)gtid_set[0]);
5432 }
5433
5434 return FALSE; /*success */
5435}
5436
5437
5438/**
5439 This function processes the opt_set_gtid_purged option.
5440 This function also calls set_session_binlog() function before
5441 setting the SET @@GLOBAL.GTID_PURGED in the output.
5442
5443 @param[in] mysql_con the connection to the server
5444
5445 @retval FALSE successful according to the value
5446 of opt_set_gtid_purged.
5447 @retval TRUE fail.
5448*/
5449
5450static my_bool process_set_gtid_purged(MYSQL* mysql_con)
5451{
5452 MYSQL_RES *gtid_mode_res;
5453 MYSQL_ROW gtid_mode_row;
5454 char *gtid_mode_val= 0;
5455 char buf[32], query[64];
5456
5457 if (opt_set_gtid_purged_mode == SET_GTID_PURGED_OFF)
5458 return FALSE; /* nothing to be done */
5459
5460 /*
5461 Check if the server has the knowledge of GTIDs(pre mysql-5.6)
5462 or if the gtid_mode is ON or OFF.
5463 */
5464 my_snprintf(query, sizeof(query), "SHOW VARIABLES LIKE %s",
5465 quote_for_like("gtid_mode", buf));
5466
5467 if (mysql_query_with_error_report(mysql_con, >id_mode_res, query))
5468 return TRUE;
5469
5470 gtid_mode_row = mysql_fetch_row(gtid_mode_res);
5471
5472 /*
5473 gtid_mode_row is NULL for pre 5.6 versions. For versions >= 5.6,
5474 get the gtid_mode value from the second column.
5475 */
5476 gtid_mode_val = gtid_mode_row ? (char*)gtid_mode_row[1] : NULL;
5477
5478 if (gtid_mode_val && strcmp(gtid_mode_val, "OFF"))
5479 {
5480 /*
5481 For any gtid_mode !=OFF and irrespective of --set-gtid-purged
5482 being AUTO or ON, add GTID_PURGED in the output.
5483 */
5484 if (opt_databases || !opt_alldbs || !opt_dump_triggers
5485 || !opt_routines || !opt_events)
5486 {
5487 fprintf(stderr,"Warning: A partial dump from a server that has GTIDs will "
5488 "by default include the GTIDs of all transactions, even "
5489 "those that changed suppressed parts of the database. If "
5490 "you don't want to restore GTIDs, pass "
5491 "--set-gtid-purged=OFF. To make a complete dump, pass "
5492 "--all-databases --triggers --routines --events. \n");
5493 }
5494
5495 set_session_binlog(FALSE);
5496 if (add_set_gtid_purged(mysql_con))
5497 return TRUE;
5498 }
5499 else /* gtid_mode is off */
5500 {
5501 if (opt_set_gtid_purged_mode == SET_GTID_PURGED_ON)
5502 {
5503 fprintf(stderr, "Error: Server has GTIDs disabled.\n");
5504 return TRUE;
5505 }
5506 }
5507
5508 return FALSE;
5509}
5510
5511
5512/*
5513 Getting VIEW structure
5514
5515 SYNOPSIS
5516 get_view_structure()
5517 table view name
5518 db db name
5519
5520 RETURN
5521 0 OK
5522 1 ERROR
5523*/
5524
5525static my_bool get_view_structure(char *table, char* db)
5526{
5527 MYSQL_RES *table_res;
5528 MYSQL_ROW row;
5529 MYSQL_FIELD *field;
5530 char *result_table, *opt_quoted_table;
5531 char table_buff[NAME_LEN*2+3];
5532 char table_buff2[NAME_LEN*2+3];
5533 char query[QUERY_LENGTH];
5534 FILE *sql_file= md_result_file;
5535 DBUG_ENTER("get_view_structure");
5536
5537 if (opt_no_create_info) /* Don't write table creation info */
5538 DBUG_RETURN(0);
5539
5540 verbose_msg("-- Retrieving view structure for table %s...\n", table);
5541
5542#ifdef NOT_REALLY_USED_YET
5543 sprintf(insert_pat,"SET SQL_QUOTE_SHOW_CREATE=%d",
5544 (opt_quoted || opt_keywords));
5545#endif
5546
5547 result_table= quote_name(table, table_buff, 1);
5548 opt_quoted_table= quote_name(table, table_buff2, 0);
5549
5550 if (switch_character_set_results(mysql, "binary"))
5551 DBUG_RETURN(1);
5552
5553 my_snprintf(query, sizeof(query), "SHOW CREATE TABLE %s", result_table);
5554
5555 if (mysql_query_with_error_report(mysql, &table_res, query))
5556 {
5557 switch_character_set_results(mysql, default_charset);
5558 DBUG_RETURN(0);
5559 }
5560
5561 /* Check if this is a view */
5562 field= mysql_fetch_field_direct(table_res, 0);
5563 if (strcmp(field->name, "View") != 0)
5564 {
5565 switch_character_set_results(mysql, default_charset);
5566 verbose_msg("-- It's base table, skipped\n");
5567 DBUG_RETURN(0);
5568 }
5569
5570 /* If requested, open separate .sql file for this view */
5571 if (path)
5572 {
5573 if (!(sql_file= open_sql_file_for_table(table, O_WRONLY)))
5574 DBUG_RETURN(1);
5575
5576 write_header(sql_file, db);
5577 }
5578
5579 print_comment(sql_file, 0,
5580 "\n--\n-- Final view structure for view %s\n--\n\n",
5581 result_table);
5582
5583 verbose_msg("-- Dropping the temporary view structure created\n");
5584 fprintf(sql_file, "/*!50001 DROP VIEW IF EXISTS %s*/;\n", opt_quoted_table);
5585
5586 my_snprintf(query, sizeof(query),
5587 "SELECT CHECK_OPTION, DEFINER, SECURITY_TYPE, "
5588 " CHARACTER_SET_CLIENT, COLLATION_CONNECTION "
5589 "FROM information_schema.views "
5590 "WHERE table_name=\"%s\" AND table_schema=\"%s\"", table, db);
5591
5592 if (mysql_query(mysql, query))
5593 {
5594 /*
5595 Use the raw output from SHOW CREATE TABLE if
5596 information_schema query fails.
5597 */
5598 row= mysql_fetch_row(table_res);
5599 fprintf(sql_file, "/*!50001 %s */;\n", row[1]);
5600 check_io(sql_file);
5601 mysql_free_result(table_res);
5602 }
5603 else
5604 {
5605 char *ptr;
5606 ulong *lengths;
5607 char search_buf[256], replace_buf[256];
5608 ulong search_len, replace_len;
5609 DYNAMIC_STRING ds_view;
5610
5611 /* Save the result of SHOW CREATE TABLE in ds_view */
5612 row= mysql_fetch_row(table_res);
5613 lengths= mysql_fetch_lengths(table_res);
5614 init_dynamic_string_checked(&ds_view, row[1], lengths[1] + 1, 1024);
5615 mysql_free_result(table_res);
5616
5617 /* Get the result from "select ... information_schema" */
5618 if (!(table_res= mysql_store_result(mysql)) ||
5619 !(row= mysql_fetch_row(table_res)))
5620 {
5621 if (table_res)
5622 mysql_free_result(table_res);
5623 dynstr_free(&ds_view);
5624 DB_error(mysql, "when trying to save the result of SHOW CREATE TABLE in ds_view.");
5625 DBUG_RETURN(1);
5626 }
5627
5628 lengths= mysql_fetch_lengths(table_res);
5629
5630 /*
5631 "WITH %s CHECK OPTION" is available from 5.0.2
5632 Surround it with !50002 comments
5633 */
5634 if (strcmp(row[0], "NONE"))
5635 {
5636
5637 ptr= search_buf;
5638 search_len= (ulong)(strxmov(ptr, "WITH ", row[0],
5639 " CHECK OPTION", NullS) - ptr);
5640 ptr= replace_buf;
5641 replace_len=(ulong)(strxmov(ptr, "*/\n/*!50002 WITH ", row[0],
5642 " CHECK OPTION", NullS) - ptr);
5643 replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
5644 }
5645
5646 /*
5647 "DEFINER=%s SQL SECURITY %s" is available from 5.0.13
5648 Surround it with !50013 comments
5649 */
5650 {
5651 size_t user_name_len;
5652 char user_name_str[USERNAME_LENGTH + 1];
5653 char quoted_user_name_str[USERNAME_LENGTH * 2 + 3];
5654 size_t host_name_len;
5655 char host_name_str[HOSTNAME_LENGTH + 1];
5656 char quoted_host_name_str[HOSTNAME_LENGTH * 2 + 3];
5657
5658 parse_user(row[1], lengths[1], user_name_str, &user_name_len,
5659 host_name_str, &host_name_len);
5660
5661 ptr= search_buf;
5662 search_len=
5663 (ulong)(strxmov(ptr, "DEFINER=",
5664 quote_name(user_name_str, quoted_user_name_str, FALSE),
5665 "@",
5666 quote_name(host_name_str, quoted_host_name_str, FALSE),
5667 " SQL SECURITY ", row[2], NullS) - ptr);
5668 ptr= replace_buf;
5669 replace_len=
5670 (ulong)(strxmov(ptr, "*/\n/*!50013 DEFINER=",
5671 quote_name(user_name_str, quoted_user_name_str, FALSE),
5672 "@",
5673 quote_name(host_name_str, quoted_host_name_str, FALSE),
5674 " SQL SECURITY ", row[2],
5675 " */\n/*!50001", NullS) - ptr);
5676 replace(&ds_view, search_buf, search_len, replace_buf, replace_len);
5677 }
5678
5679 /* Dump view structure to file */
5680
5681 fprintf(sql_file,
5682 "/*!50001 SET @saved_cs_client = @@character_set_client */;\n"
5683 "/*!50001 SET @saved_cs_results = @@character_set_results */;\n"
5684 "/*!50001 SET @saved_col_connection = @@collation_connection */;\n"
5685 "/*!50001 SET character_set_client = %s */;\n"
5686 "/*!50001 SET character_set_results = %s */;\n"
5687 "/*!50001 SET collation_connection = %s */;\n"
5688 "/*!50001 %s */;\n"
5689 "/*!50001 SET character_set_client = @saved_cs_client */;\n"
5690 "/*!50001 SET character_set_results = @saved_cs_results */;\n"
5691 "/*!50001 SET collation_connection = @saved_col_connection */;\n",
5692 (const char *) row[3],
5693 (const char *) row[3],
5694 (const char *) row[4],
5695 (const char *) ds_view.str);
5696
5697 check_io(sql_file);
5698 mysql_free_result(table_res);
5699 dynstr_free(&ds_view);
5700 }
5701
5702 if (switch_character_set_results(mysql, default_charset))
5703 DBUG_RETURN(1);
5704
5705 /* If a separate .sql file was opened, close it now */
5706 if (sql_file != md_result_file)
5707 {
5708 fputs("\n", sql_file);
5709 write_footer(sql_file);
5710 my_fclose(sql_file, MYF(MY_WME));
5711 }
5712 DBUG_RETURN(0);
5713}
5714
5715/*
5716 The following functions are wrappers for the dynamic string functions
5717 and if they fail, the wrappers will terminate the current process.
5718*/
5719
5720#define DYNAMIC_STR_ERROR_MSG "Couldn't perform DYNAMIC_STRING operation"
5721
5722static void init_dynamic_string_checked(DYNAMIC_STRING *str, const char *init_str,
5723 uint init_alloc, uint alloc_increment)
5724{
5725 if (init_dynamic_string(str, init_str, init_alloc, alloc_increment))
5726 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
5727}
5728
5729static void dynstr_append_checked(DYNAMIC_STRING* dest, const char* src)
5730{
5731 if (dynstr_append(dest, src))
5732 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
5733}
5734
5735static void dynstr_set_checked(DYNAMIC_STRING *str, const char *init_str)
5736{
5737 if (dynstr_set(str, init_str))
5738 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
5739}
5740
5741static void dynstr_append_mem_checked(DYNAMIC_STRING *str, const char *append,
5742 uint length)
5743{
5744 if (dynstr_append_mem(str, append, length))
5745 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
5746}
5747
5748static void dynstr_realloc_checked(DYNAMIC_STRING *str, ulong additional_size)
5749{
5750 if (dynstr_realloc(str, additional_size))
5751 die(EX_MYSQLERR, DYNAMIC_STR_ERROR_MSG);
5752}
5753
5754
5755int main(int argc, char **argv)
5756{
5757 char bin_log_name[FN_REFLEN];
5758 int exit_code, md_result_fd;
5759 MY_INIT("mysqldump");
5760
5761 compatible_mode_normal_str[0]= 0;
5762 default_charset= (char *)mysql_universal_client_charset;
5763 memset(&ignore_table, 0, sizeof(ignore_table));
5764
5765 exit_code= get_options(&argc, &argv);
5766 if (exit_code)
5767 {
5768 free_resources();
5769 exit(exit_code);
5770 }
5771
5772 /*
5773 Disable comments in xml mode if 'comments' option is not explicitly used.
5774 */
5775 if (opt_xml && !opt_comments_used)
5776 opt_comments= 0;
5777
5778 if (log_error_file)
5779 {
5780 if(!(stderror_file= freopen(log_error_file, "a+", stderr)))
5781 {
5782 free_resources();
5783 exit(EX_MYSQLERR);
5784 }
5785 }
5786
5787 if (connect_to_db(current_host, current_user, opt_password))
5788 {
5789 free_resources();
5790 exit(EX_MYSQLERR);
5791 }
5792 if (!path)
5793 write_header(md_result_file, *argv);
5794
5795 if (opt_slave_data && do_stop_slave_sql(mysql))
5796 goto err;
5797
5798 if ((opt_lock_all_tables || opt_master_data ||
5799 (opt_single_transaction && flush_logs)) &&
5800 do_flush_tables_read_lock(mysql))
5801 goto err;
5802
5803 /*
5804 Flush logs before starting transaction since
5805 this causes implicit commit starting mysql-5.5.
5806 */
5807 if (opt_lock_all_tables || opt_master_data ||
5808 (opt_single_transaction && flush_logs) ||
5809 opt_delete_master_logs)
5810 {
5811 if (flush_logs || opt_delete_master_logs)
5812 {
5813 if (mysql_refresh(mysql, REFRESH_LOG))
5814 goto err;
5815 verbose_msg("-- main : logs flushed successfully!\n");
5816 }
5817
5818 /* Not anymore! That would not be sensible. */
5819 flush_logs= 0;
5820 }
5821
5822 if (opt_delete_master_logs)
5823 {
5824 if (get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name)))
5825 goto err;
5826 }
5827
5828 if (opt_single_transaction && start_transaction(mysql))
5829 goto err;
5830
5831 /* Add 'STOP SLAVE to beginning of dump */
5832 if (opt_slave_apply && add_stop_slave())
5833 goto err;
5834
5835
5836 /* Process opt_set_gtid_purged and add SET @@GLOBAL.GTID_PURGED if required. */
5837 if (process_set_gtid_purged(mysql))
5838 goto err;
5839
5840
5841 if (opt_master_data && do_show_master_status(mysql))
5842 goto err;
5843 if (opt_slave_data && do_show_slave_status(mysql))
5844 goto err;
5845 if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
5846 goto err;
5847
5848 if (opt_alltspcs)
5849 dump_all_tablespaces();
5850
5851 if (opt_alldbs)
5852 {
5853 if (!opt_alltspcs && !opt_notspcs)
5854 dump_all_tablespaces();
5855 dump_all_databases();
5856 }
5857 else
5858 {
5859 // Check all arguments meet length condition. Currently database and table
5860 // names are limited to NAME_LEN bytes and stack-based buffers assumes
5861 // that escaped name will be not longer than NAME_LEN*2 + 2 bytes long.
5862 int argument;
5863 for (argument= 0; argument < argc; argument++)
5864 {
5865 size_t argument_length= strlen(argv[argument]);
5866 if (argument_length > NAME_LEN)
5867 {
5868 die(EX_CONSCHECK, "[ERROR] Argument '%s' is too long, it cannot be "
5869 "name for any table or database.\n", argv[argument]);
5870 }
5871 }
5872
5873 if (argc > 1 && !opt_databases)
5874 {
5875 /* Only one database and selected table(s) */
5876 if (!opt_alltspcs && !opt_notspcs)
5877 dump_tablespaces_for_tables(*argv, (argv + 1), (argc - 1));
5878 dump_selected_tables(*argv, (argv + 1), (argc - 1));
5879 }
5880 else
5881 {
5882 /* One or more databases, all tables */
5883 if (!opt_alltspcs && !opt_notspcs)
5884 dump_tablespaces_for_databases(argv);
5885 dump_databases(argv);
5886 }
5887 }
5888
5889 /* if --dump-slave , start the slave sql thread */
5890 if (opt_slave_data && do_start_slave_sql(mysql))
5891 goto err;
5892
5893 /*
5894 if --set-gtid-purged, restore binlog at the end of the session
5895 if required.
5896 */
5897 set_session_binlog(TRUE);
5898
5899 /* add 'START SLAVE' to end of dump */
5900 if (opt_slave_apply && add_slave_statements())
5901 goto err;
5902
5903 if (md_result_file)
5904 md_result_fd= my_fileno(md_result_file);
5905
5906 /*
5907 Ensure dumped data flushed.
5908 First we will flush the file stream data to kernel buffers with fflush().
5909 Second we will flush the kernel buffers data to physical disk file with
5910 my_sync(), this will make sure the data succeessfully dumped to disk file.
5911 fsync() fails with EINVAL if stdout is not redirected to any file, hence
5912 MY_IGNORE_BADFD is passed to ingnore that error.
5913 */
5914 if (md_result_file &&
5915 (fflush(md_result_file) || my_sync(md_result_fd, MYF(MY_IGNORE_BADFD))))
5916 {
5917 if (!first_error)
5918 first_error= EX_MYSQLERR;
5919 goto err;
5920 }
5921 /* everything successful, purge the old logs files */
5922 if (opt_delete_master_logs && purge_bin_logs_to(mysql, bin_log_name))
5923 goto err;
5924
5925#ifdef HAVE_SMEM
5926 my_free(shared_memory_base_name);
5927#endif
5928 /*
5929 No reason to explicitely COMMIT the transaction, neither to explicitely
5930 UNLOCK TABLES: these will be automatically be done by the server when we
5931 disconnect now. Saves some code here, some network trips, adds nothing to
5932 server.
5933 */
5934err:
5935 dbDisconnect(current_host);
5936 if (!path)
5937 write_footer(md_result_file);
5938 free_resources();
5939
5940 if (stderror_file)
5941 fclose(stderror_file);
5942
5943 return(first_error);
5944} /* main */