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