~drizzle-trunk/drizzle/development

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