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.", &current_host,
398    &current_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    &current_user, &current_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("&lt;", xml_file);
1910       break;
1911     case '>':
1912       fputs("&gt;", xml_file);
1913       break;
1914     case '&':
1915       fputs("&amp;", xml_file);
1916       break;
1917     case '\"':
1918       fputs("&quot;", 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, &gtid_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, &gtid_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