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