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